之前 HEVC代码学习42:estIntraPredLumaQT函数 对HM中的estIntraPredLumaQT函数进行了学习,下面将对JEM中的该函数进行学习。

estIntraPredLumaQT

estIntraPredLumaQT是亮度帧内预测的入口函数,完成了亮度帧内预测最优模式的选择。

JEM与HM主要区别有:
1.JEM中,亮度帧内模式预测模式数由35增加到67种,因此对HEVC的帧内快速搜索进行了改进:首先对原35种基本角度预测使用哈达玛变换进行粗选,构建候选列表;对选出的角度模式其左右相邻的扩展角度模式(新增的角度模式)进行粗选,更新候选列表;然后进行全率失真优化细选,找到最优模式。代码修改主要是在粗选阶段增加了扩展角度的搜索。
2.将构建MPM候选提到了粗选阶段。
3.xRecurIntraCodingLumaQT不再区分bCheckFirst,只比较bCheckFirst=true的情况(从estIntraPredLumaQT函数中是这样的,不知道是不是把bCheckFirst=false的情况放到了其他地方)。

流程如下:
一、初始化各种参数,其中包括EMT和NSST参数的配置。
二、同HM,为了减少率失真优化次数,默认使用帧内快速搜索算法,将分粗选和细选两个阶段进行。如果不使用快速搜索,将对所有帧内预测模式进行率失真优化。
1.粗选阶段分为三部分(注意在粗选阶段全部使用哈达玛变换计算失真,提高速度):
(1)调用getIntraDirPredictor构建MPM列表(只是构建)。
(2)遍历原HEVC中的35种基本模式使用predIntraAng计算预测值,计算比较哈达玛失真,调用xUpdateCandList构建全率失真优化候选列表。全率失真优化候选列表长度numModesForFullRD由块宽度决定。
(3)对选中的角度模式左右两侧的扩展角度模式(新增的模式)进行搜索,计算比较哈达玛失真,更新全率失真优化候选列表。
2.细选阶段:遍历已建立的MPM列表,将其加入全率失真优化候选列表中。遍历全率失真优化候选列表,调用xRecurIntraCodingLumaQT(详细分析见H.266代码学习:xRecurIntraCodingLumaQT函数)进行变换量化重构,计算比较率失真代价,找到最优模式。
三、收尾工作,记录信息:设置Cbf、上下文模型、总失真等。

代码分析:

