视频Codec原理:YUV色彩空间、帧内与帧间预测、DCT变换与量化、运动估计与补偿
各位好,我是老周。今天咱们聊聊视频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,几乎不占码率。
整体流程:一张图说清楚
下面这张图把整个编码流程串起来了。我建议你对照着看,每个模块在流程里的位置一目了然。
运动估计的搜索算法对比
运动估计是编码器里最耗时的模块,没有之一。下面这个表是我在实际项目中测试过的数据,供你参考。
| 搜索算法 | 速度 | 精度 | 适用场景 |
|---|---|---|---|
| 全搜索 | 极慢 | 最高 | 离线编码、画质优先 |
| 三步搜索 | 快 | 较高 | 通用场景 |
| 菱形搜索 | 很快 | 中等 | 实时编码、直播 |
| 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设得太高?按流程排查,比瞎调有效得多。