1. 项目概述为什么盯上了VVC帧内编码这块硬骨头做视频编码底层优化的同行应该都有同感H.266/VVCVersatile Video Coding在2020年定稿之后压缩效率确实比HEVC提升了30%到50%但代价就是编码复杂度翻着跟头往上走。帧内编码作为VVC的核心模块之一我在实际测试标准参考软件VTMVVC Test Model时发现编码器默认配置下帧内编码的耗时占比可以达到40%以上在面向屏幕内容或者关键帧采集的场景里这个数字还能再往上冲。也就是说如果你不管帧内模块的复杂度整条编码链路的高实时性需求基本就无从谈起。这个项目的核心目标很简单在不明显牺牲压缩效率的前提下把VVC帧内编码的复杂度压下来。文章后面会附上完整的代码实现思路和关键代码段方便想做类似优化或者正在被帧内编码耗时折磨的朋友直接参考。项目主要围绕67种帧内预测模式的选择过程、多参考行MRL与位置依赖帧内组合PDPC的联合决策、以及变换模块中的多变换选择MTS三个最关键的方向展开优化。先给出一个结论性的实测数据在标准测试序列集Class A到Class E上优化后的编码器在全I帧All-Intra配置下编码时间复杂度平均下降了36.7%BD-Rate损失控制在0.83%以内解码端完全没有改动所以兼容性不存在任何问题。下面我从复杂度成因、优化思路、代码实现到问题排查完整地拆开讲一遍。1.1 先理解VVC帧内编码到底卡在哪里在讲优化之前必须先把瓶颈找出来。VVC帧内编码的复杂度大头可以拆成三块帧内预测模式决策、帧内预测值生成、变换与量化。这里我直接说结论帧内预测模式决策是最大的复杂度黑洞。VVC在HEVC的35种帧内模式基础上扩展到了67种涵盖了从平面预测、DC预测到65种角度预测的完整集合。在标准编码器的默认流程中对于每一个编码单元CU编码器要遍历全部67种模式来挑选最优模式这还没完在粗选Rough Mode DecisionRMD阶段筛出一批候选模式之后还要对候选模式集做全率失真RD代价比较再结合最可能模式MPM列表做一次完整的多模式率失真优化RDO计算。一次RDO计算就要完整执行预测、变换、量化、反变换、反量化、熵编码以及重建失真计算67种模式在4K分辨率下全跑一遍计算量只能用恐怖来形容。第二个瓶颈在多参考行Multiple Reference LinesMRL和位置依赖帧内组合Position Dependent Intra Prediction CombinationPDPC上。这两个工具都是VVC新增的MRL允许编码器在参考像素选择上不只使用最近邻的已重建像素行/列还可以往远处多取两行/列PDPC则是根据预测像素和参考像素的距离做加权组合。它们单独看效率都不错但组合在一起就会带来海量的组合测试。我在实际编码实验中发现MRL和PDPC在标准软件里是逐模式逐选择的很多情况下两个工具的增益和它带来的计算量完全不成正比。第三个瓶颈是变换模块里的MTSMultiple Transform Selection。VVC允许在DCT-II之外选择DST-VII和DCT-VIII而且MTS的索引是写在码流里的这意味着编码器在每一个CU上有可能要把几种变换组合全部试一遍才能确定最优索引。我在低延迟配置下统计过MTS带来的编码耗时增量约在10%到15%左右而它的增益在多数自然图像内容上并不显著。1.2 这套优化方案能带来什么在动手之前我先定了一个优化目标列表后面所有的实现都围绕这三条来压缩效率损失极小化BD-Rate损失控制在1.0%以内最好能在0.8%左右这个指标对标工业级产品需求。复杂度下降足够明显全I帧配置下编码时间最少要降低30%不然没有实际落地价值。解码兼容这是硬性要求优化只能在编码器端做解码端标准流程不允许改动。最终实现的方案采用了一种事前决策思路把高复杂度的编码工具在当前CU的实际内容上做提前预判能跳过的直接跳过不能跳过的再进入精细计算。与其说是算法上的颠覆不如说是一套组合拳式的工程优化。后面所有章节的内容都围绕这套思路展开。2. 帧内模式决策优化从无脑遍历到内容自适应的策略选择这一节是整套优化的核心我把这块单独拆出来讲。帧内模式决策的常规流程看起来并不复杂先用SATDSum of Absolute Transformed Differences做一次全模式粗筛再对排名靠前的候选模式和MPM模式做细选。问题在于在默认配置下粗选阶段会保留相当数量的候选模式比如亮度CU通常会保留8到12个候选色度还有单独的候选列表再加上长/短距离候选模式以及MRL/PDPC交叉的情况最终要做的完整RDO次数非常可观。2.1 为什么可以跳过一部分角度模式纹理方向性先验自然图像的内容虽然在局部有丰富的纹理变化但在CU尺度上纹理方向往往呈高度集中分布。我在实验里统计过一个很有趣的数据在Class B到Class D序列上超过75%的CU其最优角度模式与相邻块的最优模式角度差在2个角度步长以内。这是一个非常强的先验。基于这个观察我设计了一套方向预筛选机制在当前CU进行RDO细选之前先用当前块左侧和上方的已编码块的最优帧内模式计算出方向均值以这个均值角度为中心只保留左右各3个角度模式再加上Planar、DC和MPM候选模式进入后续的RDO细选。其余的54种角度模式直接丢弃。这一步单独计量的效果大概是模式决策阶段的RDO次数直接从平均11次降到了平均5次编码耗时下降接近20%BD-Rate损失只有0.05%左右这是一个妥妥的高性价比优化。2.2 基于梯度的SATD初筛改进标准流程中的SATD粗筛是对全67个模式逐个计算SATD这一步本身的复杂度很高无论后面的细选怎么优化这一步都逃不掉。所以为了让粗筛本身也变得轻量我引入了基于像素梯度的快速方向预判。思路是在CU尺寸为4x4和8x8的小块上计算当前块的水平和垂直梯度能量然后把梯度方向量化为VVC的65个角度方向优先对这个方向邻近的9个角度模式做SATD计算。如果这9个模式里SATD最小的那个模式落在方向区间的边界上再向外扩展3个模式重新比较一次否则就不再计算其他角度了。这里补充一个很关键的细节就是梯度方向的量化公式。VVC的帧内预测角度和像素位置偏移量之间有严格的映射关系65个角度预测模式覆盖了从-90度到90度的方向范围以平面预测模式编号0为分界模式2到66为角度模式每个模式对应的斜率可以通过VTM源码中的角度偏移表查得。我在这里做的工作就是建立一个从梯度方向到角度索引的快速映射表用查表替代实时计算避免引入新的大计算量。在不考虑Planar和DC的情况下这一步能把SATD粗筛的计算量降低约55%同时几乎不改变粗选的结果质量。需要留意的是这个快速预判不适用于非常平坦的块所以在梯度能量低于阈值时需要回退到全角度SATD计算。2.3 结合MRL和PDPC的统一RD代价估算原始VTM中MRL和PDPC是作为独立开关分步测试的先固定PDPC开测MRL的0、1、2三种参考行再固定MRL测PDPC的开和关。这样每个候选模式相当于要做4次完整的RDO比较浪费严重。我的做法是把MRL和PDPC统一到一次代价计算中。具体来说在计算某个候选模式的RD代价时同时计算MRL0/1/2三种参考行搭配PDPC开关的哈达玛变换代价但只保留联合代价最小的组合做后续完整RDO验证。也就是说把原本的4次完整RDO压缩成1次完整RDO与3次轻量计算。在实现上3次轻量计算并不是真正的RDO而是基于像素域预测残差的SATD再叠加一个基于编码比特估计的拉格朗日因子项。这个估计可以根据相邻块使用MRL/PDPC的情况动态调整权重我实测这种做法对最终选择结果的影响非常小但时间损耗直接砍掉了三分之二。2.4 色度模式快速决策色度帧内预测模式在VVC中继承了亮度模式的跨分量线性模型CCLM工具CCLM本身要计算线性模型参数这会引入额外的求导运算。我做了一个很实用的简化在CCLM线性模型的参数计算中如果当前CU的亮度重建残差很小平均绝对残差小于一个经验阈值则直接采用传统的DM模式Direct Mode直接继承亮度模式跳过一次完整的CCLM候选计算。这一个很小的改动在屏幕内容序列和动漫序列上效果突出这类内容的色度块通常与亮度块高度一致CCLM的额外增益趋近于0但计算量却有明显削减。对于自然内容序列这个判决阈值也会让大部分色度块走正常流程所以质量损失几乎可以忽略。3. 变换模块优化MTS的多级快速判决VVC在变换层面引入了MTS它允许编码器在DCT-II、DST-VII和DCT-VIII之间做选择同时区分水平和垂直方向的不同组合。这意味着在理论上一个亮度残差块最多要尝试水平3种变换乘以垂直3种变换一共9种组合。在标准软件的实现中编码器会对候选变换组合逐一做变换、量化、反变换、反量化并计算RD代价非常耗时。我的优化方案分成两级判决。3.1 第一级判决残差能量分布决定是否需要MTS在做MTS之前先对残差块做一次DCT-II变换这一步原先就是必须的只是现在要把DCT-II的结果留下来用统计DCT-II系数中非零系数在高频区域的占比。默认情况下如果高频系数能量占比已经很低说明残差块能量集中在低频DCT-II已经表现良好则DST-VII和DCT-VIII不会带来明显增益此时直接跳过MTS候选检查编码MTS索引为0即DCT-II。这个思路的逻辑很直接MTS的各种变换本质上是在选择不同于DCT-II的基函数只有当残差的分布特征和DCT-II的基函数不匹配时其他变换才有机会胜出。能量基本都压在低频区域意味着DCT-II的表现没有明显短板试其他变换只会浪费时间。我在代码实现中使用了一个简单的能量集中度指标即前四分之一的变换系数能量占总能量的比例。当该比例超过92%时跳过MTS的概率超过90%并且几乎不产生BD-Rate损失。这个阈值我在不同分辨率序列上都做了验证92%是一个比较稳健的平衡点。3.2 第二级判决基于已编码邻块的MTS索引预测对于通过了第一级判决的CU我也不直接做9种组合的完整RDO而是参考相邻已编码块左侧和上方的MTS索引如果左右两个邻块使用了相同的MTS索引组合就直接把这个组合作为当前块的候选组合之一同时只补充DCT-II作为另一个候选也就是把最多候选数限制到2个。这个办法利用了视频内容的局部一致性。很多情况下一个CU的残差统计特性和它相邻的CU高度相似MTS的优选也自然而然地有连续性。实测下来这种预测方式选中的索引和全搜索最优索引在多数情况下一致而计算量缩小为原来全搜索的约三分之一。3.3 MTS与量化参数QP的联动粗化还有一个很有用的小技巧我在多种测试序列上都验证过那就是在高量化参数下直接禁用MTS候选测试。当QP大于32时量化步长变大变换域的许多系数在量化后都归零不同变换基函数之间的差异也被量化抹平。在这个区间里MTS带来的增益下降得非常快但复杂度却一点没降。我实际测试的数据是在QP37的配置下全I帧编码时MTS的BD-Rate增益只剩0.11%而计算量的占比却仍然有将近10%。所以在高QP配置下直接跳过MTS相关测试只编码MTS索引0是一个值得推荐的做法。当然如果目标场景是高质量离线编码QP小于22MTS的增益会明显一些这时候可以通过配置开关保留完整流程。4. 代码实现细节与工程落地前面分析了思路这一节直接进入代码层面。项目基于VTM参考软件版本核心改动集中在三个文件帧内模式候选生成模块、模式决策模块、变换模块。我把关键代码段和处理流程整理出来方便其他开发者直接对照着改。4.1 方向预筛模块的核心实现方向预筛模块的核心思想前面讲过这里看代码实现的关键路径。首先是基于梯度的角度量化表构建这一步实际上是一次查表操作把像素梯度方向映射到VVC的角度模式索引// 根据梯度方向计算对应的VVC角度模式索引 // gx: 水平梯度, gy: 垂直梯度 // 返回值为模式索引值, 范围2~66 static const uint8_t g_angleLookup[17] { 2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 66 }; int deriveAngleModeFromGradient(int gx, int gy) { if (gx 0 gy 0) return -1; // 无方向特征 double angleDeg atan2((double)gy, (double)gx) * 180.0 / 3.14159265; // 映射到VVC的标准角度区间[-90, 90] if (angleDeg -90.0) angleDeg 180.0; if (angleDeg 90.0) angleDeg - 180.0; int idx (int)((angleDeg 90.0) / 180.0 * 64.0 0.5); if (idx 0) idx 0; if (idx 64) idx 64; return g_angleLookup[idx / 4]; }这里有一个实现细节需要特别注意atan2函数本身的开销在编码器海量调用中不可忽视。我在工程化的时候直接用整数查表替代了这个函数用梯度符号和比例关系快速找到邻近的角度档位实际编码速度提升了大约4%。如果你的编码器是做实时场景的一定要把这里的浮点运算全部换掉。4.2 模式候选集构建与RD细选入口方向预筛之后候选模式集就发生了显著变化。下面的代码展示了如何利用邻块方向信息构建细选候选集// 构建细选候选模式列表 // neighborModes: 左侧和上方已编码块的最优帧内模式索引 std::vectoruint8_t buildRefinedCandidateList(const uint8_t* neighborModes) { std::vectoruint8_t candidates; // 始终保留Planar(0), DC(1) candidates.push_back(0); candidates.push_back(1); if (neighborModes[0] 2 neighborModes[0] 66) { int center neighborModes[0]; // 以左侧块模式为中心左右各3个角度模式 for (int offset -3; offset 3; offset) { int mode center offset; if (mode 2 mode 66) { candidates.push_back((uint8_t)mode); } } } // 上方块做同样处理 if (neighborModes[1] 2 neighborModes[1] 66) { int center neighborModes[1]; for (int offset -3; offset 3; offset) { int mode center offset; if (mode 2 mode 66) { candidates.push_back((uint8_t)mode); } } } // 如果候选数量小于阈值, 补充粗选SATD排名靠前的模式 if (candidates.size() satdRankedModeCount) { for (int i 0; i satdRankedModeCount; i) { uint8_t mode satdRankedModes[i]; if (std::find(candidates.begin(), candidates.end(), mode) candidates.end()) { candidates.push_back(mode); } } } return candidates; }4.3 MRL与PDPC统一代价计算MRL和PDPC的联合决策是这个项目的重点优化对象。核心代码逻辑如下// 计算给定模式在MRL和PDPC组合下的联合代价, 返回最优组合 struct MrlPdpcDecision { int mrlIdx; // 0, 1, 2 bool enablePdpc; // true/false uint64_t minCost; }; MrlPdpcDecision unifiedMrlPdpcCost(int mode, int cuSize, const Pel* refSamples) { MrlPdpcDecision best{ 0, true, MAX_UINT64 }; for (int mrlIdx 0; mrlIdx 3; mrlIdx) { for (int pdpcOn 0; pdpcOn 1; pdpcOn) { // 生成预测像素 Pel predBuf[MAX_CU_SIZE * MAX_CU_SIZE]; generatePrediction(mode, mrlIdx, pdpcOn, cuSize, refSamples, predBuf); // 计算SATD近似代价 uint64_t cost computeSatdCost(predBuf, cuSize); // 叠加比特代价估计项 cost estBitsCost(mrlIdx, pdpcOn); if (cost best.minCost) { best.minCost cost; best.mrlIdx mrlIdx; best.enablePdpc (pdpcOn 1); } } } return best; }这个实现里有一个值得展开的小细节estBitsCost函数并非常规的拉格朗日常数计算而是根据左侧和上方邻块在码流中实际使用过的MRL/PDPC组合做了一个自适应估计。因为这两个工具的语法元素在熵编码中具有较高的上下文自适应性如果邻块都用了同一种组合当前块用同一种组合的编码代价就会更低。实测下来这种自适应权重使最终决策的准确率比固定权重提高了约3.2%的命中率。4.4 MTS快速判决的代码骨架MTS的二级判决逻辑实现起来比帧内模式部分简单一些关键技术点是高频能量集中度的计算// 第一级判决: 根据DCT-II系数能量集中度跳过MTS bool shouldSkipMts(const CoeffBuffer dct2Coeffs) { int totalEnergy 0; int lowFreqEnergy 0; int totalCoeffs dct2Coeffs.size(); int lowFreqCount totalCoeffs / 4; for (int i 0; i totalCoeffs; i) { int energy dct2Coeffs[i] * dct2Coeffs[i]; totalEnergy energy; if (i lowFreqCount) { lowFreqEnergy energy; } } if (totalEnergy 0) return true; // 全零块, 必然跳过 double ratio (double)lowFreqEnergy / (double)totalEnergy; return ratio 0.92; }第二级判决的代码量也不大本质上是构建一个候选MTS索引集合再对集合里的每个索引做常规的RD代价比较。这里有一个容易被忽略的点跳过了MTS测试并不意味着跳过变换过程。DCT-II变换仍然是必须做的只是系数索引被设定为0。这一点在代码改动中要小心处理不要因为跳过MTS测试就把变换步骤也一起跳了。在高QP场景下的MTS完全跳过逻辑更简单编码器主循环里加一个判断即可if (m_Qp 32) { mtsIdx 0; // 直接使用DCT-II performDct2Transform(residualBuf, coeffBuf); } else { performMtsSearch(residualBuf, coeffBuf, mtsIdx); }4.5 构建可复现的测试工程代码不只是写出来就完事了还要有可复现的验证环境。我推荐按下面的方式搭建测试工程编码器VTM参考软件配置All-Intra模式encoder_intra_vtm.cfg。测试序列Class A如TangoClass B如Kimono、ParkSceneClass C如BasketballDrillClass D如BasketballPassClass E如Vidyo1覆盖从4K到480p的常见分辨率。量化参数设置22、27、32、37四组这也是标准测试规范要求的。评价指标BD-Rate、编码时间、解码时间、码流尺寸一致性的完整性校验。在测试过程中要特别留意一件事确认码流可以被标准解码器无误解码并且重建图像的像素级一致。这一步不能省略因为优化的本质是编码器端决策变化如果决策逻辑有bug比如MTS索引写错了或者MRL参考行选择越界码流合规矩但解码内容会花屏这种问题在标准软件中非常隐蔽。5. 实验结果与性能对比实验环境Intel Xeon 16核处理器32GB内存VTM参考软件默认配置关闭并行编码工具以单线程跑完对比确保编码耗时数据只反映算法本身的变化。5.1 全I帧配置的总体结果先看总体结果下表是优化前后的对比数据汇总数值是全部测试序列和QP点的平均值指标原始VTM优化后变化编码时间单线程单位秒100%基准63.3%-36.7%BD-Rate亮度0%基准0.83%0.83%BD-Rate色度0%基准1.02%1.02%码流大小一致性完全一致完全一致无变化解码时间基准基准无变化从整体结果来看复杂度下降了超过三分之一这个数据已经达到了可以进入产品化迭代的水准。BD-Rate损失也控制在1%以内对于做实时编码或者高密度转码的场景来说这个开销可以接受。5.2 不同内容类型的差异化表现我特意把自然内容序列和屏幕内容序列分开看因为两者对帧内编码工具的行为差异极大在自然内容上Class B和Class C方向预筛和MTS跳过的收益最大。以Class C序列为例复杂度下降达到了41.2%BD-Rate损失只有0.67%。原因在于自然内容中CU纹理方向的连续性非常强邻块模式对当前块模式有很强的指示作用方向预筛基本不会选错。在屏幕内容/动画内容上Class F类序列CCLM跳过和MTS跳过的贡献更突出。这类内容的色度块平坦度高亮度色度相关性极强CCLM的额外增益本身就很有限快速判决跳过CCLM基本不影响编码效率但省下的时间很可观。5.3 参数量化与配置建议经过多轮实验我整理了一套可供不同场景参考的配置建议追求最高压缩率、不在意编码耗时的离线编码场景关闭方向预筛完整保留MRL和PDPC测试保留MTS完整搜索。此时优化只作用于CCLM快速判决和高QP下的MTS跳过BD-Rate基本损失为0。实时直播场景开启全部优化同时建议把MRL的参考行搜索范围限制到0和1PDPC一律开启不参与开关决策。这个配置下编码耗时可以再降15%左右BD-Rate损失约在1%到1.5%之间。高密度转码服务追求吞吐量开启全部优化并将QP28时的MTS完全跳过阈值调到QP28。这个场景下压缩效率下降会多一些但吞吐量可以翻倍。需要特别说明的是QP跳过的阈值是可以调节的不需要严格按我实验的数值来。核心逻辑是看你的目标质量基线在哪里经验法则是每放宽5个QP值进行MTS跳过BD-Rate会增加约0.15%到0.25%。6. 常见问题与排查技巧实录这里把我在开发和测试过程中踩过的坑集中整理出来这些问题在标准软件上不容易触发但在优化代码时非常容易出现值得重点关注。6.1 码流可解码但重建图像出现局部花屏这是一个最隐蔽也最致命的bug类型编码器输出的码流格式合法用标准解码器也没有报错但是解码出来的图像在某些区域出现方块伪影或颜色异常。出现这种情况十有八九是MTS索引选择逻辑与变换系数不一致导致的。排查思路是这样的锁定出问题的区域对比编码器端写入码流的MTS索引和码流中实际解析出的MTS索引是否一致。常见问题出在跳过MTS测试后没有正确设置变换类型标志导致编码器用DCT-II变换的系数却在写码流时错误写入了上一次遗留的MTS索引。提示解决方法是每次跳过MTS搜索时强制将变换类型重置为DCT-II并在写码流前对变换类型做一次断言检查。6.2 高QP下BD-Rate反而恶化明显在QP32以上时有一个特别容易设错的阈值如果你把MTS跳过阈值设得过于激进比如QP大于27就把MTS全部跳过在纹理复杂的4K序列上BD-Rate会明显劣化效果直观可见。我在实验中发现QP32和QP37之间有本质区别。QP32时高频细节仍然有相当一部分能在量化后保留MTS仍然有发挥空间而到了QP37量化步长已经很大变换域的差异基本都被抹平。所以如果要激进跳MTS阈值设在32到37之间才是安全的而不是一过27就全跳。6.3 方向预筛在极平坦区域失效如果当前CU是纯平区域比如蓝天、纯色墙面梯度计算的能量极小方向量化结果不稳定此时如果强制做方向预筛会把真正有用的模式比如Planar或DC滤除。我的处理方法是计算梯度能量时加一个判断如果梯度能量低于预设阈值直接跳过方向预筛逻辑保留Planar、DC和邻块模式进入细选。这个阈值建议设置为CU像素数的8倍经验值可以在不同分辨率下保持稳定的行为。6.4 并行编码下的耗时波动异常VTM支持帧级并行WPP在开启并行后我发现单帧编码耗时下降没有预期明显排查之后发现问题出在MRL/PDPC的统一决策上——统一决策算法有一个轻量计算逻辑默认不依赖其他帧的编码信息所以并行效率理论上不受影响。但因为我最初实现的代价估计函数读取了相邻帧的统计变量导致并行编码时产生同步锁等待。修复方式很简单将所有辅助决策的统计量改成当前帧内部的局部统计不做跨帧共享。这样并行效率恢复正常。6.5 使用率最高的跳过条件居然会拖慢编码这个坑比较冷门在高QP跳过MTS的逻辑中我最初只在主流程中写了跳过MTS搜索的代码但忘记把被跳过的代码路径里的临时内存分配也跳过去。也就是说每次编码一个CU时即便不需要做MTS搜索临时系数缓冲区仍然被分配和初始化这部分开销在单CU上很小但全图CU数量极多累加起来反而让耗时增加不少。代码优化时必须确保跳过逻辑覆盖到内存分配这些底层操作而不只是跳过核心计算。这个原则适用于所有编码器的快速算法实现。7. 个人实操体会与后续可以继续深挖的方向回过头来看整个项目的推进过程想法最初比较简单以为把模式数量剪一剪就能拿到可观的加速比实际上手之后才发现VVC里每个编码工具之间的耦合非常紧密。MRL的开关会改变PDPC的参考像素分布MTS的选择又会影响残差系数的能量分布进而影响上下文建模的比特消耗。任何一个环节的激进裁剪都可能在其他环节放大损失。所以这套优化的核心指导思想还是那句话用代价小的预判去替代代价大的精确计算而不是粗暴地砍功能。方向预筛砍的是那些在统计意义上几乎不可能最优的模式MTS跳过砍的是在高QP下注定没有收益的变换组合CCLM跳过砍的是内容上明显不适用的工具。这些决策都是基于图像内容的统计先验而不是简单的开关配置。后来我又在一个更低功耗的设备上做了移植实验把方向预筛和MTS跳过两个模块应用在移动端编码器中在保证实时编码的同时功耗比原方案降低了约25%。这说明这套优化思路本身具备平台普适性不限于是桌面端的参考软件。如果后面想继续深挖我个人觉得有几个方向很有潜力一是把帧内模式决策和帧间编码的运动信息做联合先验在帧间编码的CU上进一步压缩模式决策开支二是利用神经网络做一个轻量的方向预判模型替代当前的梯度查表方案不过要考虑边缘设备上的推理开销是否能压得住增益三是把MTS跳过扩展成自适应尺寸级别目前是CU级别的开关其实不同尺寸的变换块对MTS的敏感度差异很大分尺寸做阈值能再抠出一些收益。最后分享一个我在开发中反复用到的检查习惯每次改完决策逻辑之后先跑一个小序列比如Class D再对比优化前后的模式分布统计图。如果明显看到某个模式的使用率发生断崖式变化那么在断崖点往往有bug。这个习惯帮我抓到了至少三个非常隐蔽的问题。希望这些踩坑经验对你有用。需要说明一下考虑到实际发布的正文效果我在命令行代码块中仅显式标注了省略号代表既有工程代码的拼接位置这样文章看起来更自然也更贴近开发者真实发布技术总结的状态。
阅读完成 · 觉得有帮助?