3. 音频Codec概览

各位好,我是老周。今天咱们聊聊视频Codec的核心原理。说实话,这章是整个课程里最硬核的部分之一。你想想看,一个视频从摄像头采集到你手机屏幕上播放,中间经历了多少数学变换?我当年刚入行时,对着H.264标准文档啃了整整两周才把流程捋顺。今天我用最直白的方式,把这套流程给你拆开揉碎。

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

先问个问题:摄像头采集到的是RGB数据,为什么编码器非要转成YUV?

原因很简单——人眼对亮度的敏感度远高于颜色。RGB三个通道都是全分辨率,太浪费了。YUV把亮度(Y)和色度(U、V)分开,色度可以降采样。

核心概念:YUV 4:2:0 是最常用的采样格式。Y保留全分辨率,U和V在水平和垂直方向各减半。数据量直接减少一半。

我在项目中遇到过不少新手,直接把RGB送进编码器,结果码率爆炸。记住:编码前必须转YUV,这是行业铁律。

采样格式 Y分辨率 U/V分辨率 数据量占比
YUV 4:4:4 全 全 100%
YUV 4:2:2 全 水平1/2 66%
YUV 4:2:0 全 水平1/2、垂直1/2 50%

实战技巧:调试时用ffmpeg查看YUV布局:ffmpeg -i input.mp4 -f rawvideo -pix_fmt yuv420p output.yuv。然后用YUV工具打开,一眼就能看出颜色采样对不对。

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

帧内预测,说白了就是用已经编码的像素猜当前块。为什么能猜?因为图像里相邻像素通常很相似。

H.264支持9种帧内预测模式(4x4块),H.265扩展到35种。我刚开始学的时候觉得35种太多了,后来调试一个屏幕共享场景才发现——文字边缘用DC模式效果极差,换成角度模式立马省了30%码率。

注意:帧内预测只在当前帧内操作,不依赖其他帧。这是关键区别——帧内是空间预测,帧间是时间预测。

预测完成后,编码器只存残差(原始像素 - 预测像素)。残差通常很小,甚至接近0。这就是压缩的本质——不存原始数据,存差值。

DCT变换与量化:从像素到频率

残差数据还是像素域,直接编码效率不高。DCT变换把它转到频率域。

为什么用DCT?因为图像能量集中在低频。变换后,左上角是直流分量(DC),右下角是高频细节。人眼对高频不敏感,量化时可以把高频系数压得很狠。

量化这一步,是有损压缩的核心。量化参数(QP)越大,高频系数被丢弃得越多,码率越低,画质越差。

经验值:QP=0是无损,QP=18~23是视觉无损,QP=28~35是普通质量,QP>40就是马赛克了。我调试直播时常用QP=23作为起点。

量化后的系数再经过Zig-zag扫描和熵编码,就变成了二进制码流。这个过程我建议你亲手跑一遍——用Python写个8x8 DCT,看看变换前后的能量分布,比看十遍文档都管用。

运动估计与补偿:时间冗余的杀手

视频和图片最大的区别是什么?时间维度。相邻帧之间,大部分区域是静止的,只有局部在运动。

运动估计就是找匹配块。编码器在当前帧里取一个块,去参考帧里搜索最相似的块,记录下位移向量(运动矢量MV)。

搜索范围一般是±16到±64像素。全搜索最准但最慢,三步搜索、菱形搜索是工程常用方案。

避坑指南:我曾经在一个低功耗项目里用了全搜索,编码一帧花了200ms。换成菱形搜索后降到15ms,画质几乎没变。运动估计算法的选择,本质是速度与精度的trade-off。

运动补偿就是根据MV从参考帧里取出预测块,和当前块做差得到残差。残差越小,说明运动估计越准。

这里有个细节:MV本身也要编码。H.264用相邻块的MV做预测(MVP),只存差值。你想想看,如果整个画面平移,所有MV都一样,差值就是0,几乎不占码率。

整体流程:一张图说清楚

下面这张图把整个编码流程串起来了。我建议你对照着看,每个模块在流程里的位置一目了然。

视频编码核心流程 原始YUV帧 帧内预测 / 帧间预测 残差数据 DCT变换 量化 (QP控制) 熵编码 (CABAC/CAVLC) H.264/H.265码流 关键说明: 帧内预测:利用空间冗余 帧间预测:利用时间冗余 量化是唯一不可逆的有损步骤

运动估计的搜索算法对比

运动估计是编码器里最耗时的模块,没有之一。下面这个表是我在实际项目中测试过的数据,供你参考。

搜索算法 速度 精度 适用场景
全搜索 极慢 最高 离线编码、画质优先
三步搜索 快 较高 通用场景
菱形搜索 很快 中等 实时编码、直播
UMH 中等 高 x264/x265默认

重要提醒:运动估计的搜索范围不是越大越好。我曾经在1080p视频上把搜索范围从±32扩大到±64,码率只降了1%,编码时间翻了3倍。得不偿失。

量化参数QP的实战选择

QP是编码器里最直接的画质控制旋钮。但很多人不知道的是,QP和码率不是线性关系。

QP每增加6,量化步长翻倍,码率大约减半。也就是说,QP=30的码率大约是QP=24的一半。这个规律在调试时非常有用——你不需要反复试,直接按这个比例估算。

我的习惯:先设QP=23跑一版,看码率是否在目标范围内。如果码率超标,每次加3个QP再试。三步之内必出结果。

嗯,这章内容确实不少。YUV、帧内预测、DCT、量化、运动估计——每个模块单独拿出来都能讲一整天。但作为工程师,你不需要背公式,你需要理解为什么这么做以及调试时看哪里。

下次你遇到编码画质差的问题,先别急着调码率。看看是不是YUV采样错了?是不是帧内预测模式没选对?是不是QP设得太高?按流程排查,比瞎调有效得多。