ffmpeg 使用 h264 为 MPEG-TS 生成奇怪的 NAL 后缀

ffmpeg producing strange NAL suffixes for MPEG-TS with h264

我正在制作 h264 流分析器,在写入和读取用 MPEG-TS 打包的同一帧时发现了奇怪的 ffmpeg 行为。

我已经转储了 HEX 格式的编码和解码帧数据,并发现了这些差异:

在帧的开头添加了NAL定界符:

+ 00
+ 00
+ 00
+ 01
+ 09
+ f0

这对我来说绝对合法。

但是奇怪的事情来了:

如果当前数据包不是最后一个则添加一些后缀(即最后写入的帧中没有这个后缀)。并将此后缀添加到当前读取帧(即这不是下一帧的前缀)。

+ e0
+ 00
+ 00
+ 00
+ 01
+ ce
+ 8c
+ 4d
+ 9d
+ 10
+ 8e
+ 25
+ e9
+ fe

(刚好以 e0 字节开始)

我正在尝试理解这可能意味着什么。如果 00000001 是 NAL header,那么它后面跟着 ce 字节,禁止 zero-bit 等于 1,这绝对是坏的。

我正在使用来自 ffmpeg github repo 最后与 89092fafdde894c6ba4d4f8e3cd1cce0d68bfc22 commit 合并的 fork。

ffmpeg 使用 --disable-everything --enable-encoder=libopenh264 --enable-muxer=mpegts --enable-demuxer=mpegts --enable-protocol=file --enable-parser=h264 --enable-decoder=libopenh264 --enable-shared --disable-static --disable-programs --disable-doc --enable-libopenh264 选项构建

所以我找到了问题。

长话短说:

pInputFormatContext->flags |= AVFMT_FLAG_KEEP_SIDE_DATA;

avformat_open_input

之后

解释:

我在调试时发现 AVPacket 在执行

时在 utils.c:1661 处损坏
av_packet_merge_side_data(pkt);

更重要的是,我发现了之前看到的附加数据的子序列:

#define FF_MERGE_MARKER 0x8c4d9d108e25e9feULL

用于av_packet_merge_side_data

Side 在 AVPacket 中的数据类型是 AV_PKT_DATA_MPEGTS_STREAM_ID (78),它只在 demuxers 和 muxers 中使用,但不在编解码器中使用。

我读到 av_read_frame 的注释时感到很困惑,我曾用它从文件中读取帧数据:

Return the next frame of a stream.
This function returns what is stored in the file, and does not validate
that what is there are valid frames for the decoder. It will split what is
stored in the file into frames and return one for each call. It will not
omit invalid data between valid frames so as to give the decoder the maximum
information possible for decoding.

我完全不知道为什么流标记在我使用的两台 PC 上不同,但禁用将边数据合并到数据包的数据中就可以了。

所以我认为这是 ffmpeg 的文档问题,它向我保证 "I will be returned what is stored in file" 没有提到可以添加一些额外的数据。