2. H265编码结构:CTU、CU、PU、TU详解

H265(HEVC)相比H264,最大的变化之一就是编码结构。说白了,H264是以宏块(Macroblock)为基本单位,固定16x16大小。而H265引入了更灵活的树形划分结构。

我个人刚接触H265时,第一反应是:这玩意儿怎么这么复杂?但真正用起来才发现,灵活度高了,压缩效率确实上去了。今天我们就来把这几个概念掰开揉碎。

2.1 编码树单元(CTU)

CTU是H265编码的顶层单元。你可以把它想象成一块待切割的“土地”。

  • 大小:CTU的尺寸由编码器配置决定,常见的有64x64、32x32、16x16。
  • 作用:编码器从CTU开始,递归地向下划分,生成更小的单元。
  • 类比:H264的宏块最大16x16,而H265的CTU最大64x64。大块的好处是,对于平坦区域(比如天空、白墙),一个CTU就能搞定,码率省很多。

关键点:CTU是树形结构的根节点。每个CTU可以包含一个亮度CTB(Coding Tree Block)和两个色度CTB。

我在项目中遇到过一个问题:移动端解码器对64x64的CTU支持不太好,有些老芯片会卡顿。后来我强制把CTU大小限制在32x32,兼容性就好了很多。嗯,这里要注意,不是越大越好,得看目标平台。

2.2 编码单元(CU)

CU是从CTU划分出来的基本编码单位。它决定了采用帧内预测还是帧间预测。

划分方式很灵活:

  • CTU可以划分成4个CU,每个CU又可以继续划分成4个更小的CU。
  • 最小CU可以是8x8。
  • 划分深度用四叉树表示,深度0表示CTU本身,深度1表示划分一次,以此类推。

你想想看,为什么H265要搞这么复杂的划分?说白了,就是为了适配不同纹理的图像区域。纹理复杂的地方用小CU,平坦的地方用大CU。

CU大小 适用场景 码率消耗
64x64 平坦区域(天空、背景) 低
32x32 中等纹理 中
16x16 细节较多 较高
8x8 复杂纹理、边缘 高

实战建议:编码器通常有参数控制最大划分深度。比如x265的--max-cu-depth参数。我一般设成3或4,再深收益就不大了。

2.3 预测单元(PU)

CU决定用哪种预测模式,而PU是真正执行预测的基本单元。

一个CU可以包含一个或多个PU。为什么这么设计?因为预测模式不同,划分方式也不同。

  • 帧内预测:CU就是PU,不再细分。H265支持35种帧内预测方向(H264只有9种)。
  • 帧间预测:CU可以划分成多个PU。支持对称划分(2Nx2N、2NxN、Nx2N、NxN)和非对称划分(比如2NxnU、2NxnD等)。

我记得有一次调试运动估计,发现运动剧烈的区域用非对称划分效果特别好。说白了,就是物体边缘不一定是正方形的,非对称PU能更好地贴合运动边界。

避坑指南:我曾经在编码运动模糊严重的视频时,发现PU划分过于细碎,导致码率飙升。后来调整了运动估计的搜索范围,PU划分就合理多了。别盲目追求小PU,码率和画质要平衡。

2.4 变换单元(TU)

TU是残差变换的基本单位。预测做完之后,原始像素减去预测值得到残差,残差要经过DCT变换(或DST变换)才能压缩。

TU的大小和CU、PU的关系:

  • TU从CU递归划分而来,也是四叉树结构。
  • TU最大32x32,最小4x4。
  • TU不能跨越PU边界(帧内模式下),但帧间模式下TU可以跨越PU边界。

为什么TU要单独划分?因为残差的能量分布和预测模式有关。预测做得好的区域,残差小,可以用大TU;预测不准的区域,残差大,用小TU更精细。

TU大小 变换类型 适用场景
32x32 DCT 残差平坦
16x16 DCT 一般残差
8x8 DCT 残差较复杂
4x4 DST(帧内)或DCT(帧间) 残差剧烈变化

注意:4x4帧内预测残差使用DST变换,而不是DCT。DST对小块残差的能量集中效果更好。这是H265相比H264的一个小改进。

2.5 四者关系总结

CTU、CU、PU、TU的关系,可以用一句话概括:CTU是根,CU是决策者,PU是预测执行者,TU是变换执行者。

下面这张图展示了它们的层级关系:

H265编码单元层级关系 CTU / CU / PU / TU 层级关系 CTU (64x64) CU (决策预测模式) PU (执行预测) TU (残差变换) 帧内预测 帧间预测 DCT DST 说明: 1. CTU是根节点,递归划分出CU。 2. CU决定预测模式,PU执行预测,TU处理残差变换。 3. PU和TU的划分相互独立,但受CU约束。

2.6 实际编码流程

了解了这些概念,我们来看看实际编码时是怎么走的:

  1. 编码器读入一帧图像,先划分成CTU网格。
  2. 对每个CTU,递归划分CU,计算每种划分方式的率失真代价(RD cost)。
  3. 选定CU划分后,再决定PU划分方式,执行预测,得到残差。
  4. 对残差进行TU划分,执行DCT/DST变换、量化、熵编码。
  5. 输出码流。

小技巧:用FFmpeg的h264_videotoolbox或hevc_videotoolbox编码时,可以通过-qp参数控制量化,但CTU/CU的划分是编码器内部决定的。如果想精细控制,得用x265命令行:

ffmpeg -i input.mp4 -c:v libx265 -x265-params "ctu=64:max-cu-depth=4" output.mp4

2.7 常见问题与避坑

  • CTU太大导致解码延迟高:实时通信场景建议用32x32或16x16。
  • CU划分过深:码率会涨,而且编码时间暴增。我一般限制最大深度为3。
  • PU非对称划分:对运动估计精度要求高,否则反而降低压缩率。
  • TU大小选择:残差能量集中时用大TU,否则用小TU。编码器会自动选,但你可以通过--tu-intra-depth和--tu-inter-depth限制。

曾经踩过的坑:有一次编码监控视频,画面大部分是静止背景,但CTU划分特别碎。后来发现是运动估计的参考帧数量太少,导致编码器误判为运动区域。增加参考帧后,CTU划分就合理了,码率降了30%。

好了,这一章的内容就到这里。CTU、CU、PU、TU这四个概念是H265编码的基石,理解了它们,后面的帧内预测、帧间预测、变换量化就好办了。