原始未压缩视频数据量极大,无法直接存储 / 传输: 举个例子:1080P 60fps、8bit 420 视频 单帧像素:1920×1080 = 2073600 YUV420:每像素平均 1.5 字节 每秒数据量:1920×1080×1.5×60 ≈ 178MB/s 一部 90 分钟电影:≈945GB。
这么大的数据,一方面网络传输困难,另外一方面存储也相当麻烦,所以为了解决视频数据的传输和存储问题, 需要对视频数据进行压缩处理。
一、编码压缩策略
编码核心目标:去除冗余信息,压缩体积;解码还原画面 视频存在三类可压缩冗余:
- 空间冗余:同一帧内相邻像素颜色亮度接近(比如蓝天墙面)
- 时间冗余:相邻帧画面大部分几乎不变(背景不动,只有人物动)
- 视觉冗余:人眼对亮度敏感、对色彩细节不敏感,可丢失部分色彩信息
二、编码核心模块
2.1 帧类型划分,消除时间冗余(帧间预测)
编码器把画面分成 3 种帧,核心是用已编码画面预测当前帧,只存差值
- I 帧(关键帧,Intra) 独立完整画面,不依赖任何其他帧,只做帧内压缩; 缺点:体积最大;场景切换、视频 seek 跳转必须靠 I 帧。
- P 帧(前向预测帧,Predictive) 参考前面 I/P 帧,只记录画面移动变化(运动矢量 + 残差差值); 体积远小于 I 帧。
- B 帧(双向预测帧,Bi-predictive) 同时参考前一帧、后一帧画面,预测精度最高,压缩率最好; 缺点:需要缓存前后帧,增加编码 / 解码延迟,直播低延时场景常禁用 B 帧。
2.2 分块(宏块 / CTU):处理空间冗余
整张画面太大,编码器会把图像切分成固定大小块处理:
- H.264:宏块 MB,基础 16×16 像素
- H.265 (HEVC):CTU 编码树单元,最大 64×64,可四叉树拆分成 32/16/8×8 小块 对每个块二选一压缩方式: 1)帧内预测(Intra) :只用当前帧内周边像素预测(I 帧全部用这个) 2)帧间预测(Inter) :参考其他帧,计算运动矢量 MV,记录块往哪移动,只存预测误差(残差)
2.3 变换(DCT 离散余弦变换):把空间信息转频率信息
人眼对低频(大面积明暗)敏感,高频(细微纹理、噪点)不敏感。 将像素块从「像素空间」转换为「频率系数」:
- 低频系数:画面主体明暗,保留完整
- 高频系数:细小纹理,后续可大幅压缩丢弃
2.4 量化 Quantization:有损压缩核心
对 DCT 变换后的频率系数除以量化步长,缩小数值、大量高频系数直接归零。
- QP 量化参数:QP 越大,压缩越强、画质越糊;QP 越小,画质清晰、文件更大。 这一步是有损压缩根源,丢失的细节无法复原。
2.5 熵编码:无损二次压缩(无信息丢失)
图像数据分布不均匀:0 大量出现、大数值极少。 高频出现的符号用短比特码字 ,低频符号用长比特码字,整体总比特减少。 熵解码本质:查表,把变长比特串还原成原始符号。
量化后剩下的系数、运动矢量、帧类型等参数是零散数字,做无损压缩打包:
- H.264:CAVLC、CABAC
- H.265/AV1:CABAC(效率更高) 作用:把重复出现的短符号用更短二进制编码,进一步缩小码流体积,不损失画质。
三、解码核心模块
与编码相对应
3.1、熵解码(还原系数、MV、参数)
3.1.1. CAVLC 解码(上下文自适应变长编码)
编码侧逻辑
对残差块量化后的系数分组,给不同组合分配固定变长码表,按顺序写入比特流。
解码步骤
- 从码流依次读取比特;
- 逐位匹配预设码表,识别出:非零系数个数、拖尾 1 数量、系数幅值、符号;
- 还原出一整块 DCT 量化系数数组;
- 切换下一个块,重复读取匹配。
缺点:只使用静态码表,不根据前后数据自适应调整,压缩效率一般。
3.1.2. CABAC 解码(上下文自适应二进制算术解码,现代标准核心)
CABAC 解码分 4 大核心步骤,是工业主流:
步骤 1:二值化 Binarization
编码器会把所有待编码数字(MV 差值、QP、预测模式、残差幅值)转换成只有 0/1 的二进制串(bin)。 解码第一步:拿到算术解码器输出的一串 0/1 二进制位。
步骤 2:上下文模型选择 Context Model
CABAC 的 "自适应" 来源: 不同位置、不同类型的数据,0 和 1 出现概率完全不同。 解码器维护一组概率模型(每个模型存:0 的概率、1 的概率),读取当前数据前,根据相邻已解码块信息选择对应上下文模型。 例:平坦区域残差多为 0 → 该上下文模型 0 概率接近 90%。
步骤 3:算术解码 Arithmetic Decoding(核心运算)
算术编码不逐个符号存码字,而是把一整段数据映射到 0~1 之间的小数区间; 解码时根据输入比特流,不断缩小区间,解出单个 bin(0 或 1):
- 读取码流比特更新区间上下限;
- 用当前上下文的 0/1 概率分割区间;
- 判断当前码流数值落在 0 区间还是 1 区间,输出 bin;
- 更新上下文概率(自适应更新:如果这次解出 0,就略微提高该模型下一次 0 的概率)。
步骤 4:逆二值化 Debinarization
把连续解出的一串 0/1 二进制 bin,还原成原始十进制数值:运动矢量差值、量化残差、块划分模式等。
3.2 反量化(恢复频率系数)
解码链路中,熵解码输出量化系数 ,反量化是它的逆运算: 把缩小后的整数系数,还原回接近原始 DCT 系数的幅度,供给后续反 DCT(IDCT)。
基础公式:
= 反量化后的重建频率系数
关键特性
- 无法完全复原原始 DCT 系数 量化时向下取整丢失小数,反量化只能得到近似值,差值就是量化误差;
- 纯线性运算,计算极简单,硬件加速友好;
- 只改变系数幅值,不改变矩阵内 0 / 非 0 的分布。
真实编码不只用单一 Qstep,会搭配量化缩放矩阵(Quant Matrix),区分亮度 / 色度、帧内 / 帧间块,适配人眼视觉特性:
完整标准公式
:位置 (x,y) 对应的缩放矩阵系数
- 低频位置 M 偏小,压缩力度轻,保留细节;
- 高频位置 M 偏大,压缩力度重,更容易被量化成 0。
QP 越大 → Qstep 越大 → 反量化后系数幅值偏差越大 → 画面越糊、压缩率越高。
量化存在的问题
- 块效应(分块马赛克) 不同块量化误差不一致,块边缘亮度色差断层;
- 模糊、细节丢失 高频纹理(发丝、文字、边缘)量化后归零,反量化后依然是 0,细节永久消失;
- 色彩失真 色度通道量化步长更大,反量化误差更高,画面容易发灰、偏色。
3.3 反 DCT 变换(转回像素残差块)
一维主要是音频使用;视频主要用二维反 DCT(分两步:先行逆变换,再列逆变换)
二维可分离,计算简化:
- 对系数矩阵每一行做一维反 DCT
- 对结果矩阵每一列做一维反 DCT 输出:像素残差块矩阵
3.4 帧内 / 帧间补偿(根据运动矢量取出参考帧块 + 叠加残差)
反 DCT 输出的是残差块(差值),不是完整像素; 补偿的核心公式统一:
重建像素 = 预测像素块 + 残差块
补偿就是拿到预测像素,和残差相加,还原当前图像块。 根据预测像素来源,分成两种:帧内补偿、帧间补偿。
3.4.1 帧内补充
只使用同一帧内部、已经解码完成的相邻像素(上方、左方、左上)做参考,不依赖其他帧。 一张图里每个块的预测值,由旁边已重建好的像素插值推算。
特点
- 独立解码,不需要缓存其他帧,视频拖拽、卡顿恢复靠 I 帧;
- 只消除空间冗余,没有时间冗余压缩,同等画质下码率最大;
- 画面细节复杂区域切换场景时强制用 I 帧 + 帧内预测;
- 缺陷:平坦区域还行,大面积静态背景压缩效率远不如帧间。
3.4.2 帧间补偿
参考之前 / 之后已经完整解码并缓存的参考帧 ,不是当前帧。 通过运动矢量 MV 描述当前图像块在上 / 下参考帧的偏移位置,取出对应区域作为预测块。
关键细分:P 帧补偿 / B 帧补偿
-
P 帧前向帧间补偿 只取过去已解码帧作为参考,单个运动矢量; 延迟低,直播低延时场景常用。
-
B 帧双向帧间补偿 同时取前向参考帧 + 后向参考帧,生成两个预测块再加权平均; 预测精度更高,残差更小,压缩率更好; 缺点:解码需要缓存未来帧,引入额外延时,实时直播一般关闭 B 帧。
亚像素插值
真实物体运动不会刚好偏移整数像素(比如人物缓慢移动,偏移 0.5 像素)。 参考帧只有整数像素点,编码器 / 解码器通过滤波插值生成半像素、1/4 像素预测值,大幅减小残差。 H.264/H.265 使用 6 抽头滤波做亚像素插值。
优势
消除时间冗余:相邻帧背景几乎不变,只记录物体移动偏移 + 微小残差,码率远低于 I 帧。
典型缺陷
- 快速运动物体:MV 预测不准,残差变大,出现模糊、拖影;
- 遮挡区域:参考帧找不到对应像素,预测失效,残差巨大,产生马赛克;
- 全局镜头移动(摇镜头):全图 MV 偏移,依然比 I 帧省码率。
| 对比项 | 帧内补偿(Intra) | 帧间补偿(Inter) |
|---|---|---|
| 参考来源 | 同帧已解码相邻像素 | 其他缓存参考帧 |
| 适用帧 | I 帧 | P、B 帧 |
| 压缩效率 | 差,码率高 | 优秀,码率大幅降低 |
| 解码延迟 | 无额外帧缓存延迟 | B 帧需缓存后帧,延迟更高 |
| 依赖关系 | 仅块间依赖,可独立刷新 | 依赖其他帧,丢参考帧会大面积花屏 |
| 核心作用 | 消除空间冗余 | 消除时间冗余 |
3.5 拼接所有图像块
所有操作都是对独立小块(4×4/8×8/16×16/32×32 CTU)单独运算,每一步输出只是一小块像素;拼接就是把分散的小块按坐标放回原图对应位置,拼成一整帧完整画面。
3.5.1 亮度 Y、色度 U/V 分开拼接
YUV420 格式三层分辨率不同,拼接是三层独立分开执行:
- 亮度平面 Y 分辨率等于原始画面,每个 CTU 对应一块完整 Y 像素,直接按坐标写入 Y 缓存。
- 色度平面 U、V 宽高均为 Y 的 1/2,色度块尺寸对应缩小一半; 一块 64×64 Y CTU,只对应一块 32×32 U、一块 32×32 V 色度块。
解码补偿完成后,分别填充 Y、U、V 三块独立内存缓冲区,互不干扰。
3.5.2 边界特殊处理
画面宽 / 高无法被 CTU 尺寸整除时,边缘会出现不完整小块(如画面宽 1923,CTU64,最后一列只剩 3 像素宽度):
- 编码器只编码有效画面内像素;
- 解码补偿后仅拷贝有效像素,超出画面范围的像素丢弃,不写入缓存;
- 硬件解码器会做边界填充对齐内存,方便 GPU 读取渲染。