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

H.264 把自己分成两层:VCL 只管压得小,NAL 只管装得进——把【怎么压】和【怎么传】彻底拆开,这是它成为通用标准的关键设计。

📝 本节和前面几节的关系

9.1.2 讲了码流内部的分层,这一节讲H.264 整体上的两层划分,两者层次不同,别混淆。

一、两层各管一件事

H.264 的整个体系切成两块: VCL(视频编码层)——真正的压缩数据:片、宏块、残差;它只关心压得小不小; NAL(网络抽象层)——给 VCL 数据加一个头,把数据切成适合网络传输的单元;它只关心传得对不对。 所以【编码】与【传输】被彻底解耦,两边可以各自独立演进。

二、为什么要这么分

在 H.264 之前,视频编码标准是【面向具体网络】设计的: H.261 假设跑在 ISDN 上,H.263 假设跑在电路交换网或包网上; 网络一变,标准就得跟着打补丁; 而 H.264 的时代要同时面对 RTP、TS、MP4、文件、甚至不可靠的移动网络; 于是它干脆把【适配网络】这件事单独抽成一层——这就是 NAL 的由来。 一层不够用的地方,分两层往往是最省事的解法。

三、NAL 做了什么

NAL 的工作听起来很简单,但解决的都是真问题: 切片——把 VCL 数据切成一个个 NAL 单元,每个都带一个字节的头; 标识——头里的类型字段告诉接收方这一包是 SPS、PPS 还是片数据; 优先级——nal_ref_idc 字段标记重要性,网络拥塞时优先保它; 边界——加起始码或长度前缀,让接收方能切回原来的单元。 所以 NAL 层不碰任何压缩逻辑,它是纯粹的信封。

四、分层的代价

拆成两层不是没有成本,代价主要有两条: 多了一层头——每个 NAL 单元至少多 1 字节,对极小分辨率(比如低码率监控)来说占比不小; 错误处理变复杂——丢包时要判断【丢的是哪一类 NAL】,不同类型的丢失后果完全不同(丢 PPS 比丢一个片严重得多); 但从整体看,换来的通用性远远值得。 这也解释了为什么后来的 H.265 直接沿用了这套两层结构(第十一章)。

五、和 9.1.2 的区别

这里有一个很容易混淆的地方,专门澄清一句: VCL/NAL 是【系统级】的两层划分——一个管编码内容、一个管传输封装; 9.1.2 的五层是【码流内部】的层级划分——序列、图像、片、宏块、子块; 两者不在同一维度上:五层全部属于 VCL 的内容,而它们最终都会被装进一个个 NAL 单元往外传。 所以问题的正确提法是:这五层的元素被切分到哪些 NAL 单元里?

六、动手 Demo:VCL 与 NAL 两层

H.264 把自己的数据分成两个层面,各自解决一类问题。

rows = [("VCL", "视频编码层", "片、宏块的编码数据"),
        ("NAL", "网络抽象层", "给 VCL 数据加头,适配网络")]
for a, b, c in rows:
    print("%-4s %-10s %s" % (a, b, c))

实跑输出:

--------------------------------------------------------------------
VCL 与 NAL 两层
--------------------------------------------------------------------

H.264 把自己的数据分成两个层面,各自解决一类问题。

  层      全称           装什么
  ------------------------------------------------------------
  VCL     视频编码层     片、宏块的编码数据(真正的压缩结果)
  NAL     网络抽象层     给 VCL 数据加头,适配各种传输网络

  这么分的理由只有一条:**把【怎么压】和【怎么传】拆开。**
  **VCL 只管压得小,NAL 只管装得进——两边各自演进,互不影响。**
  于是同一份 H.264 码流可以塞进 RTP、TS、MP4,甚至直接走文件。

这么分的理由只有一条:把【怎么压】和【怎么传】拆开。 VCL 只管压得小,NAL 只管装得进——两边各自演进、互不影响。

30 秒实验

  1. 把同一个视频分别封装成 MP4 与 TS,对比两者的文件大小。
  2. 差别主要来自封装开销——NAL 层的数据是一样的,信封换了而已。

常见误区

  1. 把 VCL/NAL 与五层结构当成一回事。它们分属系统级与码流内部两个维度。
  2. 以为 NAL 会参与压缩。它只是加头与切片,不碰任何编码逻辑。
  3. 以为两层结构是多余的。它正是 H.264 能同时服务文件与流媒体的原因。
自测三问(点开对答案) 1. VCL 与 NAL 分别负责什么? —— VCL 负责编码内容,NAL 负责加头与切片,适配网络传输。 2. 分成两层解决了什么问题? —— 把编码与传输解耦,让同一份码流能适配多种网络与封装。 3. NAL 头里的优先级字段有什么用? —— 标记该单元的重要性,网络拥塞时优先保障关键数据。

相关笔记