19

在仔细阅读FFmpeg Bitstream Filters Documentation之后,我仍然不明白它们的真正用途。

该文件指出过滤器:

执行比特流级别修改而不执行解码

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

4

1 回答 1

48

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

对于“原始”(附件b)H264(.h264/.bin/.264 文件),单个最终单元数据(sps/pps 标头比特流或 cabac 编码的帧数据)以最终单元序列连接,并以开头代码 (00 00 01 XX) 介于两者之间,其中 XX 是最终单元类型。(为了防止最终数据本身有 00 00 01 数据,它被 RBSP 转义。)所以一个h264 帧解析器可以简单地在开始代码标记处剪切文件。他们搜索从 00 00 01 开始(包括 00 00 01)的连续数据包,直到并排除下一个 00 00 01 出现。然后他们解析 nal 单元类型和 slice header 以找到每个数据包属于哪个帧,并返回一组 nal组成一帧的单元作为h264 解码器的输入。

但是,.mp4 文件中的 H264 数据是不同的。您可以想象,如果多路复用格式中已经有长度标记,那么 00 00 01 开始代码可以被认为是多余的,就像 mp4 的情况一样。因此,为了每帧节省 3 个字节,他们删除了 00 00 01 前缀。他们还将 PPS/SPS 放在文件头中,而不是在第一帧之前添加它,而且这些也错过了它们的 00 00 01 前缀。所以,如果我将这个输入到 h264 解码器中,它需要所有 nal 单元的前缀,它就行不通了。h264_mp4toannexb _比特流过滤器通过识别文件头的提取部分中的 pps/sps 来解决这个问题(ffmpeg 称之为“额外数据”),在每个帧数据包中添加起始码,并在输入之前将它们连接在一起在 h264 解码器中。

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

这种“比特流调整”有助于保持解码器简单和统一的其他情况,但允许我们支持碰巧存在于野外的所有文件变体:

  • mpeg4 (divx) b 帧解包(为了在 AVI 中获得像 IBP 这样编码为 IPB 的 B 帧序列并获得正确的时间戳,人们提出了 B 帧打包的概念,其中 IBP / IPB 被打包在帧中我-(PB)-(),即第三个数据包是空的,第二个有两个帧。这意味着在解码阶段与 P 和 B 帧相关联的时间戳是正确的。这也意味着一个数据包有两帧输入数据,这违反了 ffmpeg 的一帧进一帧输出概念,因此我们编写了一个 bsf 将数据包分成两部分 - 同时删除标记表示该数据包包含两个帧,因此是 BSF 而不是解析器 - 在将其输入解码器之前。实际上,这解决了帧多线程的其他难题。VP9 做同样的事情(称为超帧),但在解析器中拆分帧,因此解析器/BSF 拆分在理论上并不总是完美的;也许VP9应该被称为BSF)
  • hevc mp4 到附件b 的转换(与上述相同,但适用于 hevc)
  • aac adts 到 asc的转换(这与 h264/hevc 附件 b 与 mp4 基本相同,但用于 aac 音频)
于 2015-08-16T12:27:55.093 回答