xIntraCodingTUBlock在xRecurIntraCodingLumaQT函数和xRecurIntraChromaCodingQT函数中均会被调用,进行给定变换模式和帧内预测模式下的一系列操作。
调用xIntraCodingTUBlock函数的目的,就是对tu在给定变换模式和帧内模式的情况下,求得解码端reco像素和orig的失真。
函数流程:
对pu进行帧内预测得到pred像素,由pred像素和orig像素得到残差像素resi,将resi通过调用transformNxN和invTransformNxN函数,得到解码端得到的resi像素,其与pred求和即的reco像素;最后通过reco像素和orig像素,求得失真,返回。
具体的会有很多种情况,函数中都有注释。
与VTM1中的代码相比,没太大差别,就多了LM预测。
void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2, uint32_t* numSig )
{
if (!tu.blocks[compID].valid())
{
return;
}
CodingStructure &cs = *tu.cs;
const CompArea &area = tu.blocks[compID]; //tu的area
const SPS &sps = *cs.sps;
const PPS &pps = *cs.pps;
const ChannelType chType = toChannelType(compID);
const int bitDepth = sps.getBitDepth(chType);
PelBuf piOrg = cs.getOrgBuf (area); //原始像素
PelBuf piPred = cs.getPredBuf (area); //预测像素
PelBuf piResi = cs.getResiBuf (area); //残差像素
PelBuf piOrgResi = cs.getOrgResiBuf(area); //编码端pred和orig的残差像素
PelBuf piReco = cs.getRecoBuf (area); //重建像素
const PredictionUnit &pu = *cs.getPU(area.pos(), chType); //pu,方便帧内预测等操作
const uint32_t uiChFinalMode = PU::getFinalIntraMode(pu, chType);
//chromaIntra预测时,是否可以进行跨组件预测
const bool bUseCrossCPrediction = pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isChroma( compID ) && PU::isChromaIntraModeCrossCheckMode( pu ) && checkCrossCPrediction;
const bool ccUseRecoResi = m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate();
#if !JVET_L0059_MTS_SIMP
const uint8_t transformIndex = tu.cu->emtFlag && compID == COMPONENT_Y ? tu.emtIdx : DCT2_EMT ;
#endif
//===== init availability pattern =====
PelBuf sharedPredTS( m_pSharedPredTransformSkip[compID], area );
if( default0Save1Load2 != 2 ) //当前tu的变换模式是DCT2
{
const bool bUseFilteredPredictions = IntraPrediction::useFilteredIntraRefSamples( compID, pu, true, tu ); //参考像素是否滤波
initIntraPatternChType( *tu.cu, area, bUseFilteredPredictions ); //帧内预测参考像素模板的初始化
//===== get prediction signal =====
if( compID != COMPONENT_Y && PU::isLMCMode( uiChFinalMode ) )
{
{
xGetLumaRecPixels( pu, area ); //获取色度块对应的亮度块的重建像素
}
predIntraChromaLM( compID, piPred, pu, area, uiChFinalMode ); //色度帧内LM模式预测
}
else
{
predIntraAng( compID, piPred, pu, bUseFilteredPredictions ); //帧内角度预测,得到pred像素
}
// save prediction
if( default0Save1Load2 == 1 ) //当前变换模式为DCT2,并且之后还有其它变换模式
{
sharedPredTS.copyFrom( piPred ); //sharedPredTS拷贝此时角度预测的pred像素
}
}
else //当前tu的变换模式不是DCT2
{
// load prediction
piPred.copyFrom( sharedPredTS ); //直接拷贝sharedPredTS得到pred像素,即DCT2时角度预测的pred
}
DTRACE( g_trace_ctx, D_PRED, "@(%4d,%4d) [%2dx%2d] IMode=%d\n", tu.lx(), tu.ly(), tu.lwidth(), tu.lheight(), uiChFinalMode );
//DTRACE_PEL_BUF( D_PRED, piPred, tu, tu.cu->predMode, COMPONENT_Y );
//===== get residual signal =====
piResi.copyFrom( piOrg );
piResi.subtract( piPred ); //orig减去pred像素得到resi像素
if (pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isLuma(compID))
{
piOrgResi.copyFrom (piResi);
}
if (bUseCrossCPrediction) //色度预测时,跨组件预测
{
if (xCalcCrossComponentPredictionAlpha(tu, compID, ccUseRecoResi) == 0)
{
return;
} //跨组件预测,CCLM
CrossComponentPrediction::crossComponentPrediction(tu, compID, cs.getResiBuf(tu.Y()), piResi, piResi, false);
}
//===== transform and quantization =====
//--- init rate estimation arrays for RDOQ ---
//--- transform and quantization ---
TCoeff uiAbsSum = 0;
const QpParam cQP(tu, compID); //量化参数qp
#if RDOQ_CHROMA_LAMBDA
m_pcTrQuant->selectLambda(compID);
#endif
//对resi进行变换量化
m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx());
DTRACE( g_trace_ctx, D_TU_ABS_SUM, "%d: comp=%d, abssum=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_TU_ABS_SUM ), compID, uiAbsSum );
//--- inverse transform ---
if (uiAbsSum > 0)
{
m_pcTrQuant->invTransformNxN(tu, compID, piResi, cQP); //反变换反量化,得到解码端解码的resi
}
else
{
piResi.fill(0);
}
//===== reconstruction =====
if (bUseCrossCPrediction) //色度预测时,跨组件预测
{
CrossComponentPrediction::crossComponentPrediction(tu, compID, cs.getResiBuf(tu.Y()), piResi, piResi, true);
}
//resi加pred得到reco像素
piReco.reconstruct(piPred, piResi, cs.slice->clpRng( compID )); //reconstruct
//===== update distortion =====
{ //由orig和reco像素求得失真
ruiDist += m_pcRdCost->getDistPart( piOrg, piReco, bitDepth, compID, DF_SSE );
}
}