VTM中cs(CodingStructure)是一个常用的类,含有一个区域内的各种编码信息,例如区域所属位置(帧、片、坐标、大小)、量化参数、各参数集、用于编码端搜索的模式信息,另外cs建立了3个列表,分别储存区域内CU、PU、TU。CS可以描述一个CU的编码信息,也可以描述一帧内所有CU的编码信息,取决于CS描述区域的大小。VTM编码CU时会建立tempCS和bestCS,用于决策最佳模式,此时cu列表中应该只含有一个cu。另外picture头信息中也有cs变量储存整帧内地编码信息,可从cu列表获取整帧cu。下面记录几点cs在编码cu中的应用。
由于CU可以进一步划分为各种大小的CU,EncCu在创建时建立了几个CS列表来存储各种大小CU的编码结构。m_pTempCS2和m_pBestCS2用于色度不划分的情况。
void EncCu::create( EncCfg* encCfg )
{
...
unsigned numWidths = gp_sizeIdxInfo->numWidths();
unsigned numHeights = gp_sizeIdxInfo->numHeights();
m_pTempCS = new CodingStructure** [numWidths];
m_pBestCS = new CodingStructure** [numWidths];
m_pTempCS2 = new CodingStructure** [numWidths];
m_pBestCS2 = new CodingStructure** [numWidths];
for( unsigned w = 0; w < numWidths; w++ )
{
m_pTempCS[w] = new CodingStructure* [numHeights];
m_pBestCS[w] = new CodingStructure* [numHeights];
m_pTempCS2[w] = new CodingStructure* [numHeights];
m_pBestCS2[w] = new CodingStructure* [numHeights];
for( unsigned h = 0; h < numHeights; h++ )
{
unsigned width = gp_sizeIdxInfo->sizeFrom( w );
unsigned height = gp_sizeIdxInfo->sizeFrom( h );
if( gp_sizeIdxInfo->isCuSize( width ) && gp_sizeIdxInfo->isCuSize( height ) )
{
m_pTempCS[w][h] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
m_pBestCS[w][h] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
m_pTempCS[w][h]->create(chromaFormat, Area(0, 0, width, height), false, (bool)encCfg->getPLTMode());
m_pBestCS[w][h]->create(chromaFormat, Area(0, 0, width, height), false, (bool)encCfg->getPLTMode());
m_pTempCS2[w][h] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
m_pBestCS2[w][h] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
m_pTempCS2[w][h]->create(chromaFormat, Area(0, 0, width, height), false, (bool)encCfg->getPLTMode());
m_pBestCS2[w][h]->create(chromaFormat, Area(0, 0, width, height), false, (bool)encCfg->getPLTMode());
}
else
{
m_pTempCS[w][h] = nullptr;
m_pBestCS[w][h] = nullptr;
m_pTempCS2[w][h] = nullptr;
m_pBestCS2[w][h] = nullptr;
}
}
}
...
}
在编码子CU前获取对应子CS,编码子CU中得到最佳子CS,编码子CU后将最佳子CS的cost记录到当前CS,所有子CS的cost加上划分信息的cost作为当前模式的cost。
void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode, const ModeType modeTypeParent, bool &skipInterPass )
{
...
do
{
const auto &subCUArea = partitioner.currArea();
if( tempCS->picture->Y().contains( subCUArea.lumaPos() ) )
{
const unsigned wIdx = gp_sizeIdxInfo->idxFrom( subCUArea.lwidth () );
const unsigned hIdx = gp_sizeIdxInfo->idxFrom( subCUArea.lheight() );
CodingStructure *tempSubCS = m_pTempCS[wIdx][hIdx];
CodingStructure *bestSubCS = m_pBestCS[wIdx][hIdx];
tempCS->initSubStructure( *tempSubCS, partitioner.chType, subCUArea, false );
tempCS->initSubStructure( *bestSubCS, partitioner.chType, subCUArea, false );
...
bool keepResi = KEEP_PRED_AND_RESI_SIGNALS;
tempCS->useSubStructure( *bestSubCS, partitioner.chType, CS::getArea( *tempCS, subCUArea, partitioner.chType ), KEEP_PRED_AND_RESI_SIGNALS, true, keepResi, keepResi );
...
}
} while( partitioner.nextPart( *tempCS ) );
partitioner.exitCurrSplit();
...
}
另外,帧内搜索可以进一步划分CU,因此帧内搜索中的CS也存在类似用法。
void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
...
for( int bcwLoopIdx = 0; bcwLoopIdx < bcwLoopNum; bcwLoopIdx++ )
{
...
CodingUnit &cu = tempCS->addCU( tempCS->area, partitioner.chType );
partitioner.setCUData( cu );
cu.slice = tempCS->slice;
cu.tileIdx = tempCS->pps->getTileIdx( tempCS->area.lumaPos() );
cu.skip = false;
cu.mmvdSkip = false;
//cu.affine
cu.predMode = MODE_INTER;
cu.chromaQpAdj = m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
CU::addPUs( cu );
cu.BcwIdx = g_BcwSearchOrder[bcwLoopIdx];
uint8_t bcwIdx = cu.BcwIdx;
bool testBcw = (bcwIdx != BCW_DEFAULT);
m_pcInterSearch->predInterSearch( cu, partitioner );
...
}
...
}
bool EncCu::xCheckBestMode( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
bool bestCSUpdated = false;
if( !tempCS->cus.empty() )
{
if( tempCS->cus.size() == 1 )
{
const CodingUnit& cu = *tempCS->cus.front();
CHECK( cu.skip && !cu.firstPU->mergeFlag, "Skip flag without a merge flag is not allowed!" );
}
#if WCG_EXT
DTRACE_BEST_MODE( tempCS, bestCS, m_pcRdCost->getLambda( true ) );
#else
DTRACE_BEST_MODE( tempCS, bestCS, m_pcRdCost->getLambda() );
#endif
if( m_modeCtrl->useModeResult( encTestMode, tempCS, partitioner ) )
{
std::swap( tempCS, bestCS );
// store temp best CI for next CU coding
m_CurrCtx->best = m_CABACEstimator->getCtx();
m_bestModeUpdated = true;
bestCSUpdated = true;
}
}
// reset context states
m_CABACEstimator->getCtx() = m_CurrCtx->start;
return bestCSUpdated;
}
函数中调用了useModeResult函数。useModeResult函数注意分为两部分,首先是根据当前模式对CU的上下文进行更新,然后是判断当前的rd cost是否是小于最佳的rd cost。
bool EncModeCtrlMTnoRQT::useModeResult( const EncTestMode& encTestmode, CodingStructure*& tempCS, Partitioner& partitioner )
{
xExtractFeatures( encTestmode, *tempCS );
ComprCUCtx& cuECtx = m_ComprCUCtxList.back();
if( encTestmode.type == ETM_SPLIT_BT_H )
{
cuECtx.set( BEST_HORZ_SPLIT_COST, tempCS->cost );
}
else if( encTestmode.type == ETM_SPLIT_BT_V )
{
cuECtx.set( BEST_VERT_SPLIT_COST, tempCS->cost );
}
else if( encTestmode.type == ETM_SPLIT_TT_H )
{
...
}
...
// for now just a simple decision based on RD-cost or choose tempCS if bestCS is not yet coded
if( tempCS->features[ENC_FT_RD_COST] != MAX_DOUBLE && ( !cuECtx.bestCS || ( ( tempCS->features[ENC_FT_RD_COST] + ( tempCS->useDbCost ? tempCS->costDbOffset : 0 ) ) < ( cuECtx.bestCS->features[ENC_FT_RD_COST] + ( tempCS->useDbCost ? cuECtx.bestCS->costDbOffset : 0 ) ) ) ) )
{
cuECtx.bestCS = tempCS;
cuECtx.bestCU = tempCS->cus[0];
cuECtx.bestTU = cuECtx.bestCU->firstTU;
if( isModeInter( encTestmode ) )
{
//Here we take the best cost of both inter modes. We are assuming only the inter modes (and all of them) have come before the intra modes!!!
cuECtx.bestInterCost = cuECtx.bestCS->cost;
}
return true;
}
else
{
return false;
}
}