关于h.264:ffmpeg使用h264为MPEG-TS产生奇怪的NAL后缀

ffmpeg producing strange NAL suffixes for MPEG-TS with h264

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

我已经在HEX中转储了编码和解码帧数据,发现了这些差异:

在帧的开头添加了NAL分隔符:

1
2
3
4
5
6
+ 00
+ 00
+ 00
+ 01
+ 09
+ f0

对我来说绝对合法。

但是奇怪的事情来了:

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
+ e0
+ 00
+ 00
+ 00
+ 01
+ ce
+ 8c
+ 4d
+ 9d
+ 10
+ 8e
+ 25
+ e9
+ fe

(恰好以添加的e0字节开头)

我试图理解这可能意味着什么。如果00000001是NAL标头,则其后跟ce字节,其中绝对零的被禁止的零位等于1.

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

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选项构建


所以我找到了问题。

TL; DR:

1
pInputFormatContext->flags |= AVFMT_FLAG_KEEP_SIDE_DATA;

avformat_open_input

之后的

解释:

我在调试时发现AVPacket在执行

时损坏在utils.c:1661

1
av_packet_merge_side_data(pkt);

更何况,我发现了之前看到的其他数据的子序列:

1
#define FF_MERGE_MARKER 0x8c4d9d108e25e9feULL

用于av_packet_merge_side_data

AVPacket中Side的数据类型为AV_PKT_DATA_MPEGTS_STREAM_ID (78),仅在多路分解器和多路复用器中使用,而在编解码器中不使用。

我对从文件

中读取帧数据所用的av_read_frame注释已感到困惑

1
2
3
4
5
6
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的文档问题,它向我保证了"将返回文件中存储的内容",而没有提及可以添加一些其他数据。