//亮度分量预测
Void
TEncSearch::estIntraPredLumaQT(TComDataCU* pcCU,TComYuv*    pcOrgYuv,TComYuv*    pcPredYuv,TComYuv*    pcResiYuv,TComYuv*    pcRecoYuv,
#if COM16_C806_LARGE_CTUPel*        resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES]
#elsePel         resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE]
#endifDEBUG_STRING_FN_DECLARE(sDebug))
{const UInt         uiDepth               = pcCU->getDepth(0);     //划分深度
#if JVET_C0024_QTBTconst 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];
#elseconst 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_RSAFconst UInt         uiWidth               = pcCU->getWidth (0) >> uiInitTrDepth;
#endif
#endifconst ChromaFormat chFmt                 = pcCU->getPic()->getChromaFormat();     //YUV格式const UInt         numberValidComponents = getNumberValidComponents(chFmt);           //可用分量const TComSPS     &sps                   = *(pcCU->getSlice()->getSPS());         //SPSconst TComPPS     &pps                   = *(pcCU->getSlice()->getPPS());     //PPSDistortion   uiOverallDistY        = 0;     UInt         CandNum;           //候选数Double       CandCostList[ FAST_UDI_MAX_RDMODE_NUM ];           //67种模式的代价列表
#if JVET_C0024_PBINTRA_FASTDouble    CandHadList[ FAST_UDI_MAX_RDMODE_NUM ];for (Int i=0; i<FAST_UDI_MAX_RDMODE_NUM; i++)     //遍历67种模式,将代价置为最大{CandHadList[i] = MAX_DOUBLE;}
#endif
#if !COM16_C806_LARGE_CTUPel          resiLumaPU[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE];
#endifBool    bMaintainResidual[NUMBER_OF_STORED_RESIDUAL_TYPES];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());// Lambda calculation at equivalent Qp of 4 is recommended because at that Qp, the quantisation divisor is 1.
#if FULL_NBITconst 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//计算Lambdaconst 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 =====//设置QP,清理Cbfif ( pps.getUseDQP() == true){
#if JVET_C0024_DELTA_QP_FIXpcCU->setQPSubParts( pcCU->getQP(0), 0, pcCU->getWidth(0), pcCU->getHeight(0) );
#elsepcCU->setQPSubParts( pcCU->getQP(0), 0, uiDepth );
#endif}else{
#if JVET_C0024_DELTA_QP_FIXpcCU->setQPSubParts( pcCU->getSlice()->getSliceQp(), 0, pcCU->getWidth(0), pcCU->getHeight(0) );
#elsepcCU->setQPSubParts( pcCU->getSlice()->getSliceQp(), 0, uiDepth );
#endif}#if JVET_D0127_REDUNDANCY_REMOVAL
#if JVET_C0024_QTBT//初始化NSST相关信息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;
#elseBool 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_QTBTstatic UInt   uiSavedRdModeListNSST[35], uiSavedNumRdModesNSST, uiSavedHadModeListNSST[35];static Double dSavedModeCostNSST[35], dSavedHadListNSST[FAST_UDI_MAX_RDMODE_NUM];
#elsestatic UInt   uiSavedRdModeListNSST[4][35], uiSavedNumRdModesNSST[4];static Double dSavedModeCostNSST[4][35];
#endif
#if JVET_C0024_PBINTRA_FASTUInt uiHadModeList[67];
#endif
#endif#if COM16_C806_EMT
#if JVET_C0024_QTBTstatic Double dBestModeCostStore; // RD cost of the best mode for each PU using DCT2   //存储使用DCT2的PU最佳模式的RD coststatic Double dModeCostStore[35]; // RD cost of each mode for each PU using DCT2  //存储使用DCT2的PU每一个模式的RD cost,长度为35是因为粗选阶段只使用原HEVC的35种预测模式static UInt   uiSavedRdModeList[35], uiSavedNumRdModes;
#elsestatic Double dBestModeCostStore[4]; // RD cost of the best mode for each PU using DCT2static Double dModeCostStore[4][35]; // RD cost of each mode for each PU using DCT2static UInt   uiSavedRdModeList[4][35], uiSavedNumRdModes[4];
#endif// Marking EMT usage for faster EMT// 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//EMT标志UChar ucEmtUsageFlag = ( (uiWidth <= EMT_INTRA_MAX_CU && uiHeight <= EMT_INTRA_MAX_CU) ? ( pcCU->getEmtCuFlag(0)==1 ? 2 : 1 ) : 0 );
#elseUChar ucEmtUsageFlag = ( pcCU->getWidth(0) <= EMT_INTRA_MAX_CU ? ( pcCU->getEmtCuFlag(0)==1 ? 2 : 1 ) : 0 );
#endifBool  bAllIntra = (m_pcEncCfg->getIntraPeriod()==1);#if JVET_C0024_QTBT//当块的块和高乘积小于64且非AI时,ucEmtUsageFlag=0,不使用EMTif (uiWidth*uiHeight<64 && !bAllIntra)
#elseif( pcCU->getPartitionSize(0) == SIZE_NxN && !bAllIntra )
#endif{ucEmtUsageFlag = 0;}
#if JVET_D0077_SAVE_LOAD_ENC_INFOUInt  uiZorderIdx = pcCU->getZorderIdxInCtu();        //CTU中Z scan下的绝对地址UChar saveLoadTag = getSaveLoadTag( uiZorderIdx, uiWIdx, uiHIdx );        if( saveLoadTag == LOAD_ENC_INFO /*&& getSaveLoadEmtFlag(uiWIdx, uiHIdx) == 0*/ ){ucEmtUsageFlag = 0;}
#if JVET_D0127_REDUNDANCY_REMOVALNSSTFlag |= saveLoadTag == LOAD_ENC_INFO;
#endif
#endif
#endif//===== loop over partitions =====//迭代分块TComTURecurse tuRecurseCU(pcCU, 0);TComTURecurse tuRecurseWithPU(tuRecurseCU, false, (uiInitTrDepth==0)?TComTU::DONT_SPLIT : TComTU::QUAD_SPLIT);#if COM16_C806_EMTUInt uiPU = 0;
#endifdo        //遍历一个CU的所有PU{const UInt uiPartOffset=tuRecurseWithPU.GetAbsPartIdxTU();      //当前PU的偏移
//  for( UInt uiPU = 0, uiPartOffset=0; uiPU < uiNumPU; uiPU++, uiPartOffset += uiQNumParts )//{#if COM16_C806_EMTUInt uiRdModeList[FAST_UDI_MAX_RDMODE_NUM];         //模式RD代价列表
#if JVET_C0024_QTBT assert(uiPartOffset==0);Int numModesForFullRD = g_aucIntraModeNumFast_UseMPM[uiWIdx][uiHIdx];       //完整率失真优化的选择的模式数,由PU的宽和高决定
#elseInt numModesForFullRD = m_pcEncCfg->getFastUDIUseMPMEnabled()?g_aucIntraModeNumFast_UseMPM[ uiWidthBit ] : g_aucIntraModeNumFast_NotUseMPM[ uiWidthBit ];
#if VCEG_AZ07_INTRA_65ANG_MODESnumModesForFullRD -= 1;
#endif
#endifif( ucEmtUsageFlag != 2 )       //对当前块进行EMT,使用存储的DCT2结果用于加速。{
#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_MODESInt numModesAvailable     = 67; //total number of Intra modes   帧内模式总数量
#elseInt numModesAvailable     = 35; //total number of Intra modes
#endif
#if !COM16_C806_EMTUInt uiRdModeList[FAST_UDI_MAX_RDMODE_NUM];
#if JVET_C0024_QTBTassert(uiPartOffset==0);Int numModesForFullRD = g_aucIntraModeNumFast_UseMPM[uiWIdx][uiHIdx];
#elseInt numModesForFullRD = m_pcEncCfg->getFastUDIUseMPMEnabled()?g_aucIntraModeNumFast_UseMPM[ uiWidthBit ] : g_aucIntraModeNumFast_NotUseMPM[ uiWidthBit ];
#if VCEG_AZ07_INTRA_65ANG_MODESnumModesForFullRD -= 1;
#endif
#endif
#endif// this should always be trueassert (tuRecurseWithPU.ProcessComponentSection(COMPONENT_Y));initIntraPatternChType( tuRecurseWithPU, COMPONENT_Y, true DEBUG_STRING_PASS_INTO(sTemp2) );            //初始化Bool doFastSearch = (numModesForFullRD != numModesAvailable);       //当numModesForFullRD和numModesAvailable不相等时,进行快速搜索。if (doFastSearch)       //快速搜索{assert(numModesForFullRD < numModesAvailable);#if JVET_D0127_REDUNDANCY_REMOVALfor (Int i = 0; i < numModesForFullRD + 2; i++)       //置numModesForFullRD+2代价为最大
#elsefor( Int i=0; i < numModesForFullRD; i++ )
#endif{CandCostList[ i ] = MAX_DOUBLE;}CandNum = 0;#if VCEG_AZ07_INTRA_65ANG_MODESInt uiPreds[6] = {-1, -1, -1, -1, -1, -1};        //预测列表都置为-1Int iAboveLeftCase=0, iMode=-1;#if JVET_C0055_INTRA_MPM//根据相邻块的预测模式获取MPMpcCU->getIntraDirPredictor( uiPartOffset, uiPreds, COMPONENT_Y, &iMode ); // Pre-calculate the MPMs, so avoid redundant MPM calculations during the SATD loop
#elsepcCU->getIntraDirPredictor( uiPartOffset, uiPreds, COMPONENT_Y, iAboveLeftCase, &iMode ); // Pre-calculate the MPMs, so avoid redundant MPM calculations during the SATD loop
#endifassert( iMode >= 0 );iMode = min(iMode+1, 6);      //MPM最多为6个Char bSatdChecked[NUM_INTRA_MODE];memset( bSatdChecked, 0, NUM_INTRA_MODE*sizeof(Char) );
#endifconst 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;       /************************************************************************35个基本模式搜索*************************************************************************************/
#if JVET_D0127_REDUNDANCY_REMOVALif (NSSTFlag){        //使用NSST时
#endiffor( Int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ )        //遍历所有67种模式,实际跳过了奇数角度模式,只遍历原HEVC中的35种模式{UInt       uiMode = modeIdx;        //模式索引Distortion uiSad  = 0;      //失真#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_QTBTif( iNumberOfPassesROT <= pcCU->getROTIdx(CHANNEL_TYPE_LUMA, 0) )
#elseif( iNumberOfPassesROT <= pcCU->getROTIdx(0) )
#endif{continue;}}
#endif#if VCEG_AZ07_INTRA_65ANG_MODESif( uiMode>DC_IDX && (uiMode&1) )       //跳过奇数角度模式{// Skip checking extended Angular modes in the first round of SATDcontinue;}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.//计算bit数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;#if DEBUG_INTRA_SEARCH_COSTSstd::cout << "1st pass mode " << uiMode << " SAD = " << uiSad << ", mode bits = " << iModeBits << ", cost = " << cost << "\n";
#endif#if JVET_C0024_FAST_MRG
#if JVET_D0127_REDUNDANCY_REMOVAL//比较滤波是真代价,更新列表,更新候选数CandNumCandNum += updateCandList(uiMode, cost, numModesForFullRD + 2, uiRdModeList, CandCostList);
#elseCandNum += updateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );
#endif
#else
#if JVET_D0127_REDUNDANCY_REMOVALCandNum += xUpdateCandList( uiMode, cost, numModesForFullRD + 2, uiRdModeList, CandCostList );
#elseCandNum += xUpdateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );
#endif
#endif
#if JVET_C0024_PBINTRA_FAST
#if JVET_D0127_REDUNDANCY_REMOVAL//更新候选列表updateCandList(uiMode, uiSad, numModesForFullRD+2, uiHadModeList, CandHadList);
#elseif (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}
#if JVET_D0127_REDUNDANCY_REMOVALif (NSSTSaveFlag){
#if JVET_C0024_QTBTuiSavedNumRdModesNSST = numModesForFullRD;::memcpy(uiSavedRdModeListNSST, uiRdModeList, (numModesForFullRD + 2)*sizeof(UInt));::memcpy(dSavedModeCostNSST, CandCostList, (numModesForFullRD + 2)*sizeof(Double));
#elseuiSavedNumRdModesNSST[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_QTBTif (pcCU->getROTIdx(CHANNEL_TYPE_LUMA, 0) == 3){
#elseif (pcCU->getROTIdx(0) == 3 && pcCU->getPartitionSize(0) == SIZE_2Nx2N){
#endif
#if JVET_C0024_QTBTnumModesForFullRD = uiSavedNumRdModesNSST;::memcpy(uiRdModeList, uiSavedRdModeListNSST, (numModesForFullRD + 2)*sizeof(UInt));::memcpy(CandCostList, dSavedModeCostNSST, (numModesForFullRD + 2)*sizeof(Double));
#elsenumModesForFullRD = 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));
#endifInt 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_FASTcnt = 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_QTBTnumModesForFullRD = uiSavedNumRdModesNSST;::memcpy(uiRdModeList, uiSavedRdModeListNSST, numModesForFullRD*sizeof(UInt));::memcpy(CandCostList, dSavedModeCostNSST, numModesForFullRD*sizeof(Double));
#elsenumModesForFullRD = 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_MODESUInt uiParentCandList[FAST_UDI_MAX_RDMODE_NUM];memcpy( uiParentCandList, uiRdModeList, sizeof(UInt)*numModesForFullRD );// Second round of SATD for extended Angular modes/***************************************************************扩展角度搜索***********************************************************///对第一轮搜索得到的最可能模式,进行第二轮角度扩展搜索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))
#elseif( uiParentMode>2 && uiParentMode<(NUM_INTRA_MODE-2) )
#endif{for( Int subModeIdx = -1; subModeIdx <= 1; subModeIdx+=2 ){UInt uiMode = uiParentMode + subModeIdx;        //左右两侧的角度模式#if COM16_C1044_NSST
#if !JVET_C0024_QTBTif( pcCU->getPartitionSize(0)==SIZE_2Nx2N )
#endif{const Int iNumberOfPassesROT = ( uiMode<=DC_IDX ) ? 3 : 4;
#if JVET_C0024_QTBTif( iNumberOfPassesROT <= pcCU->getROTIdx(CHANNEL_TYPE_LUMA, 0) )
#elseif( iNumberOfPassesROT <= pcCU->getROTIdx(0) )
#endif{continue;}}
#endifif( !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//使用哈达玛变换计算失真,计算bit数和率失真代价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_COSTSstd::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 );
#elseCandNum += xUpdateCandList( uiMode, cost, numModesForFullRD, uiRdModeList, CandCostList );
#endif
#if JVET_C0024_PBINTRA_FASTif (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;}
#endifbSatdChecked[uiMode] = true; // Mark as checked}}}}
#endif/**************************************************快速搜索细选阶段**************************************************/if (m_pcEncCfg->getFastUDIUseMPMEnabled())        //快速搜索{
#if !VCEG_AZ07_INTRA_65ANG_MODESInt uiPreds[NUM_MOST_PROBABLE_MODES] = {-1, -1, -1};Int iMode = -1;pcCU->getIntraDirPredictor( uiPartOffset, uiPreds, COMPONENT_Y, &iMode );
#endif//MPM候选数const Int numCand = ( iMode >= 0 ) ? iMode : Int(NUM_MOST_PROBABLE_MODES);//将MPM加入候选列表中for( Int j=0; j < numCand; j++){Bool mostProbableModeIncluded = false;Int mostProbableMode = uiPreds[j];#if COM16_C1044_NSST
#if !JVET_C0024_QTBTif( pcCU->getPartitionSize(0)==SIZE_2Nx2N )
#endif{const Int iNumberOfPassesROT = ( mostProbableMode<=DC_IDX ) ? 3 : 4;
#if JVET_C0024_QTBTif( iNumberOfPassesROT <= pcCU->getROTIdx(CHANNEL_TYPE_LUMA, 0) )
#elseif( iNumberOfPassesROT <= pcCU->getROTIdx(0) )
#endif{continue;}}
#endiffor( Int i=0; i < numModesForFullRD; i++){mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i]);}if (!mostProbableModeIncluded)        {uiRdModeList[numModesForFullRD++] = mostProbableMode;}}}}else        //不使用快速搜索,将所有模式加入列表中{for( Int i=0; i < numModesForFullRD; i++){uiRdModeList[i] = i;}}
#if COM16_C806_EMTif( ucEmtUsageFlag==1 )     //当前块使用EMT和DCT2,不存储DCT2的结果{// Store the modes to be checked with RD
#if JVET_C0024_QTBTuiSavedNumRdModes = numModesForFullRD;::memcpy( uiSavedRdModeList, uiRdModeList, numModesForFullRD*sizeof(UInt) );
#elseuiSavedNumRdModes[uiPU] = numModesForFullRD;::memcpy( uiSavedRdModeList[uiPU], uiRdModeList, numModesForFullRD*sizeof(UInt) );
#endif}}else if( ucEmtUsageFlag==2 )    //当前块使用EMT和DCT2,存储DCT2的结果用于加速{if( bAllIntra && m_pcEncCfg->getUseFastIntraEMT() ){
#if !COM16_C983_RSAF && !JVET_C0024_QTBTUInt uiWidth = pcCU->getWidth (0) >> uiInitTrDepth;
#endif
#if JVET_C0024_QTBTconst Double dThrFastMode = 1.0 + 1.4/sqrt( (Double) (uiWidth*uiHeight) );
#elsedouble 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-passcase 16: dThrFastMode = 1.12; break; // Skip checking 16x16 Intra modes using the R-D cost in the DCT2-passcase 32: dThrFastMode = 1.06; break; // Skip checking 32x32 Intra modes using the R-D cost in the DCT2-passdefault: dThrFastMode = 1.06; break; // Skip checking 32x32 Intra modes using the R-D cost in the DCT2-pass}
#endifnumModesForFullRD=0;// Skip checking the modes with much larger R-D cost than the best mode
#if JVET_C0024_QTBTfor( Int i=0; i < uiSavedNumRdModes; i++){if( dModeCostStore[i] <= dThrFastMode * dBestModeCostStore ){uiRdModeList[numModesForFullRD++] = uiSavedRdModeList[i];}}
#elsefor( 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_QTBTnumModesForFullRD = uiSavedNumRdModes;::memcpy( uiRdModeList, uiSavedRdModeList, numModesForFullRD*sizeof(UInt) );
#elsenumModesForFullRD = uiSavedNumRdModes[uiPU];::memcpy( uiRdModeList, uiSavedRdModeList[uiPU], numModesForFullRD*sizeof(UInt) );
#endif}}
#endif//===== check modes (using r-d costs) =====//使用RD cost检测模式
#if HHI_RQT_INTRA_SPEEDUP_MODUInt   uiSecondBestMode  = MAX_UINT;Double dSecondBestPUCost = MAX_DOUBLE;
#endifDEBUG_STRING_NEW(sPU)UInt       uiBestPUMode  = 0;       //最优模式Distortion uiBestPUDistY = 0;       //最优失真  Double     dBestPUCost   = MAX_DOUBLE;      //最优代价#if JVET_C0024_PBINTRA_FASTif( pcCU->getSlice()->getSliceType()!=I_SLICE       //帧间模式且ucEmtUsageFlag!=2时
#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_QTBTBool isBestRSAF = false;
#endiffor (Int isNonRSAF = 0;  isNonRSAF < (isRSAFEnabled? 2 : 1) ;  isNonRSAF++) {
#endif#if ENVIRONMENT_VARIABLE_DEBUG_AND_TESTUInt 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//遍历需要完整RD Cost检测的模式,选最优for( UInt uiMode = 0; uiMode < numModesForFullRD; uiMode++ )
#endif{// set luma prediction modeUInt uiOrgMode = uiRdModeList[uiMode];        //原始模式#if COM16_C983_RSAF if (isRSAFEnabled)
#if JVET_C0024_QTBTif ( (uiWidth*uiHeight>1024 || uiOrgMode == DC_IDX) ^ isNonRSAF) //RSAF scan first
#elseif ( (uiWidth>32 || uiOrgMode == DC_IDX) ^ isNonRSAF) //RSAF scan first
#endifcontinue;
#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] );
#elsem_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST] );
#endif// determine residual for partitionDistortion uiPUDistY = 0;         //初始化当前失真Double     dPUCost   = 0.0;       //初始化当前代价#if COM16_C983_RSAFif ( isRSAFEnabled &&
#if JVET_C0024_QTBTuiWidth*uiHeight>=64 && uiWidth*uiHeight<=1024 && uiOrgMode!=DC_IDX
#elseuiWidth>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_SPEEDUPxRecurIntraCodingLumaQT_RSAF( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTUm_resiPUBuffer,
#elseresiLumaPU,
#endifuiPUDistY, true, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) );
#elsexRecurIntraCodingLumaQT_RSAF( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTUm_resiPUBuffer,
#elseresiLumaPU,
#endifuiPUDistY, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) );
#endif}else{
#endif
#if HHI_RQT_INTRA_SPEEDUP//重构帧内亮度分量,计算率失真代价xRecurIntraCodingLumaQT( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTUm_resiPUBuffer,
#elseresiLumaPU,
#endifuiPUDistY, true, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) );
#elsexRecurIntraCodingLumaQT( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTUm_resiPUBuffer,
#elseresiLumaPU, #endifuiPUDistY, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) );
#endif#if COM16_C983_RSAF}#endif#if DEBUG_INTRA_SEARCH_COSTSstd::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//如果使用EMT且ucEmtUsageFlag为1时,存储当前PU的代价if ( 1==ucEmtUsageFlag && m_pcEncCfg->getUseFastIntraEMT() ){
#if JVET_C0024_QTBTdModeCostStore[uiMode] = dPUCost;
#elsedModeCostStore[uiPU][uiMode] = dPUCost;
#endif}
#endif// check r-d cost//如果当前代价小于最优代价,将当前模式置为最优模式if( dPUCost < dBestPUCost ){
#if COM16_C983_RSAF && !JVET_C0024_QTBTif (isRSAFEnabled){isBestRSAF = (isNonRSAF == 0);}
#endifDEBUG_STRING_SWAP(sPU, sMode)
#if HHI_RQT_INTRA_SPEEDUP_MODuiSecondBestMode  = uiBestPUMode;dSecondBestPUCost = dBestPUCost;
#endifuiBestPUMode  = uiOrgMode;uiBestPUDistY = uiPUDistY;dBestPUCost   = dPUCost;
#if COM16_C806_EMT//如果使用EMT且ucEmtUsageFlag为1时,存储当前PU的代价if ( 1==ucEmtUsageFlag && m_pcEncCfg->getUseFastIntraEMT() ){
#if JVET_C0024_QTBTdBestModeCostStore = dPUCost;
#elsedBestModeCostStore[uiPU] = dPUCost;
#endif}
#endifxSetIntraResultLumaQT( 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_CTUm_resiPUBuffer[storedResidualIndex],
#elseresiLumaPU[storedResidualIndex],
#endiftuRecurseWithPU, 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 ) );
#endiffor (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_MODelse if( dPUCost < dSecondBestPUCost ){uiSecondBestMode  = uiOrgMode;dSecondBestPUCost = dPUCost;}
#endif} // Mode loop#if COM16_C983_RSAF} // RSAF-enabled modes loop
#endif #if !JVET_C0024_QTBT
#if COM16_C983_RSAF && COM16_C983_RSAF_ESTIMATION_MODE_FULLif (!isBestRSAF)
#endif#if HHI_RQT_INTRA_SPEEDUP
#if HHI_RQT_INTRA_SPEEDUP_MODfor( UInt ui =0; ui < 2; ++ui )
#endif{
#if HHI_RQT_INTRA_SPEEDUP_MODUInt uiOrgMode   = ui ? uiSecondBestMode  : uiBestPUMode;if( uiOrgMode == MAX_UINT ){break;}
#elseUInt uiOrgMode = uiBestPUMode;
#endif#if ENVIRONMENT_VARIABLE_DEBUG_AND_TESTif (DebugOptionList::ForceLumaMode.isSet()){uiOrgMode = DebugOptionList::ForceLumaMode.getInt();}
#endifpcCU->setIntraDirSubParts ( CHANNEL_TYPE_LUMA, uiOrgMode, uiPartOffset, uiDepth + uiInitTrDepth );DEBUG_STRING_NEW(sModeTree)// set context modelsm_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST] );// determine residual for partitionDistortion uiPUDistY = 0;Double     dPUCost   = 0.0;
#if COM16_C983_RSAF && !COM16_C983_RSAF_ESTIMATION_MODE_FULLif (isBestRSAF)xRecurIntraCodingLumaQT_RSAF( pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTUm_resiPUBuffer,
#elseresiLumaPU,
#endifuiPUDistY, false, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sModeTree));else
#endifxRecurIntraCodingLumaQT(pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTUm_resiPUBuffer,
#elseresiLumaPU,
#endifuiPUDistY, false, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sModeTree));// check r-d costif( dPUCost < dBestPUCost ){DEBUG_STRING_SWAP(sPU, sModeTree)uiBestPUMode  = uiOrgMode;uiBestPUDistY = uiPUDistY;dBestPUCost   = dPUCost;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_CTUm_resiPUBuffer[storedResidualIndex],
#elseresiLumaPU[storedResidualIndex],
#endiftuRecurseWithPU, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE );}}}const UInt uiQPartNum = tuRecurseWithPU.GetAbsPartIdxNumParts();::memcpy( m_puhQTTempTrIdx,  pcCU->getTransformIdx()       + uiPartOffset, uiQPartNum * sizeof( UChar ) );
#if COM16_C806_EMT ::memcpy( m_puhQTTempEmtTuIdx,   pcCU->getEmtTuIdx()+uiPartOffset,  uiQPartNum * sizeof( UChar ) );::memcpy( m_puhQTTempEmtCuFlag,  pcCU->getEmtCuFlag()+uiPartOffset, uiQPartNum * sizeof( UChar ) );
#endiffor (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}}} // Mode loop
#endif
#if VCEG_AZ08_INTRA_KLT
#if COM16_C983_RSAF && COM16_C983_RSAF_ESTIMATION_MODE_FULL
#if VCEG_AZ08_USE_KLTelse if (pcCU->getSlice()->getSPS()->getUseIntraKLT()){
#elseelse{
#endif
#if HHI_RQT_INTRA_SPEEDUP
#if HHI_RQT_INTRA_SPEEDUP_MODfor (UInt ui = 0; ui < 2; ++ui)
#endif{
#if HHI_RQT_INTRA_SPEEDUP_MODUInt uiOrgMode = ui ? uiSecondBestMode : uiBestPUMode;if (uiOrgMode == MAX_UINT){break;}
#elseUInt uiOrgMode = uiBestPUMode;
#endif#if ENVIRONMENT_VARIABLE_DEBUG_AND_TESTif (DebugOptionList::ForceLumaMode.isSet()){uiOrgMode = DebugOptionList::ForceLumaMode.getInt();}
#endifpcCU->setIntraDirSubParts(CHANNEL_TYPE_LUMA, uiOrgMode, uiPartOffset, uiDepth + uiInitTrDepth);DEBUG_STRING_NEW(sModeTree)// set context modelsm_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]);// determine residual for partitionDistortion uiPUDistY = 0;Double     dPUCost = 0.0;
#if COM16_C983_RSAF && !COM16_C983_RSAF_ESTIMATION_MODE_FULLif (isBestRSAF)xRecurIntraCodingLumaQT_RSAF(pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTUm_resiPUBuffer,
#elseresiLumaPU,
#endifuiPUDistY, false, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sModeTree));else
#endifxRecurIntraCodingLumaQT_RSAF(pcOrgYuv, pcPredYuv, pcResiYuv,
#if COM16_C806_LARGE_CTUm_resiPUBuffer,
#elseresiLumaPU,
#endifuiPUDistY, false, dPUCost, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sModeTree));// check r-d costif (dPUCost < dBestPUCost){DEBUG_STRING_SWAP(sPU, sModeTree)uiBestPUMode = uiOrgMode;uiBestPUDistY = uiPUDistY;dBestPUCost = dPUCost;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_CTUm_resiPUBuffer[storedResidualIndex],
#elseresiLumaPU[storedResidualIndex],
#endiftuRecurseWithPU, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE);}}}const UInt uiQPartNum = tuRecurseWithPU.GetAbsPartIdxNumParts();::memcpy(m_puhQTTempTrIdx, pcCU->getTransformIdx() + uiPartOffset, uiQPartNum * sizeof(UChar));
#if COM16_C806_EMT ::memcpy(m_puhQTTempEmtTuIdx, pcCU->getEmtTuIdx() + uiPartOffset, uiQPartNum * sizeof(UChar));::memcpy(m_puhQTTempEmtCuFlag, pcCU->getEmtCuFlag() + uiPartOffset, uiQPartNum * sizeof(UChar));
#endiffor (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}}} // Mode loop
#endif}
#endif
#endif
#endifDEBUG_STRING_APPEND(sDebug, sPU)//--- update overall distortion ---//更新总失真uiOverallDistY += uiBestPUDistY;//--- update transform index and cbf ---//更新变换索引和cbfconst 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 ) );
#endiffor (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_QTBTassert(0);
#endifconst 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_EMTuiPU++;
#endif//=== update PU data ====//更新PU数据信息pcCU->setIntraDirSubParts     ( CHANNEL_TYPE_LUMA, uiBestPUMode, uiPartOffset, uiDepth + uiInitTrDepth );} while (tuRecurseWithPU.nextSection(tuRecurseCU));#if !JVET_C0024_QTBTif( uiNumPU > 1 ){ // set Cbf for all blocksUInt 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]);
#elsem_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]);
#endif//===== set distortion (rate and r-d costs are determined later) =====//设置总失真pcCU->getTotalDistortion() = uiOverallDistY;
}

H.266代码学习:estIntraPredLumaQT函数相关推荐

  1. H.266代码学习:decompressCtu和xDecompressCU函数

    今天来学习一下JEM的decompressCtu和xDecompressCU函数.之前在 H.266代码学习:decodeCtu和xDecodeCU函数 学习了的学习中提到,decodeCtu和xDe ...

  2. H.266代码学习:xIntraCodingTUBlock函数

    今天来继续学习帧内编码的重要函数xIntraCodingTUBlock,上次 H.266代码学习:xRecurIntraCodingLumaQT函数 学习中提到,xIntraCodingTUBlock ...

  3. H.266代码学习:decodeCtu和xDecodeCU函数

    之前 HEVC代码学习39:decodeCtu和xDecodeCU函数 中对HM中的CTU解码函数进行了学习,这里来学习一下JEM中的. 首先需要强调的是,这里只是用来解码flag.系数等,没有进行预 ...

  4. H.266代码学习:xEncodeCU函数

    之前在HEVC代码学习35:xEncodeCU函数中介绍过xEncodeCU函数,今天来看JEM中的xEncodeCU,其中难点在于QTBT编码结构. HM中使用compressCtu对每个CTU进行 ...

  5. H.266代码学习:JEM使用方法

    之前在HEVC代码学习0:HM使用+码流分析教程中详细介绍了HM使用方法,而H.266参考代码JEM已经成型,因此这里简单介绍下JEM的使用方法. 阅读建议: JEM使用方法与HM类似,使用中改动在于 ...

  6. VVC/H.266代码阅读(VTM8.0)(三. Slice到CTU的处理 )

    本文是本系列的第三篇博客,内容是分析从Slice到CTU的处理代码. 该系列相关博客为: VVC/H.266代码阅读(VTM8.0)(一. NALU提取) VVC/H.266代码阅读(VTM8.0)( ...

  7. AV1代码学习:函数encode_frame和aom_codec_encode

    1.encode_frame函数 在编码端aomenc.c的main函数中,在进入编码过程循环后,循环读取视频的每一帧数据,然后通过encode_frame函数对每一帧进行编码. encode_fra ...

  8. H.266/VVC代码学习:帧内预测之角度预测函数(predIntraAng、xPredIntraAng)

    predIntraAng函数 VTM中,帧内预测的角度预测的入口函数为predIntraAng函数,该函数主要是用于进行传统的帧内预测(Planar.DC.角度预测),然后对Planar和DC模式使用 ...

  9. H.266/VVC-VTM代码学习27-VTM中编码器主函数逻辑

    H.266/VVC专栏传送 上一篇:H.266/VVC-VTM代码学习26-VTM中RDcost的计算与λ的设定(二) 下一篇:持续创作中- 目录 H.266/VVC专栏传送 前言 一.简介 二.代码 ...

最新文章

  1. insight切换窗口 source_Source Insight函数调用关系显示设置
  2. python----四种内置数据结构(dict、list、tuple、set)
  3. 嵌入式linux入门-常用命令介绍
  4. neo4j安装和启动
  5. 大数据初探——Hadoop历史
  6. LED闪烁和流水灯,调试教程,在线仿真器的使用
  7. 记录几个CentOS安装包(rpm)的下载地址-离线安装必备
  8. (14) ZYNQ AXI4-Lite总线简介(学无止境)
  9. 2019.10.15学习总结
  10. 1954-计算机基础知识大赛 1
  11. Eclipse中使用SVN Eclipse配置SVN
  12. 数组(Java基础内容)
  13. 什么是敏捷项目管理?
  14. 华为智慧屏鸿蒙评测,搭载鸿蒙系统的荣耀智慧屏值得入手吗?荣耀智慧屏全面评测...
  15. python word 合并单元格_在word文档选项卡中检测合并单元格
  16. Unity提供的消息推送机制
  17. 【ZUFE-经费报销】浙江财经大学发票报销经验分享(以新苗报销为例)
  18. Python和Go语言的区别
  19. 数据结构实验--基于线性表的图书信息管理系统
  20. 2022年高压电工上岗证题库及答案

热门文章

  1. 怎样把日常要做的事情记录和显示在桌面便签日历上
  2. 作为一名测试人员,如何拾开发者牙慧,开启兼职赚钱之路
  3. 基于分布式数据库集群的大数据职位信息统计
  4. 记录一下公司中对于app启动时长的做法
  5. python中的注释有哪些符号_python表示注释的符号是什么
  6. 如何白嫖world.js、china.js以及各个省的js和json文件
  7. Stack Overflow 2022 开发者调查报告出炉啦
  8. rickey.gong git common commands
  9. mysql数据库导入后莫名丢失_MySQL数据库导入或者同步大量数据时数据丢失解决方案...
  10. 国内有哪些量化交易平台?