ffmpeg 中的比特流过滤器是什么?

What are bitstream filters in ffmpeg?

仔细阅读了FFmpeg Bitstream Filters Documentation,我还是不明白它们到底是干什么用的

文档指出过滤器:

performs bitstream level modifications without performing decoding

谁能进一步向我解释一下?用例会大大澄清事情。此外,还有明显不同的过滤器。它们有何不同?

让我举例说明。 FFmpeg 视频解码器通常通过将每次调用的一个视频帧转换为 avcodec_decode_video2 来工作。因此,输入预计为 "one image" 比特流数据。让我们考虑一下从文件(磁盘字节数组)到图像的问题。

对于"raw"(附件b)H264(.h264/.bin/.264 文件),单个最终单元数据(sps/pps header 比特流或cabac-encoded帧数据)连接在一系列最终单元中,中间有一个起始代码(00 00 01 XX),其中 XX 是最终单元类型。 (为了防止nal数据本身有00 00 01数据,所以进行了RBSP转义。)所以一个h264 frame parser can simply cut the file at start code markers. They search for successive packets that start with and including 00 00 01, until and excluding the next occurence of 00 00 01. Then they parse the nal unit type and slice header to find which frame each packet belongs to, and return a set of nal units making up one frame as input to the h264 decoder.

不过,.mp4 文件中的 H264 数据不同。你可以想象,如果 muxing 格式中已经有长度标记,那么 00 00 01 开始代码可以被认为是多余的,就像 mp4 的情况一样。因此,为了每帧节省 3 个字节,他们删除了 00 00 01 前缀。他们还将 PPS/SPS 放在文件 header 中,而不是在第一帧之前添加它,并且这些也丢失了它们的 00 00 01 前缀。因此,如果我将其输入 h264 解码器(它需要所有最终单元的前缀),它就无法工作。 h264_mp4toannexb 比特流过滤器通过识别文件 header 的提取部分中的 pps/sps(ffmpeg 称其为 "extradata")来解决此问题,并在单个帧的前面加上每个 nal带有起始码的数据包,并在将它们输入 h264 解码器之前将它们连接在一起。

您现在可能会觉得 "parser" 和 "bitstream filter" 之间有非常细微的区别。这是真的。我认为官方定义是解析器获取一系列输入数据并将其拆分为帧而不丢弃任何数据或添加任何数据。解析器唯一做的就是改变数据包边界。另一方面,允许比特流过滤器实际修改数据。我不确定这个定义是否完全正确(参见下面的 vp9),但这是 mp4toannexb 是 BSF 而不是解析器的概念原因(因为它添加了 00 00 01 前缀)。

其他 "bitstream tweaks" 有助于保持解码器简单和统一的情况,但允许我们支持碰巧存在于野外的所有文件变体:

  • mpeg4 (divx) b frame unpacking (to get B-frames sequences like IBP, which are coded as IPB, in AVI and get timestamps correct, people came up with this concept of B-frame packing where I-B-P / I-P-B is packed in frames as I-(PB)-(), i.e. the third packet is empty and the second has two frames. This means the timestamp associated with the P and B frame at the decoding phase is correct. It also means you have two frames worth of input data for one packet, which violates ffmpeg's one-frame-in-one-frame-out concept, so we wrote a bsf to split the packet back in two - along with deleting the marker that says that the packet contains two frames, hence a BSF and not a parser - before inputting it into the decoder. In practice, this solves otherwise hard problems with frame multithreading. VP9 does the same thing (called superframes), but splits frames in the parser,因此 parser/BSF 拆分在理论上并不总是完美的;也许 VP9 应该被称为 BSF)
  • hevc mp4 到 annexb 的转换(与上面相同,但对于 hevc)
  • aac adts to asc 转换(这与 h264/hevc annexb vs. mp4 基本相同,但对于 aac 音频)