mediacodec h264 硬解首帧延迟一种可能优化
1. 问题
在 mediacodec 解码 h264 视频的时候,有时候会出现首帧出来延迟的情况。一般来说,如果视频流不包含 B 帧,应该是丢一个完整包进去就能解码得到一帧,但是有些视频流不是这种情况。首帧可能会延迟几个包才出来
2. 分析
首先我们需要明确一个知识点就是,解码器一般会对解码出来的帧按 PTS 进行重拍后再输出给开发者。
对一个解码器来说,如果存在 B 帧的情况,由于解码顺序不等于显示顺序,且解码器输出时是严格按照显示循序输出的,所以解码器内部需要维护一个队列,将解码得到的帧重排序,并以正确的显示顺序输出。
在 h264 语法标准中,sps vui 部分有一个 num_reorder_frames 参数,此参数就是用于控制显示帧排序缓冲区大小的参数。
有可能 sps 并没有携带 vui 部分,如果没有携带,则解码器采用预设参数决定缓冲区大小
对于解码器来说,其预先并不知道是否存在 B 帧,所以如果没有 sps vui 指定 num_reorder_frames 参数,那么有些解码器会默认维护一个缓冲区,以正确处理后续包可能存在 B 帧的情况
重排序缓冲区的存在就造成了解码延迟的发生,解码出来的帧会先缓存起来
3. 解决
解决办法就是开发者手动解析码流,得到 sps 时,手动修改或者添加 sps vui 字段,将 num_reorder_frames 设置为 0 (当然这是针对开发者确定码流确定没有 B 帧的情况)
可以参考:
https://github.com/google/ExoPlayer/issues/8514#issuecomment-769726637
注意,h264 语法中的 max_num_ref_frames 参数,指定的是解码时参考帧缓存队列大小,与 num_reorder_frames 不同,不要混淆
4. 总结
对于有些视频,sps 会携带 sps::vui 以及 num_reorder_frames 参数,有的视频没有携带
对于同一个不带 sps::vui::num_reorder_frames 参数的视频,测试了 ffmpeg 自带的软解码器,不对码流做任何修改,首帧也能够 0 延时出来,所以能够验证不同解码器维护缓冲区的默认策略不太一样
对于携带了 sps::vui::num_reorder_frames 参数的视频,测试了 ffmpeg 自带的软解码器,不对码流做任何修改,解码会延迟 num_reorder_frames 指定的帧数,所以 ffmpeg 自带软解码器会遵循 num_reorder_frames 制定的值