xRecurIntraChromaCodingQT函数主要是由上层函数estIntraPredChromaQT函数调用,利用传来的预测模式进行预测计算残差信号,接着遍历所有可用的变换模式,对残差信号进行变换、量化、重建等,从而可以求出相应的RD Cost。
注意:这里色度编码模式分为Cb Cr单独编码和JointCbCr(即CbCr联合编码)两种,并且都对这两种编码模式进行了变换模式的遍历。
代码和注释如下:
ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitioner& partitioner, const double bestCostSoFar, const PartSplit ispType )
{
UnitArea currArea = partitioner.currArea();
const bool keepResi = cs.sps->getUseLMChroma() || KEEP_PRED_AND_RESI_SIGNALS;
if( !currArea.Cb().valid() ) return ChromaCbfs( false );
TransformUnit &currTU = *cs.getTU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA );//当前TU块
const PredictionUnit &pu = *cs.getPU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA );//当前PU
bool lumaUsesISP = false;
uint32_t currDepth = partitioner.currTrDepth;//当前分区的深度
const PPS &pps = *cs.pps;
ChromaCbfs cbfs ( false );
if (currDepth == currTU.depth)//如果当前分区深度和当前TU块的深度相等,则不需要继续划分
{
if (!currArea.Cb().valid() || !currArea.Cr().valid())
{
return cbfs;
}
CodingStructure &saveCS = *m_pSaveCS[1];
saveCS.pcv = cs.pcv;
saveCS.picture = cs.picture;
saveCS.area.repositionTo( cs.area );
saveCS.initStructData( MAX_INT, true );
if( !currTU.cu->isSepTree() && currTU.cu->ispMode )
{
saveCS.clearCUs();
CodingUnit& auxCU = saveCS.addCU( *currTU.cu, partitioner.chType );
auxCU.ispMode = currTU.cu->ispMode;
saveCS.sps = currTU.cs->sps;
saveCS.clearPUs();
saveCS.addPU( *currTU.cu->firstPU, partitioner.chType );
}
TransformUnit &tmpTU = saveCS.addTU(currArea, partitioner.chType);
cs.setDecomp(currArea.Cb(), true); // set in advance (required for Cb2/Cr2 in 4:2:2 video) 预先设置(4:2:2视频中Cb2/Cr2所需)
const unsigned numTBlocks = ::getNumberValidTBlocks( *cs.pcv );
CompArea& cbArea = currTU.blocks[COMPONENT_Cb];//Cb区域
CompArea& crArea = currTU.blocks[COMPONENT_Cr];//Cr区域
double bestCostCb = MAX_DOUBLE;//最佳Cb的Cost
double bestCostCr = MAX_DOUBLE;//最佳Cr的Cost
Distortion bestDistCb = 0;//最佳Cb失真
Distortion bestDistCr = 0;//最佳Cr失真
int maxModesTested = 0;
bool earlyExitISP = false;
TempCtx ctxStartTU( m_CtxCache );
TempCtx ctxStart ( m_CtxCache );
TempCtx ctxBest ( m_CtxCache );
ctxStartTU = m_CABACEstimator->getCtx();
currTU.jointCbCr = 0;
// Do predictions here to avoid repeating the "default0Save1Load2" stuff
// 在此处进行预测以避免重复“default0Save1Load2”的内容
int predMode = pu.cu->bdpcmModeChroma ? BDPCM_IDX : PU::getFinalIntraMode(pu, CHANNEL_TYPE_CHROMA);// 获取预测模式
PelBuf piPredCb = cs.getPredBuf(cbArea);//Cb预测值
PelBuf piPredCr = cs.getPredBuf(crArea);//Cr预测值
initIntraPatternChType( *currTU.cu, cbArea);
initIntraPatternChType( *currTU.cu, crArea);
if( PU::isLMCMode( predMode ) )//如果是LM_CHROMA LM_T LM_L模式
{
xGetLumaRecPixels( pu, cbArea );
predIntraChromaLM( COMPONENT_Cb, piPredCb, pu, cbArea, predMode );
predIntraChromaLM( COMPONENT_Cr, piPredCr, pu, crArea, predMode );
}
else
{
predIntraAng( COMPONENT_Cb, piPredCb, pu);
predIntraAng( COMPONENT_Cr, piPredCr, pu);
}
// determination of chroma residuals including reshaping and cross-component prediction
// 包括重塑和交叉分量预测的色度残差测定
//----- get chroma residuals -----
//获取色度残差
PelBuf resiCb = cs.getResiBuf(cbArea);//Cb残差
PelBuf resiCr = cs.getResiBuf(crArea);//Cr残差
resiCb.copyFrom( cs.getOrgBuf (cbArea) );
resiCr.copyFrom( cs.getOrgBuf (crArea) );
resiCb.subtract( piPredCb );
resiCr.subtract( piPredCr );
//----- get reshape parameter ----
//获取重建参数
bool doReshaping = ( cs.picHeader->getLmcsEnabledFlag() && cs.picHeader->getLmcsChromaResidualScaleFlag()
&& (cs.slice->isIntra() || m_pcReshape->getCTUFlag()) && (cbArea.width * cbArea.height > 4) );
if( doReshaping )
{
const Area area = currTU.Y().valid() ? currTU.Y() : Area(recalcPosition(currTU.chromaFormat, currTU.chType, CHANNEL_TYPE_LUMA, currTU.blocks[currTU.chType].pos()), recalcSize(currTU.chromaFormat, currTU.chType, CHANNEL_TYPE_LUMA, currTU.blocks[currTU.chType].size()));
const CompArea &areaY = CompArea(COMPONENT_Y, currTU.chromaFormat, area);
int adj = m_pcReshape->calculateChromaAdjVpduNei(currTU, areaY);
currTU.setChromaAdj(adj);
}
//----- get cross component prediction parameters -----
//获取交叉分量预测参数
bool checkCrossComponentPrediction = PU::isChromaIntraModeCrossCheckMode( pu ) && pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && TU::getCbf( currTU, COMPONENT_Y );
int compAlpha[MAX_NUM_COMPONENT] = { 0, 0, 0 };
if( checkCrossComponentPrediction )
{
compAlpha[COMPONENT_Cb] = xCalcCrossComponentPredictionAlpha( currTU, COMPONENT_Cb, m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate() );
compAlpha[COMPONENT_Cr] = xCalcCrossComponentPredictionAlpha( currTU, COMPONENT_Cr, m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate() );
if( compAlpha[COMPONENT_Cb] == 0 && compAlpha[COMPONENT_Cr] == 0 )
{
checkCrossComponentPrediction = false;
}
}
//===== store original residual signals (std and crossCompPred) =====
//存储原始残差信号(std和crossCompPred)
CompStorage orgResiCb[5], orgResiCr[5]; // 0:std, 1-3:jointCbCr (placeholder at this stage), 4:crossComp
for( int k = 0; k < (checkCrossComponentPrediction?5:1); k+=4 )
{
orgResiCb[k].create( cbArea );
orgResiCr[k].create( crArea );
if( k >= 4 ) {
CrossComponentPrediction::crossComponentPrediction( currTU, COMPONENT_Cb, cs.getResiBuf(currTU.Y()), resiCb, orgResiCb[k], false);
CrossComponentPrediction::crossComponentPrediction( currTU, COMPONENT_Cr, cs.getResiBuf(currTU.Y()), resiCr, orgResiCr[k], false);
} else {
orgResiCb[k].copyFrom( resiCb );
orgResiCr[k].copyFrom( resiCr );
}
if( doReshaping )
{
int cResScaleInv = currTU.getChromaAdj();
orgResiCb[k].scaleSignal( cResScaleInv, 1, currTU.cu->cs->slice->clpRng(COMPONENT_Cb) );
orgResiCr[k].scaleSignal( cResScaleInv, 1, currTU.cu->cs->slice->clpRng(COMPONENT_Cr) );
}
}
//对残差进行变换
for( uint32_t c = COMPONENT_Cb; c < numTBlocks; c++)
{
const ComponentID compID = ComponentID(c);
const CompArea& area = currTU.blocks[compID];
double dSingleCost = MAX_DOUBLE;//RD Cost
int bestModeId = 0;//最佳模式
Distortion singleDistCTmp = 0;
double singleCostTmp = 0;
const int crossCPredictionModesToTest = checkCrossComponentPrediction ? 2 : 1;
#if JVET_Q0784_LFNST_COMBINATION
const bool tsAllowed = TU::isTSAllowed(currTU, compID) && m_pcEncCfg->getUseChromaTS() && !currTU.cu->lfnstIdx;//变换跳过允许使用标志
#else
const bool tsAllowed = TU::isTSAllowed(currTU, compID) && (m_pcEncCfg->getUseChromaTS());
#endif
uint8_t nNumTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests
std::vector<TrMode> trModes;
#if JVET_Q0820_ACT
if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING)//无损编码
{
nNumTransformCands = 1;
CHECK(!tsAllowed && !currTU.cu->bdpcmModeChroma, "transform skip should be enabled for LS");
if (currTU.cu->bdpcmModeChroma)
{
trModes.push_back(TrMode(0, true));
}
else
{
trModes.push_back(TrMode(1, true));
}
}
else
{
#endif
trModes.push_back(TrMode(0, true)); // DCT2
if (tsAllowed)//如果允许TS
{
trModes.push_back(TrMode(1, true));//TS
}
#if JVET_Q0820_ACT
}
#endif
CHECK(!currTU.Cb().valid(), "Invalid TU");
const int totalModesToTest = crossCPredictionModesToTest * nNumTransformCands;//总共需要测试的模式
bool cbfDCT2 = true;
const bool isOneMode = false;
maxModesTested = totalModesToTest > maxModesTested ? totalModesToTest : maxModesTested;
int currModeId = 0;//当前测试的模式
int default0Save1Load2 = 0;
if (!isOneMode)
{
ctxStart = m_CABACEstimator->getCtx();
}
//遍历所有需要测试的变换模式(DCT-2和TS)
for (int modeId = 0; modeId < nNumTransformCands; modeId++)
{//遍历所有的交叉预测模式
for (int crossCPredictionModeId = 0; crossCPredictionModeId < crossCPredictionModesToTest; crossCPredictionModeId++)
{
resiCb.copyFrom( orgResiCb[4*crossCPredictionModeId] );//Cb残差
resiCr.copyFrom( orgResiCr[4*crossCPredictionModeId] );//Cr残差
currTU.compAlpha [compID] = ( crossCPredictionModeId ? compAlpha[compID] : 0 );
currTU.mtsIdx[compID] = currTU.cu->bdpcmModeChroma ? MTS_SKIP : trModes[modeId].first;
currModeId++;
const bool isFirstMode = (currModeId == 1);
const bool isLastMode = false; // Always store output to saveCS and tmpTU
#if JVET_AHG14_LOSSLESS
if( !( m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING ) )
{
#endif
//if DCT2's cbf==0, skip ts search
//如果 DCT的cbf为0,则跳过变换跳过的遍历
if (!cbfDCT2 && trModes[modeId].first == MTS_SKIP)
{
break;
}
if (!trModes[modeId].second)
{//如果当前变换为false,则跳过
continue;
}
#if JVET_AHG14_LOSSLESS
}
#endif
if (!isFirstMode) // if not first mode to be tested 如果不是第一个测试的模式
{
m_CABACEstimator->getCtx() = ctxStart;
}
singleDistCTmp = 0;
if (nNumTransformCands > 1)//如果变换模式数大于1,此时需要比较DCT-2和TS,此时loadTr参数为true
{
xIntraCodingTUBlock(currTU, compID, crossCPredictionModeId != 0, singleDistCTmp, default0Save1Load2, nullptr, modeId == 0 ? &trModes : nullptr, true);
}
else
{
xIntraCodingTUBlock(currTU, compID, crossCPredictionModeId != 0, singleDistCTmp, default0Save1Load2);
}
//为了在cbf为零时不编码TS标志,禁止cbf为零的TS情况。
if (((crossCPredictionModeId == 1) && (currTU.compAlpha[compID] == 0)) || ((currTU.mtsIdx[compID] == MTS_SKIP && !currTU.cu->bdpcmModeChroma) && !TU::getCbf(currTU, compID))) //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden.
{
#if JVET_Q0820_ACT
if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)
#endif
singleCostTmp = MAX_DOUBLE;
#if JVET_Q0820_ACT
else
{
uint64_t fracBitsTmp = xGetIntraFracBitsQTChroma(currTU, compID);
singleCostTmp = m_pcRdCost->calcRdCost(fracBitsTmp, singleDistCTmp);
}
#endif
}
else if( lumaUsesISP && bestCostSoFar != MAX_DOUBLE && c == COMPONENT_Cb )
{
uint64_t fracBitsTmp = xGetIntraFracBitsQTSingleChromaComponent( cs, partitioner, ComponentID( c ) );
singleCostTmp = m_pcRdCost->calcRdCost( fracBitsTmp, singleDistCTmp );
if( isOneMode || ( !isOneMode && !isLastMode ) )
{
m_CABACEstimator->getCtx() = ctxStart;
}
}
else if( !isOneMode )
{
uint64_t fracBitsTmp = xGetIntraFracBitsQTChroma( currTU, compID );
singleCostTmp = m_pcRdCost->calcRdCost( fracBitsTmp, singleDistCTmp );
}
if( singleCostTmp < dSingleCost )
{
dSingleCost = singleCostTmp;
bestModeId = currModeId;
if ( c == COMPONENT_Cb )
{
bestCostCb = singleCostTmp;
bestDistCb = singleDistCTmp;
}
else
{
bestCostCr = singleCostTmp;
bestDistCr = singleDistCTmp;
}
if (currTU.mtsIdx[compID] == MTS_DCT2_DCT2)
{
cbfDCT2 = TU::getCbfAtDepth(currTU, compID, currDepth);
}
if( !isLastMode )
{
#if KEEP_PRED_AND_RESI_SIGNALS
saveCS.getPredBuf (area).copyFrom(cs.getPredBuf (area));
saveCS.getOrgResiBuf(area).copyFrom(cs.getOrgResiBuf(area));
#endif
saveCS.getPredBuf (area).copyFrom(cs.getPredBuf (area));
if( keepResi )
{
saveCS.getResiBuf (area).copyFrom(cs.getResiBuf (area));
}
saveCS.getRecoBuf (area).copyFrom(cs.getRecoBuf (area));
tmpTU.copyComponentFrom(currTU, compID);
ctxBest = m_CABACEstimator->getCtx();
}
}
}
}
if( lumaUsesISP && dSingleCost > bestCostSoFar && c == COMPONENT_Cb )
{
//Luma + Cb cost is already larger than the best cost, so we don't need to test Cr
//Luma + Cb的成本已经超过了最佳成本,所以我们不需要测试Cr
cs.dist = MAX_UINT;
m_CABACEstimator->getCtx() = ctxStart;
earlyExitISP = true;
break;
//return cbfs;
}
// Done with one component of separate coding of Cr and Cb, just switch to the best Cb contexts if Cr coding is still to be done
// 使用Cr和Cb单独编码的一个组件完成,如果仍要进行Cr编码,只需切换到最佳Cb上下文
#if JVET_Q0820_ACT
if ((c == COMPONENT_Cb && bestModeId < totalModesToTest) || (c == COMPONENT_Cb && m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING))
#else
if ( c == COMPONENT_Cb && bestModeId < totalModesToTest)
#endif
{
m_CABACEstimator->getCtx() = ctxBest;
currTU.copyComponentFrom(tmpTU, COMPONENT_Cb); // Cbf of Cb is needed to estimate cost for Cr Cbf
}
}
if ( !earlyExitISP )
{
// Test using joint chroma residual coding
// 联合色度残差编码测试
double bestCostCbCr = bestCostCb + bestCostCr;
Distortion bestDistCbCr = bestDistCb + bestDistCr;
int bestJointCbCr = 0;
#if !JVET_Q0695_CHROMA_TS_JCCR
bool lastIsBest = false;
#endif
std::vector<int> jointCbfMasksToTest;
if ( cs.sps->getJointCbCrEnabledFlag() && (TU::getCbf(tmpTU, COMPONENT_Cb) || TU::getCbf(tmpTU, COMPONENT_Cr)))
{
jointCbfMasksToTest = m_pcTrQuant->selectICTCandidates(currTU, orgResiCb, orgResiCr);
}
#if JVET_Q0695_CHROMA_TS_JCCR
bool checkDCTOnly = (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_DCT2_DCT2 && !TU::getCbf(tmpTU, COMPONENT_Cr)) ||
(TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_DCT2_DCT2 && !TU::getCbf(tmpTU, COMPONENT_Cb)) ||
(TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_DCT2_DCT2 && TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_DCT2_DCT2);
bool checkTSOnly = (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_SKIP && !TU::getCbf(tmpTU, COMPONENT_Cr)) ||
(TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_SKIP && !TU::getCbf(tmpTU, COMPONENT_Cb)) ||
(TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_SKIP && TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_SKIP);
if (jointCbfMasksToTest.size() && currTU.cu->bdpcmModeChroma)
{
CHECK(!checkTSOnly || checkDCTOnly, "bdpcm only allows transform skip");
}
#endif
for( int cbfMask : jointCbfMasksToTest )
{
#if !JVET_Q0695_CHROMA_TS_JCCR
Distortion distTmp = 0;
#endif
currTU.jointCbCr = (uint8_t)cbfMask;
currTU.compAlpha[COMPONENT_Cb] = 0;
currTU.compAlpha[COMPONENT_Cr] = 0;
#if JVET_Q0695_CHROMA_TS_JCCR
ComponentID codeCompId = ((currTU.jointCbCr >> 1) ? COMPONENT_Cb : COMPONENT_Cr);
ComponentID otherCompId = ((codeCompId == COMPONENT_Cb) ? COMPONENT_Cr : COMPONENT_Cb);
#if JVET_Q0784_LFNST_COMBINATION
bool tsAllowed = TU::isTSAllowed(currTU, codeCompId) && (m_pcEncCfg->getUseChromaTS()) && !currTU.cu->lfnstIdx;
#else
bool tsAllowed = TU::isTSAllowed(currTU, codeCompId) && (m_pcEncCfg->getUseChromaTS());
#endif
uint8_t numTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests
bool cbfDCT2 = true;
std::vector<TrMode> trModes;
if (checkDCTOnly || checkTSOnly)
{
numTransformCands = 1;
}
if (!checkTSOnly || currTU.cu->bdpcmModeChroma)
{
trModes.push_back(TrMode(0, true)); // DCT2
}
if (tsAllowed && !checkDCTOnly)
{
trModes.push_back(TrMode(1, true));//TS
}
for (int modeId = 0; modeId < numTransformCands; modeId++)
{
if (modeId && !cbfDCT2)
{
continue;
}
if (!trModes[modeId].second)
{
continue;
}
Distortion distTmp = 0;
currTU.mtsIdx[codeCompId] = currTU.cu->bdpcmModeChroma ? MTS_SKIP : trModes[modeId].first;
currTU.mtsIdx[otherCompId] = MTS_DCT2_DCT2;
#else
// encoder bugfix: initialize mtsIdx for chroma under JointCbCrMode.
currTU.mtsIdx[COMPONENT_Cb] = currTU.mtsIdx[COMPONENT_Cr] = MTS_DCT2_DCT2;
#endif
m_CABACEstimator->getCtx() = ctxStartTU;
resiCb.copyFrom( orgResiCb[cbfMask] );
resiCr.copyFrom( orgResiCr[cbfMask] );
#if JVET_Q0695_CHROMA_TS_JCCR
if (numTransformCands > 1)
{
xIntraCodingTUBlock(currTU, COMPONENT_Cb, false, distTmp, 0, nullptr, modeId == 0 ? &trModes : nullptr, true);
}
else
#endif
xIntraCodingTUBlock( currTU, COMPONENT_Cb, false, distTmp, 0 );
double costTmp = std::numeric_limits<double>::max();
if( distTmp < std::numeric_limits<Distortion>::max() )
{
uint64_t bits = xGetIntraFracBitsQTChroma( currTU, COMPONENT_Cb );
costTmp = m_pcRdCost->calcRdCost( bits, distTmp );
#if JVET_Q0695_CHROMA_TS_JCCR
if (!currTU.mtsIdx[codeCompId])
{
cbfDCT2 = true;
}
#endif
}
#if JVET_Q0695_CHROMA_TS_JCCR
else if (!currTU.mtsIdx[codeCompId])
{
cbfDCT2 = false;
}
#endif
if( costTmp < bestCostCbCr )
{
bestCostCbCr = costTmp;
bestDistCbCr = distTmp;
bestJointCbCr = currTU.jointCbCr;
// store data
#if !JVET_Q0695_CHROMA_TS_JCCR
if( cbfMask != jointCbfMasksToTest.back() )
#endif
{
#if KEEP_PRED_AND_RESI_SIGNALS
saveCS.getOrgResiBuf(cbArea).copyFrom(cs.getOrgResiBuf(cbArea));
saveCS.getOrgResiBuf(crArea).copyFrom(cs.getOrgResiBuf(crArea));
#endif
saveCS.getPredBuf (cbArea).copyFrom(cs.getPredBuf (cbArea));
saveCS.getPredBuf (crArea).copyFrom(cs.getPredBuf (crArea));
if( keepResi )
{
saveCS.getResiBuf (cbArea).copyFrom(cs.getResiBuf (cbArea));
saveCS.getResiBuf (crArea).copyFrom(cs.getResiBuf (crArea));
}
saveCS.getRecoBuf (cbArea).copyFrom(cs.getRecoBuf (cbArea));
saveCS.getRecoBuf (crArea).copyFrom(cs.getRecoBuf (crArea));
tmpTU.copyComponentFrom(currTU, COMPONENT_Cb);
tmpTU.copyComponentFrom(currTU, COMPONENT_Cr);
ctxBest = m_CABACEstimator->getCtx();
}
#if !JVET_Q0695_CHROMA_TS_JCCR
else
{
lastIsBest = true;
}
#endif
}
#if JVET_Q0695_CHROMA_TS_JCCR
}
#endif
}
// Retrieve the best CU data (unless it was the very last one tested)
#if !JVET_Q0695_CHROMA_TS_JCCR
if ( !( maxModesTested == 1 && jointCbfMasksToTest.empty() ) && !lastIsBest )
#endif
{
#if KEEP_PRED_AND_RESI_SIGNALS
cs.getPredBuf (cbArea).copyFrom(saveCS.getPredBuf (cbArea));
cs.getOrgResiBuf(cbArea).copyFrom(saveCS.getOrgResiBuf(cbArea));
cs.getPredBuf (crArea).copyFrom(saveCS.getPredBuf (crArea));
cs.getOrgResiBuf(crArea).copyFrom(saveCS.getOrgResiBuf(crArea));
#endif
cs.getPredBuf (cbArea).copyFrom(saveCS.getPredBuf (cbArea));
cs.getPredBuf (crArea).copyFrom(saveCS.getPredBuf (crArea));
if( keepResi )
{
cs.getResiBuf (cbArea).copyFrom(saveCS.getResiBuf (cbArea));
cs.getResiBuf (crArea).copyFrom(saveCS.getResiBuf (crArea));
}
cs.getRecoBuf (cbArea).copyFrom(saveCS.getRecoBuf (cbArea));
cs.getRecoBuf (crArea).copyFrom(saveCS.getRecoBuf (crArea));
currTU.copyComponentFrom(tmpTU, COMPONENT_Cb);
currTU.copyComponentFrom(tmpTU, COMPONENT_Cr);
m_CABACEstimator->getCtx() = ctxBest;
}
// Copy results to the picture structures
cs.picture->getRecoBuf(cbArea).copyFrom(cs.getRecoBuf(cbArea));
cs.picture->getRecoBuf(crArea).copyFrom(cs.getRecoBuf(crArea));
cs.picture->getPredBuf(cbArea).copyFrom(cs.getPredBuf(cbArea));
cs.picture->getPredBuf(crArea).copyFrom(cs.getPredBuf(crArea));
cbfs.cbf(COMPONENT_Cb) = TU::getCbf(currTU, COMPONENT_Cb);
cbfs.cbf(COMPONENT_Cr) = TU::getCbf(currTU, COMPONENT_Cr);
currTU.jointCbCr = ( (cbfs.cbf(COMPONENT_Cb) + cbfs.cbf(COMPONENT_Cr)) ? bestJointCbCr : 0 );
cs.dist += bestDistCbCr;
}
}
else
{
unsigned numValidTBlocks = ::getNumberValidTBlocks( *cs.pcv );
ChromaCbfs SplitCbfs ( false );
if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
{
partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs );
}
else if( currTU.cu->ispMode )
{
partitioner.splitCurrArea( ispType, cs );
}
else
THROW( "Implicit TU split not available" );
do
{
ChromaCbfs subCbfs = xRecurIntraChromaCodingQT( cs, partitioner, bestCostSoFar, ispType );
for( uint32_t ch = COMPONENT_Cb; ch < numValidTBlocks; ch++ )
{
const ComponentID compID = ComponentID( ch );
SplitCbfs.cbf( compID ) |= subCbfs.cbf( compID );
}
} while( partitioner.nextPart( cs ) );
partitioner.exitCurrSplit();
if( lumaUsesISP && cs.dist == MAX_UINT )
{
return cbfs;
}
{
cbfs.Cb |= SplitCbfs.Cb;
cbfs.Cr |= SplitCbfs.Cr;
if( !lumaUsesISP )
{
for( auto &ptu : cs.tus )
{
if( currArea.Cb().contains( ptu->Cb() ) || ( !ptu->Cb().valid() && currArea.Y().contains( ptu->Y() ) ) )
{
TU::setCbfAtDepth( *ptu, COMPONENT_Cb, currDepth, SplitCbfs.Cb );
TU::setCbfAtDepth( *ptu, COMPONENT_Cr, currDepth, SplitCbfs.Cr );
}
}
}
}
}
return cbfs;
}