此系列是为了记录自己学习VTM10.0的过程,目前正在看编码端。主要的参考文档有JVET-S2001-vH和JVET-S2002-v1。由于本人水平有限,出现的错误恳请大家指正,欢迎与大家一起交流进步。
上一篇博文(VTM10.0代码学习11)的末尾留着一个涉及CU划分的分支没讲,本篇博文就来说说。这个分支里会调用函数xCheckModeSplit(),而这个函数里面又会调用xCompressCU()。所以从CTU到任何一个CU的编码过程可以描述为如下,先从compressCtu()开始,之后就是xCompressCU()和xCheckModeSplit()的交替。那接下来就先从xCompressCU()中涉及划分的分支说起
1. 涉及划分的分支
int signalModeConsVal = tempCS->signalModeCons( getPartSplit( currTestMode ), partitioner, modeTypeParent );
int numRoundRdo = signalModeConsVal == LDT_MODE_TYPE_SIGNAL ? 2 : 1;
bool skipInterPass = false;
for( int i = 0; i < numRoundRdo; i++ )
{
}
这三个变量皆与modeType的设置有关系。当numRoundRdo为2时,modeType需要先后设置为MODE_TYPE_INTER和MODE_TYPE_INTRA进行测试。
for循环里的内容就参考1.1小节
1.1 for循环
if( signalModeConsVal == LDT_MODE_TYPE_SIGNAL )
{
tempCS->modeType = partitioner.modeType = (i == 0) ? MODE_TYPE_INTER : MODE_TYPE_INTRA;
}
else if( signalModeConsVal == LDT_MODE_TYPE_INFER )
{
tempCS->modeType = partitioner.modeType = MODE_TYPE_INTRA;
}
else if( signalModeConsVal == LDT_MODE_TYPE_INHERIT )
{
tempCS->modeType = partitioner.modeType = modeTypeParent;
}
设置modeType
if( modeTypeParent == MODE_TYPE_ALL && tempCS->modeType == MODE_TYPE_INTER )
{
m_pcIntraSearch->setSaveCuCostInSCIPU( true );
m_pcIntraSearch->setNumCuInSCIPU( 0 );
}
else if( modeTypeParent == MODE_TYPE_ALL && tempCS->modeType != MODE_TYPE_INTER )
{
m_pcIntraSearch->setSaveCuCostInSCIPU( false );
if( tempCS->modeType == MODE_TYPE_ALL )
{
m_pcIntraSearch->setNumCuInSCIPU( 0 );
}
}
与SCIPU有关
xCheckModeSplit( tempCS, bestCS, partitioner, currTestMode, modeTypeParent, skipInterPass );
//recover cons modes
tempCS->modeType = partitioner.modeType = modeTypeParent;
tempCS->treeType = partitioner.treeType = treeTypeParent;
partitioner.chType = chTypeParent;
xCheckModeSplit():进行划分模式的测试,具体参考第2大节
之后恢复到未划分之前的modeType、treeType和chType
if( modeTypeParent == MODE_TYPE_ALL )
{
m_pcIntraSearch->setSaveCuCostInSCIPU( false );
if( numRoundRdo == 2 && tempCS->modeType == MODE_TYPE_INTRA )
{
m_pcIntraSearch->initCuAreaCostInSCIPU();
}
}
与SCIPU有关
if( skipInterPass )
{
break;
}
如果skipInterPass为True,跳过之后modeType为MODE_TYPE_INTRA的测试
2. xCheckModeSplit()
const int qp = encTestMode.qp;
const Slice &slice = *tempCS->slice;
const int oldPrevQp = tempCS->prevQP[partitioner.chType];
const auto oldMotionLut = tempCS->motionLut;
const auto oldPLT = tempCS->prevPLT;
const PartSplit split = getPartSplit( encTestMode );
const ModeType modeTypeChild = partitioner.modeType;
tempCS->initStructData( qp );
oldPrevQp、oldMotionLut和oldPLT都是进行划分模式测试之后需要恢复的变量
split:当前测试的划分模式
modeTypeChild:划分后的modeType
initStructData():初始化父CU的tempCS
m_CABACEstimator->getCtx() = m_CurrCtx->start;
const TempCtx ctxStartSP( m_CtxCache, SubCtx( Ctx::SplitFlag, m_CABACEstimator->getCtx() ) );
const TempCtx ctxStartQt( m_CtxCache, SubCtx