4、H265帧间预测:运动估计、运动补偿、Merge模式、AMVP技术
帧间预测,说白了就是利用视频相邻帧之间的冗余信息来压缩数据。你想想看,一个物体在连续几帧里,位置可能变了,但长相没变。我们只需要告诉解码器:「这个块上一帧在那个位置,现在挪到这里了」,就能省下大量比特。
H265的帧间预测比H264复杂了不少,但核心思路没变:运动估计找参考块,运动补偿重建残差。不过H265多了Merge和AMVP这两个「聪明」的模式,让编码效率又上了一个台阶。
4.1 运动估计与运动补偿
运动估计(Motion Estimation, ME)是编码器最耗时的环节之一。我早期优化编码器时,发现ME能占到整个编码时间的60%以上。说白了,就是在参考帧里找一个最匹配的块。
H265支持的运动矢量精度最高到1/4像素。整像素搜索完,还要做亚像素插值。插值滤波器用的是DCT-IF(离散余弦变换插值滤波器),比H264的Wiener滤波器精度更高。
运动估计的核心流程:
- 确定搜索范围(通常为[-64, 64]像素)
- 整像素搜索(菱形搜索、六边形搜索等)
- 亚像素精化(1/2像素 → 1/4像素)
- 计算率失真代价(J = D + λ·R)
运动补偿(Motion Compensation, MC)就是根据运动矢量,从参考帧里把预测块「抠」出来。然后和当前块做差,得到残差块。残差再经过变换、量化、熵编码,就写进码流了。
这里有个细节:H265的预测块(PB)大小可以是64x64、32x32、16x16、8x8、4x4。但4x4只在特殊情况下用,我一般建议至少用8x8,否则码率开销太大。
4.2 Merge模式
Merge模式是H265的一大亮点。它的思路很简单:我不传运动矢量,只传一个索引。解码器根据索引,从候选列表里拿一个运动矢量直接用。
为什么会这样设计?因为相邻块的运动往往高度相关。一个宏块和它左边的块,大概率是同一个物体的运动。那何必重复传呢?
Merge模式的候选列表最多5个,按以下顺序构建:
| 候选序号 | 来源 | 说明 |
|---|---|---|
| 0 | 空域左方(A0, A1) | 当前块左侧的相邻块 |
| 1 | 空域上方(B0, B1, B2) | 当前块上方的相邻块 |
| 2 | 时域同位(Col) | 参考帧中相同位置的块 |
| 3 | 组合候选 | 前两个候选的加权组合 |
| 4 | 零矢量 | (0, 0) 兜底 |
我个人的经验:在低码率场景下(比如视频会议),Merge模式的使用率能到70%以上。因为画面运动小,相邻块的运动矢量几乎一样。这时候传一个索引比传一个完整的运动矢量省太多比特了。
Merge模式还有一个变种叫Skip模式。Skip模式不仅不传运动矢量,连残差都不传。解码器直接用预测块当重建块。这种模式在静止背景或缓慢运动的区域特别高效。
4.3 AMVP技术
AMVP(Advanced Motion Vector Prediction)是H265的另一个关键技术。它和Merge模式有点像,但有个本质区别:AMVP只预测运动矢量,不直接使用。编码器会传一个MVD(运动矢量差值),告诉解码器「预测值和我实际用的值差多少」。
AMVP的候选列表只有2个候选,比Merge少。构建方式如下:
- 空域候选:从左侧和上方各选一个
- 时域候选:从参考帧的同位块获取
- 如果候选不足:用零矢量补齐
编码器会从这2个候选里选一个率失真代价最小的,然后计算MVD。解码器拿到MVD后,加上预测值,就得到实际运动矢量。
我曾经踩过的坑:AMVP的时域候选需要做缩放。因为参考帧和当前帧的时间距离可能不同。如果不做缩放,运动矢量会偏差很大。HM参考软件里有个函数叫getScaledMV,就是干这个的。我第一次写的时候忘了调用,结果编码出来的视频全是马赛克。
4.4 Merge vs AMVP 对比
| 特性 | Merge模式 | AMVP |
|---|---|---|
| 传输内容 | 候选索引(merge_idx) | 候选索引 + MVD |
| 候选数量 | 最多5个 | 2个 |
| 运动矢量精度 | 直接使用候选MV | 预测MV + MVD |
| 适用场景 | 运动简单、相邻块相似 | 运动复杂、需要精细调整 |
| 码率开销 | 低(只传索引) | 中(索引 + 差值) |
实际编码时,编码器会为每个预测单元(PU)做一次模式决策:是用Merge、Skip还是AMVP?这个决策基于率失真优化(RDO)。说白了,就是算一笔账:用哪种模式,失真最小、码率最低。
4.5 帧间预测整体流程
我把帧间预测的决策流程画了一张图,方便你理解:
4.6 实际编码中的注意事项
讲几个我在项目中遇到的坑:
- 参考帧管理:H265支持最多16个参考帧(H264只有16个?不对,H264也是16个,但H265的DPB管理更复杂)。我建议B帧用2个参考帧就够了,P帧用4个。再多对压缩率提升微乎其微,反而增加内存带宽。
- 运动搜索范围:不是越大越好。1080p视频,搜索范围±64像素基本够用。4K视频可以扩大到±128。我见过有人设±256,编码时间翻倍,码率只降了0.5%。
- Merge候选列表裁剪:HM参考软件里有个去重逻辑。如果两个候选的运动矢量相同,只保留一个。这个逻辑一定要实现,否则候选列表里全是重复的,浪费索引比特。
一个小技巧:在FFmpeg里用libx265编码时,可以通过-x265-params调整帧间预测参数。比如-x265-params "merange=64:subme=5"可以控制搜索范围和亚像素精度。我个人习惯在实时编码场景用subme=5,离线编码用subme=7。
帧间预测是H265压缩率的核心来源。Merge和AMVP这两个技术,说白了就是「用更少的比特传运动信息」。理解它们,你就能明白为什么H265比H264能省50%的码率。