VVC的BCW提供了多种双向预测权重,编码的需要进行决策。这里记录下文档JVET-N0646中提及的编码端加速算法以及VTM中的部分实现。
在不等权重条件下,affine模式部分条件下跳过运动估计。等权重的affine运动估计后,只有affine inter模式是当前最佳模式的情况下进行运动估计才进行其他权重的运动估计。
对于low-delay图像,需要进行5种权重的RD检测,包括1/4像素、1像素、和4像素精度,首先检测1/4像素精度,在1像素和4像素精度下跳过部分权重RD。首先计算1/4像素精度下不等权重的RDcost,1像素和4像素条件下仅对等权重条件和1/4像素精度下最小的那组权重进行RD检测。
对于一些RA模式的图像,同一帧可能同时出现在两个参考帧列表。在同时满足(a.参考帧相同;b.时间层大于1;c.运动矢量精度为1/4。)3个条件下跳过不等权重的运动估计。这个规则也适用于4参数的affine双向预测。
在同时满足(a.时间层为4;b.任意参考帧POC距离当前帧小于1;c.QP大于32。)时跳过不等权重的RDO决策。
双向预测的运动估计中会固定一个MV搜索另一个MV,设MV1固定,调整MV0。MV0的搜索目标是
为了进行定点计算,搜索目标改为
VTM在EncCfg对象中加入了m_BcwFast来表示开启快速算法,其值可以使用函数getUseBcwFast()得到。
对应1.2内容。
if( m_pcEncCfg->getUseBcwFast() && tempCS->slice->getCheckLDC() && g_BcwSearchOrder[bcwLoopIdx] != BCW_DEFAULT
&& (m_bestBcwIdx[0] >= 0 && g_BcwSearchOrder[bcwLoopIdx] != m_bestBcwIdx[0])
&& (m_bestBcwIdx[1] >= 0 && g_BcwSearchOrder[bcwLoopIdx] != m_bestBcwIdx[1]))
{
continue;
}
如果当前最佳模式是帧间模式,且当前权重为不等权重,且当前权重为不等权重,跳过此次RD检测。也就是说,最佳模式是帧间模式时,仅对等权重或者最佳权重进行RD检测。
if( m_pcEncCfg->getUseBcwFast() )
{
auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >(m_modeCtrl);
if( blkCache )
{
bool isBestInter = blkCache->getInter(bestCS->area);
uint8_t bestBcwIdx = blkCache->getBcwIdx(bestCS->area);
if( isBestInter && g_BcwSearchOrder[bcwLoopIdx] != BCW_DEFAULT && g_BcwSearchOrder[bcwLoopIdx] != bestBcwIdx )
{
continue;
}
}
}
如果等权重下cost大于其他模式的1.05倍,跳过不等权重RD检测。如果是单向预测,跳过不等权重的RD检测。第一次检测后,且满足条件(对应 1.4 中条件),则跳过后续RDO检测。
double skipTH = MAX_DOUBLE;
skipTH = (m_pcEncCfg->getUseBcwFast() ? 1.05 : MAX_DOUBLE);
if( equBcwCost > curBestCost * skipTH )
{
break;
}
if( m_pcEncCfg->getUseBcwFast() )
{
if( isEqualUni == true && m_pcEncCfg->getIntraPeriod() == -1 )
{
break;
}
}
if( g_BcwSearchOrder[bcwLoopIdx] == BCW_DEFAULT && xIsBcwSkip(cu) && m_pcEncCfg->getUseBcwFast() )
{
break;
}
bool xIsBcwSkip(const CodingUnit& cu)
{
if (cu.slice->getSliceType() != B_SLICE)
{
return true;
}
return((m_pcEncCfg->getBaseQP() > 32) && ((cu.slice->getTLayer() >= 4)
|| ((cu.refIdxBi[0] >= 0 && cu.refIdxBi[1] >= 0)
&& (abs(cu.slice->getPOC() - cu.slice->getRefPOC(REF_PIC_LIST_0, cu.refIdxBi[0])) == 1
|| abs(cu.slice->getPOC() - cu.slice->getRefPOC(REF_PIC_LIST_1, cu.refIdxBi[1])) == 1))));
}
仅在affine是最佳模式条件下进行不等权重的affine运动搜索。
if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getUseAffine()
&& checkAffine
&& (bcwIdx == BCW_DEFAULT || m_affineModeSelected || !m_pcEncCfg->getUseBcwFast())
)
{
...
MvField cHevcMvField[2];
cHevcMvField[0].setMvField( pu.mv[REF_PIC_LIST_0], pu.refIdx[REF_PIC_LIST_0] );
cHevcMvField[1].setMvField( pu.mv[REF_PIC_LIST_1], pu.refIdx[REF_PIC_LIST_1] );
// do affine ME & Merge
cu.affineType = AFFINEMODEL_4PARAM;
Mv acMvAffine4Para[2][33][3];
int refIdx4Para[2] = { -1, -1 };
xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffineCost, cMvHevcTemp, acMvAffine4Para, refIdx4Para, bcwIdx, enforceBcwPred,
((cu.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0));
if ( pu.cu->imv == 0 )
{
storeAffineMotion( pu.mvAffi, pu.refIdx, AFFINEMODEL_4PARAM, bcwIdx );
}
if ( cu.slice->getSPS()->getUseAffineType() )
{
if ( uiAffineCost < uiHevcCost * 1.05 ) ///< condition for 6 parameter affine ME
{
...
xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffine6Cost, cMvHevcTemp, acMvAffine4Para, refIdx4Para, bcwIdx, enforceBcwPred,
((cu.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0));
...
}
uiAffineCost += m_pcRdCost->getCost( 1 ); // add one bit for affine_type
}
...
}
非LDC条件下选择affine模式时,跳过不等权重的帧间双向运动估计。
// Bi-predictive Motion estimation
if( ( cs.slice->isInterB() ) && ( PU::isBipredRestriction( pu ) == false )
&& (cu.slice->getCheckLDC() || bcwIdx == BCW_DEFAULT || !m_affineModeSelected || !m_pcEncCfg->getUseBcwFast())
)
{...}
参考帧POC相同时跳过运动估计,对应1.3中条件。
if( m_pcEncCfg->getUseBcwFast() && (bcwIdx != BCW_DEFAULT)
&& (pu.cu->slice->getRefPic(eRefPicList, iRefIdxTemp)->getPOC() == pu.cu->slice->getRefPic(RefPicList(1 - iRefList), pu.refIdx[1 - iRefList])->getPOC())
&& (!pu.cu->imv && pu.cu->slice->getTLayer()>1))
{
continue;
}