本文聚焦 H.264/AVC 编码器内部最基础的两个决策单元:宏块(Macroblock, MB)划分 与码率分配(Rate Allocation)。我会先说明测试边界:样本为 1080p30 的 screen-capture、talking-head 与 fast-motion 三类视频,编码器使用 x264 的 medium preset,目标码率分别取 2 Mbps、4 Mbps、8 Mbps。文中不比较品牌,只讨论参数如何影响压缩效率与画质。
一、宏块与 H.264 的空间分层结构
H.264 将一帧图像按 16×16 像素划分为宏块,这是编码决策的最小管理单元。每个宏块内部又可以进一步拆分为更小的子块,用于运动补偿和变换编码:
- 16×16:整体一个运动向量,适合平坦区域。
- 16×8 / 8×16:水平或垂直分割,适合有明显边缘的运动。
- 8×8:四个子块,每个独立运动向量。
- 8×4 / 4×8 / 4×4:最细粒度,适合复杂纹理或快速运动。
子块越小,运动向量越精确,残差能量越低,但需要更多的头信息(mvd、ref_idx、cbf 等)。因此,编码器需要在"残差降低收益"与"头信息比特成本"之间做率失真优化(RDO, Rate-Distortion Optimization)。
关键参数:subme 与 partitions
在 x264 中:
subme(subpixel motion estimation refinement):控制子像素运动估计的精度,范围 0--11。值越高,RDO 越充分,但 CPU 开销显著增加。partitions:决定允许哪些块划分类型,如p8x8,b8x8,i8x8,i4x4等。
bash
# 一个强调复杂运动的 x264 命令示例
x264 --preset medium --crf 23 \
--partitions p8x8,b8x8,i8x8,i4x4 \
--subme 9 \
--ref 4 \
-o output.mp4 input.y4m
| 子块尺寸 | 适用场景 | 优势 | 代价 |
|---|---|---|---|
| 16×16 | 天空、墙面等平坦区域 | 头信息少,编码快 | 复杂区域残差大 |
| 16×8 / 8×16 | 水平/垂直运动边缘 | 兼顾一致性与精度 | 比 16×16 多一个 MV |
| 8×8 | 中等复杂度场景 | 灵活性较好 | 头信息明显增加 |
| 4×4 | 快速运动、细密纹理 | 残差最小 | 头信息最多,编码最慢 |
二、码率分配:帧级、宏块级与 GOP 结构
H.264 的码率控制并不是均匀地给每个宏块分配比特,而是根据图像内容、帧类型和缓冲区状态动态调整。
1. GOP 与帧类型比特分布
典型的 GOP 结构为 IBBPBBP...。三种帧类型的比特消耗差异很大:
- I 帧:独立编码,通常比特最高,用于随机访问和错误恢复。
- P 帧:参考前向帧,比特中等。
- B 帧:双向参考,压缩效率最高,但编码/解码延迟最大。
2. 宏块级 QP 调整
编码器通过 mbtree(Macroblock Tree)或 aq-mode(Adaptive Quantization)对宏块级 QP 进行微调:
- mbtree:追踪宏块被后续帧参考的时间长度,参考越久的宏块分配更少 QP(更高质量)。
- aq-mode:根据局部对比度调整 QP,保留视觉敏感区域的细节。
bash
# 启用 mbtree 与 aq-mode 3(x264 后期版本支持)
x264 --preset slow --crf 23 \
--vbv-maxrate 4000 --vbv-bufsize 8000 \
--aq-mode 3 --aq-strength 0.9 \
--mbtree \
-o output.mp4 input.y4m
3. 码率控制模式对比
| 模式 | 原理 | 优点 | 限制 |
|---|---|---|---|
| CRF | 固定质量因子,码率随内容波动 | 画质稳定,适合存档 | 无法保证文件大小 |
| ABR | 编码器按目标平均码率分配 | 便于网络传输 | 画质波动大 |
| CBR | 强制恒定码率 | 直播/低延迟场景必需 | 复杂场景会出现块效应 |
| 2-pass | 第一次统计复杂度,第二次精分配 | 文件大小可控且质量较好 | 编码时间翻倍 |
三、实测:不同参数对压缩效率的影响
使用 x264 medium preset,在 1080p30 样本上对比三组参数:
| 参数组合 | 平均码率 | SSIM | 编码耗时 | 主观观感 |
|---|---|---|---|---|
| baseline, no mbtree, subme=5 | 4.0 Mbps | 0.961 | 1.0× | 运动区域轻微涂抹 |
| +mbtree, subme=7 | 4.0 Mbps | 0.968 | 1.6× | 静止文字更清晰 |
| +mbtree, subme=9, aq-mode=3 | 4.0 Mbps | 0.973 | 2.4× | 暗部细节保留更好 |
从数据可以看到:在固定码率下,更精细的宏块划分与自适应量化能提升客观指标,但编码耗时呈非线性增长。对于在线压缩服务来说,这意味着必须在服务器成本与输出质量之间做取舍。
一个常被忽视的变量:参考帧数 ref
ref 决定 P/B 帧能参考多少前面的帧。增加 ref 通常能提升压缩效率,但收益递减明显:
ref=1→ref=3:通常有 5%--10% 的码率节省。ref=4→ref=8:多数场景节省不到 3%,但解码内存翻倍。
对于浏览器端播放场景,过高的 ref 还会增加解码缓冲延迟。
四、限制与常见坑
- 4×4 划分并非总是更优:在码率充足时,头信息开销可能超过残差收益,导致使用 8×8 反而更省比特。
- mbtree 对低延迟场景不友好:mbtree 需要向前看若干帧,会增加编码延迟,直播场景常需关闭。
- VBV 缓冲会覆盖 QP 决策 :当
--vbv-maxrate和--vbv-bufsize设置过严时,编码器会强制降低 QP 以填满缓冲,可能破坏 CRF 的画质一致性。 - B 帧数量影响交互体验:B 帧越多压缩效率越高,但拖动进度条时的解码恢复点越少,seek 延迟增加。
五、选型建议与 FAQ
Q1:做视频归档应该用 CRF 还是 2-pass?
A:如果文件大小不敏感,优先 CRF(如 --crf 18);如果需要严格控制体积,用 2-pass ABR。
Q2:在线视频压缩为什么很难做到"视觉无损"同时体积很小?
A:视觉无损通常需要保留高频细节,但 H.264 的 4×4 变换和量化会丢弃部分高频系数。要在较低码率下维持视觉无损,需要更现代的编码器(如 H.265、AV1)或更激进的预处理。
Q3:mbtree 和 aq-mode 能同时开吗?
A:可以。mbtree 负责时域重要性分配,aq-mode 负责空域对比度保护,二者互补。但 aq-strength 过高会导致平坦区域出现噪点。
Q4:为什么同样的 CRF, fast-motion 视频比 talking-head 大很多?
A:CRF 固定的是质量因子,而 fast-motion 的残差能量和运动向量信息都远高于静态场景,因此需要更多比特才能达到同一质量。
Q5:宏块划分对解码端有什么影响?
A:划分越细,解码器需要处理的运动向量越多,对低功耗设备(手机、电视芯片)的解码负担越大。浏览器软解 4×4 密集划分的 1080p 视频时容易掉帧。
H.264 的宏块划分和码率分配是理解现代视频编码的入口。掌握这些参数后,再去看 H.265 的 CTU、AV1 的 Superblock,会发现核心思路一脉相承:在有限的比特预算内,把码率花在"人眼最敏感、后续帧最依赖"的地方。