H.266/VVC VTM読書12-残差符号化
54221 ワード
1、EncCu::xEncodeInterResidual()
フレーム間予測のモード決定において、よく用いられるレート歪み決定の流れの1つは、モードパラメータの設定->このモードによるフレーム間予測(動き補償)->符号化モード情報と残差->符号率rの計算->再構成誤差dの計算->レートrd costの計算と、このモードを使用するか否かの判断である.VTMは、符号化モード情報と残差とその後続部分を関数xEncodeInterResidual()にカプセル化する.xEncodeInterResidual()ではsbtパラメータが構成され、sbtが使用されているかどうかを判断します.各モードにパラメータを配置した後、主にInterSearch::encodeResAndCalcrdInterCU()を呼び出してレート歪み計算を完了し、xEncodeDontSplit()などの関数を呼び出してブロック分割、dQP、色度QP偏執占有ビットを追加し、最終的にxCheckBestMode()を呼び出してこのモードを使用するか否かを判断する.
1、InterSearch::encodeResAndCalcRdInterCU()
関数はまず残差が伝送を必要とするか否かを判断し,必要でなければ歪とモード情報が占有するビットを直接計算し,レート歪計算を完了する.残差を伝送する必要がある場合、InterSearch::x E s t i mateInterResidualQT()を呼び出して量子化逆量子化を完了した後、再構成歪を計算し、符号化残差とモード情報を統計するために必要なビットを計算し、レート歪計算を完了する必要がある.
3、InterSearch::xEstimateInterResidualQT()
関数はまずこのブロックをさらに分割せず、様々な変換モードを試み、transformNxN()とinvTransformNxN()を呼び出して変換と逆変換を行い、再構成値を得、m_CABACEstimator->residual_coding()などの関数は占有ビットを計算し,分割されないrd costを計算する.次いで、異なる分割方式を試み、この関数を再帰的に呼び出して、各分割方式のrd costを計算し、最適モードを保持する.さらに分割する必要がある場合は、xEncodeInterResidualQT()を呼び出してcbfおよび残差符号化を完了する必要がある.
フレーム間予測のモード決定において、よく用いられるレート歪み決定の流れの1つは、モードパラメータの設定->このモードによるフレーム間予測(動き補償)->符号化モード情報と残差->符号率rの計算->再構成誤差dの計算->レートrd costの計算と、このモードを使用するか否かの判断である.VTMは、符号化モード情報と残差とその後続部分を関数xEncodeInterResidual()にカプセル化する.xEncodeInterResidual()ではsbtパラメータが構成され、sbtが使用されているかどうかを判断します.各モードにパラメータを配置した後、主にInterSearch::encodeResAndCalcrdInterCU()を呼び出してレート歪み計算を完了し、xEncodeDontSplit()などの関数を呼び出してブロック分割、dQP、色度QP偏執占有ビットを追加し、最終的にxCheckBestMode()を呼び出してこのモードを使用するか否かを判断する.
void EncCu::xEncodeInterResidual( CodingStructure *&tempCS
, CodingStructure *&bestCS
, Partitioner &partitioner
, const EncTestMode& encTestMode
, int residualPass
, bool* bestHasNonResi
, double* equBcwCost
)
{
...
{
reloadCU = true; // enable cu reloading
cu->skip = false;
cu->sbtInfo = 0;
const bool skipResidual = residualPass == 1;
if( skipResidual || histBestSbt == MAX_UCHAR || !CU::isSbtMode( histBestSbt ) )
{
m_pcInterSearch->encodeResAndCalcRdInterCU( *tempCS, partitioner, skipResidual );
if (tempCS->slice->getSPS()->getUseColorTrans())
{
bestCS->tmpColorSpaceCost = tempCS->tmpColorSpaceCost;
bestCS->firstColorSpaceSelected = tempCS->firstColorSpaceSelected;
}
numRDOTried += mtsAllowed ? 2 : 1;
xEncodeDontSplit( *tempCS, partitioner );
xCheckDQP( *tempCS, partitioner );
#if JVET_Q0267_RESET_CHROMA_QP_OFFSET
xCheckChromaQPOffset( *tempCS, partitioner );
#endif
...
currBestCost = tempCS->cost;
sbtOffCost = tempCS->cost;
sbtOffDist = tempCS->dist;
sbtOffRootCbf = cu->rootCbf;
currBestSbt = CU::getSbtInfo(cu->firstTU->mtsIdx[COMPONENT_Y] > MTS_SKIP ? SBT_OFF_MTS : SBT_OFF_DCT, 0);
currBestTrs = cu->firstTU->mtsIdx[COMPONENT_Y];
#if WCG_EXT
DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) );
#else
DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda() );
#endif
xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );
}
...
for( int sbtModeIdx = 0; sbtModeIdx < numSbtRdo; sbtModeIdx++ )
{
uint8_t sbtMode = m_pcInterSearch->getSbtRdoOrder( sbtModeIdx );
uint8_t sbtIdx = CU::getSbtIdxFromSbtMode( sbtMode );
uint8_t sbtPos = CU::getSbtPosFromSbtMode( sbtMode );
...
//we need to restart the distortion for the new tempCS, the bit count and the cost
tempCS->dist = 0;
tempCS->fracBits = 0;
tempCS->cost = MAX_DOUBLE;
cu->skip = false;
//set SBT info
cu->setSbtIdx( sbtIdx );
cu->setSbtPos( sbtPos );
//try residual coding
m_pcInterSearch->encodeResAndCalcRdInterCU( *tempCS, partitioner, skipResidual );
if (tempCS->slice->getSPS()->getUseColorTrans())
{
bestCS->tmpColorSpaceCost = tempCS->tmpColorSpaceCost;
bestCS->firstColorSpaceSelected = tempCS->firstColorSpaceSelected;
}
numRDOTried++;
xEncodeDontSplit( *tempCS, partitioner );
xCheckDQP( *tempCS, partitioner );
#if JVET_Q0267_RESET_CHROMA_QP_OFFSET
xCheckChromaQPOffset( *tempCS, partitioner );
#endif
if( NULL != bestHasNonResi && ( bestCostInternal > tempCS->cost ) )
{
bestCostInternal = tempCS->cost;
if( !( tempCS->getPU( partitioner.chType )->ciipFlag ) )
*bestHasNonResi = !cu->rootCbf;
}
if( tempCS->cost < currBestCost )
{
currBestSbt = cu->sbtInfo;
currBestTrs = tempCS->tus[cu->sbtInfo ? cu->getSbtPos() : 0]->mtsIdx[COMPONENT_Y];
assert( currBestTrs == 0 || currBestTrs == 1 );
currBestCost = tempCS->cost;
}
#if WCG_EXT
DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) );
#else
DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda() );
#endif
xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );
}
if( bestCostBegin != bestCS->cost )
{
m_sbtCostSave[0] = sbtOffCost;
m_sbtCostSave[1] = currBestCost;
}
} //end emt loop
...
}
1、InterSearch::encodeResAndCalcRdInterCU()
関数はまず残差が伝送を必要とするか否かを判断し,必要でなければ歪とモード情報が占有するビットを直接計算し,レート歪計算を完了する.残差を伝送する必要がある場合、InterSearch::x E s t i mateInterResidualQT()を呼び出して量子化逆量子化を完了した後、再構成歪を計算し、符号化残差とモード情報を統計するために必要なビットを計算し、レート歪計算を完了する必要がある.
void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &partitioner, const bool &skipResidual
, const bool luma, const bool chroma
)
{
...
xEstimateInterResidualQT(cs, partitioner, &zeroDistortion, luma, chroma);
...
uint64_t finalFracBits = xGetSymbolFracBitsInter( cs, partitioner );
...
// update with clipped distortion and cost (previously unclipped reconstruction values were used)
Distortion finalDistortion = 0;
for (int comp = 0; comp < numValidComponents; comp++)
{
const ComponentID compID = ComponentID(comp);
if (compID == COMPONENT_Y && !luma)
continue;
if (compID != COMPONENT_Y && !chroma)
continue;
CPelBuf reco = cs.getRecoBuf (compID);
CPelBuf org = cs.getOrgBuf (compID);
#if WCG_EXT
if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (
m_pcEncCfg->getLmcs() && (cs.picHeader->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())))
{
const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] );
if (compID == COMPONENT_Y && !(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()) )
{
const CompArea &areaY = cu.Y();
CompArea tmpArea1(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size());
PelBuf tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1);
tmpRecLuma.copyFrom(reco);
tmpRecLuma.rspSignal(m_pcReshape->getInvLUT());
finalDistortion += m_pcRdCost->getDistPart(org, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma);
}
else
finalDistortion += m_pcRdCost->getDistPart(org, reco, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma);
}
else
#endif
{
finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE );
}
}
cs.dist = finalDistortion;
cs.fracBits = finalFracBits;
cs.cost = m_pcRdCost->calcRdCost(cs.fracBits, cs.dist);
...
}
3、InterSearch::xEstimateInterResidualQT()
関数はまずこのブロックをさらに分割せず、様々な変換モードを試み、transformNxN()とinvTransformNxN()を呼び出して変換と逆変換を行い、再構成値を得、m_CABACEstimator->residual_coding()などの関数は占有ビットを計算し,分割されないrd costを計算する.次いで、異なる分割方式を試み、この関数を再帰的に呼び出して、各分割方式のrd costを計算し、最適モードを保持する.さらに分割する必要がある場合は、xEncodeInterResidualQT()を呼び出してcbfおよび残差符号化を完了する必要がある.
void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &partitioner, Distortion *puiZeroDist /*= NULL*/
, const bool luma, const bool chroma
, PelUnitBuf* orgResi
)
{
...
if (bCheckFull)
{
TransformUnit &tu = csFull->addTU(CS::getArea(cs, currArea, partitioner.chType), partitioner.chType);
...
for( uint32_t c = 0; c < numTBlocks; c++ )
{
...
for( int transformMode = 0; transformMode < numTransformCandidates; transformMode++ )
{
for( int crossCPredictionModeId = 0; crossCPredictionModeId < crossCPredictionModesToTest; crossCPredictionModeId++ )
{
...
if( nNumTransformCands > 1 )
{
if( transformMode == 0 )
{
m_pcTrQuant->transformNxN( tu, compID, cQP, &trModes, m_pcEncCfg->getMTSInterMaxCand() );
tu.mtsIdx[compID] = trModes[0].first;
}
#if JVET_AHG14_LOSSLESS
if( !( m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0 ) )
{
m_pcTrQuant->transformNxN( tu, compID, cQP, currAbsSum, m_CABACEstimator->getCtx(), true );
}
#else
m_pcTrQuant->transformNxN( tu, compID, cQP, currAbsSum, m_CABACEstimator->getCtx(), true );
#endif
}
else
{
m_pcTrQuant->transformNxN( tu, compID, cQP, currAbsSum, m_CABACEstimator->getCtx() );
}
...
if (currAbsSum > 0) //if non-zero coefficients are present, a residual needs to be derived for further prediction
{
...
currCompFracBits = m_CABACEstimator->getEstFracBits();
PelBuf resiBuf = csFull->getResiBuf(compArea);
CPelBuf orgResiBuf = csFull->getOrgResiBuf(compArea);
m_pcTrQuant->invTransformNxN(tu, compID, resiBuf, cQP);
if (slice.getPicHeader()->getLmcsEnabledFlag() && isChroma(compID) && slice.getPicHeader()->getLmcsChromaResidualScaleFlag() && tu.blocks[compID].width*tu.blocks[compID].height > 4)
{
resiBuf.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(compID));
}
if (bUseCrossCPrediction)
{
crossComponentPrediction(tu, compID, lumaResi, resiBuf, resiBuf, true);
}
...
}
...
} // component loop
...
csFull->fracBits += m_CABACEstimator->getEstFracBits();
csFull->dist += uiSingleDist;
#if WCG_EXT
if( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() )
{
csFull->cost = m_pcRdCost->calcRdCost(csFull->fracBits, csFull->dist, false);
}
else
#endif
csFull->cost = m_pcRdCost->calcRdCost(csFull->fracBits, csFull->dist);
} // check full
// code sub-blocks
if( bCheckSplit )
{
...
do
{
xEstimateInterResidualQT(*csSplit, partitioner, bCheckFull ? nullptr : puiZeroDist
, luma, chroma
, orgResi
);
csSplit->cost = m_pcRdCost->calcRdCost( csSplit->fracBits, csSplit->dist );
} while( partitioner.nextPart( *csSplit ) );
partitioner.exitCurrSplit();
...
...
}
if( csSplit && csFull )
{
csSplit->releaseIntermediateData();
csFull ->releaseIntermediateData();
}
}
}