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

H.264 把码流自顶向下分成五级:序列级、图像级、片级、宏块级、子块级——越往上写得越少,越往下越重复,丢一个 SPS 会让整段码流报废。

📝 本节和前面几节的关系

9.2 讲完了原理与流程,9.3 这三节回到码流本身,把它拆到字节级。

一、五级各自管什么

自顶向下,H.264 的分层结构是这五级: 序列级(SPS)——分辨率、帧率、档次、级别; 图像级(PPS)——熵编码方式、QP 初值; 片级(Slice header)——帧类型、参考帧列表、QP 偏移; 宏块级(宏块头)——分块方式、运动矢量差; 子块级(残差)——变换量化后的系数。

二、【片】这一级为什么重要

五级里最容易忽略、却最有工程价值的是【片】: 片是独立的解码单元——一个片可以在不理解其他片的情况下解出来; 这就给丢包提供了边界——一片丢了,其他片还能解(会有一块花屏); 也让并行成为可能——多片可以分给多个线程或核; 代价是每个片都要重新写片头、重新初始化上下文,压缩比会下降; 所以片切得越细,抗丢包越好、压缩比越差——又一组取舍。 直播与弱网场景常把一帧切成多个片,就是这个道理。

三、为什么【越往上越少】

这个规律不是刻意的,而是内容的重复程度决定的: 分辨率、帧率这些参数整段视频只有一套,写一次就够; 片头的部分字段变化也不多; 而每个宏块都有自己的分块方式与矢量——重复次数等于宏块数; 所以把稳定的信息提到上层,是压缩的常识(第 9.1.2 节)。 这也是为什么【丢上层参数】的后果远大于【丢几个宏块】。

四、参数集可以单独传输

SPS 与 PPS 还有一个特殊之处——它们是独立单元,不属于任何一帧: 可以被重复发送,也可以被单独缓存; 于是客户端中途加入时,只要收到 SPS/PPS + 一个 IDR,就能立刻开始播; 这正是 HLS/DASH 分片能无缝衔接的底层原因之一; 反过来,转封装或裁剪时如果弄丢了 SPS/PPS,文件就播不了——这是实际工作中很常见的一类故障。

五、从分层结构到码流字节

这一节给的是骨架,后面两节给的是血肉: 9.3.2 码流结构——这些层级按什么顺序排列在一段码流里; 9.3.3 NAL Unit——每个单元具体由哪些字节组成; 读这两个小节时,可以随时回头对照本节的五级目录,看每一级落在哪个 NAL 单元里。

六、动手 Demo:H.264 的五级分层结构

H.264 把码流自顶向下分成五级,每级各有自己的头。

rows = [("序列级", "SPS", "分辨率、帧率、档次、级别"),
        ("图像级", "PPS", "熵编码方式、QP 初值"),
        ("片级", "Slice header", "帧类型、参考帧、QP 偏移"),
        ("宏块级", "宏块头", "分块方式、运动矢量差"),
        ("子块级", "残差", "变换量化后的系数")]
for a, b, c in rows:
    print("%-6s %-14s %s" % (a, b, c))

实跑输出:

--------------------------------------------------------------------
H.264 的五级分层结构
--------------------------------------------------------------------

H.264 把码流自顶向下分成五级,每级各有自己的头。

  层级       头               管什么
  -----------------------------------------------------
  序列级     SPS              分辨率、帧率、档次、级别
  图像级     PPS              熵编码方式、QP 初值
  片级       Slice header     帧类型、参考帧、QP 偏移
  宏块级     宏块头           分块方式、运动矢量差
  子块级     残差             变换量化后的系数

  这套结构的意义在**重用**:
  **序列级的东西只写一次,图像级的变化少,越往下越具体、越重复。**
  所以丢一个 SPS,**后面成千上万个宏块一起报废**——这也是为什么 SPS/PPS 通常要重复发送。

这套结构的意义在重用:序列级只写一次,越往下越具体、越重复。 所以丢一个 SPS,后面成千上万个宏块一起报废——这也是 SPS/PPS 通常要重复发送的原因。

30 秒实验

  1. 用 FFmpeg 的 -f h264 把视频导出成裸码流,用十六进制工具看开头几个字节。
  2. 找到 0x67(SPS)与 0x68(PPS),它们就是五级结构最上面的两级。

常见误区

  1. 以为【片】只是数据分块。它是独立的解码单元,决定抗丢包与并发能力。
  2. 以为参数集属于第一帧。它们是独立单元,可以被单独发送与缓存。
  3. 以为分层只是【组织方式】。它直接决定丢包后果的严重程度。
自测三问(点开对答案) 1. H.264 码流分成哪五级? —— 序列级、图像级、片级、宏块级、子块级。 2. 【片】为什么重要? —— 它是独立解码单元,提供丢包边界与并行能力。 3. 丢一个 SPS 会有什么后果? —— 解码器不知道分辨率与参数,后续整段码流都无法解析。

相关笔记