H.264/AVC 编码原理详解
H.264/AVC 编码原理详解
H.264 是目前应用最广泛的视频编码标准,理解其编码原理对优化 RTC 视频质量至关重要。本章将深入介绍 H.264 的核心技术。
1. H.264 概述
1.1 发展历史
| 时间 | 事件 |
|---|---|
| 2003 年 | H.264 标准正式发布 |
| 2004 年 | 保真范围扩展(FRExt) |
| 2007 年 | 可伸缩视频编码(SVC)扩展 |
| 2010 年 | 多视点视频编码(MVC)扩展 |
1.2 H.264 的设计目标
| 目标 | 说明 |
|---|---|
| 高压缩效率 | 比 H.263 提升约 50% |
| 网络友好 | 适应各种网络环境 |
| 低延迟 | 支持实时通信场景 |
| 容错能力 | 内置错误恢复机制 |
1.3 与前代标准的对比
| 特性 | H.263 | MPEG-4 | H.264 |
|---|---|---|---|
| 帧内预测 | 无 | DC/AC | 9 种方向 |
| 帧间预测 | 16×16 | 16×16 | 可变块大小 |
| 变换 | 8×8 DCT | 8×8 DCT | 4×4/8×8 整数变换 |
| 熵编码 | VLC | VLC | CAVLC/CABAC |
| 环路滤波 | 可选 | 可选 | 强制 |
2. NAL 层结构
2.1 双层结构
H.264 采用双层结构:VCL(Video Coding Layer)和 NAL(Network Abstraction Layer)。
flowchart TB
subgraph VCL 层
A[编码核心]
A1[预测]
A2[变换]
A3[量化]
A4[熵编码]
end
subgraph NAL 层
B[网络抽象]
B1[NAL 单元封装]
B2[起始码]
B3[网络适配]
end
A --> B
B --> C[输出码流]
分层的目的:
- VCL:专注于编码效率,不关心传输
- NAL:负责将 VCL 数据打包成适合网络传输的格式
2.2 NAL 单元结构
NAL 单元结构:
┌──────────────┬─────────────────────────────┐
│ NAL Header │ RBSP Payload │
│ (1 字节) │ (变长) │
└──────────────┴─────────────────────────────┘
NAL Header 格式:
|0|1|2|3|4|5|6|7|
|F|NRI| Type |
F (forbidden_zero_bit): 必须为 0
NRI (nal_ref_idc): 重要性标识 (00-11)
Type: NAL 单元类型 (1-31)
2.3 常用 NAL 类型
| Type | 名称 | 说明 |
|---|---|---|
| 1 | 非 IDR 切片 | P/B 帧数据 |
| 5 | IDR 切片 | I 帧(关键帧) |
| 6 | SEI | 补充增强信息 |
| 7 | SPS | 序列参数集 |
| 8 | PPS | 图像参数集 |
| 9 | AUD | 访问单元分隔符 |
2.4 SPS 与 PPS
SPS(Sequence Parameter Set):序列级参数
| 参数 | 说明 |
|---|---|
| profile_idc | Profile 标识 |
| level_idc | Level 标识 |
| pic_width_in_mbs | 图像宽度(宏块数) |
| pic_height_in_map_units | 图像高度 |
| max_num_ref_frames | 最大参考帧数 |
| frame_mbs_only_flag | 是否只有帧宏块 |
PPS(Picture Parameter Set):图像级参数
| 参数 | 说明 |
|---|---|
| pic_parameter_set_id | PPS 标识 |
| seq_parameter_set_id | 关联的 SPS |
| num_slice_groups | 片组数量 |
| num_ref_idx_l0_active | L0 参考帧数量 |
| entropy_coding_mode_flag | 熵编码模式 |
3. 宏块结构
3.1 宏块组成
一个 16×16 的宏块由以下部分组成:
宏块 (16×16):
┌─────────────────────────────────┐
│ 16×16 亮度 (Y) │
│ 可分割为 16×16, 16×8, 8×16, │
│ 8×8, 8×4, 4×8, 4×4 │
├─────────────┬───────────────────┤
│ 8×8 Cb │ 8×8 Cr │
│ (色度U) │ (色度V) │
└─────────────┴───────────────────┘
对于 YUV420:
- 1 个 16×16 亮度块
- 2 个 8×8 色度块
3.2 宏块分割模式
帧内预测分割:
帧内预测支持的块大小:
┌──────────────────┐ ┌────────┬────────┐
│ │ │ │ │
│ 16×16 │ │ 16×8 │ 8×16 │
│ │ │ │ │
└──────────────────┘ └────────┴────────┘
更小的 4×4 块用于细节区域:
┌────┬────┬────┬────┐
│4×4 │4×4 │4×4 │4×4 │
├────┼────┼────┼────┤
│4×4 │4×4 │4×4 │4×4 │
├────┼────┼────┼────┤
│4×4 │4×4 │4×4 │4×4 │
├────┼────┼────┼────┤
│4×4 │4×4 │4×4 │4×4 │
└────┴────┴────┴────┘
帧间预测分割:
帧间预测支持的块大小:
16×16 16×8 8×16
┌──────┐ ┌──────┐ ┌──┬───┐
│ │ │ │ │ │ │
│ │ ├──────┤ │ │ │
│ │ │ │ │ │ │
└──────┘ └──────┘ └──┴───┘
8×8 可进一步分割:
┌──┬──┐
│8×8│8×8│ 每个 8×8 可分为: 8×4, 4×8, 4×4
├──┼──┤
│8×8│8×8│
└──┴──┘
3.3 分割选择策略
| 场景 | 推荐分割 | 原因 |
|---|---|---|
| 平坦区域 | 16×16 | 大块预测效率高 |
| 边缘区域 | 4×4 | 小块更精确 |
| 运动物体 | 匹配物体大小 | 减少残差 |
| 纹理复杂 | 小块 | 更好匹配纹理 |
4. 帧内预测
4.1 帧内预测原理
帧内预测利用同一帧内已编码像素预测当前块:
帧内预测示意:
已编码像素 (上方)
┌─────────────────────┐
│ A B C D E F │
左 ├──┌─────────────────┤
侧 │ │ │
已 │I │ 当前块 │
编 │J │ (待预测) │
码 │ │ │
└──┴─────────────────┘
预测值由 A-F 和 I-J 计算得出
4.2 4×4 亮度预测模式
H.264 为 4×4 块提供 9 种预测模式:
9 种帧内预测方向:
模式 0 (垂直) 模式 1 (水平) 模式 2 (DC)
┌─────────┐ ┌─────────┐ ┌─────────┐
│ │ │ │ │ │─────────│ │ 平均值 │
│ │ │ │ │ │─────────│ │ 平均值 │
│ │ │ │ │ │─────────│ │ 平均值 │
│ │ │ │ │ │─────────│ │ 平均值 │
└─────────┘ └─────────┘ └─────────┘
模式 3-8 (对角方向):
模式 3: 左下45° 模式 4: 右下45° 模式 5: 垂直偏右
模式 6: 水平偏下 模式 7: 垂直偏左 模式 8: 水平偏上
4.3 16×16 亮度预测模式
对于大块,H.264 提供 4 种简化的预测模式:
| 模式 | 名称 | 适用场景 |
|---|---|---|
| 0 | 垂直 | 垂直边缘 |
| 1 | 水平 | 水平边缘 |
| 2 | DC | 平坦区域 |
| 3 | 平面 | 渐变区域 |
4.4 色度预测
色度块(8×8)也有 4 种预测模式,与 16×16 亮度类似:
| 模式 | 名称 |
|---|---|
| 0 | DC |
| 1 | 水平 |
| 2 | 垂直 |
| 3 | 平面 |
4.5 模式选择
编码器通过率失真优化(RDO)选择最佳模式:
代价计算:
Cost = D + λ × R
D: 失真(原始块与重建块的差异)
R: 码率(编码该模式需要的比特数)
λ: 拉格朗日乘子(由 QP 决定)
选择 Cost 最小的模式
5. 帧间预测
5.1 帧间预测原理
帧间预测从参考帧中寻找匹配块:
flowchart LR
subgraph 当前帧
A[当前块<br>待编码]
end
subgraph 参考帧
B[搜索窗口]
C[最佳匹配块]
end
A --> |运动估计| B
B --> |找到| C
C --> |运动矢量 MV| D[编码]
C --> |残差| D
5.2 运动估计
整像素搜索:
搜索范围示例 (±16 像素):
参考帧:
┌─────────────────────────────┐
│ │
│ ┌─────────────┐ │
│ │ 搜索窗口 │ │
│ │ 32×32 │ │
│ │ ┌──┐ │ │
│ │ │最│ │ │
│ │ │佳│ │ │
│ │ │匹│ │ │
│ │ │配│ │ │
│ │ └──┘ │ │
│ └─────────────┘ │
│ │
└─────────────────────────────┘
亚像素精度:
亚像素插值:
整像素位置: ● ● ● ●
|
1/2 像素插值: ● × ● × ● × ●
|
1/4 像素插值: ●○×○●○×○●○×○●
● = 整像素
× = 1/2 像素
○ = 1/4 像素
H.264 支持 1/4 像素精度
5.3 运动矢量
运动矢量结构:
运动矢量 (MV):
┌──────────────────────────┐
│ 水平分量 (mvx) │ 垂直分量 (mvy) │
│ (有符号) │ (有符号) │
└──────────────────────────┘
示例:
当前块位置: (100, 200)
匹配块位置: (105, 198)
运动矢量: (5, -2)
表示当前块相对于参考帧向右移动5像素,向上移动2像素
运动矢量预测:
由于相邻块的运动通常具有空间相关性(同一物体的运动在相邻块间相似),H.264 不直接编码运动矢量,而是编码预测差值。
利用空间相关性预测 MV:
B (上方块) 已编码
│
C ─── A (左块) ─── 当前块 (待编码)
(左上) 已编码
MV_A = 左边已编码块的运动矢量
MV_B = 上边已编码块的运动矢量
MV_C = 左上或右上已编码块的运动矢量
预测值: MV_pred = median(MV_A, MV_B, MV_C) // 取中值
实际编码: MVD = MV - MV_pred // 只传差值
预测编码的优势:
- 相邻块 MV 相似时,MVD 接近零,编码比特少
- 中值预测对异常值不敏感,稳定性好
- 典型可节省 30-50% 的运动矢量编码比特
```
5.4 参考帧管理
多参考帧:
H.264 支持最多 16 个参考帧:
参考帧列表:
List 0 (前向参考):
┌───┬───┬───┬───┬───┐
│-5 │-4 │-3 │-2 │-1 │ ← 当前帧
└───┴───┴───┴───┴───┘
List 1 (后向参考,用于 B 帧):
当前帧 →
┌───┬───┬───┬───┬───┐
│+1 │+2 │+3 │+4 │+5 │
└───┴───┴───┴───┴───┘
参考帧选择的好处:
- 场景切换时选择最佳参考
- 周期性场景可选择更远的参考
- 提高压缩效率
5.5 B 帧预测
B 帧可以同时使用前向和后向参考:
B 帧预测模式:
时间轴: ────────────────────────────>
│ │ │
I帧 B帧 P帧
(参考1) (当前) (参考2)
B 帧可使用的预测:
1. 前向预测: 从 I 帧预测
2. 后向预测: 从 P 帧预测
3. 双向预测: 从 I 帧和 P 帧加权平均
双向预测示例:
预测值 = 0.5 × 前向预测值 + 0.5 × 后向预测值
## 6. 变换与量化
### 6.1 整数变换
H.264 使用 4×4 整数变换替代传统 DCT:
**整数变换的优势**:
- 无舍入误差
- 计算简单(只用加法和移位)
- 逆变换精确可逆
**变换过程**:
4×4 残差块 → 整数变换 → 量化
变换核 (简化):
┌───────────┐
│ 1 1 1 1│
│ 2 1 -1 -2│
│ 1 -1 -1 1│
│ 1 -2 2 -1│
└───────────┘
计算复杂度低,适合硬件实现
### 6.2 量化
**量化公式**:
量化:
|Coeff| = (|残差| × QScale + Offset) >> QBits
反量化:
残差' = |Coeff| × QScale
QP 范围: 0-51
QStep 随 QP 指数增长
**QP 与 QStep 的关系**:
| QP | QStep | 相对精度 |
|----|-------|----------|
| 0 | 0.625 | 最高 |
| 12 | 2.5 | 高 |
| 24 | 10 | 中 |
| 36 | 40 | 低 |
| 51 | 224 | 最低 |
### 6.3 变换系数扫描
**之字形扫描**(用于 4×4 块):
系数扫描顺序:
┌───┬───┬───┬───┐
│ 0 │ 1 │ 5 │ 6 │
├───┼───┼───┼───┤
│ 2 │ 4 │ 7 │12 │
├───┼───┼───┼───┤
│ 3 │ 8 │11 │13 │
├───┼───┼───┼───┤
│ 9 │10 │14 │15 │
└───┴───┴───┴───┘
从低频(0)到高频(15)排序
便于后续熵编码
## 7. 熵编码
### 7.1 CAVLC
**Context-Adaptive Variable Length Coding**
CAVLC 用于 Baseline Profile,特点:
- 基于上下文自适应选择码表
- 利用系数分布特性
**编码流程**:
残差系数编码:
1. 编码非零系数个数和拖尾1个数
(coeff_token, 根据相邻块选择码表)
2. 编码拖尾1的符号
(每个拖尾1用1bit表示符号)
3. 编码剩余非零系数的幅值
(level_prefix + level_suffix)
4. 编码最后一个非零系数前的零个数
(total_zeros)
5. 编码每个非零系数前的连续零个数
(run_before)
### 7.2 CABAC
**Context-Based Adaptive Binary Arithmetic Coding**
CABAC 用于 Main/High Profile,压缩效率更高:
CABAC 编码流程:
┌──────────────┐
│ 语法元素 │
└──────┬───────┘
↓
┌──────────────┐
│ 二值化 │ ← 将语法元素转为二进制串
└──────┬───────┘
↓
┌──────────────┐
│ 上下文建模 │ ← 根据上下文选择概率模型
└──────┬───────┘
↓
┌──────────────┐
│ 算术编码 │ ← 根据概率进行算术编码
└──────┬───────┘
↓
┌──────────────┐
│ 输出比特流 │
└──────────────┘
**CABAC 的优势**:
| 特性 | 说明 |
|------|------|
| 自适应概率 | 根据已编码数据动态调整概率 |
| 上下文模型 | 利用相邻块的相关性 |
| 算术编码 | 可以分配小数比特 |
**CAVLC vs CABAC**:
| 特性 | CAVLC | CABAC |
|------|-------|-------|
| 复杂度 | 低 | 高 |
| 压缩效率 | 基准 | +5-15% |
| 并行性 | 好 | 差 |
| 适用场景 | 移动设备 | 高清视频 |
## 8. 环路滤波
### 8.1 去块滤波
**块效应产生原因**:
- 块边界使用不同的预测模式
- 量化导致块边界的系数失真
**滤波强度**:
边界强度 (Boundary Strength, BS):
BS = 4: 边界两边都是帧内预测
BS = 3: 边界一边是帧内预测
BS = 2: 参考帧不同或运动矢量差 ≥ 1 像素
BS = 1: 参考帧相同且运动矢量差 < 1 像素
BS = 0: 不需要滤波
BS 越大,滤波强度越高
**滤波条件**:
只有满足以下条件才滤波:
|p0 - q0| < α(QP) AND
|p1 - p0| < β(QP) AND
|q1 - q0| < β(QP)
其中 α 和 β 由 QP 决定,QP 越大,阈值越大(高压缩时允许更强滤波)。
**滤波效果**:
滤波前: 滤波后:
┌───┬───┐ ┌───────┐
│ A │ B │ 边界 │ 平滑 │
├───┼───┤ ────> │ 过渡 │
│ C │ D │ │ │
└───┴───┘ └───────┘
#### 滤波顺序
宏块滤波顺序:
1. 先滤波垂直边界 (从左到右)
┌─┼─┼─┼─┐
│ │ │ │ │
└─┴─┴─┴─┘
2. 再滤波水平边界 (从上到下)
┌───┬───┬───┬───┐
├───┼───┼───┼───┤
├───┼───┼───┼───┤
└───┴───┴───┴───┘
3. 亮度先滤波,色度后滤波
## 9. Profile 与 Level
### 9.1 Profile 分类
| Profile | 特性 | 应用 |
|---------|------|------|
| Baseline | 无 B 帧、CABAC | 移动设备、视频通话 |
| Constrained Baseline | Baseline 子集 | WebRTC |
| Main | B 帧、CABAC | 广播 |
| High | 8×8 变换、量化矩阵 | 高清视频 |
**WebRTC 选择 Constrained Baseline 的原因**:
- 无 B 帧,保证低延迟
- 无 CABAC,解码复杂度低
- 广泛的硬件支持
### 9.2 Level 定义
| Level | 最大分辨率 | 最大帧率 | 最大码率 | 最大参考帧 |
|-------|-----------|----------|----------|-----------|
| 3.0 | 720p | 30fps | 10 Mbps | 4 |
| 3.1 | 720p | 30fps | 14 Mbps | 4 |
| 4.0 | 1080p | 30fps | 20 Mbps | 4 |
| 4.1 | 1080p | 30fps | 50 Mbps | 4 |
| 5.0 | 4K | 30fps | 135 Mbps | 16 |
### 9.3 Profile-Level-ID
在 SDP 中通过 profile-level-id 协商:
profile-level-id = 42e01f
解析:
0x42 = 66 = Baseline Profile
0xe0 = 约束标志
0x1f = 31 = Level 3.1
## 10. 编码工具选择
### 10.1 实时通信推荐配置
| 参数 | 推荐值 | 原因 |
|------|--------|------|
| Profile | Constrained Baseline | 低延迟、广泛支持 |
| B 帧 | 不使用 | 降低延迟 |
| 参考帧数 | 1-3 | 平衡效率与延迟 |
| 熵编码 | CAVLC | 低复杂度 |
| GOP 大小 | 大(按需请求关键帧) | 避免带宽突发 |
### 10.2 码率控制
| 场景 | 推荐策略 |
|------|----------|
| 网络稳定 | CBR(恒定码率) |
| 网络波动 | ABR(自适应码率) |
| 低延迟 | 固定 QP 或简单 ABR |
### 10.3 错误恢复策略
| 策略 | 说明 |
|------|------|
| 定期关键帧 | 简单但带宽浪费 |
| 按需关键帧 | 通过 PLI 请求 |
| NACK 重传 | 请求丢失的包 |
| FEC | 前向纠错 |
## 11. 总结
### 11.1 H.264 核心技术
| 技术 | 作用 | 关键点 |
|------|------|--------|
| 帧内预测 | 去除空间冗余 | 多方向预测 |
| 帧间预测 | 去除时间冗余 | 运动估计、多参考帧 |
| 整数变换 | 能量集中 | 4×4 块、无舍入误差 |
| 量化 | 去除视觉冗余 | QP 控制 |
| 熵编码 | 去除编码冗余 | CAVLC/CABAC |
| 环路滤波 | 消除块效应 | 去块滤波 |
### 11.2 关键优化点
1. **宏块分割**:根据内容选择合适的块大小
2. **运动估计精度**:1/4 像素精度平衡效率与复杂度
3. **参考帧管理**:合理利用多参考帧
4. **码率控制**:自适应码率应对网络波动
5. **错误恢复**:按需请求关键帧 + NACK + FEC
下一章将介绍音频编码技术。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 青羽川!
评论
