3. H265帧内预测:35种模式深度拆解

帧内预测,说白了就是利用当前块周围已经解码的像素,来「猜」当前块的内容。H.265/HEVC 把帧内预测从 H.264 的 9 种一口气扩展到了 35 种——这个数字我刚开始接触时也觉得有点吓人,但拆开来看,其实就三大类:DC、Planar、以及 33 种角度模式。

为什么需要这么多模式?因为视频内容千变万化。平坦的天空、纹理复杂的织物、带有明显方向边缘的建筑……每种场景适合的预测方式都不一样。模式越多,编码器就越能找到最贴近原始块的那个「猜测」,残差自然就小了。

核心要点:帧内预测的本质是空间冗余消除。用已解码的相邻像素(参考像素)预测当前块,只编码预测残差。

3.1 35种模式的整体分类

我们先看一张总览图,把 35 种模式的位置关系搞清楚。

H.265 帧内预测 35 种模式总览 H.265 帧内预测 35 种模式总览 DC 模式(模式 0) Planar 模式(模式 1) 角度预测(模式 2~34) DC 模式 取参考像素的平均值 适合平坦区域 计算简单,硬件友好 Planar 模式 双线性插值生成渐变 适合平滑渐变区域 主观质量好 角度预测 33 个方向覆盖 360° 沿纹理方向预测 角度步长精细 角度模式细分:水平方向(2~17)| 垂直方向(18~34) 模式编号对照 模式 0:DC | 模式 1:Planar | 模式 2~17:水平角度(2 最水平,17 最接近垂直) 模式 18~34:垂直角度(18 最接近水平,34 最垂直) 模式 26 为纯垂直预测,模式 10 为纯水平预测

从图上可以看得很清楚:DC 和 Planar 各占一个模式号,剩下的 33 个全部是角度模式。角度模式又分为水平方向(模式 2~17)和垂直方向(模式 18~34),覆盖了从近乎水平到近乎垂直的所有方向。

我的经验:实际编码中,Planar 模式的使用率往往比 DC 高,尤其是在低码率场景下。Planar 生成的预测块更平滑,主观视觉上更舒服。DC 模式在硬件实现上更简单,但容易产生块效应。

3.2 DC 模式详解

DC 模式是 35 种模式里最「朴实」的一个。它的做法很简单:取当前块上方和左侧参考像素的平均值,用这个平均值填充整个块。

具体来说,对于一个 N×N 的块:

// DC 值计算(伪代码)
sum = 0;
count = 0;

// 累加上方参考像素(如果可用)
for (i = 0; i < N; i++) {
    sum += refAbove[i];
    count++;
}

// 累加左侧参考像素(如果可用)
for (i = 0; i < N; i++) {
    sum += refLeft[i];
    count++;
}

dcVal = (sum + count/2) / count;  // 四舍五入

// 所有像素都赋值为 dcVal
for (y = 0; y < N; y++)
    for (x = 0; x < N; x++)
        pred[y][x] = dcVal;

这里有个细节:如果上方或左侧的参考像素不可用(比如在图像边界),只取可用的一侧。如果两侧都不可用,DC 值直接取默认值(通常是 1 << (bitDepth - 1))。

注意:DC 模式对边界像素的处理有特殊规则。块内第一行和第一列的像素会与参考像素做一次滤波,减少块边界的不连续性。这个滤波操作在 H.264 中是没有的,H.265 新增的。

DC 模式最适合什么场景?我个人经验是:天空、墙壁、桌面这类大面积平坦区域。在这些场景下,DC 模式预测准确,计算量又小,编码器通常会优先选择它。

3.3 Planar 模式详解

Planar 模式比 DC 复杂一些,但原理很直观——它生成一个双线性插值的渐变平面。你可以想象成:用四个边的参考像素,在块内做一个平滑的过渡。

计算公式如下:

// Planar 预测(伪代码)
// 对于位置 (x, y),预测值为:
// pred[x][y] = (hor + ver + N) / (2*N)

// 水平分量:从左侧到右侧的线性插值
hor = (N - 1 - x) * refLeft[y] + (x + 1) * refTopRight;

// 垂直分量:从上侧到底部的线性插值  
ver = (N - 1 - y) * refAbove[x] + (y + 1) * refBottomLeft;

// 其中 refTopRight 是右上角参考像素
// refBottomLeft 是左下角参考像素

注意这里用到了两个特殊的参考像素:右上角(refTopRight)和左下角(refBottomLeft)。这两个像素提供了块外部的「趋势」信息,让渐变更加自然。

我记得有一次在优化编码器的主观质量时,发现 Planar 模式对渐变背景(比如黄昏的天空、光滑的金属表面)效果特别好。DC 模式在这些场景下会产生明显的块状感,而 Planar 模式几乎看不出块边界。

关键区别:DC 模式是「填平均值」,Planar 模式是「画渐变」。前者适合平坦区域,后者适合有亮度/色度缓慢变化的区域。

3.4 角度预测模式详解

33 种角度模式是 H.265 帧内预测的重头戏。它们覆盖了从 -135° 到 +135° 的范围(以水平方向为 0°),步长精细到约 5° 左右。

