MP4文件写SEI信息保存H264文件后FFmpeg推流RTMP有报错信息导致前端播放器播放停止问题分析
问题
这几天开发一个带字幕信息MP4将MP4转H264文件并将每帧字幕信息信息写入H264文件中每帧SEI中。可以将SEI写入H264文件中。但是在使用FFmpeg将h264文件推流成RTMP视频流时报错.报错信息类似如如下:
SEI type 5 size 9920 truncated(被截取的) at 6136 当出现如此错误,FFmpeg推流可以继续推流,但是网页端播放器播放会终止。
查阅相关资料说是需要防竞争。但是很奇怪的是我写的另一个程序拉流然后推流程序,也是每一帧写入了SEI信息(同样的写SEI方法)但是没有出现这样的问题。这个很让我疑惑。难道每帧写到h264和推流每一帧难道不一样吗?
问题分析
在网络传输h264数据时,一个AVPacket包就是一个NALU,解码器可以很方便的检测出NAL分界和解码。但是如果编码数据存储为一个文件,原来的解码器将无法从数据流中分别出每个NAL的起始位置和终止位置,为此h.264用起始码来解决这一问题。 H.264编码时,在每个NAL前添加起始码 0x000001,解码器在码流中检测到起始码,当前NAL结束。为了防止NAL内部出现0x000001的数据,h.264又提出'防止竞争 emulation prevention"机制,在编码完一个NAL时,如果检测出有连续两个0x00字节,就在后面插入一个0x03。当解码器在NAL内部检测到0x000003的数据,就把0x03抛弃,恢复原始数据。这样的解释似乎能说明拉流然后推流RTMP不会出现 'SEI type 5 size 9920 truncated(被截取的) at 6136'错误问题。而H264 FFmpeg推流会出现这个报错的问题.
解决方案
按照分析原理就是在添加SEI信息时如果SEI转二进制字节时如果出现0x0000时插入0x03起到避免SEI数据内部出现0x000000情况,导致与NALU单元标识(0x000001后0x00000001)一样情况,导致写入H264文件后,FFmpeg解析NALU单元时不能正确解析除NALU单元(可能把部分SEI中出现了0x0000作为SEI截断单元)这个时为什么报SEI type 5 size 9920 truncated(被截取的) at 6136 的原因。
错误的思路
错误思路一
不应该在写完所有的SEI到h264文件之后再去加0x03。因为这是你不太好能区分NALU单元(可能能区分,但也增加处理难度)
错误思路二
在AVPacket包调用了如下代码实现AVPacket包自动添加0x03防竞争字节。但是导视频帧有拉花问题,帧也有丢失。具体问题未知
AVBitStreamFilterContext* bsf = av_bitstream_filter_init("h264_metadata");
av_bitstream_filter_filter(bsf, codec_ctx, NULL, &dst_pkt->data, &dst_pkt->size, src_pkt->data, src_pkt->size, 0);
av_bitstream_filter_close(bsf);
最终解决办法
觉得肯定能行的思路是将SEI信息转换为字节准备写入AVPacket的SEI单元之前,对SEI字节进行加入0x03防竞争处理。
参考
1.H.264裸流结构分析
2.【知识点】H264, H265硬件编解码基础及码流分析
3.H264 HEVC中的防竞争机制(C++ 实现)
4.【FFmpeg】H.264 格式分析 ② ( 网络抽象层单元 NALU | NALU 功能结构 | VCL 视频编码层 | NAL 网络提取层 | H.264 封装模式 - annexb 模式 )
5.H.264 NAL层解析(0x00000001,编码,打包,NALU)
浙公网安备 33010602011771号