在执行亮度分量的预测时,在确定好最后的要执行RD cost的候选模式后,对于每个模式,都调用一遍xRecurIntraCodingLumaQT(),在此函数里面完成预测,求残差,变换量化和重建,并返回失真。
Void
TEncSearch::xRecurIntraCodingLumaQT(TComYuv* pcOrgYuv,
TComYuv* pcPredYuv,
TComYuv* pcResiYuv,
#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
Distortion& ruiDistY,
#if HHI_RQT_INTRA_SPEEDUP
Bool bCheckFirst,
#endif
Double& dRDCost,
TComTU& rTu
DEBUG_STRING_FN_DECLARE(sDebug))
{
TComDataCU *pcCU = rTu.getCU();
const UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
const UInt uiFullDepth = rTu.GetTransformDepthTotal();
const UInt uiTrDepth = rTu.GetTransformDepthRel();//变换深度
#if JVET_C0024_QTBT
Bool bCheckFull = true;// 判断是否将当前的PU按照整个模式进行变换和量化。
Bool bCheckSplit = false;//是否进行分割;
assert(uiAbsPartIdx ==0 && uiTrDepth==0);//uiTrDepth肯定为0;
UInt uiWidth = pcCU->getWidth(uiAbsPartIdx);
UInt uiHeight = pcCU->getHeight(uiAbsPartIdx);
UInt uiWIdx = g_aucConvertToBit[ uiWidth ] ;
UInt uiHIdx = g_aucConvertToBit[ uiHeight ] ;
#else
const UInt uiLog2TrSize = rTu.GetLog2LumaTrSize();
Bool bCheckFull = ( uiLog2TrSize <= pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() );
Bool bCheckSplit = ( uiLog2TrSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) );
#endif
#if !COM16_C806_LARGE_CTU
Pel resiLumaSplit [NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE];
Pel resiLumaSingle[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE];
#endif
//两种类型,一种应该是用普通方法计算(真实值-预测值),一种是用CCP方法预测的
Bool bMaintainResidual[NUMBER_OF_STORED_RESIDUAL_TYPES];//维持残差,存储的残差类型数量=2;
for (UInt residualTypeIndex = 0; residualTypeIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; residualTypeIndex++)
{
bMaintainResidual[residualTypeIndex] = true; //assume true unless specified otherwise
}
bMaintainResidual[RESIDUAL_ENCODER_SIDE] = !(m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate());//如果使用基于重建的CCP估计的残差则为false;
#if COM16_C806_EMT
UInt uiSigNum;
#endif
#if HHI_RQT_INTRA_SPEEDUP
#if JVET_C0024_QTBT
Int isIntraSlice = (pcCU->getSlice()->getSliceType() == I_SLICE);//是否是I slice;
#else
Int maxTuSize = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize();
Int isIntraSlice = (pcCU->getSlice()->getSliceType() == I_SLICE);
// don't check split if TU size is less or equal to max TU size
Bool noSplitIntraMaxTuSize = bCheckFull;
if(m_pcEncCfg->getRDpenalty() && ! isIntraSlice)
{
// in addition don't check split if TU size is less or equal to 16x16 TU size for non-intra slice
noSplitIntraMaxTuSize = ( uiLog2TrSize <= min(maxTuSize,4) );
// if maximum RD-penalty don't check TU size 32x32
if(m_pcEncCfg->getRDpenalty()==2)
{
bCheckFull = ( uiLog2TrSize <= min(maxTuSize,4));
}
}
if( bCheckFirst && noSplitIntraMaxTuSize )
{
bCheckSplit = false;
}
#endif
#else
Int maxTuSize = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize();
Int isIntraSlice = (pcCU->getSlice()->getSliceType() == I_SLICE);
// if maximum RD-penalty don't check TU size 32x32
if((m_pcEncCfg->getRDpenalty()==2) && !isIntraSlice)
{
bCheckFull = ( uiLog2TrSize <= min(maxTuSize,4));
}
#endif
#if COM16_C806_EMT && HHI_RQT_INTRA_SPEEDUP
// Re-use the selected transform indexes in the previous call of xRecurIntraCodingQT
#if JVET_C0024_QTBT
UInt uiInitTrDepth = 0;
#else
UInt uiInitTrDepth = pcCU->getPartitionSize(0) == SIZE_2Nx2N ? 0 : 1;
#endif
UChar ucSavedEmtTrIdx = 0;
Bool bCheckInitTrDepth = false;
static UInt uiInitAbsPartIdx;
if ( uiTrDepth==uiInitTrDepth )//一定成立
{
uiInitAbsPartIdx = uiAbsPartIdx;
}
if ( !bCheckFirst && uiTrDepth==uiInitTrDepth )//bCheckFirst 默认为true;
{
ucSavedEmtTrIdx = m_puhQTTempEmtTuIdx[uiAbsPartIdx-uiInitAbsPartIdx];
bCheckInitTrDepth = true;
}
#endif
#if JVET_C0024_QTBT
assert(bCheckFull && !bCheckSplit);
#endif
//初始化
Double dSingleCost = MAX_DOUBLE;
Distortion uiSingleDistLuma = 0;
UInt uiSingleCbfLuma = 0;
Bool checkTransformSkip = pcCU->getSlice()->getPPS()->getUseTransformSkip();//是否使用跳过变换
Int bestModeId[MAX_NUM_COMPONENT] = { 0, 0, 0};
#if COM16_C806_EMT
UChar bestTrIdx = 0;
UChar nNumTrCands = pcCU->getEmtCuFlag(uiAbsPartIdx) ? 4 : 1;//如果EmtCuFlag为true,则nNumTrCands等于4,否则等于1,是表示Emt变换的候选模式数量吗???;
Bool bAllIntra = (m_pcEncCfg->getIntraPeriod()==1);//全I帧;
#endif
#if JVET_C0024_QTBT
checkTransformSkip &= TUCompRectHasAssociatedTransformSkipFlag(pcCU->getSlice()->isIntra(), rTu.getRect(COMPONENT_Y), pcCU->getSlice()->getPPS()->getPpsRangeExtension().getLog2MaxTransformSkipBlockSize());
#else
checkTransformSkip &= TUCompRectHasAssociatedTransformSkipFlag(rTu.getRect(COMPONENT_Y), pcCU->getSlice()->getPPS()->getPpsRangeExtension().getLog2MaxTransformSkipBlockSize());
#endif
checkTransformSkip &= (!pcCU->getCUTransquantBypass(0));
#if JVET_F0031_RMV_REDUNDANT_TRSKIP//只有当主要变换被禁用时,才发送transform skip flag;
checkTransformSkip &= (!pcCU->getEmtCuFlag(uiAbsPartIdx));
#endif
assert (rTu.ProcessComponentSection(COMPONENT_Y));
#if !JVET_C0024_QTBT
const UInt totalAdjustedDepthChan = rTu.GetTransformDepthTotalAdj(COMPONENT_Y);
if ( m_pcEncCfg->getUseTransformSkipFast() )
{
checkTransformSkip &= (pcCU->getPartitionSize(uiAbsPartIdx)==SIZE_NxN);
}
#endif
#if VCEG_AZ08_INTRA_KLT
#if !JVET_C0024_QTBT
UInt bestTMKLT = 0;
#endif
#if VCEG_AZ08_USE_KLT
Bool checkTM = pcCU->getSlice()->getSPS()->getUseIntraKLT() && (bCheckFirst == false);//TM表示要使用KLT,此程序中永远为false;
#else
Bool checkTM = (bCheckFirst == false);
#endif
if (checkTM)//默认为false;
{
UInt uiMaxTrWidth = g_uiDepth2Width[USE_MORE_BLOCKSIZE_DEPTH_MAX - 1];
UInt uiMinTrWidth = g_uiDepth2Width[USE_MORE_BLOCKSIZE_DEPTH_MIN - 1];
#if !JVET_C0024_QTBT
UInt uiWidth = pcCU->getWidth(0) >> uiTrDepth;
UInt uiHeight = pcCU->getHeight(0) >> uiTrDepth;
#endif
Bool bCheckKLTFlag = (uiWidth == uiHeight) && (uiWidth <= uiMaxTrWidth) && (uiWidth >= uiMinTrWidth);
checkTM &= bCheckKLTFlag;
#if VCEG_AZ05_INTRA_MPI //for speed up only
Int iMPIidx = pcCU->getMPIIdx(uiAbsPartIdx);
checkTM = checkTM & (iMPIidx == 0);
#endif
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
Int iPdpcIdx = pcCU->getPDPCIdx(uiAbsPartIdx);
checkTM = checkTM & (iPdpcIdx == 0);
#endif
#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST //for speed up only
#if JVET_C0024_QTBT
Int iRotidx = pcCU->getROTIdx(CHANNEL_TYPE_LUMA, uiAbsPartIdx);//ROT表示Rotation operation for low-frequency transform;
#else
Int iRotidx = pcCU->getROTIdx(uiAbsPartIdx);
#endif
checkTM = checkTM & (iRotidx == 0);
#endif
}
#endif
//按照一整个TU进行变换、量化;
if( bCheckFull )//永远成立
{
if(checkTransformSkip == true)//skip TransformSkip;
{
//----- store original entropy coding status ,存储原始的熵编码状态
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->store( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_QT_TRAFO_ROOT ] );
#else
m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
#endif
//初始化
Distortion singleDistTmpLuma = 0;
UInt singleCbfTmpLuma = 0;
Double singleCostTmp = 0;
Int firstCheckId = 0;
#if VCEG_AZ08_INTRA_KLT
pcCU->setKLTFlagSubParts(0, COMPONENT_Y, uiAbsPartIdx, uiFullDepth);//将KLTFlag设置为0
#endif
/// 遍历两次是为了选取最优的模式,modeId能够决定xIntraCodingLumaBlk的倒数第二个参数,该参数控制了预测像素如何生成
for(Int modeId = firstCheckId; modeId < 2; modeId ++)
{
#if COM16_C806_EMT
#if HHI_RQT_INTRA_SPEEDUP//即第一次遍历时循环nNumTrCands次,第二次遍历只循环1次;
UChar numTrIdxCands = ((modeId == firstCheckId && !bCheckInitTrDepth) ? nNumTrCands : 1 );//modeId=0时,numTrIdxCands=nNumTrDepth,否则等于1;
#else
UChar numTrIdxCands = ((modeId == firstCheckId) ? nNumTrCands : 1 );
#endif
//循环次数是numTrIdxCands,这是为了选取最优的变换///
for (UChar ucTrIdx = 0; ucTrIdx < numTrIdxCands; ucTrIdx++)
{
// Skip checking other transform candidates if zero CBF is encountered,如果遇到零CBF,就跳过check其他变换候选模式;
if( ucTrIdx && !uiSingleCbfLuma && bAllIntra && m_pcEncCfg->getUseFastIntraEMT() )
{
continue;
}
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if( this->getSaveLoadTag(pcCU->getZorderIdxInCtu(), uiWIdx, uiHIdx) == LOAD_ENC_INFO && ucTrIdx && ucTrIdx != this->getSaveLoadEmtIdx(uiWIdx, uiHIdx) )
{
continue;
}
#endif
#endif
DEBUG_STRING_NEW(sModeString)
Int default0Save1Load2 = 0;//模式重复使用标志
singleDistTmpLuma=0;
#if COM16_C806_EMT
if (modeId == firstCheckId && ucTrIdx == 0)//如果modeId=0且ucTrIdx == 0,即第一次模式遍历中的第一次变换
#else
if(modeId == firstCheckId)
#endif
{
default0Save1Load2 = 1;//表示保存信息
}
else//否则
{
default0Save1Load2 = 2;//表示加载信息
}
#if COM16_C806_EMT
#if HHI_RQT_INTRA_SPEEDUP
pcCU->setEmtTuIdxSubParts( bCheckInitTrDepth?ucSavedEmtTrIdx:ucTrIdx, uiAbsPartIdx, uiFullDepth );//设置EmtTuIdx为ucTrIdx;
#else
pcCU->setEmtTuIdxSubParts( txIdx, uiAbsPartIdx, uiFullDepth );
#endif
#endif
#if COM16_C983_RSAF
pcCU->setLumaIntraFilter(uiAbsPartIdx, false);
pcCU->setLumaIntraFilterHidden(uiAbsPartIdx, true);
#endif
#if JVET_C0024_QTBT//modeId为0时TransformSkip=0,modeId为时TransformSkip为1,所以表示modeId=0表示不跳过变换,modeId=1表示跳过变换
pcCU->setTransformSkipSubParts ( modeId, COMPONENT_Y, uiAbsPartIdx, 0 );//将TransformSkip标记设置为modeId;
#else
pcCU->setTransformSkipSubParts ( modeId, COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan );
#endif //预测、变换和量化,反量化反变换,重建等
xIntraCodingTUBlock( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT
m_resiSingleBuffer[uiWIdx][uiHIdx],
#else
m_resiSingleBuffer[uiLog2TrSize],
#endif
#else
resiLumaSingle,
#endif
false, singleDistTmpLuma, COMPONENT_Y, rTu DEBUG_STRING_PASS_INTO(sModeString)
, default0Save1Load2
#if COM16_C806_EMT
, &uiSigNum
#endif
);//倒数第6个参数为false,表示不进行CCP,倒数第二个参数表示如何得到预测信息;
singleCbfTmpLuma = pcCU->getCbf( uiAbsPartIdx, COMPONENT_Y, uiTrDepth );
//----- determine rate and r-d cost,确定码率和率失真代价 -----
#if COM16_C806_EMT
if( (modeId == 1 && singleCbfTmpLuma == 0) || (modeId==0 && ucTrIdx && ucTrIdx!=DCT2_EMT && uiSigNum<=g_iEmtSigNumThr) )
#else
if(modeId == 1 && singleCbfTmpLuma == 0)
#endif
{
//In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden.
singleCostTmp = MAX_DOUBLE;
}
else
{
UInt uiSingleBits = xGetIntraBitsQT( rTu, true, false, false );
singleCostTmp = m_pcRdCost->calcRdCost( uiSingleBits, singleDistTmpLuma );
}//更新代价;
if(singleCostTmp < dSingleCost)
{
DEBUG_STRING_SWAP(sDebug, sModeString)
dSingleCost = singleCostTmp;
uiSingleDistLuma = singleDistTmpLuma;
uiSingleCbfLuma = singleCbfTmpLuma;
#if COM16_C806_EMT
bestTrIdx = ucTrIdx;
#endif
bestModeId[COMPONENT_Y] = modeId;
if(bestModeId[COMPONENT_Y] == firstCheckId)//如果最优的modeId==0,则保存变换系数和重建值;
{
xStoreIntraResultQT(COMPONENT_Y, rTu );
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->store( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_TEMP_BEST ] );
#else
m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_TEMP_BEST ] );
#endif
}
if (pcCU->getSlice()->getPPS()->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag())//允许进行CCP
{
const Int xOffset = rTu.getRect( COMPONENT_Y ).x0;
const Int yOffset = rTu.getRect( COMPONENT_Y ).y0;
for (UInt storedResidualIndex = 0; storedResidualIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; storedResidualIndex++)//循环两次,有两种残差类型
{
if (bMaintainResidual[storedResidualIndex])//如果为true,即表示是正常计算的残差值
{//存储CCP结果;
xStoreCrossComponentPredictionResult(resiLuma[storedResidualIndex],
#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT
m_resiSingleBuffer[uiWIdx][uiHIdx][storedResidualIndex],
#else
m_resiSingleBuffer[uiLog2TrSize][storedResidualIndex],
#endif
#else
resiLumaSingle[storedResidualIndex],
#endif
rTu, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE);//将 m_resiSingleBuffer的内容复制给resiLuma[];
}
}
}
}
if (modeId == firstCheckId)
{
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load ( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_QT_TRAFO_ROOT ] );
#else
m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
#endif
}
#if COM16_C806_EMT
}
numTrIdxCands循环结束/
#endif
}
///modeId 2次循环结束/
#if JVET_C0024_QTBT
pcCU ->setTransformSkipSubParts ( bestModeId[COMPONENT_Y], COMPONENT_Y, uiAbsPartIdx, 0 );//将TransSkip又设置为最优的modeId;
#else
pcCU ->setTransformSkipSubParts ( bestModeId[COMPONENT_Y], COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan );
#endif
#if COM16_C806_EMT
pcCU ->setEmtTuIdxSubParts ( bestTrIdx, uiAbsPartIdx, uiFullDepth );//将EmtTuIdx又设置为最优的变换索引
#endif
if(bestModeId[COMPONENT_Y] == firstCheckId)
{
xLoadIntraResultQT(COMPONENT_Y, rTu );
pcCU->setCbfSubParts ( uiSingleCbfLuma << uiTrDepth, COMPONENT_Y, uiAbsPartIdx, rTu.GetTransformDepthTotalAdj(COMPONENT_Y) );//设置cbf;
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_TEMP_BEST ] );
#else
m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiFullDepth ][ CI_TEMP_BEST ] );
#endif
}
}
else//checkTransformSkip == false;
{
#if COM16_C806_EMT
#if HHI_RQT_INTRA_SPEEDUP
UChar numTrIdxCands = ( !bCheckInitTrDepth ) ? nNumTrCands : 1;//numTrIdxCands等于nNumTrCands ;
#else
UChar numTrIdxCands = nNumTrCands;
#endif
///循环次数为numTrIdxCands/
for (UChar ucTrIdx = 0; ucTrIdx < numTrIdxCands; ucTrIdx++)
{
UInt singleDistYTmp = 0;
UInt singleCbfYTmp = 0;
Double singleCostTmp = 0;
Bool bSaveEmtResults = ucTrIdx<(numTrIdxCands-1);//numTrIdxCands为4时且大于 ucTrIdx时bSaveEmtResults =1,否则等于0,即进行多次变换时且前3个变换才保存信息
// Skip checking other transform candidates if zero CBF is encountered,如果遇到零CBF,就跳过其他变换候选的检测;
if ( ucTrIdx && !uiSingleCbfLuma && bAllIntra && m_pcEncCfg->getUseFastIntraEMT() )
{
continue;
}
#if JVET_D0077_SAVE_LOAD_ENC_INFO
if( this->getSaveLoadTag(pcCU->getZorderIdxInCtu(), uiWIdx, uiHIdx) == LOAD_ENC_INFO && ucTrIdx && ucTrIdx != this->getSaveLoadEmtIdx(uiWIdx, uiHIdx) )
{
continue;
}
#endif
#endif
//----- store original entropy coding status ,存储原始的熵编码状态;
#if VCEG_AZ08_INTRA_KLT
#if COM16_C806_EMT
if (bCheckSplit || bSaveEmtResults || checkTM)
#else
if( bCheckSplit )
#endif
#else
#if COM16_C806_EMT
if (bCheckSplit || bSaveEmtResults)
#else
if (bCheckSplit)
#endif
#endif
{
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->store( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_QT_TRAFO_ROOT ] );
#else
m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
#endif
}
#if COM16_C806_EMT//numTrIdxCands为4时且bSaveEmtResults为true时,default0Save1Load2为1,numTrIdxCands为4时且bSaveEmtResults为false时,default0Save1Load2为2,;
Int default0Save1Load2 = numTrIdxCands>1 ? ( bSaveEmtResults ? 1 : 2 ) : 0;//numTrIdxCands为1时default0Save1Load2为0;
#endif
//----- code luma/chroma block with given intra prediction mode and store Cbf,用给定的帧内预测模式和储存的CBF编码亮度和色度块;
#if COM16_C983_RSAF
pcCU->setLumaIntraFilter(uiAbsPartIdx, false);
pcCU->setLumaIntraFilterHidden(uiAbsPartIdx, true);
#endif
#if COM16_C806_EMT
#if HHI_RQT_INTRA_SPEEDUP
pcCU->setEmtTuIdxSubParts( bCheckInitTrDepth?ucSavedEmtTrIdx:ucTrIdx, uiAbsPartIdx, uiFullDepth );//将EmtTuIdx设置为ucTrIdx,在xIntraCodingTUBlock函数里面会用到
#else
pcCU->setEmtTuIdxSubParts( trIdx, uiAbsPartIdx, uiFullDepth );
#endif
#if JVET_C0024_QTBT
pcCU ->setTransformSkipSubParts ( 0, COMPONENT_Y, uiAbsPartIdx, 0 );//将TransformSkip设置为0;
#else
pcCU ->setTransformSkipSubParts ( 0, COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan );
#endif
#if VCEG_AZ08_INTRA_KLT
pcCU->setKLTFlagSubParts(0, COMPONENT_Y, uiAbsPartIdx, uiFullDepth);//将KLTFlag设置为0;
#endif//对当前TU求残差,变换,量化,反量化,反变换,重建等一系列编码工作,并求得失真 ;
xIntraCodingTUBlock( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT
m_resiSingleBuffer[uiWIdx][uiHIdx],
#else
m_resiSingleBuffer[uiLog2TrSize],
#endif
#else
resiLumaSingle,
#endif
false, singleDistYTmp, COMPONENT_Y, rTu DEBUG_STRING_PASS_INTO(sDebug), default0Save1Load2, &uiSigNum);//倒数第6个参数表示是否使用CCP
#else
dSingleCost = 0.0;
#if JVET_C0024_QTBT
pcCU ->setTransformSkipSubParts ( 0, COMPONENT_Y, uiAbsPartIdx, 0 );
#else
pcCU ->setTransformSkipSubParts ( 0, COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan );
#endif
xIntraCodingTUBlock( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT
m_resiSingleBuffer[uiWIdx][uiHIdx],
#else
m_resiSingleBuffer[uiLog2TrSize],
#endif
#else
resiLumaSingle,
#endif
false, uiSingleDistLuma, COMPONENT_Y, rTu DEBUG_STRING_PASS_INTO(sDebug) );
#endif
#if VCEG_AZ08_INTRA_KLT
#if COM16_C806_EMT
if (bCheckSplit || bSaveEmtResults || checkTM)
#else
if( bCheckSplit )
#endif
#else
#if COM16_C806_EMT
if (bCheckSplit || bSaveEmtResults)
#else
if (bCheckSplit)
#endif
#endif
{
#if COM16_C806_EMT
singleCbfYTmp = pcCU->getCbf( uiAbsPartIdx, COMPONENT_Y, uiTrDepth );
#else
uiSingleCbfLuma = pcCU->getCbf( uiAbsPartIdx, COMPONENT_Y, uiTrDepth );
#endif
}
//----- determine rate and r-d cost ,确定码率和率失真代价;
#if COM16_C806_EMT
if( ucTrIdx && ucTrIdx!=DCT2_EMT && uiSigNum<=g_iEmtSigNumThr )
{
singleCostTmp = MAX_DOUBLE;
}
else
{
#endif
UInt uiSingleBits = xGetIntraBitsQT( rTu, true, false, false );
#if JVET_C0024_QTBT
if(m_pcEncCfg->getRDpenalty() && (uiWIdx+uiHIdx+(1<<MIN_CU_LOG2)>=10) && !isIntraSlice)
#else
if(m_pcEncCfg->getRDpenalty() && (uiLog2TrSize==5) && !isIntraSlice)
#endif
{
uiSingleBits=uiSingleBits*4;
}
#if COM16_C806_EMT
singleCostTmp = m_pcRdCost->calcRdCost( uiSingleBits, singleDistYTmp );//根据比特数和失真计算率失真代价;
}
#else
dSingleCost = m_pcRdCost->calcRdCost( uiSingleBits, uiSingleDistLuma );
#endif
#if COM16_C806_EMT
if(singleCostTmp < dSingleCost)
{
#endif
if (pcCU->getSlice()->getPPS()->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag())
{
const Int xOffset = rTu.getRect( COMPONENT_Y ).x0;
const Int yOffset = rTu.getRect( COMPONENT_Y ).y0;
for (UInt storedResidualIndex = 0; storedResidualIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; storedResidualIndex++)
{
if (bMaintainResidual[storedResidualIndex])
{
xStoreCrossComponentPredictionResult(resiLuma[storedResidualIndex],
#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT
m_resiSingleBuffer[uiWIdx][uiHIdx][storedResidualIndex],
#else
m_resiSingleBuffer[uiLog2TrSize][storedResidualIndex],
#endif
#else
resiLumaSingle[storedResidualIndex],
#endif
rTu, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE);
}
}
}
#if COM16_C806_EMT//更新代价,失真和最优的变换索引;
dSingleCost = singleCostTmp;
uiSingleDistLuma = singleDistYTmp;
uiSingleCbfLuma = singleCbfYTmp;
bestTrIdx = ucTrIdx;
if( bSaveEmtResults && ( uiSingleCbfLuma || !bAllIntra || !m_pcEncCfg->getUseFastIntraEMT() ) )
{
xStoreIntraResultQT( COMPONENT_Y, rTu );
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->store( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_TEMP_BEST ] );
#else
m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_TEMP_BEST ] );
#endif
}
}
if( bSaveEmtResults && ( uiSingleCbfLuma || !bAllIntra || !m_pcEncCfg->getUseFastIntraEMT() ) )
{
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load ( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_QT_TRAFO_ROOT ] );
#else
m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
#endif
}
}
numTrIdxCands循环结束//
pcCU->setEmtTuIdxSubParts( bestTrIdx, uiAbsPartIdx, uiFullDepth );//重新设置EmtTuIdx为bestTrIdx
//numTrIdxCands等于4时,如果bestTrIdx小于3且...
if( bestTrIdx < (numTrIdxCands-1) && ( uiSingleCbfLuma || !bAllIntra || !m_pcEncCfg->getUseFastIntraEMT() ) )
{
xLoadIntraResultQT( COMPONENT_Y, rTu );
pcCU->setCbfSubParts ( uiSingleCbfLuma << uiTrDepth, COMPONENT_Y, uiAbsPartIdx, uiFullDepth );
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_TEMP_BEST ] );
#else
m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiFullDepth ][ CI_TEMP_BEST ] );
#endif
}
#endif
}
#if VCEG_AZ08_INTRA_KLT
if (checkTM && uiSingleCbfLuma)
{
//backup the former results
Double dSingleCostBackUp = dSingleCost;
UInt uiSingleCbfYBackUp = uiSingleCbfLuma;
UInt uiSingleDistYBackUp = uiSingleDistLuma;
uiSingleDistLuma = 0;
dSingleCost = 0.0;
uiSingleCbfLuma = 0;
#if VCEG_AZ08_INTRA_KLT
pcCU->setKLTFlagSubParts(1, COMPONENT_Y, uiAbsPartIdx, uiFullDepth);
#endif
xStoreIntraResultQT(COMPONENT_Y, rTu);
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->store(m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_TEMP_BEST]);
//----- store original entropy coding status,存储原始的熵编码状态
m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_QT_TRAFO_ROOT]);
#else
m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiFullDepth][CI_TEMP_BEST]);
//----- store original entropy coding status -----
m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiFullDepth][CI_QT_TRAFO_ROOT]);
#endif
//----- code luma block with given intra prediction mode and store Cbf,用给定的帧内预测和存储cbf编码亮度块;
Bool bSuccessful;
#if COM16_C983_RSAF
pcCU->setLumaIntraFilter(uiAbsPartIdx, false);
pcCU->setLumaIntraFilterHidden(uiAbsPartIdx, true);
#endif
#if COM16_C806_EMT
pcCU->setEmtTuIdxSubParts(0, uiAbsPartIdx, uiFullDepth);
#if JVET_C0024_QTBT
pcCU->setTransformSkipSubParts(0, COMPONENT_Y, uiAbsPartIdx, 0);
#else
pcCU->setTransformSkipSubParts(0, COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan);
#endif //xIntraCodingTUBlockTM过程和xIntraCodingTUBlock大致一样,但不知道TM表示什么意思
bSuccessful = xIntraCodingTUBlockTM(pcOrgYuv, pcPredYuv, pcResiYuv,
uiSingleDistLuma, COMPONENT_Y, rTu DEBUG_STRING_PASS_INTO(sDebug), &uiSigNum, TMPRED0_TMPREDKLT1_ORI2);
#else
dSingleCost = 0.0;
#if JVET_C0024_QTBT
pcCU->setTransformSkipSubParts(0, COMPONENT_Y, uiAbsPartIdx, 0);
#else
pcCU->setTransformSkipSubParts(0, COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan);
#endif
#if JVET_C0024_QTBT
bSuccessful =
#endif
xIntraCodingTUBlockTM(pcOrgYuv, pcPredYuv, pcResiYuv,
uiSingleDistLuma, COMPONENT_Y, rTu DEBUG_STRING_PASS_INTO(sDebug)
#if JVET_C0024_QTBT
, TMPRED0_TMPREDKLT1_ORI2
#else
#if COM16_C983_RSAF
, false
, bStub
#endif
#endif
);
#endif
uiSingleCbfLuma = pcCU->getCbf(uiAbsPartIdx, COMPONENT_Y, uiTrDepth);//cbf/CBF表示coded block flags;
if (bSuccessful == true && uiSingleCbfLuma) //assume only cbf being nonzero, can use TM mode
{
//----- determine rate and r-d cost ,确定码率和率失真代价
UInt uiSingleBits = xGetIntraBitsQT(rTu, true, false, false);
#if JVET_C0024_QTBT
if(m_pcEncCfg->getRDpenalty() && (uiWIdx+uiHIdx+(MIN_CU_LOG2<<1)>=10) && !isIntraSlice)
#else
if (m_pcEncCfg->getRDpenalty() && (uiLog2TrSize == 5) && !isIntraSlice)
#endif
{
uiSingleBits = uiSingleBits * 4;//为什么乘以4???
}
dSingleCost = m_pcRdCost->calcRdCost(uiSingleBits, uiSingleDistLuma);
}
else
{
dSingleCost = MAX_DOUBLE;
}
//代价更新
if (dSingleCostBackUp <= dSingleCost)
{
dSingleCost = dSingleCostBackUp;
uiSingleCbfLuma = uiSingleCbfYBackUp;
uiSingleDistLuma = uiSingleDistYBackUp;
pcCU->setKLTFlagSubParts(0, COMPONENT_Y, uiAbsPartIdx, uiFullDepth);
#if COM16_C806_EMT
pcCU->setEmtTuIdxSubParts(bestTrIdx, uiAbsPartIdx, uiFullDepth);
#endif
#if JVET_C0024_QTBT
pcCU->setTransformSkipSubParts(bestModeId[COMPONENT_Y], COMPONENT_Y, uiAbsPartIdx, 0); //1.30.2016 uiFullDepth);
#else
pcCU->setTransformSkipSubParts(bestModeId[COMPONENT_Y], COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan); //1.30.2016 uiFullDepth);
#endif
xLoadIntraResultQT(COMPONENT_Y, rTu);
pcCU->setCbfSubParts(uiSingleCbfLuma << uiTrDepth, COMPONENT_Y, uiAbsPartIdx, uiFullDepth);
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_TEMP_BEST]);
#else
m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiFullDepth][CI_TEMP_BEST]);
#endif
}
else//dSingleCostBackUp > dSingleCost
{
#if !JVET_C0024_QTBT
bestTMKLT = 1;
#endif
bestModeId[COMPONENT_Y] = 0;
#if JVET_C0024_QTBT && COM16_C806_EMT
bestTrIdx = 0;
#endif
#if COM16_C806_EMT
pcCU->setEmtTuIdxSubParts(0, uiAbsPartIdx, uiFullDepth);
#endif
}
}
#endif
}
#if !JVET_C0024_QTBT
if( bCheckSplit )
{
//----- store full entropy coding status, load original entropy coding status -----
if( bCheckFull )
{
m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_TEST ] );
m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
}
else
{
m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
}
//----- code splitted block -----
Double dSplitCost = 0.0;
Distortion uiSplitDistLuma = 0;
UInt uiSplitCbfLuma = 0;
#if COM16_C806_EMT
Bool bSplitSelected = true;
#endif
TComTURecurse tuRecurseChild(rTu, false);
DEBUG_STRING_NEW(sSplit)
do
{
DEBUG_STRING_NEW(sChild)
#if HHI_RQT_INTRA_SPEEDUP
xRecurIntraCodingLumaQT( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTU
m_resiSplitBuffer[uiLog2TrSize],
#else
resiLumaSplit,
#endif
uiSplitDistLuma, bCheckFirst, dSplitCost, tuRecurseChild DEBUG_STRING_PASS_INTO(sChild) );
#else
xRecurIntraCodingLumaQT( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTU
m_resiSplitBuffer[uiLog2TrSize],
#else
resiLumaSplit,
#endif
uiSplitDistLuma, dSplitCost, tuRecurseChild DEBUG_STRING_PASS_INTO(sChild) );
#endif
DEBUG_STRING_APPEND(sSplit, sChild)
uiSplitCbfLuma |= pcCU->getCbf( tuRecurseChild.GetAbsPartIdxTU(), COMPONENT_Y, tuRecurseChild.GetTransformDepthRel() );
#if COM16_C806_EMT
if( dSplitCost>dSingleCost && m_pcEncCfg->getUseFastIntraEMT() )
{
bSplitSelected = false;
break;
}
#endif
} while (tuRecurseChild.nextSection(rTu) );
#if COM16_C806_EMT
if( bSplitSelected )
{
#endif
UInt uiPartsDiv = rTu.GetAbsPartIdxNumParts();
{
if (uiSplitCbfLuma)
{
const UInt flag=1<<uiTrDepth;
UChar *pBase=pcCU->getCbf( COMPONENT_Y );
for( UInt uiOffs = 0; uiOffs < uiPartsDiv; uiOffs++ )
{
pBase[ uiAbsPartIdx + uiOffs ] |= flag;
}
}
}
//----- restore context states -----
m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
//----- determine rate and r-d cost -----
UInt uiSplitBits = xGetIntraBitsQT( rTu, true, false, false );
dSplitCost = m_pcRdCost->calcRdCost( uiSplitBits, uiSplitDistLuma );
#if COM16_C806_EMT
}
#endif
//===== compare and set best =====
if( dSplitCost < dSingleCost )
{
//--- update cost ---
DEBUG_STRING_SWAP(sSplit, sDebug)
ruiDistY += uiSplitDistLuma;
dRDCost += dSplitCost;
if (pcCU->getSlice()->getPPS()->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag())
{
const Int xOffset = rTu.getRect( COMPONENT_Y ).x0;
const Int yOffset = rTu.getRect( COMPONENT_Y ).y0;
for (UInt storedResidualIndex = 0; storedResidualIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; storedResidualIndex++)
{
if (bMaintainResidual[storedResidualIndex])
{
xStoreCrossComponentPredictionResult(resiLuma[storedResidualIndex],
#if COM16_C806_LARGE_CTU
m_resiSplitBuffer[uiLog2TrSize][storedResidualIndex],
#else
resiLumaSplit[storedResidualIndex],
#endif
rTu, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE);
}
}
}
return;
}
//----- set entropy coding status -----
m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_TEST ] );
//--- set transform index and Cbf values ---
pcCU->setTrIdxSubParts( uiTrDepth, uiAbsPartIdx, uiFullDepth );
const TComRectangle &tuRect=rTu.getRect(COMPONENT_Y);
pcCU->setCbfSubParts ( uiSingleCbfLuma << uiTrDepth, COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan );
pcCU ->setTransformSkipSubParts ( bestModeId[COMPONENT_Y], COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan );
#if COM16_C806_EMT
pcCU->setEmtTuIdxSubParts( bestTrIdx, uiAbsPartIdx, uiFullDepth );
#endif
#if VCEG_AZ08_INTRA_KLT
pcCU->setKLTFlagSubParts(bestTMKLT, COMPONENT_Y, uiAbsPartIdx, uiFullDepth);
#endif
//--- set reconstruction for next intra prediction blocks ---
const UInt uiQTLayer = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize;
const UInt uiZOrder = pcCU->getZorderIdxInCtu() + uiAbsPartIdx;
const UInt uiWidth = tuRect.width;
const UInt uiHeight = tuRect.height;
Pel* piSrc = m_pcQTTempTComYuv[ uiQTLayer ].getAddr( COMPONENT_Y, uiAbsPartIdx );
UInt uiSrcStride = m_pcQTTempTComYuv[ uiQTLayer ].getStride ( COMPONENT_Y );
Pel* piDes = pcCU->getPic()->getPicYuvRec()->getAddr( COMPONENT_Y, pcCU->getCtuRsAddr(), uiZOrder );
UInt uiDesStride = pcCU->getPic()->getPicYuvRec()->getStride ( COMPONENT_Y );
for( UInt uiY = 0; uiY < uiHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride )
{
for( UInt uiX = 0; uiX < uiWidth; uiX++ )
{
piDes[ uiX ] = piSrc[ uiX ];
}
}
}
#endif
ruiDistY += uiSingleDistLuma;//累加失真
dRDCost += dSingleCost;//累加代价
}