视频格式之VP8

VP8 是 Google 推出的开源免费无损专利 视频编码标准,2010 年发布,前身 On2 TrueMotion VP7,主要配套容器:WebM(.webm),也可封装进 MKV。

VP8 基于块的混合视频编码标准,仅支持 YUV 4:2:0 8 比特采样,无 B 帧,仅 I/P 帧。 整套码流由独立帧构成,每一帧划分为若干码流分区 (Partition),分区间可并行解码。 解码器核心流水线:BoolCoder 熵解码 → 预测模式 / MV 解码 → 残差反量化逆变换 → 像素预测叠加 → 环路滤波输出重建图像。

一、整体结构层次

VP8 码流层级从大到小: 码流 → 帧段 (Frame) → 宏块行 (Macroblock Row) → 宏块 (MB 16x16) → 子块 (4x4/8x8)

cpp 复制代码
┌─────────────────────────────────────────────────────────────────┐
│              VP8 Frame Bitstream Layout                         │
├─────────────────────────────────────────────────────────────────┤
│                                                               │
│  ┌──────────────┐ ┌──────────────────────────┐               │
│  │ VP8_HEADER   │ │      Partition 0         │               │
│  │ (3 bytes)    │ │ (first_partition_length) │               │
│  ├──────────────┤ ├──────────────────────────┤               │
│  │ type=0/1     │ │ - Frame Tag (4 bytes)   │               │
│  │ version      │ │ - Frame Dimensions      │               │
│  │ show_frame   │ │ - Quantization Params   │               │
│  │ partition_len│ │ - Loop Filter Params    │               │
│  └──────────────┘ │ - Probability Tables    │               │
│                   └──────────────────────────┘               │
│                                                               │
│  ┌─────────────────────────────────────────────────────────┐  │
│  │              Partitions 1-3 (Macroblock Data)           │  │
│  │  ┌──────────┬──────────┬──────────┐                    │  │
│  │  │ MB 0     │ MB 1     │ MB N-1   │                    │  │
│  │  │ Mode+MV  │ Mode+MV  │ Mode+MV  │                    │  │
│  │  │ Residual │ Residual │ Residual │                    │  │
│  │  └──────────┴──────────┴──────────┘                    │  │
│  └─────────────────────────────────────────────────────────┘  │
│                                                               │
└─────────────────────────────────────────────────────────────────┘

1.1 FrameHEADER

cpp 复制代码
typedef struct {
unsigned int type : 1;                    // 帧类型: 0=关键帧, 1=非关键帧
unsigned int version : 3;                 // 版本号
unsigned int show_frame : 1;              // 是否显示此帧
unsigned int first_partition_length_in_bytes : 19;  // 第一分区长度(最大8Mb)
} VP8_HEADER;
字段 位宽 值范围 说明
type 1 0 或 1 帧类型:0=关键帧(Key Frame),1=非关键帧(Inter Frame)
version 3 0-7 版本号:当前 VP8 版本,通常为 0
show_frame 1 0 或 1 显示标志:0=不显示,1=显示此帧
first_partition_length_in_bytes 19 0-524,287 第一分区长度:最大约 512KB(2^19 = 524,288 字节)

1.2 key frame

  • 独立解码:不依赖任何参考帧
  • 完整图像:包含完整的帧内预测信息
  • 重置状态:重置所有参考帧和概率表
  • I 帧:类似于 H.264 的 I 帧
