VVC/JEM代码学习2:estIntraPredLumaQT

(为个人理解)

     此函数的作用是计算亮度分量的预测值,备选预测模式是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;
}

你可能感兴趣的:(VVC/JEM代码学习2:estIntraPredLumaQT)