3. 图像划分:CTU / CU / PU / TU 与四叉树结构

H.265 相比 H.264 最大的变化在哪?我个人觉得,就是图像划分方式彻底变了。H.264 用宏块,大小固定 16x16。H.265 呢?它搞了一套 CTU、CU、PU、TU 的层级体系,配合四叉树递归划分。说白了,就是把一张图切成无数个大小不一的块,然后针对每个块做最合适的编码。

你想想看,一张画面里,有的区域很平坦(比如天空),有的区域细节特别多(比如树叶)。如果都用同样大小的块去处理,要么平坦区域浪费码率,要么细节区域压缩质量不够。H.265 这套划分机制,就是为了解决这个矛盾。

3.1 最大编码单元(CTU)与最小编码单元

CTU,全称 Coding Tree Unit,编码树单元。它是 H.265 图像划分的起点。一张 4K 或 1080p 的帧,首先会被分割成若干个 CTU。CTU 的大小是可配置的,标准支持 64x64、32x32 和 16x16。实际项目中,64x64 是最常用的。

核心概念:CTU 是四叉树的根节点。一个 CTU 可以递归向下划分,直到达到最小编码单元(SCU,Smallest Coding Unit)。SCU 的大小通常是 8x8 或 4x4。

我刚开始接触 HEVC 时,有个误区:以为 CTU 越大越好。64x64 确实能带来更高的压缩比,但编码复杂度也直线上升。后来在优化一个实时编码器时,我吃过这个亏——64x64 的 CTU 在软件编码器上跑不动,延迟飙到 200ms。最后不得不根据分辨率动态调整:1080p 用 64x64,720p 以下用 32x32。

参数 CTU(最大编码单元) SCU(最小编码单元)
典型大小 64x64 8x8
作用 四叉树根节点,划分起点 四叉树叶节点,划分终点
对码率影响 越大压缩比越高 越小细节保留越好
对复杂度影响 越大编码越慢 越小编码越慢

3.2 四叉树划分结构

四叉树是 H.265 划分的核心算法。它的逻辑很简单:一个节点(方块)可以分成四个子节点(四个小方块)。每个子节点又可以继续分,直到满足条件为止。

为什么会用四叉树?因为图像内容在空间上往往是自相似的。平坦区域不需要细分,纹理复杂区域需要细分到小块。四叉树正好能自适应地表达这种结构。

下面这张图展示了一个 64x64 CTU 经过四叉树划分后的典型结果:

四叉树划分示例(64x64 CTU) 64x64 32x32 32x32 32x32 32x32 16x16 16x16 16x16 8x8 四叉树结构 64 32 32 32 16 8 划分规则 深度0: 64x64 深度1: 32x32 深度2: 16x16 → 深度3: 8x8

实战技巧:四叉树的深度直接决定了编码质量与速度的平衡。深度越深,块越小,细节保留越好,但码率和耗时都会增加。我一般建议:深度不超过 3 层(即最小块 8x8),再往下分收益就很低了。

3.3 CU、PU、TU 三者的关系

CTU 划分完成后,每个叶节点就是一个 CU(Coding Unit,编码单元)。但 CU 只是负责「这块归我管」,具体怎么编码,还要看 PU 和 TU。

这三者的分工很明确:

  • CU(编码单元):决策单元。决定用帧内还是帧间预测,以及划分方式。
  • PU(预测单元):预测单元。负责具体的预测操作,比如运动估计、帧内方向选择。
  • TU(变换单元):变换单元。负责残差数据的 DCT 变换和量化。

一个 CU 可以包含多个 PU 和多个 TU。PU 的划分方式决定了预测的精细程度,TU 的划分方式决定了变换的粒度。它们之间是独立的,但又有联系——PU 的边界会影响 TU 的划分。

注意:PU 和 TU 的划分不能跨越 CU 边界。也就是说,一个 CU 内部的 PU 和 TU 再怎么分,都不能跑到隔壁 CU 去。这是 H.265 标准强制规定的。

3.4 PU 的划分模式

PU 的划分取决于 CU 用的是帧内预测还是帧间预测。帧内预测的 PU 只能是正方形(2Nx2N 或 NxN),而帧间预测的 PU 可以是非正方形的矩形。

帧间预测的 PU 划分模式有 8 种:

模式 描述 适用场景
2Nx2N 不划分,整个 CU 作为一个 PU 平坦区域、静止背景
2NxN 水平分成两个矩形 PU 水平方向有运动边界
Nx2N 垂直分成两个矩形 PU 垂直方向有运动边界
NxN 分成四个正方形 PU 复杂运动区域
2NxnU 上 1/4、下 3/4 不对称划分 物体边缘在 CU 上部
2NxnD 上 3/4、下 1/4 不对称划分 物体边缘在 CU 下部
nLx2N 左 1/4、右 3/4 不对称划分 物体边缘在 CU 左侧
nRx2N 左 3/4、右 1/4 不对称划分 物体边缘在 CU 右侧

我曾经在优化运动估计时,发现不对称划分模式(2NxnU 等)对斜向运动的物体特别有效。比如一个球从画面左上向右下运动,用对称划分很难精确匹配,但不对称划分就能很好地贴合运动边界。不过,不对称划分的计算量也大,低功耗设备上建议禁用。

3.5 TU 与变换块

TU 负责残差数据的变换。H.265 支持 4x4、8x8、16x16 和 32x32 四种大小的 DCT 变换。TU 的划分也是基于四叉树,但它的根节点是 CU,而不是 CTU。

TU 的大小选择会影响编码质量:

  • 大 TU(16x16、32x32):能量集中效果好,适合平坦区域,码率低。
  • 小 TU(4x4、8x8):细节保留好,适合纹理复杂区域,码率高。

关键点:TU 的划分深度不能超过 CU 的划分深度。比如一个 16x16 的 CU,TU 最大只能是 16x16,最小可以是 4x4。但 TU 不能比 CU 还大。

3.6 实际编码中的划分策略

说了这么多理论,实际编码器里是怎么选划分方式的?我总结了几条经验:

  1. 先粗分,再细分:从 CTU 开始,先尝试不划分(2Nx2N),计算 RD cost。如果效果不好,再递归向下划分。这叫「自上而下」的搜索策略。
  2. 提前终止:如果当前 CU 的 RD cost 已经足够低,就不需要再往下分了。这个阈值需要根据码率控制目标动态调整。
  3. 跳过对称划分:在低延迟场景下,不对称划分(2NxnU 等)的收益往往不如直接分成更小的 CU。我一般会直接跳过不对称模式,省下 20%-30% 的编码时间。
  4. TU 大小跟随 CU:如果 CU 是 32x32,TU 优先尝试 32x32。如果残差能量集中在低频,大 TU 就够了;如果残差有高频细节,再递归分小。

嗯,这里要注意:划分决策是编码器最耗时的部分。一个 1080p 的帧有大约 510 个 64x64 CTU,每个 CTU 平均要评估几十种划分组合。如果全遍历,编码时间会爆炸。所以实际产品中,都会用各种启发式算法来加速。

我的建议:如果你在写自己的编码器,先实现一个简单的「固定深度划分」版本。比如所有 CU 固定为 16x16,PU 只用 2Nx2N。跑通了再逐步加入四叉树递归和不对称模式。一步到位容易出 bug,而且性能调优无从下手。

最后说一句,CTU/CU/PU/TU 这套体系,是 H.265 相比 H.264 最大的进步,也是最大的复杂度来源。理解了它,你就掌握了 HEVC 的一半精髓。