cpp 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                   VP8 Key Frame Structure                      │
├─────────────────────────────────────────────────────────────────┤
│                                                               │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                     VP8_HEADER (3 bytes)                │   │
│  │  type=0 (KEY_FRAME), version, show_frame, part_len     │   │
│  └───────────────────┬─────────────────────────────────────┘   │
│                      │                                         │
│                      ▼                                         │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │              Partition 0 (帧头分区)                      │   │
│  │  ┌───────────────────────────────────────────────────┐  │   │
│  │  │ Start Code: 0x9D 0x01 0x2A                      │  │   │
│  │  │ (3 bytes)                                       │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ Frame Width (14 bits) + Horizontal Scale (2 bits)│  │   │
│  │  │ Frame Height (14 bits) + Vertical Scale (2 bits) │  │   │
│  │  │ (4 bytes total)                                 │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ Clamp Type (1 bit)                              │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ Segmentation Enabled (1 bit)                     │  │   │
│  │  │ + Segmentation Data (optional)                   │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ Loop Filter Parameters                          │  │   │
│  │  │   - filter_type (1 bit)                         │  │   │
│  │  │   - filter_level (6 bits)                       │  │   │
│  │  │   - sharpness_level (3 bits)                     │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ Quantization Parameters                         │  │   │
│  │  │   - base_qindex (7 bits)                        │  │   │
│  │  │   - delta-q values (optional)                    │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ Entropy Probability Tables                      │  │   │
│  │  │   - Coefficient Probs                          │  │   │
│  │  │   - Mode Probs                                 │  │   │
│  │  └───────────────────────────────────────────────────┘  │   │
│  └───────────────────┬─────────────────────────────────────┘   │
│                      │                                         │
│                      ▼                                         │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │              Partitions 1-N (宏块数据)                   │   │
│  │  ┌───────────────────────────────────────────────────┐  │   │
│  │  │ Macroblock Mode Info                             │  │   │
│  │  │   - Intra Prediction Mode                       │  │   │
│  │  │   - Y Mode, UV Mode                             │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ Residual Data (DCT Coefficients)                │  │   │
│  │  │   - Y plane (16x16)                             │  │   │
│  │  │   - U plane (8x8)                               │  │   │
│  │  │   - V plane (8x8)                               │  │   │
│  │  └───────────────────────────────────────────────────┘  │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                               │
└─────────────────────────────────────────────────────────────────┘

1.3.1 起始码(Start Code)

作为关键帧的同步标记,解码器通过此序列识别关键帧的开始。

cpp 复制代码
/* Start / synch code */
cx_data[0] = 0x9D;
cx_data[1] = 0x01;
cx_data[2] = 0x2a;

1.3.2 帧尺寸与缩放因子

cpp 复制代码
┌─────────────────────────────────────────────────────────┐
│ 字节 3-4: 宽度信息                                      │
│  ┌─────────────────────────────────────────────────┐   │
│  │ bit 15-14: Horizontal Scale (0-3)              │   │
│  │ bit 13-0: Width (0-16383)                      │   │
│  └─────────────────────────────────────────────────┘   │
├─────────────────────────────────────────────────────────┤
│ 字节 5-6: 高度信息                                      │
│  ┌─────────────────────────────────────────────────┐   │
│  │ bit 15-14: Vertical Scale (0-3)                │   │
│  │ bit 13-0: Height (0-16383)                     │   │
│  └─────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘

缩放因子说明:

缩放比例 说明
0 1/1 无缩放
1 1/2 水平/垂直缩小一半
2 1/4 缩小到 1/4
3 1/8 缩小到 1/8

1.3.3 Clamp Type(钳位类型)

钳位类型

  • RECON_CLAMP_REQUIRED (0):重建像素需要钳位
  • RECON_CLAMP_NOTREQUIRED (1):重建像素不需要钳位

1.3.4 环路滤波参数

参数 位宽 值范围 说明
filter_type 1 0-1 滤波类型:0=普通,1=简单
filter_level 6 0-63 滤波强度(0=禁用,63=最强)
sharpness_level 3 0-7 锐化程度

1.3.5 量化参数

关键帧使用基础量化索引(base_qindex):

量化索引范围:0(最高质量)~ 127(最高压缩率)

1.3 非关键帧Inter Frame

非关键帧(Inter Frame) 是 VP8 编码流中的依赖帧,需要参考之前解码的帧进行预测。它通过帧间预测和运动补偿实现高效压缩,是 VP8 实现高压缩率的核心。

  • 依赖参考帧:使用 Last/Golden/AltRef 参考帧
  • 差分编码:只编码与参考帧的差异
  • P 帧:类似于 H.264 的 P 帧

非关键帧的设计体现了 VP8 的高效压缩策略:

  1. 帧间预测:利用时间冗余,只编码与参考帧的差异
  2. 多参考帧:支持 Last/Golden/AltRef 三个参考帧,提高预测精度
  3. 灵活的参考帧更新:选择性更新参考帧,平衡压缩效率和错误恢复能力
  4. 运动向量编码优化:小 MV 用查表,大 MV 直接编码
