← 首页

WeCodec 知识库 · 视频编码

块划分、变换与量化

用一个 8×8 块的真实数字走一遍 DCT 和量化

编码器把画面切成块,对每块做变换,再做量化。变换只是换一种表示方式,把像素换成频率系数,能量集中到左上角。量化把系数除以步长再取整,大部分高频系数变成 0。

变换和后面的熵编码都能精确还原,画质损失来自量化。

1. 先切块

编码器不会整帧处理,而是先把画面切成方块,每块分别做预测、变换和量化。H.264 的基本单位叫宏块(macroblock),通常是 16×16 像素(维基百科:Macroblock)。

HEVC 改用编码树单元 CTU(coding tree unit),可以是 64×64、32×32 或 16×16(维基百科:HEVC)。CTU 按四叉树往下切:一个方块要么不切,要么切成四个一样大的小方块,小方块还能继续切。AV1 的对应单位叫超级块(superblock),大小是 128×128 或 64×64(维基百科:AV1)。

16×1616×1616×1632×3232×3216×1616×1616×1616×16整块 64×64 是一个 CTU先四等分成 32×32纹理复杂处继续切到 16×16、8×8平坦处保持大块
图 1 一个 64×64 CTU 的四叉树切分示意。颜色越深,块越小。

天空这类平坦区域,用大块就够了,还能省下描述切分方式的比特。树叶、文字这类细节多的区域,切成小块预测得更准。大块对高分辨率视频更划算:一组 HEVC 测试里,把 CTU 从 64×64 限制到 16×16,码率平均上升 11.0%(维基百科:Coding tree unit)。

2. DCT:把像素换成频率

视频编码器会先预测每块的内容,再对预测残差做变换,残差就是真实画面减去预测画面。JPEG 没有预测这一步,直接变换像素,但变换和量化的做法一样。下面用维基百科 JPEG 条目里的一个经典例子来演示(维基百科:JPEG)。

DCT(discrete cosine transform,离散余弦变换)把 8×8 个像素值换成 8×8 个频率系数。左上角是直流系数(DC),代表整块的平均亮度。越往右下,系数代表的纹理越细(同上)。

原始像素(8 bit 灰度)52556166706164736359559010985697262596811314410466736358711221541067069676168104126886870796560707768587585716459556165838779696865767894每个值减 128,再做二维 DCTDCT 系数(四舍五入到整数)-415-30-612756-20-204-22-611013-7-95-47777-25-29105-6-491234-15-1062212-7-13-4-22-33-832-6-2142-100-2-1-34-100-1-4-1002
图 2 8×8 像素块做 DCT 前后的数值。数据来自维基百科 JPEG 条目,颜色越深表示系数绝对值越大。

结果里左上角是 -415,其余较大的系数都挤在左上几格,右下角大多接近 0。相邻像素通常很接近,所以能量天然集中在低频,这就是 DCT 好用的原因(维基百科:Discrete cosine transform)。

3. 量化:丢信息的那一步

量化把每个系数除以对应的步长,再四舍五入成整数。步长越大,丢掉的越多。下图上半部分是 JPEG 在质量 50 时常用的量化表:左上角步长小,右下角步长大,因为人眼对细密纹理的强弱不敏感(维基百科:JPEG)。

量化表(JPEG 质量 50)1611101624405161121214192658605514131624405769561417222951878062182237566810910377243555648110411392496478871031211201017292959811210010399DCT 系数 ÷ 步长,四舍五入量化结果:20 个非零,44 个为 0-26-3-622-1000-2-411000-315-1-1000-312-1000010000000000000000000000000000000
图 3 量化表和量化后的系数。数据来自维基百科 JPEG 条目。

拿直流系数算一下:-415.37 ÷ 16 ≈ -25.96,取整得 -26。右下角的系数本来就小,再除以 100 左右的步长,全部变成 0。64 个系数量化完,只剩 20 个不是 0。

解码时把整数乘回步长,再做反变换。取整时丢掉的小数部分找不回来,所以重建的像素和原图有误差。步长越大,误差越大,码率越低。

4. 扫描和熵编码

量化后的系数要排成一列才能编码。JPEG 按之字形(zigzag)从左上往右下扫,低频系数排在前面,后面是一长串 0(维基百科:JPEG)。

-26-3-622-1000-2-411000-315-1-1000-312-1000010000000000000000000000000000000扫到第 26 个系数后全是 0
图 4 对量化结果做之字形扫描。深色格是非零系数,红圈是最后一个非零系数。

按这个顺序,前 26 个系数是:-26, -3, 0, -3, -2, -6, 2, -4, 1, -3, 1, 1, 5, 1, 2, -1, 1, -1, 2, 0, 0, 0, 0, 0, -1, -1,后面 38 个全是 0。

连续的 0 很好压。JPEG 用游程编码(run-length encoding)把一串 0 记成一个长度,再用霍夫曼编码给常见的值分配短码(同上)。这两步都是熵编码,只换写法,不丢信息。

5. 视频标准和 JPEG 的差别

视频标准沿用了切块、变换、量化这条路,但细节不同。

对比项JPEGH.264HEVC
变换对象原始像素预测残差预测残差
变换8×8 DCT整数变换,4×4 和 8×8整数 DCT 和 DST,4×4 到 32×32
量化控制量化表对数刻度的步长,可配按频率调整的量化矩阵本页未展开

H.264 和 HEVC 的变换信息来自维基百科:Advanced Video Coding和维基百科:HEVC。DST(discrete sine transform,离散正弦变换)是 DCT 的近亲,只是基函数换成了正弦。

视频标准改用整数变换,是为了让编码端和解码端算出的结果逐位一致。H.261、MPEG-2 这类早期标准用浮点公式加容差来定义变换,不同解码器的输出会有细微差别(维基百科:Advanced Video Coding)。VVC 又在 HEVC 的方形变换块之外,加入了长方形变换块(维基百科:Versatile Video Coding)。

在 H.264 里,量化强度由量化参数 QP 控制,取值 0 到 51,数值越大,量化越重,画质越低(Werner Robitza:Understanding Rate Control Modes)。编码器怎么给每帧定 QP,见《码率控制:CBR、VBR、CRF》。

参考资料

  1. 《JPEG》,Wikipedia https://en.wikipedia.org/wiki/JPEG
  2. 《Discrete cosine transform》,Wikipedia https://en.wikipedia.org/wiki/Discrete_cosine_transform
  3. 《Macroblock》,Wikipedia https://en.wikipedia.org/wiki/Macroblock
  4. 《Coding tree unit》,Wikipedia https://en.wikipedia.org/wiki/Coding_tree_unit
  5. 《Advanced Video Coding》,Wikipedia https://en.wikipedia.org/wiki/Advanced_Video_Coding
  6. 《High Efficiency Video Coding》,Wikipedia https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding
  7. 《AV1》,Wikipedia https://en.wikipedia.org/wiki/AV1
  8. 《Versatile Video Coding》,Wikipedia https://en.wikipedia.org/wiki/Versatile_Video_Coding
  9. 《Understanding Rate Control Modes (x264, x265, vpx)》,Werner Robitza https://slhck.info/video/2017/03/01/rate-control.html