(为个人理解)
此函数的作用是计算亮度分量的预测值,备选预测模式是67种,DC+planar+65种角度预测模式。首先通过getIntraDirPredictor函数得到6 MPMs。然后对HEVC中原始的35种角度模式进行遍历,根据SADT选取N(5)种作为初始候选列表;再根据SADT更新候选列表里的候选模式。再将N个候选模式和前3个MPM模式合并。最后在合并的模式中选取一个RD cost最小的一个预测模式。
TEncSearch::estIntraPredLumaQT(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))
{
const UInt uiDepth = pcCU->getDepth(0);//当前CU的深度;
#if JVET_C0024_QTBT
const UInt uiInitTrDepth = 0;
const UInt uiWidth = pcCU ->getWidth ( 0 ) ;
const UInt uiHeight = pcCU ->getHeight ( 0 ) ;
const UInt uiWIdx = g_aucConvertToBit[uiWidth];
const UInt uiHIdx = g_aucConvertToBit[uiHeight];
#else
const UInt uiInitTrDepth = pcCU->getPartitionSize(0) == SIZE_2Nx2N ? 0 : 1;
const UInt uiNumPU = 1<<(2*uiInitTrDepth);
const UInt uiQNumParts = pcCU->getTotalNumPart() >> 2;
const UInt uiWidthBit = pcCU->getIntraSizeIdx(0);
#if COM16_C983_RSAF
const UInt uiWidth = pcCU->getWidth (0) >> uiInitTrDepth;
#endif
#endif
const ChromaFormat chFmt = pcCU->getPic()->getChromaFormat();
const UInt numberValidComponents = getNumberValidComponents(chFmt);//3;
const TComSPS &sps = *(pcCU->getSlice()->getSPS());
const TComPPS &pps = *(pcCU->getSlice()->getPPS());
Distortion uiOverallDistY = 0;
UInt CandNum;
Double CandCostList[ FAST_UDI_MAX_RDMODE_NUM ];
#if JVET_C0024_PBINTRA_FAST
Double CandHadList[ FAST_UDI_MAX_RDMODE_NUM ];
for (Int i=0; igetUseReconBasedCrossCPredictionEstimate());
// Lambda calculation at equivalent Qp of 4 is recommended because at that Qp, the quantisation divisor is 1.
#if FULL_NBIT
const Double sqrtLambdaForFirstPass= (m_pcEncCfg->getCostMode()==COST_MIXED_LOSSLESS_LOSSY_CODING && pcCU->getCUTransquantBypass(0)) ?
sqrt(0.57 * pow(2.0, ((LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP_PRIME - 12) / 3.0)))
: m_pcRdCost->getSqrtLambda();
#else
const Double sqrtLambdaForFirstPass= (m_pcEncCfg->getCostMode()==COST_MIXED_LOSSLESS_LOSSY_CODING && pcCU->getCUTransquantBypass(0)) ?
sqrt(0.57 * pow(2.0, ((LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP_PRIME - 12 - 6 * (sps.getBitDepth(CHANNEL_TYPE_LUMA) - 8)) / 3.0)))
: m_pcRdCost->getSqrtLambda();
#endif
//===== set QP and clear Cbf =====
if ( pps.getUseDQP() == true)
{
#if JVET_C0024_DELTA_QP_FIX
pcCU->setQPSubParts( pcCU->getQP(0), 0, pcCU->getWidth(0), pcCU->getHeight(0) );
#else
pcCU->setQPSubParts( pcCU->getQP(0), 0, uiDepth );
#endif
}
else
{
#if JVET_C0024_DELTA_QP_FIX
pcCU->setQPSubParts( pcCU->getSlice()->getSliceQp(), 0, pcCU->getWidth(0), pcCU->getHeight(0) );
#else
pcCU->setQPSubParts( pcCU->getSlice()->getSliceQp(), 0, uiDepth );
#endif
}
#if JVET_D0127_REDUNDANCY_REMOVAL
#if JVET_C0024_QTBT
Bool NSSTFlag = (pcCU->getROTIdx(CHANNEL_TYPE_LUMA, 0) == 0) || (uiWidth > 64 || uiHeight > 64);
Bool NSSTSaveFlag = (pcCU->getROTIdx(CHANNEL_TYPE_LUMA, 0) == 0)
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
&& (pcCU->getPDPCIdx(0) == 0)
#endif
;
#else
Bool NSSTFlag = (pcCU->getROTIdx(0) == 0) || pcCU->getPartitionSize(0) == SIZE_NxN;
Bool NSSTSaveFlag = (pcCU->getROTIdx(0) == 0) && pcCU->getPartitionSize(0) == SIZE_2Nx2N
#if COM16_C1046_PDPC_INTRA
&& (pcCU->getPDPCIdx(0) == 0)
#endif
#if COM16_C806_EMT
&& (pcCU->getEmtCuFlag(0) == 0)
#endif
;
#endif
#if JVET_C0024_QTBT
static UInt uiSavedRdModeListNSST[35], uiSavedNumRdModesNSST, uiSavedHadModeListNSST[35];
static Double dSavedModeCostNSST[35], dSavedHadListNSST[FAST_UDI_MAX_RDMODE_NUM];
#else
static UInt uiSavedRdModeListNSST[4][35], uiSavedNumRdModesNSST[4];
static Double dSavedModeCostNSST[4][35];
#endif
#if JVET_C0024_PBINTRA_FAST
UInt uiHadModeList[67];
#endif
#endif
#if COM16_C806_EMT
#if JVET_C0024_QTBT
static Double dBestModeCostStore; // RD cost of the best mode for each PU using DCT2
static Double dModeCostStore[35]; // RD cost of each mode for each PU using DCT2
static UInt uiSavedRdModeList[35], uiSavedNumRdModes;
#else
static Double dBestModeCostStore[4]; // RD cost of the best mode for each PU using DCT2
static Double dModeCostStore[4][35]; // RD cost of each mode for each PU using DCT2
static UInt uiSavedRdModeList[4][35], uiSavedNumRdModes[4];
#endif
// Marking EMT usage for faster EMT,EMT表示Explicit multiple core transform,是变换部分的
// 0: EMT not applicable for current CU (pcCU->getWidth(0) <= EMT_INTRA_MAX_CU)
// 1: EMT can be applied for current CU, and DCT2 is being checked
// 2: EMT is being checked for current CU. Stored results of DCT2 can be utilized for speedup
#if JVET_C0024_QTBT
UChar ucEmtUsageFlag = ( (uiWidth <= EMT_INTRA_MAX_CU && uiHeight <= EMT_INTRA_MAX_CU) ? ( pcCU->getEmtCuFlag(0)==1 ? 2 : 1 ) : 0 );
#else
UChar ucEmtUsageFlag = ( pcCU->getWidth(0) <= EMT_INTRA_MAX_CU ? ( pcCU->getEmtCuFlag(0)==1 ? 2 : 1 ) : 0 );
#endif
Bool bAllIntra = (m_pcEncCfg->getIntraPeriod()==1);
#if JVET_C0024_QTBT
if (uiWidth*uiHeight<64 && !bAllIntra)
#else
if( pcCU->getPartitionSize(0) == SIZE_NxN && !bAllIntra )
#endif
{
ucEmtUsageFlag = 0;
}
#if JVET_D0077_SAVE_LOAD_ENC_INFO
UInt uiZorderIdx = pcCU->getZorderIdxInCtu();//当前cu在CTU中以z扫描顺序的索引;
UChar saveLoadTag = getSaveLoadTag( uiZorderIdx, uiWIdx, uiHIdx );
if( saveLoadTag == LOAD_ENC_INFO /*&& getSaveLoadEmtFlag(uiWIdx, uiHIdx) == 0*/ )
{
ucEmtUsageFlag = 0;
}
#if JVET_D0127_REDUNDANCY_REMOVAL
NSSTFlag |= saveLoadTag == LOAD_ENC_INFO;//NNST表示non-separable secondary transforms;
#endif
#endif
#endif
//===== loop over partitions =====划分CU的循环;
TComTURecurse tuRecurseCU(pcCU, 0);
TComTURecurse tuRecurseWithPU(tuRecurseCU, false, (uiInitTrDepth==0)?TComTU::DONT_SPLIT : TComTU::QUAD_SPLIT);
#if COM16_C806_EMT
UInt uiPU = 0;
#endif
do
{
const UInt uiPartOffset=tuRecurseWithPU.GetAbsPartIdxTU();//表示什么意思;
// for( UInt uiPU = 0, uiPartOffset=0; uiPU < uiNumPU; uiPU++, uiPartOffset += uiQNumParts )
//{
#if COM16_C806_EMT
UInt uiRdModeList[FAST_UDI_MAX_RDMODE_NUM];
#if JVET_C0024_QTBT
assert(uiPartOffset==0);
Int numModesForFullRD = g_aucIntraModeNumFast_UseMPM[uiWIdx][uiHIdx];//numModesForFullRD=3;
#else
Int numModesForFullRD = m_pcEncCfg->getFastUDIUseMPMEnabled()?g_aucIntraModeNumFast_UseMPM[ uiWidthBit ] : g_aucIntraModeNumFast_NotUseMPM[ uiWidthBit ];
#if VCEG_AZ07_INTRA_65ANG_MODES
numModesForFullRD -= 1;
#endif
#endif
if( ucEmtUsageFlag != 2 )
{
#endif
//===== init pattern for luma prediction =====
DEBUG_STRING_NEW(sTemp2)
//===== determine set of modes to be tested (using prediction signal only) =====
#if VCEG_AZ07_INTRA_65ANG_MODES
Int numModesAvailable = 67; //total number of Intra modes
#else
Int numModesAvailable = 35; //total number of Intra modes
#endif
#if !COM16_C806_EMT
UInt uiRdModeList[FAST_UDI_MAX_RDMODE_NUM];
#if JVET_C0024_QTBT
assert(uiPartOffset==0);
Int numModesForFullRD = g_aucIntraModeNumFast_UseMPM[uiWIdx][uiHIdx];
#else
Int numModesForFullRD = m_pcEncCfg->getFastUDIUseMPMEnabled()?g_aucIntraModeNumFast_UseMPM[ uiWidthBit ] : g_aucIntraModeNumFast_NotUseMPM[ uiWidthBit ];
#if VCEG_AZ07_INTRA_65ANG_MODES
numModesForFullRD -= 1;
#endif
#endif
#endif
// this should always be true
assert (tuRecurseWithPU.ProcessComponentSection(COMPONENT_Y));
initIntraPatternChType( tuRecurseWithPU, COMPONENT_Y, true DEBUG_STRING_PASS_INTO(sTemp2) );
Bool doFastSearch = (numModesForFullRD != numModesAvailable);//如果可能模式的数量不等于3,则进行快速搜索;
if (doFastSearch)//做快速搜索;
{
assert(numModesForFullRD < numModesAvailable);
#if JVET_D0127_REDUNDANCY_REMOVAL
for (Int i = 0; i < numModesForFullRD + 2; i++)//numModesForFullRD + 2=5,为什么等于5,不是6MPMs吗;
#else
for( Int i=0; i < numModesForFullRD; i++ )
#endif
{
CandCostList[ i ] = MAX_DOUBLE;
}
CandNum = 0;
#if VCEG_AZ07_INTRA_65ANG_MODES
Int uiPreds[6] = {-1, -1, -1, -1, -1, -1};
Int iAboveLeftCase=0, iMode=-1;
#if JVET_C0055_INTRA_MPM//得到6 MPMs,过程和JEM文档里写的一样;
pcCU->getIntraDirPredictor( uiPartOffset, uiPreds, COMPONENT_Y, &iMode ); // Pre-calculate the MPMs, so avoid redundant MPM calculations during the SATD loop
#else
pcCU->getIntraDirPredictor( uiPartOffset, uiPreds, COMPONENT_Y, iAboveLeftCase, &iMode ); // Pre-calculate the MPMs, so avoid redundant MPM calculations during the SATD loop
#endif
assert( iMode >= 0 );
iMode = min(iMode+1, 6);
Char bSatdChecked[NUM_INTRA_MODE];
memset( bSatdChecked, 0, NUM_INTRA_MODE*sizeof(Char) );
#endif
const TComRectangle &puRect=tuRecurseWithPU.getRect(COMPONENT_Y);
const UInt uiAbsPartIdx=tuRecurseWithPU.GetAbsPartIdxTU();
Pel* piOrg = pcOrgYuv ->getAddr( COMPONENT_Y, uiAbsPartIdx );
Pel* piPred = pcPredYuv->getAddr( COMPONENT_Y, uiAbsPartIdx );
UInt uiStride = pcPredYuv->getStride( COMPONENT_Y );
DistParam distParam;
const Bool bUseHadamard=pcCU->getCUTransquantBypass(0) == 0;
m_pcRdCost->setDistParam(distParam, sps.getBitDepth(CHANNEL_TYPE_LUMA), piOrg, uiStride, piPred, uiStride, puRect.width, puRect.height, bUseHadamard);
distParam.bApplyWeight = false;
#if JVET_D0127_REDUNDANCY_REMOVAL
if (NSSTFlag){//non-separable secondary transforms;
#endif////////////////////////执行67次循环,计算每一个模式对应的RD cost,更新候选列表///////////////////////
for( Int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ )
{
UInt uiMode = modeIdx;
Distortion uiSad = 0;
#if COM16_C1044_NSST
#if !JVET_C0024_QTBT
if( pcCU->getPartitionSize(0)==SIZE_2Nx2N )
#endif
{//mode=0是planar模式,mode=1是DC模式,其他是角度模式;
const Int iNumberOfPassesROT = ( uiMode<=DC_IDX ) ? 3 : 4;//planar或DC模式时iNumberOfPassesROT=3,其他角度模式等于4;
#if JVET_C0024_QTBT
if( iNumberOfPassesROT <= pcCU->getROTIdx(CHANNEL_TYPE_LUMA, 0) )
#else
if( iNumberOfPassesROT <= pcCU->getROTIdx(0) )
#endif
{
continue;
}
}
#endif
#if VCEG_AZ07_INTRA_65ANG_MODES
if( uiMode>DC_IDX && (uiMode&1) )//uimode等于奇数时,即该模式是JEM新加的角度模式时,不进行下面的步骤,而是跳出,接着下面的角度模式;
{//即像文档里所说的,先对原始的35种角度模式进行遍历,选取N(5)种作为初始候选列表;
// Skip checking extended Angular modes in the first round of SATD
continue;
}
bSatdChecked[uiMode] = true;
#endif //只是返回一个指示对帧内参考像素是否进行滤波的标志;
const Bool bUseFilter=TComPrediction::filteringIntraReferenceSamples(COMPONENT_Y, uiMode, puRect.width, puRect.height, chFmt, sps.getSpsRangeExtension().getIntraSmoothingDisabledFlag()
#if COM16_C983_RSAF_PREVENT_OVERSMOOTHING
, sps.getUseRSAF()
#endif
);
//计算相应模式的预测值
predIntraAng( COMPONENT_Y, uiMode, piOrg, uiStride, piPred, uiStride, tuRecurseWithPU, bUseFilter, TComPrediction::UseDPCMForFirstPassIntraEstimation(tuRecurseWithPU, uiMode) );
// use hadamard transform here
uiSad+=distParam.DistFunc(&distParam);//计算哈达玛表示的失真;
UInt iModeBits = 0;
// NB xModeBitsIntra will not affect the mode for chroma that may have already been pre-estimated.
iModeBits+=xModeBitsIntra( pcCU, uiMode, uiPartOffset, uiDepth, CHANNEL_TYPE_LUMA //计算编码比特率;
#if VCEG_AZ07_INTRA_65ANG_MODES
, uiPreds, iAboveLeftCase
#endif
);
Double cost = (Double)uiSad + (Double)iModeBits * sqrtLambdaForFirstPass;//计算RD cost;
#if DEBUG_INTRA_SEARCH_COSTS
std::cout << "1st pass mode " << uiMode << " SAD = " << uiSad << ", mode bits = " << iModeBits << ", cost = " << cost << "\n";
#endif
#if JVET_C0024_FAST_MRG
#if JVET_D0127_REDUNDANCY_REMOVAL//CandNum表示候选列表中预测模式数量;
CandNum += updateCandList(uiMode, cost, numModesForFullRD + 2, uiRdModeList, CandCostList);
#else
CandNum += updateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );
#endif
#else
#if JVET_D0127_REDUNDANCY_REMOVAL
CandNum += xUpdateCandList( uiMode, cost, numModesForFullRD + 2, uiRdModeList, CandCostList );
#else
CandNum += xUpdateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );
#endif
#endif
#if JVET_C0024_PBINTRA_FAST
#if JVET_D0127_REDUNDANCY_REMOVAL
//更新亮度帧内预测模式的候选列表,包括模式和对应的cost;
updateCandList(uiMode, uiSad, numModesForFullRD+2, uiHadModeList, CandHadList);
#else
if (uiSad < CandHadList[0])
{
CandHadList[2] = CandHadList[1];
CandHadList[1] = CandHadList[0];
CandHadList[0] = uiSad;
}
else if (uiSad < CandHadList[1])
{
CandHadList[2] = CandHadList[1];
CandHadList[1] = uiSad;
}
else if (uiSad < CandHadList[2])
{
CandHadList[2] = uiSad;
}
#endif
#endif
}//该循环结束,候选列表里面只有5种模式;
//////////////////////////////////////67次循环结束//////////////////////////////////////////////
#if JVET_D0127_REDUNDANCY_REMOVAL
if (NSSTSaveFlag){
#if JVET_C0024_QTBT
uiSavedNumRdModesNSST = numModesForFullRD;
::memcpy(uiSavedRdModeListNSST, uiRdModeList, (numModesForFullRD + 2)*sizeof(UInt));
::memcpy(dSavedModeCostNSST, CandCostList, (numModesForFullRD + 2)*sizeof(Double));
#else
uiSavedNumRdModesNSST[uiPU] = numModesForFullRD;
::memcpy(uiSavedRdModeListNSST[uiPU], uiRdModeList, (numModesForFullRD + 2)*sizeof(UInt));
::memcpy(dSavedModeCostNSST[uiPU], CandCostList, (numModesForFullRD + 2)*sizeof(Double));
#endif
#if JVET_C0024_PBINTRA_FAST
::memcpy(uiSavedHadModeListNSST, uiHadModeList, (numModesForFullRD + 2)*sizeof(UInt));
::memcpy(dSavedHadListNSST, CandHadList, (numModesForFullRD + 2)*sizeof(Double));
#endif
}
}
else{
#if JVET_C0024_QTBT
if (pcCU->getROTIdx(CHANNEL_TYPE_LUMA, 0) == 3){
#else
if (pcCU->getROTIdx(0) == 3 && pcCU->getPartitionSize(0) == SIZE_2Nx2N){
#endif
#if JVET_C0024_QTBT
numModesForFullRD = uiSavedNumRdModesNSST;
::memcpy(uiRdModeList, uiSavedRdModeListNSST, (numModesForFullRD + 2)*sizeof(UInt));
::memcpy(CandCostList, dSavedModeCostNSST, (numModesForFullRD + 2)*sizeof(Double));
#else
numModesForFullRD = uiSavedNumRdModesNSST[uiPU];
::memcpy(uiRdModeList, uiSavedRdModeListNSST[uiPU], (numModesForFullRD + 2)*sizeof(UInt));
::memcpy(CandCostList, dSavedModeCostNSST[uiPU], (numModesForFullRD + 2)*sizeof(Double));
#endif
#if JVET_C0024_PBINTRA_FAST
::memcpy(uiHadModeList, uiSavedHadModeListNSST, (numModesForFullRD + 2)*sizeof(UInt));
::memcpy(CandHadList, dSavedHadListNSST, (numModesForFullRD + 2)*sizeof(Double));
#endif
Int cnt = 0;
Int i = 0;
for (i = 0; i < numModesForFullRD; i++){
if (uiRdModeList[i] <= DC_IDX){
for (UInt j = i; j < numModesForFullRD + 1 - cnt; j++){
uiRdModeList[j] = uiRdModeList[j + 1];
CandCostList[j] = CandCostList[j + 1];
}
cnt++;
i--;
}
}
#if JVET_C0024_PBINTRA_FAST
cnt = 0;
for (i = 0; i < numModesForFullRD; i++){
if (uiHadModeList[i] <= DC_IDX){
for (UInt j = i; j < numModesForFullRD + 1 - cnt; j++){
uiHadModeList[j] = uiHadModeList[j + 1];
CandHadList[j] = CandHadList[j + 1];
}
cnt++;
i--;
}
}
#endif
}
else{
#if JVET_C0024_QTBT
numModesForFullRD = uiSavedNumRdModesNSST;
::memcpy(uiRdModeList, uiSavedRdModeListNSST, numModesForFullRD*sizeof(UInt));
::memcpy(CandCostList, dSavedModeCostNSST, numModesForFullRD*sizeof(Double));
#else
numModesForFullRD = uiSavedNumRdModesNSST[uiPU];
::memcpy(uiRdModeList, uiSavedRdModeListNSST[uiPU], numModesForFullRD*sizeof(UInt));
::memcpy(CandCostList, dSavedModeCostNSST[uiPU], numModesForFullRD*sizeof(Double));
#endif
#if JVET_C0024_PBINTRA_FAST
::memcpy(CandHadList, dSavedHadListNSST, numModesForFullRD*sizeof(Double));
#endif
}
}
#endif
#if VCEG_AZ07_INTRA_65ANG_MODES
UInt uiParentCandList[FAST_UDI_MAX_RDMODE_NUM];
memcpy( uiParentCandList, uiRdModeList, sizeof(UInt)*numModesForFullRD );
// Second round of SATD for extended Angular modes,用扩展的角度模式对候选列表进行更新;
//即用获选列表里角度模式的相邻两个模式根据SATD对候选列表进行更新;
for( Int modeIdx = 0; modeIdx < numModesForFullRD; modeIdx++ )
{
UInt uiParentMode = uiParentCandList[modeIdx];
#if JVET_E0077_ENHANCED_LM
if (uiParentMode>2 && uiParentMode<(NUM_INTRA_MODE - NUM_INTRA_MODE_NON_ANG - 1))
#else
if( uiParentMode>2 && uiParentMode<(NUM_INTRA_MODE-2) )
#endif
{
for( Int subModeIdx = -1; subModeIdx <= 1; subModeIdx+=2 )
{
UInt uiMode = uiParentMode + subModeIdx;//uiMode即为uiParentMode的相邻的两个模式;
#if COM16_C1044_NSST
#if !JVET_C0024_QTBT
if( pcCU->getPartitionSize(0)==SIZE_2Nx2N )
#endif
{
const Int iNumberOfPassesROT = ( uiMode<=DC_IDX ) ? 3 : 4;
#if JVET_C0024_QTBT
if( iNumberOfPassesROT <= pcCU->getROTIdx(CHANNEL_TYPE_LUMA, 0) )
#else
if( iNumberOfPassesROT <= pcCU->getROTIdx(0) )
#endif
{
continue;
}
}
#endif
if( !bSatdChecked[uiMode] )
{
const Bool bUseFilter=TComPrediction::filteringIntraReferenceSamples(COMPONENT_Y, uiMode, puRect.width, puRect.height, chFmt, sps.getSpsRangeExtension().getIntraSmoothingDisabledFlag()
#if COM16_C983_RSAF_PREVENT_OVERSMOOTHING
, sps.getUseRSAF()
#endif
);
predIntraAng( COMPONENT_Y, uiMode, piOrg, uiStride, piPred, uiStride, tuRecurseWithPU, bUseFilter, TComPrediction::UseDPCMForFirstPassIntraEstimation(tuRecurseWithPU, uiMode) );
// use hadamard transform here
Distortion uiSad = distParam.DistFunc(&distParam);
UInt iModeBits = xModeBitsIntra( pcCU, uiMode, uiPartOffset, uiDepth, CHANNEL_TYPE_LUMA, uiPreds, iAboveLeftCase );
Double cost = (Double)uiSad + (Double)iModeBits * sqrtLambdaForFirstPass;
#if DEBUG_INTRA_SEARCH_COSTS
std::cout << "1st pass mode for extended angular mode " << uiMode << " SAD = " << uiSad << ", mode bits = " << iModeBits << ", cost = " << cost << "\n";
#endif
#if JVET_C0024_FAST_MRG
CandNum += updateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );
#else
CandNum += xUpdateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );
#endif
#if JVET_C0024_PBINTRA_FAST//如果相邻角度模式的cost小于列表里的某一个cost,则对候选列表进行更新;
if (uiSad < CandHadList[0])
{//列表里的cost是从小到大排的;
CandHadList[2] = CandHadList[1];
CandHadList[1] = CandHadList[0];
CandHadList[0] = uiSad;
}
else if (uiSad < CandHadList[1])
{
CandHadList[2] = CandHadList[1];
CandHadList[1] = uiSad;
}
else if (uiSad < CandHadList[2])
{
CandHadList[2] = uiSad;
}
#endif
bSatdChecked[uiMode] = true; // Mark as checked
}
}
}
}
#endif
if (m_pcEncCfg->getFastUDIUseMPMEnabled())
{
#if !VCEG_AZ07_INTRA_65ANG_MODES
Int uiPreds[NUM_MOST_PROBABLE_MODES] = {-1, -1, -1};
Int iMode = -1;
pcCU->getIntraDirPredictor( uiPartOffset, uiPreds, COMPONENT_Y, &iMode );
#endif
const Int numCand = ( iMode >= 0 ) ? iMode : Int(NUM_MOST_PROBABLE_MODES);
for( Int j=0; j < numCand; j++)
{
Bool mostProbableModeIncluded = false;
Int mostProbableMode = uiPreds[j];
#if COM16_C1044_NSST
#if !JVET_C0024_QTBT
if( pcCU->getPartitionSize(0)==SIZE_2Nx2N )
#endif
{
const Int iNumberOfPassesROT = ( mostProbableMode<=DC_IDX ) ? 3 : 4;
#if JVET_C0024_QTBT
if( iNumberOfPassesROT <= pcCU->getROTIdx(CHANNEL_TYPE_LUMA, 0) )
#else
if( iNumberOfPassesROT <= pcCU->getROTIdx(0) )
#endif
{
continue;
}
}
#endif
for( Int i=0; i < numModesForFullRD; i++)
{
mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i]);
}
if (!mostProbableModeIncluded)//将N个候选模式和前3个MPM模式合并;
{
uiRdModeList[numModesForFullRD++] = mostProbableMode;
}
}
}
}
else//不做快速搜索;
{
for( Int i=0; i < numModesForFullRD; i++)
{
uiRdModeList[i] = i;
}
}
#if COM16_C806_EMT
if( ucEmtUsageFlag==1 )
{
// Store the modes to be checked with RD
#if JVET_C0024_QTBT
uiSavedNumRdModes = numModesForFullRD;
::memcpy( uiSavedRdModeList, uiRdModeList, numModesForFullRD*sizeof(UInt) );
#else
uiSavedNumRdModes[uiPU] = numModesForFullRD;
::memcpy( uiSavedRdModeList[uiPU], uiRdModeList, numModesForFullRD*sizeof(UInt) );
#endif
}
}
else if( ucEmtUsageFlag==2 )
{
if( bAllIntra && m_pcEncCfg->getUseFastIntraEMT() )
{
#if !COM16_C983_RSAF && !JVET_C0024_QTBT
UInt uiWidth = pcCU->getWidth (0) >> uiInitTrDepth;
#endif
#if JVET_C0024_QTBT
const Double dThrFastMode = 1.0 + 1.4/sqrt( (Double) (uiWidth*uiHeight) );
#else
double dThrFastMode;
switch(uiWidth)
{
case 4: dThrFastMode = 1.47; break; // Skip checking 4x4 Intra modes using the R-D cost in the DCT2-pass
case 8: dThrFastMode = 1.28; break; // Skip checking 8x8 Intra modes using the R-D cost in the DCT2-pass
case 16: dThrFastMode = 1.12; break; // Skip checking 16x16 Intra modes using the R-D cost in the DCT2-pass
case 32: dThrFastMode = 1.06; break; // Skip checking 32x32 Intra modes using the R-D cost in the DCT2-pass
default: dThrFastMode = 1.06; break; // Skip checking 32x32 Intra modes using the R-D cost in the DCT2-pass
}
#endif
numModesForFullRD=0;
// Skip checking the modes with much larger R-D cost than the best mode
#if JVET_C0024_QTBT
for( Int i=0; i < uiSavedNumRdModes; i++)
{
if( dModeCostStore[i] <= dThrFastMode * dBestModeCostStore )
{
uiRdModeList[numModesForFullRD++] = uiSavedRdModeList[i];
}
}
#else
for( Int i=0; i < uiSavedNumRdModes[uiPU]; i++)
{
if( dModeCostStore[uiPU][i] <= dThrFastMode * dBestModeCostStore[uiPU] )
{
uiRdModeList[numModesForFullRD++] = uiSavedRdModeList[uiPU][i];
}
}
#endif
}
else
{
// Restore the modes to be checked with RD
#if JVET_C0024_QTBT
numModesForFullRD = uiSavedNumRdModes;
::memcpy( uiRdModeList, uiSavedRdModeList, numModesForFullRD*sizeof(UInt) );
#else
numModesForFullRD = uiSavedNumRdModes[uiPU];
::memcpy( uiRdModeList, uiSavedRdModeList[uiPU], numModesForFullRD*sizeof(UInt) );
#endif
}
}
#endif
//===== check modes (using r-d costs) =====
#if HHI_RQT_INTRA_SPEEDUP_MOD
UInt uiSecondBestMode = MAX_UINT;
Double dSecondBestPUCost = MAX_DOUBLE;
#endif
DEBUG_STRING_NEW(sPU)
UInt uiBestPUMode = 0;
Distortion uiBestPUDistY = 0;
Double dBestPUCost = MAX_DOUBLE;
#if JVET_C0024_PBINTRA_FAST
if( pcCU->getSlice()->getSliceType()!=I_SLICE
#if COM16_C806_EMT
&& ucEmtUsageFlag!=2
#endif
)
{
if(CandHadList[2] > (Double)pcCU->getInterHAD()*PBINTRA_RATIO)
{
numModesForFullRD = 2;
}
if(CandHadList[1] > (Double)pcCU->getInterHAD()*PBINTRA_RATIO)
{
numModesForFullRD = 1;
}
if(CandHadList[0] > (Double)pcCU->getInterHAD()*PBINTRA_RATIO)
{
pcCU->getTotalDistortion() = MAX_UINT;
pcCU->getInterHAD() = 0;
return ;
}
}
#endif
#if COM16_C983_RSAF
const Bool isRSAFEnabled = pcCU->getSlice()->getSPS()->getUseRSAF();
#if !JVET_C0024_QTBT
Bool isBestRSAF = false;
#endif
for (Int isNonRSAF = 0; isNonRSAF < (isRSAFEnabled? 2 : 1) ; isNonRSAF++)
{
#endif
#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST
UInt max=numModesForFullRD;
if (DebugOptionList::ForceLumaMode.isSet())
{
max=0; // we are forcing a direction, so don't bother with mode check
}
for ( UInt uiMode = 0; uiMode < max; uiMode++)
#else////////////////////////////////循环numModesForFullRD次///////////////////////////////////////
for( UInt uiMode = 0; uiMode < numModesForFullRD; uiMode++ )//遍历uiRdModeList里的预测模式;
#endif
{
// set luma prediction mode,设置亮度模式;
UInt uiOrgMode = uiRdModeList[uiMode];
#if COM16_C983_RSAF
if (isRSAFEnabled)
#if JVET_C0024_QTBT
if ( (uiWidth*uiHeight>1024 || uiOrgMode == DC_IDX) ^ isNonRSAF) //RSAF scan first
#else
if ( (uiWidth>32 || uiOrgMode == DC_IDX) ^ isNonRSAF) //RSAF scan first
#endif
continue;
#endif
//这个函数什么作用;
pcCU->setIntraDirSubParts ( CHANNEL_TYPE_LUMA, uiOrgMode, uiPartOffset, uiDepth + uiInitTrDepth );
DEBUG_STRING_NEW(sMode)
// set context models,设置环境模式;
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load( m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_CURR_BEST] );
#else
m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST] );
#endif
// determine residual for partition,决定分割残差;
Distortion uiPUDistY = 0;
Double dPUCost = 0.0;
#if COM16_C983_RSAF
if ( isRSAFEnabled &&
#if JVET_C0024_QTBT
uiWidth*uiHeight>=64 && uiWidth*uiHeight<=1024 && uiOrgMode!=DC_IDX
#else
uiWidth>4 && uiWidth<=32 && uiOrgMode!=DC_IDX &&
pcCU->getPartitionSize(0) == SIZE_2Nx2N // NxN are 4x4 TUs only, RSAF does not support them
#endif
)
{
#if HHI_RQT_INTRA_SPEEDUP
xRecurIntraCodingLumaQT_RSAF( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTU
m_resiPUBuffer,
#else
resiLumaPU,
#endif
uiPUDistY, true, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) );
#else
xRecurIntraCodingLumaQT_RSAF( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTU
m_resiPUBuffer,
#else
resiLumaPU,
#endif
uiPUDistY, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) );
#endif
}
else
{
#endif
#if HHI_RQT_INTRA_SPEEDUP//进行RQT,即四叉树迭代;
xRecurIntraCodingLumaQT( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTU
m_resiPUBuffer,
#else
resiLumaPU,
#endif
uiPUDistY, true, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) );
#else
xRecurIntraCodingLumaQT( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTU
m_resiPUBuffer,
#else
resiLumaPU,
#endif
uiPUDistY, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) );
#endif
#if COM16_C983_RSAF
}
#endif
#if DEBUG_INTRA_SEARCH_COSTS
std::cout << "2nd pass [luma,chroma] mode [" << Int(pcCU->getIntraDir(CHANNEL_TYPE_LUMA, uiPartOffset)) << "," << Int(pcCU->getIntraDir(CHANNEL_TYPE_CHROMA, uiPartOffset)) << "] cost = " << dPUCost << "\n";
#endif
#if COM16_C806_EMT
if ( 1==ucEmtUsageFlag && m_pcEncCfg->getUseFastIntraEMT() )
{
#if JVET_C0024_QTBT
dModeCostStore[uiMode] = dPUCost;
#else
dModeCostStore[uiPU][uiMode] = dPUCost;
#endif
}
#endif
// check r-d cost
if( dPUCost < dBestPUCost )
{
#if COM16_C983_RSAF && !JVET_C0024_QTBT
if (isRSAFEnabled)
{
isBestRSAF = (isNonRSAF == 0);
}
#endif
DEBUG_STRING_SWAP(sPU, sMode)
#if HHI_RQT_INTRA_SPEEDUP_MOD
uiSecondBestMode = uiBestPUMode;
dSecondBestPUCost = dBestPUCost;
#endif //初始化最优预测模式,失真和代价;
uiBestPUMode = uiOrgMode;
uiBestPUDistY = uiPUDistY;
dBestPUCost = dPUCost;
#if COM16_C806_EMT
if ( 1==ucEmtUsageFlag && m_pcEncCfg->getUseFastIntraEMT() )
{
#if JVET_C0024_QTBT
dBestModeCostStore = dPUCost;
#else
dBestModeCostStore[uiPU] = dPUCost;
#endif
}
#endif
//保存最优模式的数据;
xSetIntraResultLumaQT( pcRecoYuv, tuRecurseWithPU );
if (pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag())
{
const Int xOffset = tuRecurseWithPU.getRect( COMPONENT_Y ).x0;
const Int yOffset = tuRecurseWithPU.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_resiPUBuffer[storedResidualIndex],
#else
resiLumaPU[storedResidualIndex],
#endif
tuRecurseWithPU, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE );
}
}
}
UInt uiQPartNum = tuRecurseWithPU.GetAbsPartIdxNumParts();
#if COM16_C806_EMT
::memcpy( m_puhQTTempEmtTuIdx, pcCU->getEmtTuIdx()+uiPartOffset, uiQPartNum * sizeof( UChar ) );
::memcpy( m_puhQTTempEmtCuFlag, pcCU->getEmtCuFlag()+uiPartOffset, uiQPartNum * sizeof( UChar ) );
#endif
#if !JVET_C0024_QTBT
::memcpy( m_puhQTTempTrIdx, pcCU->getTransformIdx() + uiPartOffset, uiQPartNum * sizeof( UChar ) );
#endif
for (UInt component = 0; component < numberValidComponents; component++)
{
const ComponentID compID = ComponentID(component);
::memcpy( m_puhQTTempCbf[compID], pcCU->getCbf( compID ) + uiPartOffset, uiQPartNum * sizeof( UChar ) );
::memcpy( m_puhQTTempTransformSkipFlag[compID], pcCU->getTransformSkip(compID) + uiPartOffset, uiQPartNum * sizeof( UChar ) );
#if VCEG_AZ08_INTRA_KLT
::memcpy(m_puhQTTempKLTFlag[compID], pcCU->getKLTFlag(compID) + uiPartOffset, uiQPartNum * sizeof(UChar));
#endif
}
}
#if HHI_RQT_INTRA_SPEEDUP_MOD
else if( dPUCost < dSecondBestPUCost )
{
uiSecondBestMode = uiOrgMode;
dSecondBestPUCost = dPUCost;
}
#endif
} // Mode loop
//--- update overall distortion ---更新总的失真;
uiOverallDistY += uiBestPUDistY;
//--- update transform index and cbf ---更新变换索引和系数;
const UInt uiQPartNum = tuRecurseWithPU.GetAbsPartIdxNumParts();
#if !JVET_C0024_QTBT
::memcpy( pcCU->getTransformIdx() + uiPartOffset, m_puhQTTempTrIdx, uiQPartNum * sizeof( UChar ) );
#endif
#if COM16_C806_EMT
::memcpy( pcCU->getEmtTuIdx() + uiPartOffset, m_puhQTTempEmtTuIdx, uiQPartNum * sizeof( UChar ) );
::memcpy( pcCU->getEmtCuFlag() + uiPartOffset, m_puhQTTempEmtCuFlag, uiQPartNum * sizeof( UChar ) );
#endif
for (UInt component = 0; component < numberValidComponents; component++)
{
const ComponentID compID = ComponentID(component);
::memcpy( pcCU->getCbf( compID ) + uiPartOffset, m_puhQTTempCbf[compID], uiQPartNum * sizeof( UChar ) );
::memcpy( pcCU->getTransformSkip( compID ) + uiPartOffset, m_puhQTTempTransformSkipFlag[compID ], uiQPartNum * sizeof( UChar ) );
#if VCEG_AZ08_INTRA_KLT
::memcpy( pcCU->getKLTFlag(compID) + uiPartOffset, m_puhQTTempKLTFlag[compID], uiQPartNum * sizeof(UChar));
#endif
}
//--- set reconstruction for next intra prediction blocks 为下一个预测块重建当前块---
if( !tuRecurseWithPU.IsLastSection() )
{
#if JVET_C0024_QTBT
assert(0);
#endif
const TComRectangle &puRect=tuRecurseWithPU.getRect(COMPONENT_Y);
const UInt uiCompWidth = puRect.width;
const UInt uiCompHeight = puRect.height;
const UInt uiZOrder = pcCU->getZorderIdxInCtu() + uiPartOffset;
Pel* piDes = pcCU->getPic()->getPicYuvRec()->getAddr( COMPONENT_Y, pcCU->getCtuRsAddr(), uiZOrder );
const UInt uiDesStride = pcCU->getPic()->getPicYuvRec()->getStride( COMPONENT_Y);
const Pel* piSrc = pcRecoYuv->getAddr( COMPONENT_Y, uiPartOffset );
const UInt uiSrcStride = pcRecoYuv->getStride( COMPONENT_Y);
for( UInt uiY = 0; uiY < uiCompHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride )
{
for( UInt uiX = 0; uiX < uiCompWidth; uiX++ )
{
piDes[ uiX ] = piSrc[ uiX ];
}
}
}
#if COM16_C806_EMT
uiPU++;
#endif
//=== update PU data ====更新PU数据;
pcCU->setIntraDirSubParts ( CHANNEL_TYPE_LUMA, uiBestPUMode, uiPartOffset, uiDepth + uiInitTrDepth );
} while (tuRecurseWithPU.nextSection(tuRecurseCU));
//////////////////////////////////do while循环结束////////////////////////////////////////////////////////////
#if !JVET_C0024_QTBT
if( uiNumPU > 1 )
{ // set Cbf for all blocks
UInt uiCombCbfY = 0;
UInt uiCombCbfU = 0;
UInt uiCombCbfV = 0;
UInt uiPartIdx = 0;
for( UInt uiPart = 0; uiPart < 4; uiPart++, uiPartIdx += uiQNumParts )
{
uiCombCbfY |= pcCU->getCbf( uiPartIdx, COMPONENT_Y, 1 );
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_Y )[ uiOffs ] |= uiCombCbfY;
pcCU->getCbf( COMPONENT_Cb )[ uiOffs ] |= uiCombCbfU;
pcCU->getCbf( COMPONENT_Cr )[ uiOffs ] |= uiCombCbfV;
}
}
#endif
//===== reset context models =====
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_CURR_BEST]);
#else
m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]);
#endif
//===== set distortion (rate and r-d costs are determined later) =====
pcCU->getTotalDistortion() = uiOverallDistY;
}