角度预测的核心思想:沿着某个方向,把参考像素「投影」到当前块内。比如模式 10(纯水平预测),就是把左侧的参考像素直接向右复制;模式 26(纯垂直预测),就是把上方的参考像素直接向下复制。

对于非整数角度(比如模式 2、3、4 等),参考像素的位置可能落在两个像素之间,这时候就需要插值。H.265 使用 1/32 像素精度的线性插值:

// 角度预测插值(伪代码)
// 对于角度模式,计算投影位置
// 使用 1/32 像素精度

// 假设预测方向指向右上
// 对于当前块内位置 (x, y)
// 计算参考像素位置
refPos = offset + (x * deltaX + y * deltaY) / 32;

// 整数部分和小数部分
intPart = refPos >> 5;
fracPart = refPos & 31;

// 线性插值
predVal = ((32 - fracPart) * ref[intPart] + fracPart * ref[intPart + 1] + 16) >> 5;

这里 deltaX 和 deltaY 是角度对应的方向向量,预定义在标准中。每个模式都有固定的 deltaX/deltaY 值。

模式编号 方向描述 deltaX deltaY 典型应用场景
2 近乎水平(右上) 32 -1 接近水平的纹理
10 纯水平 32 0 水平条纹、文字
18 近乎水平(右下) 32 1 右下方向纹理
26 纯垂直 0 32 垂直条纹、建筑边缘
34 近乎垂直(左上) -1 32 左上方向纹理

你想想看,33 种角度模式意味着编码器有 33 种「猜测」方式。对于一条斜着的边缘,总有一种角度能完美贴合它。这就是 H.265 比 H.264 压缩率提升的重要原因之一。

避坑指南:我曾经在实现角度预测时踩过一个坑——参考像素的填充顺序。H.265 要求先填充上方参考像素(从左到右),再填充左侧参考像素(从上到下),最后填充右上角和左下角。如果顺序搞反,预测结果会完全错误。这个细节在标准文档的 8.4.4.2.2 节有明确说明。

3.5 参考像素的获取与滤波

所有帧内预测模式都依赖参考像素。参考像素来自当前块的上方一行、左侧一列、以及右上角和左下角的额外像素。对于 N×N 的块,需要 2N+1 个参考像素(上方 N 个、左侧 N 个、左上角 1 个)。

参考像素获取后,会经过一个可选的滤波步骤。这个滤波使用一个 3-tap 的低通滤波器:

// 参考像素滤波(3-tap 滤波器)
// 滤波后的值 = (ref[i-1] + 2*ref[i] + ref[i+1] + 2) / 4

for (i = 1; i < 2*N; i++) {
    filteredRef[i] = (ref[i-1] + 2*ref[i] + ref[i+1] + 2) >> 2;
}

滤波与否取决于块大小和预测模式。一般来说,大块(32×32 以上)的 DC 和 Planar 模式会滤波,小块(4×4、8×8)的角度模式通常不滤波。标准中有一个查表来决定是否滤波。

注意:参考像素滤波是 H.265 新增的特性,H.264 没有。这个滤波能有效减少预测噪声,但也会轻微模糊参考像素。对于纹理丰富的区域,滤波反而可能降低预测精度。编码器会根据 RD cost 决定是否启用滤波。

3.6 模式选择与编码

编码器如何从 35 种模式中选出最优的那个?答案是率失真优化(RDO)。对每种模式计算预测残差,然后比较编码后的码率和失真,选 RD cost 最小的那个。

但 35 种模式全做 RDO 太慢了。实际编码器会先用快速算法筛选:

  • 粗选阶段:用 SATD(Hadamard 变换后的绝对差和)快速评估所有模式,保留 Top N 个候选
  • 精选阶段:对候选模式做完整的 RDO(包括变换、量化、熵编码)
  • MPM 利用:利用相邻块的模式(MPM,Most Probable Mode)缩小搜索范围

MPM 是 H.265 帧内编码的一个重要优化。它利用空间相关性,从左边和上边块的模式中推导出 3 个最可能的模式。编码器优先检查 MPM,往往能提前找到最优模式。

// MPM 推导(简化版)
// 从左侧块模式 L 和上方块模式 A 推导

if (L == A) {
    if (L > 1) {  // 角度模式
        mpm[0] = L;
        mpm[1] = L - 1;
        mpm[2] = L + 1;
    } else {  // DC 或 Planar
        mpm[0] = L;
        mpm[1] = 0;  // Planar
        mpm[2] = 1;  // DC
    }
} else {
    mpm[0] = L;
    mpm[1] = A;
    mpm[2] = (L + A) / 2;  // 平均模式
}

我个人习惯在实现编码器时,先做 MPM 检查,再做粗选。这样能减少约 30% 的模式搜索时间,压缩率损失不到 1%。

总结:H.265 的 35 种帧内预测模式,本质上是用更精细的方向划分和更灵活的插值方式,来逼近自然图像中的各种纹理。DC 和 Planar 负责「面」,33 种角度模式负责「线」和「边缘」。三者配合,再加上参考像素滤波和 MPM 优化,构成了 H.265 帧内编码的核心竞争力。