x264直播(4) - http-mp4直播输出
代码中有接口支持mp4输出但是需要gpac或者lsmash库, 我选择使用lsmash, lsmash可以从github下载
- lsmash编译同前面的的方法类似, 有个修改比较麻烦: 结构体指定成员初始化
- 有个改动比较多的地方 box_default.c
#define INITIALIZE_PREDEFINED_CHILD_BY_DEFAULT_CONSTANT_PTR( child_name )
.child_name = (isom##child_name##t *)&isom##child_name##_box_default
添加一个
#define INITIALIZE_BOX_MEMBER( box_name, child_name )
uint8_t box_name####child_name = (uint8_t)((isom_##box_name##box_default.child_name = (isom##child_name##t *)&isom##child_name##_box_default));
_#define DEFINE_SIMPLE_CONTAINER_BOX_DEFAULT_CONSTANT_2( box_name, _0 )
DEFINE_SIMPLE_CONTAINER_BOX_DEFAULT_CONSTANT_TEMPLATE( box_name,
EXPAND_VA_ARGS( INITIALIZE_PREDEFINED_CHILD_BY_DEFAULT_CONSTANT_PTR( _0 ) ) )
修改为
_#define DEFINE_SIMPLE_CONTAINER_BOX_DEFAULT_CONSTANT_2( box_name, _0 )
DEFINE_SIMPLE_CONTAINER_BOX_DEFAULT_CONSTANT_TEMPLATE( box_name, );
INITIALIZE_BOX_MEMBER(box_name, _0 )
以此类似
-
遇到一个奇怪的问题, 很多结构体无法找到符号 有const属性, 把const去掉后就正常了, 这个问题尝试了比较久的时间
-
在调试过程中用到VS的一些选项
复杂宏调试时, 可以选项 C++\预处理\预处理到文件 开启, 可以生成宏展开后的全部文字
链接时重复定义可以选项 链接\常规\强制文件输出 开启
链接时手动分析lib信息可以在 链接\命令行 添加/VERBOSE 获取详细信息
编译时VS调试信息可以修改来输出, 在IDE\devenv.exe.config, 添加如下
-
编译成功后可以输出mp4格式文件了
-
http-mp4 输出类似前面的flv, 集成mp4成一个 http_mp4_output
-
mp4_output, 发现文件延迟非常大, 修改选项改善 file_param->max_chunk_duration = 0.1;
-
测试 http_mp4_output, 发现根本无法网络播放, 查找原因,
原因: 发现mp4文件播放前必须读取一堆box, 主要是moov, 正常文件moov是mp4的尾部, 所以http肯定是无法播放的
尝试 moov的定位在头部, 需要seek写入, 修改参数seek 让 file->bs->unseekable 有效, 发现还是不行
尝试 查看代码发现一个 LSMASH_FILE_MODE_FRAGMENTED, 修改 mp4->b_fragments = TRUE;
可以了, 就是把文件模式改成碎片模式 -
测试 http_mp4_output, 发现不能在中间连接, 连接上黑屏, 只能在启动后立即连接, 也就无法多人直播
尝试 头部保存更多个数据, 无效
尝试 使用 p_param->b_repeat_headers = 1; 无效
尝试 mp4->b_force_flush_pool = 1; 无效
尝试 mp4->file_param->force_moof_base = 1; 可以了
原因: mp4的帧是作为sample处理, 这种方式是需要前面box的数据, 没有前面的数据, 解码就是失败, VLC打开就黑屏卡死, 其中主要的就是moof,
在代码中有选项 file->allow_moof_base, 这个是根据版本来的, 代码默认是 ISOM_BRAND_TYPE_ISOM,
allow_moof_base 需要 ISOM_BRAND_TYPE_ISO5以上才可支持
自己修改代码添加选项 param->force_moof_base, 来控制allow_moof_base
这个问题找了比较长时间, 还改了lsmash 的一些代码 -
测试 http_mp4_output, 发现延迟比较大, 原因在于 frame进入了sample_pool, 需要到关键帧才会写入出来
如果强制关键帧, 可避免这个问题但是压缩率就极大降低了
添加选项 mp4->b_force_flush_pool = 1; 让立即写出来
原来代码
if( p_mp4->b_fragments && p_mp4->i_numframe && p_sample->prop.ra_flags != ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE )
修改为
if( (p_mp4->b_fragments && p_sample->prop.ra_flags != ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE) ||
p_mp4->b_force_flush_pool
)
- 测试 http_mp4_output, 发现效果已经很好了, flv延迟1秒, mp4 稍微多点, 2s左右, 因为mp4另外做了复杂的封装处理