cpp 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                   VP8 Inter Frame Structure                    │
├─────────────────────────────────────────────────────────────────┤
│                                                               │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                     VP8_HEADER (3 bytes)                │   │
│  │  type=1 (INTER_FRAME), version, show_frame, part_len   │   │
│  └───────────────────┬─────────────────────────────────────┘   │
│                      │                                         │
│                      ▼                                         │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │              Partition 0 (帧头分区)                      │   │
│  │  ┌───────────────────────────────────────────────────┐  │   │
│  │  │ Segmentation Enabled (1 bit)                     │  │   │
│  │  │ + Segmentation Data (optional)                   │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ Loop Filter Parameters                          │  │   │
│  │  │   - filter_type (1 bit)                         │  │   │
│  │  │   - filter_level (6 bits)                       │  │   │
│  │  │   - sharpness_level (3 bits)                     │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ Reference Frame Updates                         │  │   │
│  │  │   - refresh_golden_frame (1 bit)                │  │   │
│  │  │   - refresh_alt_ref_frame (1 bit)               │  │   │
│  │  │   - copy_buffer_to_gf (2 bits)                  │  │   │
│  │  │   - copy_buffer_to_arf (2 bits)                 │  │   │
│  │  │   - ref_frame_sign_bias (2 bits)                │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ refresh_entropy_probs (1 bit)                   │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ refresh_last_frame (1 bit)                      │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ Quantization Parameters                         │  │   │
│  │  │   - base_qindex (7 bits)                        │  │   │
│  │  │   - delta-q values (optional)                    │  │   │
│  │  └───────────────────────────────────────────────────┘  │   │
│  └───────────────────┬─────────────────────────────────────┘   │
│                      │                                         │
│                      ▼                                         │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │              Partitions 1-N (宏块数据)                   │   │
│  │  ┌───────────────────────────────────────────────────┐  │   │
│  │  │ Macroblock Mode Info                             │  │   │
│  │  │   - Prediction Mode (NEARESTMV/NEARMV/ZEROMV/    │  │   │
│  │  │     NEWMV/SPLITMV)                               │  │   │
│  │  │   - Reference Frame (Last/Golden/AltRef)         │  │   │
│  │  │   - Motion Vectors (row, col)                    │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ Residual Data (DCT Coefficients)                │  │   │
│  │  │   - Y plane (16x16)                             │  │   │
│  │  │   - U plane (8x8)                               │  │   │
│  │  │   - V plane (8x8)                               │  │   │
│  │  └───────────────────────────────────────────────────┘  │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                               │
└─────────────────────────────────────────────────────────────────┘

1.3.1 参考帧更新控制

参数 说明
refresh_golden_frame 是否用当前帧更新 Golden 参考帧
refresh_alt_ref_frame 是否用当前帧更新 AltRef 参考帧
copy_buffer_to_gf 不从当前帧更新时,从哪个缓冲区复制到 Golden
copy_buffer_to_arf 不从当前帧更新时,从哪个缓冲区复制到 AltRef

copy_buffer_to_gf/arf 值含义

来源
0 不复制
1 从 Last 帧复制
2 从 Golden/AltRef 帧复制

1.3.2 Last帧更新

refresh_last_frame:是否用当前帧更新 Last 参考帧(最近解码帧)

1.3.3 熵概率表更新

refresh_entropy_probs:是否重置/更新熵编码概率表

1.3.4 参考帧类型

cpp 复制代码
typedef enum {
INTRA_FRAME = 0,      // 帧内预测(无参考)
LAST_FRAME = 1,       // 最近解码帧
GOLDEN_FRAME = 2,     // 黄金参考帧
ALTREF_FRAME = 3,     // 备用参考帧
MAX_REF_FRAMES = 4
} MV_REFERENCE_FRAME;
cpp 复制代码
┌─────────────────────────────────────────────────────────┐
│              Reference Frame Management                │
├─────────────────────────────────────────────────────────┤
│                                                       │
│  Frame Buffer Pool                                    │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  │
│  │ Buffer0 │  │ Buffer1 │  │ Buffer2 │  │ Buffer3 │  │
│  └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘  │
│       │            │            │            │        │
│       ▼            ▼            ▼            ▼        │
│  ┌───────────────────────────────────────────────┐    │
│  │  lst_fb_idx → Last Frame (最近解码帧)         │    │
│  │  gld_fb_idx → Golden Frame (高质量参考帧)     │    │
│  │  alt_fb_idx → AltRef Frame (备用参考帧)       │    │
│  └───────────────────────────────────────────────┘    │
│                                                       │
│  更新策略示例:                                         │
│  ├── refresh_last_frame=1 → 当前帧 → Last            │
│  ├── refresh_golden_frame=1 → 当前帧 → Golden        │
│  ├── copy_buffer_to_gf=1 → Last → Golden            │
│  └── copy_buffer_to_arf=2 → Golden → AltRef         │
│                                                       │
└─────────────────────────────────────────────────────────┘

1.4 宏块(Macroblock)

