摘要:本文对 VVC(H.266)国际标准参考软件 VTM(VVC Test Model)v23.4 进行全面深度解析。从项目整体架构、模块组成,到帧内/帧间预测、变换量化、环路滤波、熵编码等核心技术模块,逐一剖析其算法原理与 C++ 实现。同时结合配置文件分析,揭示 VTM 在随机存取、全帧内、低延迟三大编码场景下的参数设定策略。适合视频编码研究者、工程师深入参考。
一、项目背景
1.1 VVC 标准简介
VVC(Versatile Video Coding,通用视频编码) ,正式标准编号为 Rec. ITU-T H.266 | ISO/IEC 23090-3 ,于 2020 年 7 月由 ITU-T VCEG 和 ISO/IEC MPEG 联合发布。相较于上一代 HEVC(H.265),VVC 在相同感知质量下可节省约 50% 的码率,代价是编码复杂度提升约 10 倍。
VVC 的主要应用场景包括:
- 8K/4K 超高清视频流媒体
- 360° 全景视频
- HDR 高动态范围视频
- VR/AR 媒体内容
- 视频会议与直播
1.2 VTM 项目定位
VTM(VVC Test Model) 是由 JVET(Joint Video Experts Team)联合开发的 VVC 官方参考软件,当前版本为 v23.4。其主要用途:
| 用途 | 说明 |
|---|---|
| 一致性检验 | 验证编解码实现是否符合标准规范 |
| 互操作性测试 | 不同厂商实现之间的互操作验证 |
| 性能基准 | 为新工具/算法提供对比基线 |
| 教学研究 | 理解 VVC 标准技术细节的权威参考 |
项目托管于 Fraunhofer HHI 的 GitLab:https://vcgit.hhi.fraunhofer.de/jvet/VVCSoftware_VTM.git
二、项目整体架构
2.1 目录结构一览
VVCSoftware_VTM-master/
├── source/
│ ├── App/ # 应用程序层
│ │ ├── EncoderApp/ # 编码器应用(EncoderApp main 入口)
│ │ ├── DecoderApp/ # 解码器应用(DecoderApp main 入口)
│ │ ├── DecoderAnalyserApp/ # 解码分析工具
│ │ ├── BitstreamExtractorApp/ # 码流提取工具
│ │ ├── SEIFilmGrainApp/ # 胶片颗粒 SEI 工具
│ │ ├── SEIRemovalApp/ # SEI 删除工具
│ │ ├── StreamMergeApp/ # 码流合并工具
│ │ ├── SubpicMergeApp/ # 子图合并工具
│ │ ├── Parcat/ # 参数集合并工具
│ │ └── utils/ # 通用工具
│ └── Lib/ # 核心库层
│ ├── CommonLib/ # 公共库(编解码共用)
│ ├── EncoderLib/ # 编码器专用库
│ ├── DecoderLib/ # 解码器专用库
│ ├── CommonAnalyserLib/ # 公共分析库
│ ├── DecoderAnalyserLib/ # 解码分析库
│ ├── Utilities/ # I/O 工具(YUV 读写等)
│ └── libmd5/ # MD5 校验库
├── cfg/ # 编码配置文件
│ ├── encoder_intra_vtm.cfg # 全帧内编码(AI)
│ ├── encoder_randomaccess_vtm.cfg # 随机存取(RA)
│ ├── encoder_lowdelay_vtm.cfg # 低延迟 B(LDB)
│ ├── encoder_lowdelay_P_vtm.cfg # 低延迟 P(LDP)
│ ├── 444/ # YUV 4:4:4 格式配置
│ ├── hbd/ # 高比特深度配置
│ ├── multi-layer/ # 多层编码配置
│ ├── rpr/ # 参考图像重采样配置
│ └── ...
├── doc/ # 软件使用手册
├── cmake/ # CMake 构建脚本
├── CMakeLists.txt # 根 CMake 构建文件
├── Makefile # Make 构建文件
└── README.md
2.2 分层架构设计
┌─────────────────────────────────────────────────────────────────────┐
│ 应用层 (App Layer) │
│ EncoderApp │ DecoderApp │ AnalyserApp │ 其他工具 Apps │
├─────────────────────────────────────────────────────────────────────┤
│ 编码器库 (EncoderLib) │
│ EncLib │ EncGOP │ EncSlice │ EncCu │ InterSearch │
│ IntraSearch │ RateCtrl │ CABACWriter │ EncALF │ EncSAO │
├─────────────────────────────────────────────────────────────────────┤
│ 解码器库 (DecoderLib) │
│ DecLib │ DecSlice │ DecCu │ CABACReader │ SEIread │
├─────────────────────────────────────────────────────────────────────┤
│ 公共库 (CommonLib) │
│ IntraPrediction │ InterPrediction │ TrQuant │
│ AdaptiveLoopFilter │ SampleAdaptiveOffset │ DeblockingFilter │
│ CodingStructure │ UnitPartitioner │ ContextModelling │
│ MatrixIntraPrediction(MIP) │ DepQuant │ Buffer │ Slice │
├──────────────────────────────────────┬──────────────────────────────┤
│ x86 SIMD 加速 (SSE/AVX) │ MIPS / ARM NEON 支持 │
└──────────────────────────────────────┴──────────────────────────────┘
三、CommonLib 公共库深度剖析
3.1 基础常量与类型定义
CommonDef.h 是整个项目的基础,定义了大量关键常量:
cpp
// 编码单元尺寸
static constexpr int MAX_CU_DEPTH = 7; // 最大 CU 深度 (log2(128)=7)
static constexpr int MAX_CU_SIZE = 128; // CTU 最大尺寸 128×128
static constexpr int MIN_CU_SIZE = 4; // 最小 CU 尺寸 4×4
// 帧内预测模式数量
static constexpr int NUM_DIR = 16;
static constexpr int NUM_INTRA_ANGULAR_MODES = 4 * NUM_DIR + 1; // 65 个角度模式
static constexpr int NUM_LUMA_MODE = 67; // 亮度模式总数(含 Planar/DC)
static constexpr int NUM_INTRA_MODE = 70; // 含色度 LMC 模式
// 帧间预测参数
static constexpr int MRG_MAX_NUM_CANDS = 6; // Merge 最大候选数
static constexpr int AFFINE_MRG_MAX_NUM_CANDS = 5; // 仿射 Merge 最大候选数
static constexpr int AMVP_MAX_NUM_CANDS = 2; // AMVP 最大候选数
// ALF(自适应环路滤波)
static constexpr int MAX_NUM_ALF_CLASSES = 25; // 最大分类数
static constexpr int MAX_NUM_ALF_LUMA_COEFF = 13; // 亮度滤波器系数数
static constexpr int ALF_FIXED_FILTER_NUM = 64; // 固定滤波器数量
// 运动向量精度
static constexpr int MV_FRACTIONAL_BITS_INTERNAL = 4; // 内部 1/16 精度
static constexpr int MV_FRACTIONAL_BITS_SIGNAL = 2; // 信号 1/4 精度
TypeDef.h 定义了全局宏开关,控制所有编码工具的使能状态:
cpp
// 典型工具开关(数值为 1 表示在当前版本中已整合)
#define JVET_AH0078_DPF 1 // 失真传播因子(DPF)
#define REUSE_CU_RESULTS 1 // CU 结果复用加速
#define ENABLE_SIMD_OPT 1 // SIMD 优化
// 针对 x86 平台支持 SSE4.1/4.2, AVX, AVX2, AVX512
3.2 编码结构 CodingStructure
CodingStructure(CodingStructure.h)是 VTM 的核心数据承载体,描述一个图像区域完整的编码信息:
cpp
class CodingStructure {
public:
UnitArea area; // 当前区域(位置 + 尺寸)
const Slice *slice; // 所属 Slice
const SPS *sps; // 序列参数集
const PPS *pps; // 图像参数集
std::vector<CodingUnit*> cus; // CU 列表
std::vector<PredictionUnit*> pus; // PU 列表
std::vector<TransformUnit*> tus; // TU 列表
PelStorage getPredBuf(); // 预测像素缓冲区
PelStorage getResiBuf(); // 残差缓冲区
PelStorage getRecoBuf(); // 重建像素缓冲区
// RD Cost 相关
double cost;
double costDbOffset;
uint64_t fracBits;
Distortion dist;
};
CodingStructure 实现了竞争式编码决策 :对于每个 CU,分配 tempCS(临时结构)和 bestCS(最优结构),通过 RD cost 比较选出最优模式。
3.3 分区分割器 UnitPartitioner
VVC 采用 QTBT(四叉树 + 二叉树)加三叉树(TT) 的灵活分割结构,由 QTBTPartitioner 类实现:
分割类型枚举 (PartSplit):
- CU_QUAD_SPLIT 四叉树分割(QT)
- CU_HORZ_SPLIT 水平二叉树分割(BT-H)
- CU_VERT_SPLIT 垂直二叉树分割(BT-V)
- CU_TRIH_SPLIT 水平三叉树分割(TT-H)
- CU_TRIV_SPLIT 垂直三叉树分割(TT-V)
- TU_MAX_TR_SPLIT TU 最大变换尺寸分割
- TU_NO_ISP / TU_1D_HORZ_SPLIT / TU_1D_VERT_SPLIT ISP 子块分割
关键参数(来自配置文件):
CTUSize = 128 # CTU 为 128×128
MinQTLumaISlice = 8 # I 帧最小 QT 叶节点尺寸
MinQTNonISlice = 8 # P/B 帧最小 QT 叶节点
MaxMTTHierarchyDepth = 3 # MTT 最大深度
四、帧内预测模块
4.1 传统角度帧内预测
VVC 将角度预测模式从 HEVC 的 33 个扩展到 65 个方向(含 Planar=0, DC=1),横跨水平、对角线、垂直四个扇区:
cpp
// CommonDef.h 中的帧内模式索引
static constexpr int PLANAR_IDX = 0; // Planar 模式
static constexpr int DC_IDX = 1; // DC 模式
static constexpr int HOR_IDX = 18; // 水平方向
static constexpr int DIA_IDX = 34; // 对角线方向
static constexpr int VER_IDX = 50; // 垂直方向
static constexpr int VDIA_IDX = 66; // 反对角线方向
static constexpr int BDPCM_IDX = (5*NUM_DIR + ANGULAR_BASE); // BDPCM 模式
IntraPrediction 类中的核心函数:
cpp
// 平坦模式预测
void xPredIntraPlanar(const CPelBuf &pSrc, PelBuf &pDst);
// DC 模式预测
void xPredIntraDc(const CPelBuf &pSrc, PelBuf &pDst,
const ChannelType channelType);
// 角度预测(含整数/分数精度插值)
void xPredIntraAng(const CPelBuf &pSrc, PelBuf &pDst,
const ChannelType channelType, const ClpRng& clpRng);
// BDPCM(块差分脉冲编码调制)
void xPredIntraBDPCM(const CPelBuf &pSrc, PelBuf &pDst,
BdpcmMode dirMode, const ClpRng &clpRng);
4.2 VVC 新增帧内工具
① MRL(Multi-Reference Line,多参考行)
cpp
static constexpr int MRL_NUM_REF_LINES = 3; // 3 条参考行选择
static constexpr int MULTI_REF_LINE_IDX[4] = { 0, 1, 2, 0 };
VVC 允许选择距当前块 第 0、1、2 行作为帧内参考,弥补复杂纹理区域单参考行预测不足的问题。
② ISP(Intra Sub-Partitions,帧内子块分割)
ISP 将一个 CU 在水平或垂直方向分割为多个矩形 TU,每个 TU 依次使用已重建子块作为参考:
cpp
// TUIntraSubPartitioner 专门处理 ISP 分割
class TUIntraSubPartitioner : public Partitioner {
void splitCurrArea(const PartSplit split, const CodingStructure &cs);
void getTUIntraSubPartitions(Partitioning &sub, const UnitArea &tuArea,
const CodingStructure &cs, const PartSplit splitType);
};
③ MIP(Matrix-based Intra Prediction,矩阵帧内预测)
MatrixIntraPrediction(MatrixIntraPrediction.h)是 VVC 最具创新性的帧内工具之一:
cpp
class MatrixIntraPrediction {
public:
// 准备输入:下采样边界像素
void prepareInputForPred(const CPelBuf &pSrc, const Area &block,
const int bitDepth, const ComponentID compId);
// 矩阵乘法预测
void predBlock(Pel *const result, const int modeIdx, const bool transpose,
const int bitDepth, const ComponentID compId);
static int getNumModesMip(const Size &block);
private:
// 根据块尺寸分组(S0: 4×4, S1: 8×8 or 4×8, S2: 16×16+)
enum class MipSizeId { S0 = 0, S1, S2, NUM };
static constexpr int MIP_MAX_INPUT_SIZE = 8; // 最大输入向量长度
static constexpr int MIP_MAX_REDUCED_OUTPUT_SAMPLES = 64; // 最大输出采样数
};
MIP 核心思想 :将边界像素下采样为向量 → 与预存矩阵相乘 → 上采样得到预测块。矩阵系数存于 MipData.h,支持最多 32 种 MIP 模式。
④ CCLM(Cross-Component Linear Model,跨分量线性模型)
色度预测采用 CCLM,从重建亮度信号线性预测:
cpp
// 从亮度重建像素估计线性模型参数 a, b
void xGetLMParameters(const PredictionUnit &pu, const ComponentID compID,
const CompArea &chromaArea, int &a, int &b, int &iShift);
// 实际色度预测:Chroma = a × Luma + b
void predIntraChromaLM(const ComponentID compID, PelBuf &piPred,
const PredictionUnit &pu, const CompArea &chromaArea,
int intraDir);
##🏃 五、帧间预测模块
5.1 运动向量精度与搜索
VVC 的 MV 精度达到 1/16 像素(内部),比 HEVC 提高了一倍:
cpp
static constexpr int MV_FRACTIONAL_BITS_INTERNAL = 4; // 1/16 精度
static constexpr int NTAPS_LUMA = 8; // 亮度 8 抽头插值
static constexpr int NTAPS_LUMA_AFFINE = 6; // 仿射 6 抽头插值
static constexpr int NTAPS_CHROMA = 4; // 色度 4 抽头插值
AMVR(自适应运动向量分辨率) :VVC 允许在同一帧内对不同 CU 选择不同的 MV 精度(1/4、1/2、整数或 4 整数像素),由 IMV 工具控制。
5.2 Merge 模式体系
VVC Merge 候选列表(最多 6 个)
├── 空间 Merge 候选(5 个空间邻居)
├── 时域 Merge 候选(TMVP/ATMVP)
├── HMVP(History-based MVP)候选 ← VVC 新增
│ static constexpr int MAX_NUM_HMVP_CANDS = 5
├── 配对平均 MVP 候选(Pairwise Average)
└── 零 MV 补位候选
MergeCtx 类管理 Merge 候选列表:
cpp
class MergeCtx {
bool mvSolid[MRG_MAX_NUM_CANDS][2]; // MV 是否稳定
bool mvValid[MRG_MAX_NUM_CANDS][2]; // MV 是否有效
bool useAltHpelIf[MRG_MAX_NUM_CANDS]; // 是否使用半像素插值
// MMVD(Merge with MVD)模式
bool mmvdSolid[MmvdIdx::BASE_MV_NUM][2];
void setMergeInfo(PredictionUnit &pu, int candIdx) const;
void setMmvdMergeCandiInfo(PredictionUnit &pu, MmvdIdx candIdx);
};
5.3 VVC 高级帧间工具
① 仿射运动预测(Affine Motion)
VVC 支持 4 参数(平移+旋转+缩放) 和 6 参数(+剪切) 仿射模型:
cpp
enum class AffineModel : uint8_t { _4_PARAMS, _6_PARAMS, NUM };
static constexpr int AFFINE_MAX_NUM_CP = 3; // 最多 3 个控制点
static constexpr int AFFINE_SUBBLOCK_SIZE = 4; // 仿射子块最小尺寸 4×4
static constexpr int AFFINE_MRG_MAX_NUM_CANDS = 5; // 仿射 Merge 候选数
xPredAffineBlk() 将 CU 划分为 4×4 子块,对每个子块分别计算 MV 并独立进行运动补偿。
② DMVR(Decoder-side Motion Vector Refinement)
cpp
// DMVR 子块尺寸
static constexpr int DMVR_SUBCU_WIDTH = 16;
static constexpr int DMVR_SUBCU_HEIGHT = 16;
static constexpr int DMVR_RANGE = 2; // 搜索半径 ±2 像素
static constexpr int DMVR_SPAN = 5; // = 2*RANGE + 1
DMVR 在解码端对双预测 MV 进行精细化搜索,无需额外码字,仅需微小的计算开销。
③ BDOF(Bi-Directional Optical Flow,双向光流精细化)
cpp
static constexpr int MAX_BDOF_APPLICATION_REGION = 16; // 最大应用区域
void applyBiOptFlow(const PredictionUnit &pu,
const CPelUnitBuf &yuvSrc0,
const CPelUnitBuf &yuvSrc1,
PelUnitBuf &yuvDst,
const BitDepths &clipBitDepths);
BDOF 利用光流约束方程在 4×4 子块级对双预测信号进行像素级精细化,显著提升双向预测精度。
④ PROF(Prediction Refinement with Optical Flow,基于光流的仿射预测精细化)
cpp
static constexpr int PROF_BORDER_EXT_W = 1;
static constexpr int PROF_BORDER_EXT_H = 1;
PROF 对仿射运动补偿后的预测块进行光流精细化,消除仿射子块边界的不连续性。
⑤ GEO(Geometric Partitioning,几何分割)
cpp
static constexpr int GEO_NUM_PARTITION_MODE = 64; // 64 种几何分割模式
static constexpr int GEO_NUM_ANGLES = 32; // 32 个分割角度
static constexpr int GEO_MAX_NUM_UNI_CANDS = 6; // 最大单向候选数
static constexpr int GEO_MAX_NUM_CANDS = 30; // 最大双向候选组合数
GEO 允许 CU 被任意角度的直线分割为两个非矩形区域,两区域使用独立的运动向量,适合覆盖物体边界的 CU。
⑥ BCW(Bi-Prediction with CU-level Weights,CU 级加权双预测)
cpp
static constexpr int BCW_NUM = 5; // 5 种权重组合 (−2/8, 3/8, 4/8, 5/8, 10/8)
static constexpr int BCW_DEFAULT = 2; // 默认 = 等权 4/8:4/8
static constexpr int BCW_SIZE_CONSTRAINT = 256; // 仅对 ≥256 像素 CU 启用
⑦ IBC(Intra Block Copy,帧内块拷贝)
cpp
static constexpr int IBC_MAX_CU_SIZE = 64; // 最大 IBC 块 64×64
static constexpr int IBC_NUM_CANDIDATES = 64; // 候选存储数
static constexpr int IBC_REF_IDX = MAX_NUM_ACTIVE_REF; // IBC 参考帧索引
IBC 在当前图像内搜索匹配块,对于屏幕内容(界面、文字、游戏)编码效率极高。
六、变换与量化模块
6.1 变换工具体系
VVC 支持多种变换类型,统一由 TrQuant 类管理:
cpp
class TrQuant {
// 正向变换 (编码端)
void transformNxN(TransformUnit &tu, const ComponentID &compID,
const QpParam &cQP, TCoeff &absSum, const Ctx &ctx,
RDPCostList &trModes, ...);
// 逆变换 (解码端)
void invTransformNxN(TransformUnit &tu, const ComponentID &compID,
PelBuf &pResi, const QpParam &cQPs);
// 变换类型选择
void getTrTypes(const TransformUnit tu, const ComponentID compID,
TransType &trTypeHor, TransType &trTypeVer);
// LFNST 正/逆变换
void fwdLfnstNxN(TCoeff* src, TCoeff* dst, uint32_t mode,
uint32_t index, uint32_t size, int zeroOutSize);
void invLfnstNxN(TCoeff* src, TCoeff* dst, uint32_t mode,
uint32_t index, uint32_t size, int zeroOutSize,
const int maxLog2TrDynamicRange);
};
VVC 支持的变换类型:
| 变换 | 说明 | 应用场景 |
|---|---|---|
| DCT-2 | 标准 2D DCT | 通用,默认选择 |
| DST-7 | 正弦类型 VII | 帧内残差(接近边界的 TU) |
| DCT-8 | 余弦类型 VIII | 帧内残差 |
| TS(Transform Skip) | 跳过变换 | 屏幕内容/高频纹理 |
| BDPCM | 块 DPCM | 屏幕内容帧内 |
MTS(Multiple Transform Selection):允许对同一 CU 评估多种变换组合(水平+垂直独立选择):
cpp
static constexpr uint32_t NUM_TRAFO_MODES_MTS = 6; // 最多 6 种变换组合
static constexpr uint32_t MTS_INTRA_MAX_CU_SIZE = 32; // 帧内 MTS 最大 CU
static constexpr uint32_t MTS_INTER_MAX_CU_SIZE = 32; // 帧间 MTS 最大 CU
LFNST(Low-Frequency Non-Separable Transform):
cpp
static constexpr int MAX_LFNST_COEF_NUM = 16; // 最多 16 个非分离变换系数
static constexpr int NUM_LFNST_NUM_PER_SET = 3; // 每组 3 个 LFNST 矩阵
LFNST 在主变换(DCT-2/DST-7)后对左上角 4×4 系数块应用一个额外的非分离变换,进一步去除能量集中区域的相关性,尤其适合帧内编码。
SBT(Sub-block Transform,子块变换):
cpp
static constexpr int SBT_MAX_SIZE = 64; // SBT 最大 CU 尺寸
static constexpr int SBT_NUM_SL = 10; // 历史保存的 PU 决策数
static constexpr int SBT_NUM_RDO = 2; // 每 PU 最多尝试的 SBT 模式数
SBT 将 CU 残差限制在半块(水平或垂直的上/左半部分),变换仅应用于有残差能量的子块,减少需要传输的系数。
6.2 量化模块
cpp
// 量化参数范围
static constexpr int MAX_QP = 63; // VVC 将 QP 范围扩展至 0-63
static constexpr int QUANT_SHIFT = 14; // Q(4) = 2^14
static constexpr int IQUANT_SHIFT = 6;
// 色度 QP 映射
static constexpr int MAX_NUM_CQP_MAPPING_TABLES = 3; // Cb/Cr/联合
static constexpr int MAX_QP_OFFSET_LIST_SIZE = 6;
// 依赖量化 (DepQuant)
// DepQuant.h: 基于 Trellis 的上下文依赖量化,显著提升 RD 效率
RDOQ(Rate-Distortion Optimized Quantization):在量化过程中考虑码率代价,选择最优量化步骤(通过 Lagrange 乘子 λ 折衷 R 和 D)。
依赖量化(DepQuant):VVC 引入了状态机依赖的量化方案,通过前后系数的状态转移进一步优化 RD 性能,是相比 HEVC 的重要改进之一。
七、环路滤波模块
7.1 去方块滤波(DBF)
VVC 的 DBF 相较 HEVC 有所增强,支持对 Cb 和 Cr 分量独立配置:
cpp
// 配置文件参数示例
DeblockingFilterBetaOffset_div2 : -2 // β 偏移
DeblockingFilterTcOffset_div2 : 0 // Tc 偏移
DeblockingFilterCbBetaOffset_div2 : -2 // Cb β 偏移
DeblockingFilterCrBetaOffset_div2 : -2 // Cr β 偏移
7.2 SAO(样本自适应偏移)
cpp
class SampleAdaptiveOffset {
// SAO 类型:Band Offset(BO)和 Edge Offset(EO)
// EO 方向:水平/垂直/135°/45°
};
SAO 通过在重建样本中添加查找表偏移量来减少量化失真,是 HEVC 引入并在 VVC 中保留的工具。
7.3 ALF(自适应环路滤波)------ VVC 核心改进
ALF 是 VVC 相较 HEVC 最重要的新增环路滤波工具之一:
cpp
class AdaptiveLoopFilter {
// 分类:将 CTU 内的 4×4 块分为 25 类
void deriveClassification(AlfClassifier **classifier,
const CPelBuf &srcLuma,
const Area &blkDst, const Area &blk);
// 滤波器应用(5×5 和 7×7 两种形状)
void (*m_filter5x5Blk)(...); // 5×5 钻石形
void (*m_filter7x7Blk)(...); // 7×7 钻石形
// CC-ALF(跨分量 ALF)
static void filterBlkCcAlf(const PelBuf &dstBuf,
const CPelUnitBuf &recSrc,
const Area &blkDst, const Area &blkSrc,
ComponentID compID, ...);
};
ALF 关键参数:
cpp
static constexpr int MAX_NUM_ALF_CLASSES = 25; // Laplacian 梯度分 25 类
static constexpr int MAX_NUM_ALF_LUMA_COEFF = 13; // 亮度 7×7 13 系数(钻石)
static constexpr int MAX_NUM_ALF_CHROMA_COEFF = 7; // 色度 5×5 7 系数
static constexpr int ALF_FIXED_FILTER_NUM = 64; // 固定 64 个预置滤波器集合
static constexpr int MAX_NUM_CC_ALF_FILTERS = 4; // CC-ALF 最多 4 个滤波器
static constexpr int MAX_NUM_CC_ALF_CHROMA_COEFF = 8; // CC-ALF 系数数
CC-ALF(Cross-Component ALF):色度 ALF 中引入亮度信号辅助滤波,进一步提升色度质量:
cpp
void applyCcAlfFilter(CodingStructure &cs, ComponentID compID,
const PelBuf &dstBuf,
const PelUnitBuf &recYuvExt, ...);
7.4 LMCS(Luma Mapping with Chroma Scaling,亮度映射+色度缩放)
cpp
// EncReshape.cpp 中实现
// LMCS = 自适应分段线性亮度映射 + 色度残差缩放
// 主要用于 HDR 内容,调整 QP 分配使亮度均匀量化
LMCSEnable : 1 # 使能 LMCS
LMCSSignalType : 0 # 0=SDR, 1=HDR-PQ, 2=HDR-HLG
LMCSOffset : 6 # 色度残差缩放偏移
八、熵编码模块(CABAC)
8.1 算术编码器架构
VVC 延续 HEVC 的 CABAC(Context-based Adaptive Binary Arithmetic Coding)框架,在 BinEncoder/BinDecoder 中实现:
编码端 CABAC 调用链:
EncCu → CABACWriter → BinEncoder
├── VLCWriter(VLC 固定码)
└── 上下文自适应模型(Contexts.h)
解码端 CABAC 调用链:
DecCu → CABACReader → BinDecoder
├── VLCReader
└── 上下文模型
8.2 上下文模型管理
cpp
// ContextModelling.h
class CUCtx {
// CU 级上下文管理
void setNumCtxBins(int n); // 设置上下文 bin 限制
void decimateNumCtxBins(int n); // 消耗上下文 bin 计数
};
// 分割决策上下文
void CtxSplit(const CodingStructure &cs, Partitioner &partitioner,
unsigned &ctxSpl, unsigned &ctxQt, unsigned &ctxHv,
unsigned &ctxHorBt, unsigned &ctxVerBt, bool *canSplit);
// Rice 参数自适应更新
void updateRiceStat(unsigned &riceStat, TCoeff rem, int remainderFlag);
VVC 引入了 TU 级 bin 约束机制,限制每个 TU 中可使用的上下文 bin 数量,有效控制解码复杂度:
cpp
static constexpr int MAX_TU_LEVEL_CTX_CODED_BIN_CONSTRAINT_LUMA = 28;
static constexpr int MAX_TU_LEVEL_CTX_CODED_BIN_CONSTRAINT_CHROMA = 28;
九、编码器核心决策:EncCu
9.1 CU 压缩主流程
EncCu::compressCtu() 是编码器的核心入口,对每个 CTU 进行 RDO 搜索:
cpp
void EncCu::compressCtu(CodingStructure &cs, const UnitArea &area,
const unsigned ctuRsAddr,
const EnumArray<int, ChannelType> &prevQP,
const EnumArray<int, ChannelType> &currQP) {
// 入口 → 递归分割 → 模式选择
xCompressCU(tempCS, bestCS, partitioner);
}
void EncCu::xCompressCU(CodingStructure *&tempCS, CodingStructure *&bestCS,
Partitioner &pm, double maxCostAllowed) {
// 1. 初始化当前级别上下文 (EncModeCtrl::initCULevel)
// 2. 遍历所有候选模式 (通过 EncModeCtrl 迭代)
// - xCheckRDCostIntra() 帧内编码 RD 代价
// - xCheckRDCostMerge2Nx2N() Merge 模式 RD 代价
// - xCheckRDCostInter() 帧间编码 RD 代价
// - xCheckModeSplit() 分割模式 RD 代价
// 3. 选出最优模式 → 更新 bestCS
}
关键核心函数(EncCu.cpp 共 4825 行):
cpp
// 分割决策
void xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS,
Partitioner &pm, const EncTestMode &encTestMode,
const ModeType modeTypeParent, ...);
// 帧内编码
bool xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS,
Partitioner &pm, const EncTestMode &encTestMode,
bool adaptiveColorTrans);
// 抑制增益计算(去块优化)
void xCalDebCost(CodingStructure &cs, Partitioner &partitioner, bool calDist);
// 几何分割
// Geo Merge 候选组合评估(多达 30 种方向组合)
9.2 编码模式控制器 EncModeCtrl
EncModeCtrl(抽象基类)管理编码决策流程,提供早终止、快速算法等优化:
cpp
class EncModeCtrl {
virtual void initCTUEncoding(const Slice &slice) = 0;
virtual void initCULevel(Partitioner &partitioner, const CodingStructure &cs) = 0;
virtual void finishCULevel(Partitioner &partitioner) = 0;
// 早终止优化
void setEarlySkipDetected();
// 快速决策相关
void setBestCostWithoutSplitFlags(double cost);
void setMtsFirstPassNoIspCost(double cost);
void setStopNonDCT2Transforms(bool val);
// ISP/MTS/LFNST 快速控制
void setISPMode(const ISPType val);
void setISPLfnstIdx(uint8_t val);
void setBestPredModeDCT2(uint16_t intraMode, bool mipFlag);
};
9.3 GOP 层编码 EncGOP
EncGOP(EncGOP.h/EncGOP.cpp)管理 GOP 级编码流程:
cpp
// EncGOP 集成的组件
├── EncSampleAdaptiveOffset // SAO 编码
├── EncAdaptiveLoopFilter // ALF 编码
├── EncReshape // LMCS 编码
├── EncSlice // Slice 编码
├── VLCWriter // VLC 码流写入
├── CABACWriter // CABAC 编码
├── SEIwrite / SEIEncoder // SEI 消息编写
├── SEIFilmGrainAnalyzer // 胶片颗粒 SEI 分析
└── RateCtrl // 码率控制
十、码率控制系统
10.1 层次化码率控制
VVC 的码率控制在三个层次进行:
cpp
class RateCtrl {
EncRCSeq *m_encRCSeq; // 序列级码控
EncRCGOP *m_encRCGOP; // GOP 级码控
EncRCPic *m_encRCPic; // 图像级码控
void init(int totalFrames, int targetBitrate,
const Fraction &frameRate, int GOPSize,
int intraPeriod, int picWidth, int picHeight, ...);
};
class EncRCPic {
void create(EncRCSeq *encRCSeq, EncRCGOP *encRCGOP, int frameLevel, ...);
void updateAfterCTU(int LCUIdx, int bits, int QP, double lambda, ...);
void updateAfterPicture(int actualHeaderBits, int actualTotalBits,
double averageQP, double averageLambda, bool isIRAP);
};
10.2 λ-QP 模型
VVC 码率控制采用 R-λ 模型,基于 Hyperbolic 函数:
R = α × λ^β (其中 α, β 为 CTU 级自适应估计参数)
λ = (α/R)^(1/β)
通过在 CTU 级持续更新 (α, β) 参数,实现精细的 QP 自适应调整。
十一、SIMD 加速架构
VTM 支持多级 x86 SIMD 优化:
source/Lib/CommonLib/x86/
├── sse41/ # SSE4.1 优化(最低兼容要求)
├── sse42/ # SSE4.2 优化
├── avx/ # AVX 优化(256-bit)
└── avx2/ # AVX2 优化(推荐生产环境)
优化覆盖的模块:
- AdaptiveLoopFilterX86.h # ALF SIMD
- BufferX86.h # 像素缓冲操作 SIMD
- InterpolationFilterX86.h # 运动补偿插值 SIMD
- TrQuantX86.h # 变换量化 SIMD
- RdCostX86.h # SAD/SATD/SSE 代价函数 SIMD
- AffineGradientSearchX86.h # 仿射梯度计算 SIMD
- IbcHashMapX86.h # IBC 哈希检索 SIMD
SIMD 运行时检测:
cpp
typedef enum { SCALAR=0, SSE41, SSE42, AVX, AVX2, AVX512 } X86_VEXT;
X86_VEXT read_x86_extension_flags(const std::string &extStrId);
内存对齐配置(AVX2 需要 32 字节对齐):
cpp
constexpr size_t MEMORY_ALIGN_DEF_SIZE = 32; // AVX2 对齐
#define xMalloc(type, len) _aligned_malloc(sizeof(type) * (len), MEMORY_ALIGN_DEF_SIZE)
十二、编码配置文件解析
12.1 随机存取(RA)配置
文件:cfg/encoder_randomaccess_vtm.cfg
ini
# 编码结构
CTUSize = 128 # 128×128 CTU(VVC 标准最大)
IntraPeriod = 32 # 每 32 帧一个 I 帧
GOPSize = 32 # 32 帧 GOP,多级 B 帧层次
DecodingRefreshType = 1 # CRA(Clean Random Access)
# MTT 分割
MaxMTTHierarchyDepth = 3 # 最大 3 级 MTT(在 QT 叶节点后)
DualITree = 1 # I 帧亮度/色度独立分割树
# 全套工具使能
MTS=1 LFNST=1 ISP=1 MIP=1 MRL=1
Affine=1 DMVR=1 BIO=1 BDOF=1 BCW=1
MMVD=1 CIIP=1 Geo=1 SbTMVP=1 SMVD=1
ALF=1 LMCS=1 JointCbCr=1 PROF=1 DepQuant=1
# 时域预滤波
TemporalFilter=1
TemporalFilterStrengthFrame8 = 0.95
TemporalFilterStrengthFrame16 = 1.5
12.2 三种编码配置对比
| 参数 | 全帧内 (AI) | 随机存取 (RA) | 低延迟 B (LDB) |
|---|---|---|---|
| IntraPeriod | -1(仅首帧)或1 | 32 | -1 |
| GOPSize | 1 | 32 | 16 |
| B 帧 | 无 | 多层 B | 只有 B(低延迟) |
| 参考帧数 | 1 | 5(双向) | 4(单向) |
| 时域滤波 | 无 | 有(强) | 有(弱) |
| 主要用途 | 图像/高质量帧 | 点播/直播 | 会议/低延 |
十三、解码器架构
13.1 解码流程
码流输入 → NALread → VLCReader → CABACReader
↓
DecLib(DecLib.cpp: 4289行)
↓
DecSlice → DecCu
↓
IntraPrediction / InterPrediction
TrQuant(逆变换逆量化)
AdaptiveLoopFilter
SampleAdaptiveOffset
DeblockingFilter
↓
重建图像输出
13.2 解码器工具类
DecoderLib 目录(共 19 个文件):
| 文件 | 功能 |
|---|---|
DecLib.cpp |
解码器主类,管理参数集、POC、参考图像列表 |
DecCu.cpp |
CU 级解码(重建预测、残差、重建) |
CABACReader.cpp |
CABAC 算术解码器 |
BinDecoder.cpp |
二值化解码器(VLC/CABAC bin) |
NALread.cpp |
NAL 单元解析(起始码检测、RBSP 脱壳) |
SEIread.cpp |
SEI 消息解析 |
VLCReader.cpp |
可变长码读取 |
十四、性能特性与工程实践
14.1 编码复杂度分布
帧内预测(I帧): ~25-30% 总编码时间
帧间搜索(P/B帧):
├── InterSearch.cpp (11458行): 全搜索/TZ搜索/仿射搜索 ~35-40%
└── IntraSearch.cpp (6376行): 帧内候选评估 ~10-15%
变换量化 (EncCu.cpp 4825行): ~15-20%
ALF/SAO/DBF: ~5-10%
熵编码: ~3-5%
14.2 快速算法(Fast Tools)
ini
# 配置文件中的快速算法开关
PBIntraFast : 1 # 快速帧内决策(哈达玛 SATD 初筛)
FastMrg : 1 # 快速 Merge(早终止)
AMaxBT : 1 # 自适应最大 BT 深度
FastLocalDualTreeMode : 1 # 快速双树决策
BcwFast : 1 # BCW 快速搜索
LCTUFast : 1 # 大 CTU 快速决策
MTTSkipping : 1 # MTT 跳过优化
MmvdDisNum : 6 # MMVD 搜索点数限制
14.3 构建方法
bash
# 创建构建目录
mkdir build && cd build
# Windows Visual Studio 2019
cmake .. -G "Visual Studio 16 2019" -A x64
# Linux Release 版本(推荐)
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
# macOS Xcode
cmake .. -G "Xcode"
14.4 基本使用
bash
# 编码(随机存取,QP=32)
EncoderApp -c encoder_randomaccess_vtm.cfg \
-c per-sequence/BasketballDrive.cfg \
-i input.yuv -o output.bin --QP 32
# 解码
DecoderApp -b output.bin -o decoded.yuv
# 解码分析(统计工具使用信息)
DecoderAnalyserApp -b output.bin
# 码流提取(多层编码)
BitstreamExtractorApp -b input.bin -o extracted.bin
十五、VVC vs HEVC 技术对比
| 特性 | HEVC (H.265) | VVC (H.266) |
|---|---|---|
| CTU 最大尺寸 | 64×64 | 128×128 |
| 分割结构 | QT | QT + BT + TT |
| 帧内预测角度 | 33 | 67 |
| 新增帧内工具 | 无 | MIP、ISP、MRL、CCLM |
| 仿射运动 | 无 | 4/6 参数仿射 |
| 高级 Merge | TMVP | HMVP、MMVD、CIIP、GEO、BCW |
| 运动精度 | 1/4 (HEVC) | 1/16 像素 |
| 帧间优化 | 无 | BDOF、DMVR、PROF |
| 变换 | DCT-2 | DCT-2/DST-7/DCT-8/MTS/LFNST/SBT |
| 量化 | 固定 | 依赖量化 + RDOQ |
| 环路滤波 | DBF+SAO | DBF+SAO+ALF(含CC-ALF)+LMCS |
| 最大 QP | 51 | 63 |
| 压缩效率 | 基准 | 约提升 50%(BD-Rate -50%) |
十六、总结与展望
VTM(VVC 参考软件)是迄今为止技术复杂度最高的视频编解码参考软件之一,本文从以下维度进行了全面剖析:
- 宏观架构:三层设计(App / EncoderLib / CommonLib),模块职责清晰
- 帧内创新:67 个角度模式 + MRL + ISP + MIP + CCLM,全面覆盖各类纹理
- 帧间突破:仿射运动、BDOF/DMVR/PROF 光流优化、GEO 几何分割、BCW 加权双预测
- 变换革命:MTS + LFNST + SBT + 依赖量化,极大提升变换域压缩效率
- 滤波升级:ALF(含 CC-ALF)+ LMCS,显著提升重建质量
- 工程优化:AVX2/SSE4.1 SIMD 全模块覆盖,运行时指令集检测
随着 VVC 在 OTT 流媒体(Disney+、Netflix)和广播(DVB、ATSC 3.0)中的逐步部署,VTM 的价值将持续提升。对于研究者来说,VTM 既是研究新算法的实验平台,也是理解 VVC 标准底层实现的不二之选。
参考资料
- ITU-T H.266 / ISO/IEC 23090-3: Versatile Video Coding 国际标准
- VTM 官方 Git 仓库: https://vcgit.hhi.fraunhofer.de/jvet/VVCSoftware_VTM
- JVET 会议文稿: https://www.jvet-experts.org/
- VTM 软件手册: VVCSoftware_VTM-master/doc/ 目录
- BD-Rate 工具: https://www.itu.int/rec/T-REC-H.265
标签: VVC, H.266, VTM, 视频编码, 帧内预测, 帧间预测, ALF, CABAC, MIP, 仿射运动, 依赖量化, LFNST, 视频压缩, ITU, ISO
项目版本: VTM v23.4 (2024, ITU/ISO/IEC)
创作日期: 2026年5月