🎬 第九章 H.264编解码基础
📄 一句话概括

编码与解码是两条反向的流水线:看起来几乎对称,代价却差一个量级——因为搜索只在编码端发生。

📝 本节和前面几节的关系

9.2.1 列了六项技术,这一节看它们按什么顺序跑起来。

一、两条流水线

把编码与解码的步骤并排写出来,镜像关系一眼可见: 编码:划分宏块 → 帧内/帧间预测 → 变换量化 → 熵编码 → 组 NAL 输出; 解码:解析 NAL → 熵解码 → 反量化反变换 → 预测重建 → 去块滤波输出; 中间的转换点是熵编码——它之前是【编码域】,之后是【像素域】。 所以两条流水线在这个点上镜像对称。

二、两处不对称

但对称只是表面,有两处根本性的不对称: 一是编码端有【预测的搜索】,解码端没有——运动矢量与预测模式都写在码流里,解码端直接读; 二是编码端也要做反量化与重建——因为下一帧的预测必须用重建帧(第 8.2 节的反馈支路); 所以编码器内部同时跑着正向与反向两条计算,工作量大得多。 这直接解释了为什么播放总比导出轻松。

三、去块滤波放在哪一端

去块滤波在两条流水线里都出现,位置值得注意: 解码端——放在最后,输出前抹平块边界; 编码端——放在重建之后,而且滤波结果要存回参考帧缓冲; 所以它不是一个显示阶段的美化,而是编码环路的一部分; 这也意味着滤波强度等参数必须写进码流,让两端做出同样的处理。 凡是会影响后续帧的处理,都必须两端严格一致。

四、为什么流程要按【宏块】走

H.264 最小的完整处理单位是宏块,而不是整帧: 帧内预测要用左邻与上邻已重建的像素——所以必须从左到右、从上到下; 帧间预测要对每个宏块单独选分块方式与矢量; 量化是在宏块级分配 QP 的(可以有 QP 偏移); 所以【宏块】既是数据单位,也是决策单位与依赖单位(第 8.3.6 节)。 这种串行依赖是编码并行化的主要障碍,也是各种【切片并行】方案要绕开的难点。

五、从流程看性能优化

理解了流程,就能理解工程上那些优化手段为什么有效: 切片(Slice)并行——片与片之间可以独立解码,把串行依赖切开; Lookahead 前瞻——提前分析后面几帧的内容,让码率分配更聪明,代价是延迟; 只跑必要步骤——解码端省掉搜索,硬件解码器因此可以做得又小又省电; 所有优化的共同点:在依赖图里找能并行的部分,或者干脆去掉某些步骤。

六、动手 Demo:编码与解码,两条反向的流水线

H.264 的编码流程与解码流程几乎是镜像关系。

enc = ["划分宏块", "帧内或帧间预测", "变换量化", "熵编码", "组 NAL 输出"]
dec = ["解析 NAL", "熵解码", "反量化反变换", "预测重建", "去块滤波输出"]
for i, (a, b) in enumerate(zip(enc, dec), 1):
    print("第 %d 步  编码 %-14s 解码 %s" % (i, a, b))

实跑输出:

--------------------------------------------------------------------
编码与解码,两条反向的流水线
--------------------------------------------------------------------

H.264 的编码流程与解码流程几乎是镜像关系。

  步骤   编码端              解码端
  --------------------------------------------------------
  1    划分宏块             解析 NAL
  2    帧内或帧间预测          熵解码
  3    变换量化             反量化反变换
  4    熵编码              预测重建
  5    组 NAL 输出         去块滤波输出

  两个不对称之处,正是前面反复讲过的:
  **一是编码端有【预测的搜索】,解码端没有**——矢量直接读;
  **二是编码端也要做反量化与重建**,因为下一帧的预测必须用重建帧。
  所以两条流水线**看起来对称,代价却差一个量级**(第 8.2 节)。

两个不对称之处:编码端有搜索,解码端没有;编码端还要做反量化与重建,因为预测必须用重建帧。 所以两条流水线看起来对称,代价却差一个量级。

30 秒实验

  1. 拿同一个视频,对比【播放】与【用 FFmpeg 重新编码】时的 CPU 占用。
  2. 差距的来源就是本节说的那两处不对称——搜索与重建。

常见误区

  1. 以为编码解码是严格的逆运算。编码端多了搜索与重建,不是简单逆过程。
  2. 以为去块滤波只是显示美化。它结果会回到参考帧缓冲,影响后续帧。
  3. 以为整帧一起处理。H.264 以宏块为决策与依赖单位,串行顺序不能乱。
自测三问(点开对答案) 1. 编码与解码流程的镜像转换点在哪? —— 熵编码/熵解码——之前是编码域,之后是像素域。 2. 两处不对称分别是什么? —— 编码端有预测搜索,且必须做反量化与重建以生成参考帧。 3. 为什么去块滤波参数要写进码流? —— 它影响后续帧的重建,两端必须做出一致的处理。

相关笔记