宏块(Macroblock) 是 VP8 编码的基本处理单元,每个宏块大小为 16x16 像素。它是帧内预测、帧间预测、变换编码和熵编码的核心操作单元。

cpp 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    Macroblock Data Structures                  │
├─────────────────────────────────────────────────────────────────┤
│                                                               │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    MACROBLOCKD                          │   │
│  │  (宏块解码状态)                                          │   │
│  │  ┌───────────────────────────────────────────────────┐  │   │
│  │  │ MODE_INFO *mode_info_context                      │  │   │
│  │  │   └── MB_MODE_INFO mbmi (宏块模式信息)             │  │   │
│  │  │   └── union b_mode_info bmi[16] (块模式信息)      │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ BLOCKD block[25] (25个块的解码状态)               │  │   │
│  │  │   ├── block[0-15]: Y平面 4x4 块                  │  │   │
│  │  │   ├── block[16-19]: U平面 4x4 块                 │  │   │
│  │  │   ├── block[20-23]: V平面 4x4 块                 │  │   │
│  │  │   └── block[24]: DC二阶变换块                     │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ short qcoeff[400] (量化系数)                     │  │   │
│  │  │ short dqcoeff[400] (反量化系数)                  │  │   │
│  │  │ char eobs[25] (每块非零系数数)                    │  │   │
│  │  ├───────────────────────────────────────────────────┤  │   │
│  │  │ short dequant_y1[16] (Y1反量化表)                │  │   │
│  │  │ short dequant_y2[16] (Y2反量化表)                │  │   │
│  │  │ short dequant_uv[16] (UV反量化表)                │  │   │
│  │  └───────────────────────────────────────────────────┘  │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                               │
└─────────────────────────────────────────────────────────────────┘

1.4.1宏块结构信息

cpp 复制代码
typedef struct {
uint8_t mode, uv_mode;        // Y 和 UV 的预测模式
uint8_t ref_frame;            // 参考帧类型(Intra/Last/Golden/AltRef)
uint8_t is_4x4;               // 是否为 4x4 块模式
int_mv mv;                    // 运动向量
uint8_t partitioning;         // 分区类型
uint8_t mb_skip_coeff;        // 是否跳过系数解码(0=需要解码,1=跳过)
uint8_t need_to_clamp_mvs;    // 是否需要钳位运动向量
uint8_t segment_id;           // 分段 ID
} MB_MODE_INFO;

1.4.2 宏块像素布局

cpp 复制代码
┌─────────────────────────────────────────────────────────┐
│              Macroblock Pixel Structure (16x16)        │
├─────────────────────────────────────────────────────────┤
│                                                       │
│  Y Plane (16x16 = 256 pixels)                         │
│  ┌──────┬──────┬──────┬──────┐                       │
│  │  0   │  1   │  2   │  3   │                       │
│  │ 4x4  │ 4x4  │ 4x4  │ 4x4  │  ← BLOCKD block[0-3]  │
│  ├──────┼──────┼──────┼──────┤                       │
│  │  4   │  5   │  6   │  7   │                       │
│  │ 4x4  │ 4x4  │ 4x4  │ 4x4  │  ← BLOCKD block[4-7]  │
│  ├──────┼──────┼──────┼──────┤                       │
│  │  8   │  9   │  10  │  11  │                       │
│  │ 4x4  │ 4x4  │ 4x4  │ 4x4  │  ← BLOCKD block[8-11] │
│  ├──────┼──────┼──────┼──────┤                       │
│  │  12  │  13  │  14  │  15  │                       │
│  │ 4x4  │ 4x4  │ 4x4  │ 4x4  │  ← BLOCKD block[12-15]│
│  └──────┴──────┴──────┴──────┘                       │
│                                                       │
│  U Plane (8x8 = 64 pixels) + V Plane (8x8 = 64 pixels)│
│  ┌──────┬──────┐    ┌──────┬──────┐                  │
│  │  16  │  17  │    │  20  │  21  │                  │
│  │ 4x4  │ 4x4  │    │ 4x4  │ 4x4  │                  │
│  ├──────┼──────┤    ├──────┼──────┤                  │
│  │  18  │  19  │    │  22  │  23  │                  │
│  │ 4x4  │ 4x4  │    │ 4x4  │ 4x4  │                  │
│  └──────┴──────┘    └──────┴──────┘                  │
│    ← BLOCKD block[16-19]     ← BLOCKD block[20-23]    │
│                                                       │
│  DC Second-Order Block                                │
│  ┌──────────────────────────────────────┐            │
│  │         block[24] (DC变换块)         │            │
│  └──────────────────────────────────────┘            │
│                                                       │
│  Total: 25 blocks                                    │
│  Total pixels: 256 (Y) + 64 (U) + 64 (V) = 384       │
│                                                       │
└─────────────────────────────────────────────────────────┘

