第2章 视频编码基础回顾:YUV色彩空间、帧内/帧间预测、变换量化、熵编码原理

好,咱们正式开始聊编码。这一章是基础,但也是整个低延迟系统的地基。我见过不少团队,一上来就追最新的编码标准,结果延迟反而下不来——说白了,基础没打牢。

今天我把四个核心模块串起来讲:YUV色彩空间、预测、变换量化、熵编码。每个点我都会结合内窥镜场景说点实际经验。

2.1 YUV色彩空间:为什么不用RGB?

先问个问题:内窥镜图像采集出来是RGB,为什么编码要用YUV?

原因很简单——人眼对亮度敏感,对色彩不敏感。YUV就是把亮度和颜色分开。Y分量管亮度,U和V管色度。这样我们可以对色度做下采样,比如4:2:0,数据量直接减半。

我在项目中遇到过:有次做胃镜编码,团队坚持用4:4:4全采样,说怕丢失细节。结果带宽撑不住,延迟飙到200ms。后来换成4:2:0,医生反馈「根本看不出区别」。嗯,人眼就是这么宽容。

内窥镜场景建议:

  • 普通检查:4:2:0,延迟优先
  • 手术导航:4:2:2,保留更多边缘信息
  • 极少情况用4:4:4(比如AI辅助诊断的原始数据流)

YUV的存储格式也值得注意。我习惯用NV12,因为它在硬件编码器里支持最好。你想想看,如果软件层转了格式,硬件再转一次,延迟就上去了。

// YUV420 NV12 内存布局示例
// Y平面:w * h 字节
// UV平面交错存储:w * h / 2 字节
// 总大小:w * h * 3 / 2

uint8_t* y_plane = buffer;
uint8_t* uv_plane = buffer + width * height;

2.2 帧内预测:空间冗余的克星

帧内预测,说白了就是「看图猜像素」。用已经编码的相邻像素,预测当前块的值。只传残差,数据量就小了。

内窥镜图像有个特点——纹理丰富,但局部平滑区域也多。比如胃壁黏膜,大片的相似纹理。这时候帧内预测特别管用。

我曾经踩过一个坑:在4K内窥镜上,默认用了HEVC的35种帧内模式。结果编码器算到冒烟,延迟直接翻倍。后来我限制了模式数量,只保留最常用的9种方向模式,质量损失不到1%,延迟降了40%。

避坑指南:

低延迟场景下,帧内模式不要全开。我建议:

  • DC模式和Planar模式必开(平滑区域好用)
  • 水平/垂直方向保留(内窥镜图像常有管状结构)
  • 对角线方向可以砍掉一半

2.3 帧间预测:时间维度的压缩

帧间预测才是降码率的大头。原理很简单:找参考帧里的相似块,算个运动矢量,传差值。

但内窥镜场景有个特殊性——运动是连续的,但幅度不大。你想想看,医生操作内窥镜,镜头移动是平滑的,不会突然跳变。所以运动搜索范围可以缩小。

我个人的习惯:搜索范围设成±16像素就够了。全搜索范围±64,那是给体育直播用的。内窥镜用那么大的搜索范围,纯属浪费算力。

场景 搜索范围 参考帧数量 延迟影响
胃镜检查 ±8 ~ ±16 1帧
肠镜检查 ±16 ~ ±32 1~2帧
手术导航 ±4 ~ ±8 1帧 极低

这里要注意:P帧依赖前面的I帧或P帧。如果网络丢包,后面的帧全完蛋。所以内窥镜系统里,我建议每30帧插一个I帧,保证错误恢复能力。

2.4 变换量化:丢掉人眼看不见的信息

变换,就是把像素域的残差转到频域。DCT变换后,低频分量集中在左上角,高频分量在右下角。量化就是砍掉那些不重要的高频系数。

量化参数QP是关键。QP越大,丢得越多,码率越低,但画质也越差。

我记得有一次:手术室那边反馈图像有「方块感」。查了半天,发现是QP设到了42。内窥镜图像边缘多,高QP下块效应特别明显。后来我把QP上限锁在37,问题解决。

内窥镜QP建议:

  • 诊断用途:QP 22~28(保留细节)
  • 手术用途:QP 28~32(平衡画质和延迟)
  • 远程会诊:QP 32~37(带宽优先)
  • QP超过40?别用,图像会糊到没法看

变换还有个细节:块大小。4x4变换保留细节好,但码率高。8x8变换压缩率高,但边缘容易模糊。我一般混合使用——平滑区域用8x8,纹理区域用4x4。

2.5 熵编码:最后的无损压缩

熵编码是编码流程的最后一步。把量化后的系数、运动矢量、模式信息,用更紧凑的方式表示。常见的有CAVLC和CABAC。

CABAC压缩率高,但计算复杂。CAVLC简单,但压缩率低一些。

我的经验是:低延迟场景下,CAVLC反而更优。为什么?因为CABAC的上下文建模太费时间。你想想看,每编一个符号都要更新概率模型,延迟就上去了。CAVLC虽然码率多10%~15%,但速度快得多。

当然,如果带宽是瓶颈,那就得上CABAC。我见过一个极端案例:远程手术,带宽只有2Mbps,硬着头皮用CABAC,延迟多了8ms,但画质保住了。

// 熵编码选择逻辑(伪代码)
if (bandwidth > 20Mbps) {
    useCAVLC();  // 延迟优先
} else if (bandwidth > 5Mbps) {
    useCABAC();  // 平衡模式
} else {
    useCABAC_with_fast_context();  // 带宽受限,优化上下文模型
}

2.6 四个模块的协同

这四个模块不是孤立的。我画个简单的流程:

  1. 输入YUV图像
  2. 帧内/帧间预测,生成残差
  3. 残差做DCT变换,得到频域系数
  4. 量化砍掉高频分量
  5. 熵编码打包成码流

每个环节都会影响延迟。我个人习惯是:先优化预测环节(因为占比最大),再调量化参数,最后才动熵编码。顺序搞反了,往往事倍功半。

本章核心要点:

  • YUV 4:2:0是内窥镜的黄金选择
  • 帧内模式不要全开,9种足够
  • 帧间搜索范围±16,别贪大
  • QP控制在22~37之间
  • 带宽够用就用CAVLC,延迟更低

下一章,我会讲低延迟编码的架构设计。到时候咱们聊聊GOP结构、码率控制这些实战内容。嗯,先消化这些基础吧。