现在好像关于JEM的博客还很少,正好自己学习JEM,就把自己学习到的一点东西记录下来。省的学了就忘,先给自己定个目标,一天至少一篇吧。今天学习了色度帧内预测,先记录一下。estIntraPredChromaQT函数的主要功能是进行色度分量的帧内预测,在11种备选的预测模式中根据RD cost选择cost最小的一种模式作为最优预测模式。11种备选模式中,前6种是属于CCLM预测,用重建的亮度分量预测色度分量,后面5种是和HEVC中的色度预测模式一致。
Void
TEncSearch::estIntraPredChromaQT(TComDataCU* pcCU,
TComYuv* pcOrgYuv,
TComYuv* pcPredYuv,
TComYuv* pcResiYuv,
TComYuv* pcRecoYuv,
#if COM16_C806_LARGE_CTU
Pel* resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES]
#else
Pel resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE]
#endif
DEBUG_STRING_FN_DECLARE(sDebug))
{
#if JVET_C0024_QTBT
const UInt uiInitTrDepth = 0;
UInt uiWIdx = g_aucConvertToBit[pcCU->getWidth(0)];
UInt uiHIdx = g_aucConvertToBit[pcCU->getHeight(0)];
#else
const UInt uiInitTrDepth = pcCU->getPartitionSize(0) != SIZE_2Nx2N && enable4ChromaPUsInIntraNxNCU(pcOrgYuv->getChromaFormat()) ? 1 : 0;
#endif
TComTURecurse tuRecurseCU(pcCU, 0);
TComTURecurse tuRecurseWithPU(tuRecurseCU, false, (uiInitTrDepth==0)?TComTU::DONT_SPLIT : TComTU::QUAD_SPLIT);
#if !JVET_C0024_QTBT
const UInt uiQNumParts = tuRecurseWithPU.GetAbsPartIdxNumParts();
#endif
const UInt uiDepthCU=tuRecurseWithPU.getCUDepth();
const UInt numberValidComponents = pcCU->getPic()->getNumberValidComponents();
do while大循环/
do
{
#if JVET_E0077_LM_MF
UInt auiSATDModeList[LM_FILTER_NUM];
UInt auiSATDSortedcost[LM_FILTER_NUM];
const UInt csx = getComponentScaleX(COMPONENT_Cb, pcCU->getSlice()->getSPS()->getChromaFormatIdc());
const UInt csy = getComponentScaleY(COMPONENT_Cb, pcCU->getSlice()->getSPS()->getChromaFormatIdc());
Int iBlockSize = (pcCU->getHeight(0) >> csy) + (pcCU->getWidth(0) >> csx);
#endif
UInt uiBestMode = 0;
Distortion uiBestDist = 0;
Double dBestCost = MAX_DOUBLE;
//----- init mode list -----
if (tuRecurseWithPU.ProcessChannelSection(CHANNEL_TYPE_CHROMA))
{
#if JVET_E0062_MULTI_DMS
UInt uiModeList[NUM_CHROMA_MODE];
#else
UInt uiModeList[FAST_UDI_MAX_RDMODE_NUM];
#endif
#if !JVET_C0024_QTBT
const UInt uiQPartNum = uiQNumParts;
#endif
const UInt uiPartOffset = tuRecurseWithPU.GetAbsPartIdxTU();
{
UInt uiMinMode = 0;
UInt uiMaxMode = NUM_CHROMA_MODE;//11;
//----- check chroma modes -----
#if JVET_E0077_ENHANCED_LM
uiMaxMode =
#endif//前6种67,68,69,70,71,72应该是CCLM的6种预测模式,后5种和HEVC里的一样;
pcCU->getAllowedChromaDir( uiPartOffset, uiModeList );//获得可用的色度预测模式,uiModeList里有11种候选模式;
#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST
if (DebugOptionList::ForceChromaMode.isSet())
{
uiMinMode=DebugOptionList::ForceChromaMode.getInt();
if (uiModeList[uiMinMode]==34)
{
uiMinMode=4; // if the fixed mode has been renumbered because DM_CHROMA covers it, use DM_CHROMA.
}
uiMaxMode=uiMinMode+1;
}
#endif
#if JVET_C0024_QTBT
assert(uiPartOffset==0);
UInt uiShort, uiLong;
UInt uiStr;
if (pcCU->getHeight(0) > pcCU->getWidth(0))
{
uiShort = pcCU->getWidth(0);
uiLong = pcCU->getHeight(0);
uiStr = pcCU->getPic()->getNumPartInCtuWidth();
}
else
{
uiShort = pcCU->getHeight(0);
uiLong = pcCU->getWidth(0);
uiStr = 1;
}
UInt uiCurrDepth = g_aucConvertToBit[pcCU->getSlice()->getSPS()->getCTUSize()] - g_aucConvertToBit[uiShort];
UInt uiCurrPartNumb = pcCU->getPic()->getNumPartitionsInCtu() >> (uiCurrDepth << 1);
UInt uiNumPartInShort = pcCU->getPic()->getNumPartInCtuWidth() >> uiCurrDepth;
#endif
DEBUG_STRING_NEW(sPU)
#if JVET_E0077_ENHANCED_LM
const TComRectangle &puRect = tuRecurseWithPU.getRect(COMPONENT_Cb);
getLumaRecPixels(tuRecurseWithPU, puRect.width, puRect.height);//得到重建的亮度采样,用于CCLM;
#if !COM16_C983_RSAF
initIntraPatternChType(tuRecurseWithPU, COMPONENT_Cb, false DEBUG_STRING_PASS_INTO(sDebug));//初始过程;
initIntraPatternChType(tuRecurseWithPU, COMPONENT_Cr, false DEBUG_STRING_PASS_INTO(sDebug));
#else
initIntraPatternChType(tuRecurseWithPU, COMPONENT_Cb, false, false DEBUG_STRING_PASS_INTO(sDebug));
initIntraPatternChType(tuRecurseWithPU, COMPONENT_Cr, false, false DEBUG_STRING_PASS_INTO(sDebug));
#endif
#endif
#if JVET_E0077_LM_MF
const UInt uiAbsPartIdx = tuRecurseWithPU.GetAbsPartIdxTU();
DistParam distParam;
const Bool bUseHadamard = true;
Int iCurLMMFIdx = 0;
//SATD checking for LMMF candidates
const Int iLMMFinRDNum = 1;
if (pcCU->getSlice()->getSPS()->getUseLMChroma() && iBlockSize >= g_aiMFLM_MinSize[pcCU->getSlice()->isIntra() ? 0 : 1])
{ //LM_FILTER_NUM=4,为什么是从69开始的,不是67,68,69,70,71,72 6个模式吗;
for (UInt uiMode = LM_CHROMA_F1_IDX; uiMode < LM_CHROMA_F1_IDX + LM_FILTER_NUM; uiMode++)
{
UInt uiSad = 0;
Pel* piOrg = pcOrgYuv->getAddr(COMPONENT_Cb, uiAbsPartIdx);
Pel* piPred = pcPredYuv->getAddr(COMPONENT_Cb, uiAbsPartIdx);
UInt uiStride = pcPredYuv->getStride(COMPONENT_Cb);
m_pcRdCost->setDistParam(distParam, pcCU->getSlice()->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA), piOrg, uiStride, piPred, uiStride, puRect.width, puRect.height, bUseHadamard);
distParam.bApplyWeight = false;
//用亮度分量预测Cb分量;
predLMIntraChroma(tuRecurseWithPU, COMPONENT_Cb, piPred, uiStride, puRect.width, puRect.height, uiMode);
Pel* piOrgPred = piPred;
Pel* piSavPred = m_pLMMFPredSaved[(uiMode - LM_CHROMA_F1_IDX) * 2];
for (Int i = 0; i < puRect.height; i++)
{
memcpy(piSavPred, piOrgPred, sizeof(Pel)* puRect.width);
piOrgPred += uiStride;
piSavPred += puRect.width;
}
uiSad += distParam.DistFunc(&distParam);
piOrg = pcOrgYuv->getAddr(COMPONENT_Cr, uiAbsPartIdx);
piPred = pcPredYuv->getAddr(COMPONENT_Cr, uiAbsPartIdx);
uiStride = pcPredYuv->getStride(COMPONENT_Cr);
m_pcRdCost->setDistParam(distParam, pcCU->getSlice()->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA), piOrg, uiStride, piPred, uiStride, puRect.width, puRect.height, bUseHadamard);
distParam.bApplyWeight = false;
//用亮度分量预测色度Cr分量,过程和预测Cb分量的过程一样;
predLMIntraChroma(tuRecurseWithPU, COMPONENT_Cr, piPred, uiStride, puRect.width, puRect.height, uiMode);
piOrgPred = piPred;
piSavPred = m_pLMMFPredSaved[(uiMode - LM_CHROMA_F1_IDX) * 2 + 1];
for (Int i = 0; i < puRect.height; i++)
{
memcpy(piSavPred, piOrgPred, sizeof(Pel)* puRect.width);//将piOrgPred所指内存区域中的sizeof(Pel)* puRect.width个字节赋值到piSavPred指向的内存区域;
piOrgPred += uiStride;
piSavPred += puRect.width;
}
//计算失真;
uiSad += distParam.DistFunc(&distParam);
//uiSad的值为Cb分量的失真与Cr分量失真的和;
auiSATDSortedcost[iCurLMMFIdx] = uiSad;
auiSATDModeList[iCurLMMFIdx] = uiMode;
for (Int k = iCurLMMFIdx; k > 0 && auiSATDSortedcost[k] < auiSATDSortedcost[k - 1]; k--)
{//对这个数组auiSATDSortedcost进行排序;
UInt tmp = auiSATDSortedcost[k];
auiSATDSortedcost[k] = auiSATDSortedcost[k - 1];
auiSATDSortedcost[k - 1] = tmp;
tmp = auiSATDModeList[k];
auiSATDModeList[k] = auiSATDModeList[k - 1];
auiSATDModeList[k - 1] = tmp;
}
iCurLMMFIdx++;
}
}//此循环结束,得到69,70,71,72 4种MMLM预测模式的代价值;
#endif
#if JVET_E0077_ENHANCED_LM
m_iCurAngMode = 0;
#endif///遍历11种色度模式,寻找代价最小的模式//
for( UInt uiMode = uiMinMode; uiMode < uiMaxMode; uiMode++ )//色度有11种帧内预测模式;
{
#if COM16_C806_LMCHROMA
if ( !pcCU->getSlice()->getSPS()->getUseLMChroma() && uiModeList[uiMode] == LM_CHROMA_IDX )
{
continue;
}
#endif
#if JVET_E0077_ENHANCED_LM//67,68,69,70,71,72时IsLMMode都为true;
if (!pcCU->getSlice()->getSPS()->getUseLMChroma() && IsLMMode(uiModeList[uiMode]))
{
continue;
}
#endif
#if JVET_E0077_LM_MF//如果69<=uimode<=72;
if (uiModeList[uiMode] >= LM_CHROMA_F1_IDX && uiModeList[uiMode] < LM_CHROMA_F1_IDX + LM_FILTER_NUM)
{
Bool bNeedRD = false;
for (Int i = 0; i < iLMMFinRDNum; i++)//iLMMFinRDNum=1;
{
if (auiSATDModeList[i] == uiModeList[uiMode])
{
bNeedRD = true;
break;
}
}
if (!bNeedRD)
{
continue;
}
}
#endif
#if JVET_C0024_QTBT && COM16_C1044_NSST
if( pcCU->getSlice()->isIntra() )
{
UInt uiIntraMode = uiModeList[uiMode];
#if JVET_E0062_MULTI_DMS && COM16_C806_LMCHROMA
if( uiIntraMode == LM_CHROMA_IDX )
{
uiIntraMode = PLANAR_IDX;
}
#if JVET_E0077_ENHANCED_LM
else if (IsLMMode(uiIntraMode))
{
uiIntraMode = PLANAR_IDX;
}
#endif
#else
if( uiIntraMode == DM_CHROMA_IDX )
{
uiIntraMode = pcCU->getPic()->getCtu(pcCU->getCtuRsAddr())->getIntraDir(CHANNEL_TYPE_LUMA, pcCU->getZorderIdxInCtu()+uiPartOffset);
}
#if COM16_C806_LMCHROMA
else if( uiIntraMode == LM_CHROMA_IDX )
{
uiIntraMode = PLANAR_IDX;
}
#endif
#if JVET_E0077_ENHANCED_LM
else if (IsLMMode(uiIntraMode))
{
uiIntraMode = PLANAR_IDX;
}
#endif
#endif
const Int iNumberOfPassesROT = ( uiIntraMode<=DC_IDX ) ? 3 : 4;
if( iNumberOfPassesROT <= pcCU->getROTIdx(CHANNEL_TYPE_CHROMA, uiPartOffset) )
{
continue;
}
}
#endif
#if JVET_E0077_ENHANCED_LM
if (!IsLMMode(uiModeList[uiMode]))//不属于LM模式,即是11种模式中的后5种模式(HEVC中的传统模式);
{
m_iCurAngMode++;
#if QC_LM_ANGULAR_PREDICTION
if (numRDChecking > 1 && uiCPLEFlag == 1 && adModecost[m_iCurAngMode - 1] > adSortedcost[iSecondRDtime - 1])
{
continue;
}
#endif
#if JVET_E0077_ENHANCED_LM && JVET_E0062_MULTI_DMS
if (m_iCurAngMode > NUM_CHROMA_MODE)
{
continue;
}
#endif
}
#endif
//----- restore context models -----重新存储上下文模型;
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load( m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_CURR_BEST] );
#else
m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepthCU][CI_CURR_BEST] );
#endif
DEBUG_STRING_NEW(sMode)
//----- chroma coding -----
Distortion uiDist = 0;
#if JVET_E0062_MULTI_DMS
assert(uiModeList[uiMode]<=(LM_CHROMA_IDX+NUM_DM_MODES));
#endif
pcCU->setIntraDirSubParts ( CHANNEL_TYPE_CHROMA, uiModeList[uiMode], uiPartOffset, uiDepthCU+uiInitTrDepth );
//求色度分量的残差,并对残差进行变换量化熵编码等,并返回一个失真;
xRecurIntraChromaCodingQT ( pcOrgYuv, pcPredYuv, pcResiYuv, resiLuma, uiDist, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) );
if( pcCU->getSlice()->getPPS()->getUseTransformSkip() )
{
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load( m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_CURR_BEST] );
#else
m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepthCU][CI_CURR_BEST] );
#endif
}
UInt uiBits = xGetIntraBitsQT( tuRecurseWithPU, false, true, false );
Double dCost = m_pcRdCost->calcRdCost( uiBits, uiDist );
//----- compare -----
if( dCost < dBestCost )//如果当前模式的代价小于最优模式的代价,则将最优模式等相关数据更新为当前模式的数据;
{
DEBUG_STRING_SWAP(sPU, sMode);
dBestCost = dCost;
uiBestDist = uiDist;
uiBestMode = uiModeList[uiMode];
xSetIntraResultChromaQT( pcRecoYuv, tuRecurseWithPU );//保存最优模式的数据;
#if JVET_C0024_QTBT
UInt uiRaster = g_auiZscanToRaster[pcCU->getZorderIdxInCtu()];
for (UInt i=0; i<uiLong; i+=uiShort)
{
UInt uiZorder = g_auiRasterToZscan[uiRaster] - pcCU->getZorderIdxInCtu();
for (UInt componentIndex = COMPONENT_Cb; componentIndex < numberValidComponents; componentIndex++)
{
const ComponentID compID = ComponentID(componentIndex);
::memcpy(m_puhQTTempCbf[compID] + uiZorder, pcCU->getCbf( compID ) + uiZorder, uiCurrPartNumb );
::memcpy(m_puhQTTempTransformSkipFlag[compID]+uiZorder, pcCU->getTransformSkip( compID ) + uiZorder, uiCurrPartNumb);
::memcpy(m_phQTTempCrossComponentPredictionAlpha[compID]+uiZorder, pcCU->getCrossComponentPredictionAlpha(compID)+uiZorder, uiCurrPartNumb );
}
uiRaster += uiNumPartInShort * uiStr;
}
#else
for (UInt componentIndex = COMPONENT_Cb; componentIndex < numberValidComponents; componentIndex++)
{
const ComponentID compID = ComponentID(componentIndex);
::memcpy( m_puhQTTempCbf[compID], pcCU->getCbf( compID )+uiPartOffset, uiQPartNum * sizeof( UChar ) );
::memcpy( m_puhQTTempTransformSkipFlag[compID], pcCU->getTransformSkip( compID )+uiPartOffset, uiQPartNum * sizeof( UChar ) );
::memcpy( m_phQTTempCrossComponentPredictionAlpha[compID], pcCU->getCrossComponentPredictionAlpha(compID)+uiPartOffset, uiQPartNum * sizeof( Char ) );
}
#endif
}
}
//此循环结束,即在11中模式中选择了代价最小的一种预测模式/
DEBUG_STRING_APPEND(sDebug, sPU)
//----- set data -----
#if JVET_C0024_QTBT
UInt uiRaster = g_auiZscanToRaster[pcCU->getZorderIdxInCtu()];
for (UInt i=0; i<uiLong; i+=uiShort)
{
UInt uiZorder = g_auiRasterToZscan[uiRaster] - pcCU->getZorderIdxInCtu();
for (UInt componentIndex = COMPONENT_Cb; componentIndex < numberValidComponents; componentIndex++)
{
const ComponentID compID = ComponentID(componentIndex);
::memcpy( pcCU->getCbf( compID )+uiZorder, m_puhQTTempCbf[compID]+uiZorder, uiCurrPartNumb );
::memcpy( pcCU->getTransformSkip( compID )+uiZorder, m_puhQTTempTransformSkipFlag[compID]+uiZorder, uiCurrPartNumb );
::memcpy( pcCU->getCrossComponentPredictionAlpha(compID)+uiZorder, m_phQTTempCrossComponentPredictionAlpha[compID]+uiZorder, uiCurrPartNumb );
}
uiRaster += uiNumPartInShort * uiStr;
}
#else
for (UInt componentIndex = COMPONENT_Cb; componentIndex < numberValidComponents; componentIndex++)
{
const ComponentID compID = ComponentID(componentIndex);
::memcpy( pcCU->getCbf( compID )+uiPartOffset, m_puhQTTempCbf[compID], uiQPartNum * sizeof( UChar ) );
::memcpy( pcCU->getTransformSkip( compID )+uiPartOffset, m_puhQTTempTransformSkipFlag[compID], uiQPartNum * sizeof( UChar ) );
::memcpy( pcCU->getCrossComponentPredictionAlpha(compID)+uiPartOffset, m_phQTTempCrossComponentPredictionAlpha[compID], uiQPartNum * sizeof( Char ) );
}
#endif
}
if( ! tuRecurseWithPU.IsLastSection() )
{
#if JVET_C0024_QTBT
assert(0);
#endif
for (UInt ch=COMPONENT_Cb; ch<numberValidComponents; ch++)
{
const ComponentID compID = ComponentID(ch);
const TComRectangle &tuRect = tuRecurseWithPU.getRect(compID);
const UInt uiCompWidth = tuRect.width;
const UInt uiCompHeight = tuRect.height;
const UInt uiZOrder = pcCU->getZorderIdxInCtu() + tuRecurseWithPU.GetAbsPartIdxTU();
Pel* piDes = pcCU->getPic()->getPicYuvRec()->getAddr( compID, pcCU->getCtuRsAddr(), uiZOrder );
const UInt uiDesStride = pcCU->getPic()->getPicYuvRec()->getStride( compID);
const Pel* piSrc = pcRecoYuv->getAddr( compID, uiPartOffset );
const UInt uiSrcStride = pcRecoYuv->getStride( compID);
for( UInt uiY = 0; uiY < uiCompHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride )
{
for( UInt uiX = 0; uiX < uiCompWidth; uiX++ )
{
piDes[ uiX ] = piSrc[ uiX ];
}
}
}
}
pcCU->setIntraDirSubParts( CHANNEL_TYPE_CHROMA, uiBestMode, uiPartOffset, uiDepthCU+uiInitTrDepth );
pcCU->getTotalDistortion () += uiBestDist;
}
} while (tuRecurseWithPU.nextSection(tuRecurseCU));
do while循环结束//
//----- restore context models -----
#if !JVET_C0024_QTBT
if( uiInitTrDepth != 0 )
{ // set Cbf for all blocks
UInt uiCombCbfU = 0;
UInt uiCombCbfV = 0;
UInt uiPartIdx = 0;
for( UInt uiPart = 0; uiPart < 4; uiPart++, uiPartIdx += uiQNumParts )
{
uiCombCbfU |= pcCU->getCbf( uiPartIdx, COMPONENT_Cb, 1 );
uiCombCbfV |= pcCU->getCbf( uiPartIdx, COMPONENT_Cr, 1 );
}
for( UInt uiOffs = 0; uiOffs < 4 * uiQNumParts; uiOffs++ )
{
pcCU->getCbf( COMPONENT_Cb )[ uiOffs ] |= uiCombCbfU;
pcCU->getCbf( COMPONENT_Cr )[ uiOffs ] |= uiCombCbfV;
}
}
#endif
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load( m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_CURR_BEST] );
#else
m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepthCU][CI_CURR_BEST] );
#endif
}