块编号与平面映射

块索引 平面 位置 尺寸
0-15 Y 16x16 区域 4x4
16-19 U 8x8 区域 4x4
20-23 V 8x8 区域 4x4
24 Y2 (DC) - 4x4(二阶变换)

二 宏块特征

2.1 帧内预测模式

cpp 复制代码
typedef enum {
DC_PRED,   // DC 预测(平均值)
V_PRED,    // 垂直预测
H_PRED,    // 水平预测
TM_PRED,   // TrueMotion 预测
B_PRED,    // 4x4 块预测(每个块独立)
// ... 帧间模式
} MB_PREDICTION_MODE;

帧内预测方向示意

复制代码
DC_PRED:  ┌───┬───┐    V_PRED:  ┌───┬───┐    H_PRED:  ┌───┬───┐
          │ A │ B │             │ A │ A │             │ A │ B │
          ├───┼───┤             ├───┼───┤             ├───┼───┤
          │ C │ X │  X=(A+B+C)/3│ C │ C │  X=A        │ C │ C │
          └───┴───┘             └───┴───┘             └───┴───┘

2.2 帧间预测模式

模式 说明
NEARESTMV 使用最近邻宏块的运动向量
NEARMV 使用次近邻宏块的运动向量
ZEROMV 使用零运动向量
NEWMV 编码新的运动向量
SPLITMV 宏块分成 4 个子块,各有独立运动向量

2.2 系数存储与Zigzag扫描

2.2.1 系数布局

每个 4x4 块包含 16 个 DCT 系数,按 Zigzag 顺序存储:

复制代码
const uint8_t kZigzag[16] = { 
0, 1,  4,  8,  5, 2,  3,  6,
9, 12, 13, 10, 7, 11, 14, 15 
};

Zigzag 扫描顺序

复制代码
原始顺序:    Zigzag顺序:
┌───┬───┬───┬───┐   ┌───┬───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │   │ 0 │ 1 │ 4 │ 8 │
├───┼───┼───┼───┤   ├───┼───┼───┼───┤
│ 4 │ 5 │ 6 │ 7 │   │ 5 │ 2 │ 3 │ 6 │
├───┼───┼───┼───┤ → ├───┼───┼───┼───┤
│ 8 │ 9 │10 │11 │   │ 9 │12 │13 │10 │
├───┼───┼───┼───┤   ├───┼───┼───┼───┤
│12 │13 │14 │15 │   │ 7 │11 │14 │15 │
└───┴───┴───┴───┘   └───┴───┴───┴───┘

2.2.2 系数缓冲区

cpp 复制代码
// MACROBLOCKD 中的系数缓冲区
DECLARE_ALIGNED(16, short, qcoeff[400]);   // 量化系数 (25块 × 16系数)
DECLARE_ALIGNED(16, short, dqcoeff[400]);  // 反量化系数
DECLARE_ALIGNED(16, char, eobs[25]);       // 每块非零系数数 (End of Block)

2.3 宏块级特性

2.3.1 分段(Segmentation)

VP8 支持将帧分成最多 4 个分段,每个分段可使用不同的量化参数和环路滤波强度:

cpp 复制代码
unsigned char segmentation_enabled;
unsigned char segment_id;                                    // 当前宏块的分段 ID
signed char segment_feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS];  // 分段特征数据

2.3.2 环路滤波 Delta

根据预测模式和参考帧类型调整滤波强度:

复制代码
signed char ref_lf_deltas[MAX_REF_LF_DELTAS];     // 参考帧相关 Delta
signed char mode_lf_deltas[MAX_MODE_LF_DELTAS];   // 模式相关 Delta

2.3.3 跳过系数

mb_skip_coeff = 1 时,表示该宏块没有残差数据,只需进行预测:

复制代码
if (xd->mode_info_context->mbmi.mb_skip_coeff) {
vp8_reset_mb_tokens_context(xd);  // 跳过系数解码
}

2.3.4 主要特性一览

特性 说明
16x16 基本单元 平衡计算复杂度和压缩效率
25 个 4x4 块 16Y + 4U + 4V + 1DC 二阶变换
帧内/帧间预测 灵活的预测模式选择
Zigzag 扫描 优化零系数的熵编码
分段支持 自适应量化和滤波
跳过系数 对于简单区域跳过残差编码