VVC/JEM代码学习23:xRecurIntraCodingLumaQT()

在执行亮度分量的预测时,在确定好最后的要执行RD cost的候选模式后,对于每个模式,都调用一遍xRecurIntraCodingLumaQT(),在此函数里面完成预测,求残差,变换量化和重建,并返回失真。

Void
TEncSearch::xRecurIntraCodingLumaQT(TComYuv*    pcOrgYuv,
                                    TComYuv*    pcPredYuv,
                                    TComYuv*    pcResiYuv,
#if COM16_C806_LARGE_CTU
                                    Pel*        resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES],
#else
                                    Pel         resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE],
#endif
                                    Distortion& ruiDistY,
#if HHI_RQT_INTRA_SPEEDUP
                                    Bool        bCheckFirst,
#endif
                                    Double&     dRDCost,
                                    TComTU&     rTu
                                    DEBUG_STRING_FN_DECLARE(sDebug))
{
  TComDataCU   *pcCU          = rTu.getCU();
  const UInt    uiAbsPartIdx  = rTu.GetAbsPartIdxTU();
  const UInt    uiFullDepth   = rTu.GetTransformDepthTotal();
  const UInt    uiTrDepth     = rTu.GetTransformDepthRel();//变换深度
#if JVET_C0024_QTBT
  Bool bCheckFull = true;// 判断是否将当前的PU按照整个模式进行变换和量化。
  Bool bCheckSplit = false;//是否进行分割;
  assert(uiAbsPartIdx ==0 && uiTrDepth==0);//uiTrDepth肯定为0;
  UInt uiWidth = pcCU->getWidth(uiAbsPartIdx);
  UInt uiHeight = pcCU->getHeight(uiAbsPartIdx);

  UInt uiWIdx  = g_aucConvertToBit[ uiWidth ] ;
  UInt uiHIdx  = g_aucConvertToBit[ uiHeight ] ;
#else
  const UInt    uiLog2TrSize  = rTu.GetLog2LumaTrSize();
        Bool    bCheckFull    = ( uiLog2TrSize  <= pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() );
        Bool    bCheckSplit   = ( uiLog2TrSize  >  pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) );
#endif

#if !COM16_C806_LARGE_CTU
        Pel     resiLumaSplit [NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE];
        Pel     resiLumaSingle[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE];
#endif
		//两种类型,一种应该是用普通方法计算(真实值-预测值),一种是用CCP方法预测的
        Bool    bMaintainResidual[NUMBER_OF_STORED_RESIDUAL_TYPES];//维持残差,存储的残差类型数量=2;
        for (UInt residualTypeIndex = 0; residualTypeIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; residualTypeIndex++)
        {
          bMaintainResidual[residualTypeIndex] = true; //assume true unless specified otherwise
        }

        bMaintainResidual[RESIDUAL_ENCODER_SIDE] = !(m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate());//如果使用基于重建的CCP估计的残差则为false;

#if COM16_C806_EMT
  UInt    uiSigNum;
#endif

#if HHI_RQT_INTRA_SPEEDUP
#if JVET_C0024_QTBT
  Int isIntraSlice = (pcCU->getSlice()->getSliceType() == I_SLICE);//是否是I slice;
#else
  Int maxTuSize = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize();
  Int isIntraSlice = (pcCU->getSlice()->getSliceType() == I_SLICE);
  // don't check split if TU size is less or equal to max TU size
  Bool noSplitIntraMaxTuSize = bCheckFull;
  if(m_pcEncCfg->getRDpenalty() && ! isIntraSlice)
  {
    // in addition don't check split if TU size is less or equal to 16x16 TU size for non-intra slice
    noSplitIntraMaxTuSize = ( uiLog2TrSize  <= min(maxTuSize,4) );

    // if maximum RD-penalty don't check TU size 32x32
    if(m_pcEncCfg->getRDpenalty()==2)
    {
      bCheckFull    = ( uiLog2TrSize  <= min(maxTuSize,4));
    }
  }
  if( bCheckFirst && noSplitIntraMaxTuSize )

  {
    bCheckSplit = false;
  }
#endif
#else
  Int maxTuSize = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize();
  Int isIntraSlice = (pcCU->getSlice()->getSliceType() == I_SLICE);
  // if maximum RD-penalty don't check TU size 32x32
  if((m_pcEncCfg->getRDpenalty()==2)  && !isIntraSlice)
  {
    bCheckFull    = ( uiLog2TrSize  <= min(maxTuSize,4));
  }
#endif

#if COM16_C806_EMT && HHI_RQT_INTRA_SPEEDUP
  // Re-use the selected transform indexes in the previous call of xRecurIntraCodingQT
#if JVET_C0024_QTBT
  UInt    uiInitTrDepth  = 0;
#else
  UInt    uiInitTrDepth     = pcCU->getPartitionSize(0) == SIZE_2Nx2N ? 0 : 1;
#endif
  UChar   ucSavedEmtTrIdx   = 0;
  Bool    bCheckInitTrDepth = false;
  static UInt uiInitAbsPartIdx;
  if ( uiTrDepth==uiInitTrDepth )//一定成立
  {
    uiInitAbsPartIdx = uiAbsPartIdx;
  }
  if ( !bCheckFirst && uiTrDepth==uiInitTrDepth )//bCheckFirst 默认为true;
  {
    ucSavedEmtTrIdx   = m_puhQTTempEmtTuIdx[uiAbsPartIdx-uiInitAbsPartIdx];
    bCheckInitTrDepth = true;
  }
#endif

#if JVET_C0024_QTBT
  assert(bCheckFull && !bCheckSplit);
#endif
  //初始化
  Double     dSingleCost                        = MAX_DOUBLE;
  Distortion uiSingleDistLuma                   = 0;
  UInt       uiSingleCbfLuma                    = 0;
  Bool       checkTransformSkip  = pcCU->getSlice()->getPPS()->getUseTransformSkip();//是否使用跳过变换
  Int        bestModeId[MAX_NUM_COMPONENT] = { 0, 0, 0};
#if COM16_C806_EMT
  UChar   bestTrIdx     = 0;
  UChar   nNumTrCands   = pcCU->getEmtCuFlag(uiAbsPartIdx) ? 4 : 1;//如果EmtCuFlag为true,则nNumTrCands等于4,否则等于1,是表示Emt变换的候选模式数量吗???;
  Bool    bAllIntra     = (m_pcEncCfg->getIntraPeriod()==1);//全I帧;
#endif

#if JVET_C0024_QTBT
  checkTransformSkip           &= TUCompRectHasAssociatedTransformSkipFlag(pcCU->getSlice()->isIntra(), rTu.getRect(COMPONENT_Y), pcCU->getSlice()->getPPS()->getPpsRangeExtension().getLog2MaxTransformSkipBlockSize());
#else
  checkTransformSkip           &= TUCompRectHasAssociatedTransformSkipFlag(rTu.getRect(COMPONENT_Y), pcCU->getSlice()->getPPS()->getPpsRangeExtension().getLog2MaxTransformSkipBlockSize());
#endif
  checkTransformSkip           &= (!pcCU->getCUTransquantBypass(0));
#if JVET_F0031_RMV_REDUNDANT_TRSKIP//只有当主要变换被禁用时,才发送transform skip flag;
  checkTransformSkip  &= (!pcCU->getEmtCuFlag(uiAbsPartIdx));
#endif

  assert (rTu.ProcessComponentSection(COMPONENT_Y));
#if !JVET_C0024_QTBT
  const UInt totalAdjustedDepthChan   = rTu.GetTransformDepthTotalAdj(COMPONENT_Y);

  if ( m_pcEncCfg->getUseTransformSkipFast() )
  {
    checkTransformSkip       &= (pcCU->getPartitionSize(uiAbsPartIdx)==SIZE_NxN);
  }
#endif


#if VCEG_AZ08_INTRA_KLT
#if !JVET_C0024_QTBT
  UInt  bestTMKLT = 0;
#endif
#if VCEG_AZ08_USE_KLT
  Bool checkTM = pcCU->getSlice()->getSPS()->getUseIntraKLT() && (bCheckFirst == false);//TM表示要使用KLT,此程序中永远为false;
#else
  Bool checkTM = (bCheckFirst == false);
#endif
  if (checkTM)//默认为false;
  {
      UInt uiMaxTrWidth = g_uiDepth2Width[USE_MORE_BLOCKSIZE_DEPTH_MAX - 1];
      UInt uiMinTrWidth = g_uiDepth2Width[USE_MORE_BLOCKSIZE_DEPTH_MIN - 1];
#if !JVET_C0024_QTBT
      UInt    uiWidth = pcCU->getWidth(0) >> uiTrDepth;
      UInt    uiHeight = pcCU->getHeight(0) >> uiTrDepth;
#endif
      Bool bCheckKLTFlag = (uiWidth == uiHeight) && (uiWidth <= uiMaxTrWidth) && (uiWidth >= uiMinTrWidth);
      checkTM &= bCheckKLTFlag;

#if VCEG_AZ05_INTRA_MPI //for speed up only
      Int iMPIidx = pcCU->getMPIIdx(uiAbsPartIdx);
      checkTM = checkTM & (iMPIidx == 0);
#endif
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
      Int iPdpcIdx = pcCU->getPDPCIdx(uiAbsPartIdx);
      checkTM = checkTM & (iPdpcIdx == 0);
#endif
#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST //for speed up only
#if JVET_C0024_QTBT
      Int iRotidx = pcCU->getROTIdx(CHANNEL_TYPE_LUMA, uiAbsPartIdx);//ROT表示Rotation operation for low-frequency transform;
#else
      Int iRotidx = pcCU->getROTIdx(uiAbsPartIdx);
#endif
      checkTM = checkTM & (iRotidx == 0);
#endif
  }
#endif
  //按照一整个TU进行变换、量化;
  if( bCheckFull )//永远成立
  {
    if(checkTransformSkip == true)//skip TransformSkip;
    { 
      //----- store original entropy coding status ,存储原始的熵编码状态
#if JVET_C0024_QTBT
      m_pcRDGoOnSbacCoder->store( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_QT_TRAFO_ROOT ] );
#else
      m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
#endif
	  //初始化
      Distortion singleDistTmpLuma                    = 0;
      UInt       singleCbfTmpLuma                     = 0;
      Double     singleCostTmp                        = 0;
      Int        firstCheckId                         = 0;
#if VCEG_AZ08_INTRA_KLT
      pcCU->setKLTFlagSubParts(0, COMPONENT_Y, uiAbsPartIdx, uiFullDepth);//将KLTFlag设置为0
#endif
	  /// 遍历两次是为了选取最优的模式,modeId能够决定xIntraCodingLumaBlk的倒数第二个参数,该参数控制了预测像素如何生成
      for(Int modeId = firstCheckId; modeId < 2; modeId ++)
      {
#if COM16_C806_EMT
#if HHI_RQT_INTRA_SPEEDUP//即第一次遍历时循环nNumTrCands次,第二次遍历只循环1次;
        UChar numTrIdxCands = ((modeId == firstCheckId && !bCheckInitTrDepth) ? nNumTrCands : 1 );//modeId=0时,numTrIdxCands=nNumTrDepth,否则等于1;
#else
        UChar numTrIdxCands = ((modeId == firstCheckId) ? nNumTrCands : 1 );
#endif
		//循环次数是numTrIdxCands,这是为了选取最优的变换///
        for (UChar ucTrIdx = 0; ucTrIdx < numTrIdxCands; ucTrIdx++)
        {
          // Skip checking other transform candidates if zero CBF is encountered,如果遇到零CBF,就跳过check其他变换候选模式;
          if( ucTrIdx && !uiSingleCbfLuma && bAllIntra && m_pcEncCfg->getUseFastIntraEMT() )
          {
            continue;
          }
#if JVET_D0077_SAVE_LOAD_ENC_INFO
          if( this->getSaveLoadTag(pcCU->getZorderIdxInCtu(), uiWIdx, uiHIdx) == LOAD_ENC_INFO && ucTrIdx && ucTrIdx != this->getSaveLoadEmtIdx(uiWIdx, uiHIdx) )
          {
            continue;
          }
#endif
#endif

        DEBUG_STRING_NEW(sModeString)
        Int  default0Save1Load2 = 0;//模式重复使用标志
        singleDistTmpLuma=0;
#if COM16_C806_EMT
        if (modeId == firstCheckId && ucTrIdx == 0)//如果modeId=0且ucTrIdx == 0,即第一次模式遍历中的第一次变换
#else
        if(modeId == firstCheckId)
#endif
        {
          default0Save1Load2 = 1;//表示保存信息
        }
        else//否则
        {
          default0Save1Load2 = 2;//表示加载信息
        }

#if COM16_C806_EMT
#if HHI_RQT_INTRA_SPEEDUP
        pcCU->setEmtTuIdxSubParts( bCheckInitTrDepth?ucSavedEmtTrIdx:ucTrIdx, uiAbsPartIdx, uiFullDepth );//设置EmtTuIdx为ucTrIdx;
#else
        pcCU->setEmtTuIdxSubParts( txIdx, uiAbsPartIdx, uiFullDepth );
#endif
#endif

#if COM16_C983_RSAF
        pcCU->setLumaIntraFilter(uiAbsPartIdx, false);
        pcCU->setLumaIntraFilterHidden(uiAbsPartIdx, true);
#endif
#if JVET_C0024_QTBT//modeId为0时TransformSkip=0,modeId为时TransformSkip为1,所以表示modeId=0表示不跳过变换,modeId=1表示跳过变换
        pcCU->setTransformSkipSubParts ( modeId, COMPONENT_Y, uiAbsPartIdx, 0 );//将TransformSkip标记设置为modeId;
#else
        pcCU->setTransformSkipSubParts ( modeId, COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan );
#endif //预测、变换和量化,反量化反变换,重建等
        xIntraCodingTUBlock( pcOrgYuv, pcPredYuv, pcResiYuv, 
#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT
          m_resiSingleBuffer[uiWIdx][uiHIdx],
#else
          m_resiSingleBuffer[uiLog2TrSize],
#endif
#else
          resiLumaSingle, 
#endif
          false, singleDistTmpLuma, COMPONENT_Y, rTu DEBUG_STRING_PASS_INTO(sModeString)
          , default0Save1Load2 
#if COM16_C806_EMT
          , &uiSigNum
#endif
          );//倒数第6个参数为false,表示不进行CCP,倒数第二个参数表示如何得到预测信息;

        singleCbfTmpLuma = pcCU->getCbf( uiAbsPartIdx, COMPONENT_Y, uiTrDepth );

        //----- determine rate and r-d cost,确定码率和率失真代价 -----
#if COM16_C806_EMT
        if( (modeId == 1 && singleCbfTmpLuma == 0) || (modeId==0 && ucTrIdx && ucTrIdx!=DCT2_EMT && uiSigNum<=g_iEmtSigNumThr) )
#else
        if(modeId == 1 && singleCbfTmpLuma == 0)
#endif
        {
          //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden.
          singleCostTmp = MAX_DOUBLE;
        }
        else
        {
          UInt uiSingleBits = xGetIntraBitsQT( rTu, true, false, false );
          singleCostTmp     = m_pcRdCost->calcRdCost( uiSingleBits, singleDistTmpLuma );
        }//更新代价;
        if(singleCostTmp < dSingleCost)
        {
          DEBUG_STRING_SWAP(sDebug, sModeString)
          dSingleCost   = singleCostTmp;
          uiSingleDistLuma = singleDistTmpLuma;
          uiSingleCbfLuma = singleCbfTmpLuma;
#if COM16_C806_EMT
          bestTrIdx     = ucTrIdx;
#endif
          bestModeId[COMPONENT_Y] = modeId;
          if(bestModeId[COMPONENT_Y] == firstCheckId)//如果最优的modeId==0,则保存变换系数和重建值;
          {
            xStoreIntraResultQT(COMPONENT_Y, rTu );
#if JVET_C0024_QTBT
            m_pcRDGoOnSbacCoder->store( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_TEMP_BEST ] );
#else
            m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_TEMP_BEST ] );
#endif
          }

          if (pcCU->getSlice()->getPPS()->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag())//允许进行CCP
          {
            const Int xOffset = rTu.getRect( COMPONENT_Y ).x0;
            const Int yOffset = rTu.getRect( COMPONENT_Y ).y0;
            for (UInt storedResidualIndex = 0; storedResidualIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; storedResidualIndex++)//循环两次,有两种残差类型
            {
              if (bMaintainResidual[storedResidualIndex])//如果为true,即表示是正常计算的残差值
              {//存储CCP结果;
                xStoreCrossComponentPredictionResult(resiLuma[storedResidualIndex], 
#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT
                  m_resiSingleBuffer[uiWIdx][uiHIdx][storedResidualIndex],
#else
                  m_resiSingleBuffer[uiLog2TrSize][storedResidualIndex],
#endif
#else
                  resiLumaSingle[storedResidualIndex], 
#endif
                  rTu, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE);//将 m_resiSingleBuffer的内容复制给resiLuma[];
              }
            }
          }
        }
        if (modeId == firstCheckId)
        {
#if JVET_C0024_QTBT
          m_pcRDGoOnSbacCoder->load ( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_QT_TRAFO_ROOT ] );
#else
          m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
#endif
        }
#if COM16_C806_EMT
        }
		numTrIdxCands循环结束/
#endif
      }
	  ///modeId 2次循环结束/
#if JVET_C0024_QTBT
      pcCU ->setTransformSkipSubParts ( bestModeId[COMPONENT_Y], COMPONENT_Y, uiAbsPartIdx, 0 );//将TransSkip又设置为最优的modeId;
#else
      pcCU ->setTransformSkipSubParts ( bestModeId[COMPONENT_Y], COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan );
#endif
#if COM16_C806_EMT
      pcCU ->setEmtTuIdxSubParts ( bestTrIdx, uiAbsPartIdx, uiFullDepth );//将EmtTuIdx又设置为最优的变换索引
#endif

      if(bestModeId[COMPONENT_Y] == firstCheckId)
      {
        xLoadIntraResultQT(COMPONENT_Y, rTu );
        pcCU->setCbfSubParts  ( uiSingleCbfLuma << uiTrDepth, COMPONENT_Y, uiAbsPartIdx, rTu.GetTransformDepthTotalAdj(COMPONENT_Y) );//设置cbf;

#if JVET_C0024_QTBT
        m_pcRDGoOnSbacCoder->load( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_TEMP_BEST ] );
#else
        m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiFullDepth ][ CI_TEMP_BEST ] );
#endif
      }
    }
    else//checkTransformSkip == false;
    {
#if COM16_C806_EMT
#if HHI_RQT_INTRA_SPEEDUP
      UChar numTrIdxCands = ( !bCheckInitTrDepth ) ? nNumTrCands : 1;//numTrIdxCands等于nNumTrCands ;
#else
      UChar numTrIdxCands = nNumTrCands;
#endif
    ///循环次数为numTrIdxCands/
      for (UChar ucTrIdx = 0; ucTrIdx < numTrIdxCands; ucTrIdx++)
      {
        UInt   singleDistYTmp     = 0;
        UInt   singleCbfYTmp      = 0;
        Double singleCostTmp      = 0;
        Bool   bSaveEmtResults    = ucTrIdx<(numTrIdxCands-1);//numTrIdxCands为4时且大于 ucTrIdx时bSaveEmtResults =1,否则等于0,即进行多次变换时且前3个变换才保存信息

        // Skip checking other transform candidates if zero CBF is encountered,如果遇到零CBF,就跳过其他变换候选的检测;
        if ( ucTrIdx && !uiSingleCbfLuma && bAllIntra && m_pcEncCfg->getUseFastIntraEMT() )
        {
          continue;
        }
#if JVET_D0077_SAVE_LOAD_ENC_INFO
        if( this->getSaveLoadTag(pcCU->getZorderIdxInCtu(), uiWIdx, uiHIdx) == LOAD_ENC_INFO && ucTrIdx && ucTrIdx != this->getSaveLoadEmtIdx(uiWIdx, uiHIdx) )
        {
          continue;
        }
#endif
#endif

      //----- store original entropy coding status ,存储原始的熵编码状态;
#if VCEG_AZ08_INTRA_KLT
#if COM16_C806_EMT
     if (bCheckSplit || bSaveEmtResults || checkTM)
#else
      if( bCheckSplit )
#endif
#else
#if COM16_C806_EMT
        if (bCheckSplit || bSaveEmtResults)
#else
        if (bCheckSplit)
#endif
#endif
      {
#if JVET_C0024_QTBT
        m_pcRDGoOnSbacCoder->store( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_QT_TRAFO_ROOT ] );
#else
        m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
#endif
      }

#if COM16_C806_EMT//numTrIdxCands为4时且bSaveEmtResults为true时,default0Save1Load2为1,numTrIdxCands为4时且bSaveEmtResults为false时,default0Save1Load2为2,;
      Int default0Save1Load2 = numTrIdxCands>1 ? ( bSaveEmtResults ? 1 : 2 ) : 0;//numTrIdxCands为1时default0Save1Load2为0;
#endif

      //----- code luma/chroma block with given intra prediction mode and store Cbf,用给定的帧内预测模式和储存的CBF编码亮度和色度块;

#if COM16_C983_RSAF
      pcCU->setLumaIntraFilter(uiAbsPartIdx, false);
      pcCU->setLumaIntraFilterHidden(uiAbsPartIdx, true);
#endif
#if COM16_C806_EMT
#if HHI_RQT_INTRA_SPEEDUP
      pcCU->setEmtTuIdxSubParts( bCheckInitTrDepth?ucSavedEmtTrIdx:ucTrIdx, uiAbsPartIdx, uiFullDepth );//将EmtTuIdx设置为ucTrIdx,在xIntraCodingTUBlock函数里面会用到
#else
      pcCU->setEmtTuIdxSubParts( trIdx, uiAbsPartIdx, uiFullDepth );
#endif
#if JVET_C0024_QTBT
      pcCU ->setTransformSkipSubParts ( 0, COMPONENT_Y, uiAbsPartIdx, 0 );//将TransformSkip设置为0;
#else
      pcCU ->setTransformSkipSubParts ( 0, COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan );
#endif
#if VCEG_AZ08_INTRA_KLT
      pcCU->setKLTFlagSubParts(0, COMPONENT_Y, uiAbsPartIdx, uiFullDepth);//将KLTFlag设置为0;
#endif//对当前TU求残差,变换,量化,反量化,反变换,重建等一系列编码工作,并求得失真 ;
      xIntraCodingTUBlock( pcOrgYuv, pcPredYuv, pcResiYuv, 
#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT
        m_resiSingleBuffer[uiWIdx][uiHIdx],
#else
        m_resiSingleBuffer[uiLog2TrSize],
#endif
#else
        resiLumaSingle, 
#endif
        false, singleDistYTmp, COMPONENT_Y, rTu DEBUG_STRING_PASS_INTO(sDebug), default0Save1Load2, &uiSigNum);//倒数第6个参数表示是否使用CCP
#else
      dSingleCost   = 0.0;
#if JVET_C0024_QTBT
      pcCU ->setTransformSkipSubParts ( 0, COMPONENT_Y, uiAbsPartIdx, 0 );
#else
      pcCU ->setTransformSkipSubParts ( 0, COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan );
#endif
      xIntraCodingTUBlock( pcOrgYuv, pcPredYuv, pcResiYuv, 
#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT
        m_resiSingleBuffer[uiWIdx][uiHIdx],
#else
        m_resiSingleBuffer[uiLog2TrSize],
#endif
#else
        resiLumaSingle, 
#endif
        false, uiSingleDistLuma, COMPONENT_Y, rTu DEBUG_STRING_PASS_INTO(sDebug) );
#endif

#if VCEG_AZ08_INTRA_KLT
#if COM16_C806_EMT
      if (bCheckSplit || bSaveEmtResults || checkTM)
#else
      if( bCheckSplit )
#endif
#else
#if COM16_C806_EMT
      if (bCheckSplit || bSaveEmtResults)
#else
      if (bCheckSplit)
#endif
#endif
      {
#if COM16_C806_EMT
        singleCbfYTmp   = pcCU->getCbf( uiAbsPartIdx, COMPONENT_Y, uiTrDepth );
#else
        uiSingleCbfLuma = pcCU->getCbf( uiAbsPartIdx, COMPONENT_Y, uiTrDepth );
#endif
      }
      //----- determine rate and r-d cost ,确定码率和率失真代价;
#if COM16_C806_EMT
      if( ucTrIdx && ucTrIdx!=DCT2_EMT && uiSigNum<=g_iEmtSigNumThr )
      {
        singleCostTmp = MAX_DOUBLE;
      }
      else
      {
#endif
      UInt uiSingleBits = xGetIntraBitsQT( rTu, true, false, false );
#if JVET_C0024_QTBT
      if(m_pcEncCfg->getRDpenalty() && (uiWIdx+uiHIdx+(1<<MIN_CU_LOG2)>=10) && !isIntraSlice)
#else
      if(m_pcEncCfg->getRDpenalty() && (uiLog2TrSize==5) && !isIntraSlice)
#endif
      {
        uiSingleBits=uiSingleBits*4;
      }

#if COM16_C806_EMT
      singleCostTmp     = m_pcRdCost->calcRdCost( uiSingleBits, singleDistYTmp );//根据比特数和失真计算率失真代价;
      }
#else
      dSingleCost       = m_pcRdCost->calcRdCost( uiSingleBits, uiSingleDistLuma );
#endif

#if COM16_C806_EMT
      if(singleCostTmp < dSingleCost)
      {
#endif
      if (pcCU->getSlice()->getPPS()->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag())
      {
        const Int xOffset = rTu.getRect( COMPONENT_Y ).x0;
        const Int yOffset = rTu.getRect( COMPONENT_Y ).y0;
        for (UInt storedResidualIndex = 0; storedResidualIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; storedResidualIndex++)
        {
          if (bMaintainResidual[storedResidualIndex])
          {
            xStoreCrossComponentPredictionResult(resiLuma[storedResidualIndex], 
#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT
              m_resiSingleBuffer[uiWIdx][uiHIdx][storedResidualIndex],
#else
              m_resiSingleBuffer[uiLog2TrSize][storedResidualIndex],
#endif
#else
              resiLumaSingle[storedResidualIndex], 
#endif
              rTu, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE);
          }
        }
      }
#if COM16_C806_EMT//更新代价,失真和最优的变换索引;
        dSingleCost      = singleCostTmp;
        uiSingleDistLuma = singleDistYTmp;
        uiSingleCbfLuma  = singleCbfYTmp;
        bestTrIdx        = ucTrIdx;

        if( bSaveEmtResults && ( uiSingleCbfLuma || !bAllIntra || !m_pcEncCfg->getUseFastIntraEMT() ) )
        {
          xStoreIntraResultQT( COMPONENT_Y, rTu );
#if JVET_C0024_QTBT
          m_pcRDGoOnSbacCoder->store( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_TEMP_BEST ] );
#else
          m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_TEMP_BEST ] );
#endif
        }
      }

      if( bSaveEmtResults && ( uiSingleCbfLuma || !bAllIntra || !m_pcEncCfg->getUseFastIntraEMT() ) )
      {
#if JVET_C0024_QTBT
        m_pcRDGoOnSbacCoder->load ( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_QT_TRAFO_ROOT ] );
#else
        m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
#endif
      }
      }
      numTrIdxCands循环结束//
      pcCU->setEmtTuIdxSubParts( bestTrIdx, uiAbsPartIdx, uiFullDepth );//重新设置EmtTuIdx为bestTrIdx
	  //numTrIdxCands等于4时,如果bestTrIdx小于3且...
      if( bestTrIdx < (numTrIdxCands-1) && ( uiSingleCbfLuma || !bAllIntra || !m_pcEncCfg->getUseFastIntraEMT() ) )
      {
        xLoadIntraResultQT( COMPONENT_Y, rTu );
        pcCU->setCbfSubParts  ( uiSingleCbfLuma << uiTrDepth, COMPONENT_Y, uiAbsPartIdx, uiFullDepth );
#if JVET_C0024_QTBT
        m_pcRDGoOnSbacCoder->load( m_ppppcRDSbacCoder[ uiWIdx][uiHIdx ][ CI_TEMP_BEST ] );
#else
        m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[ uiFullDepth ][ CI_TEMP_BEST ] );
#endif
      }
#endif
    }
#if VCEG_AZ08_INTRA_KLT
    if (checkTM && uiSingleCbfLuma)
    {
        //backup the former results
        Double  dSingleCostBackUp = dSingleCost;
        UInt    uiSingleCbfYBackUp = uiSingleCbfLuma;
        UInt    uiSingleDistYBackUp = uiSingleDistLuma;

        uiSingleDistLuma = 0;
        dSingleCost = 0.0;
        uiSingleCbfLuma = 0;
#if VCEG_AZ08_INTRA_KLT
        pcCU->setKLTFlagSubParts(1, COMPONENT_Y, uiAbsPartIdx, uiFullDepth);
#endif
        xStoreIntraResultQT(COMPONENT_Y, rTu);
#if JVET_C0024_QTBT
        m_pcRDGoOnSbacCoder->store(m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_TEMP_BEST]);
        //----- store original entropy coding status,存储原始的熵编码状态
        m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_QT_TRAFO_ROOT]);
#else
        m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiFullDepth][CI_TEMP_BEST]);
        //----- store original entropy coding status -----
        m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiFullDepth][CI_QT_TRAFO_ROOT]);
#endif
        //----- code luma block with given intra prediction mode and store Cbf,用给定的帧内预测和存储cbf编码亮度块;
        Bool bSuccessful;

#if COM16_C983_RSAF
        pcCU->setLumaIntraFilter(uiAbsPartIdx, false);
        pcCU->setLumaIntraFilterHidden(uiAbsPartIdx, true);
#endif
#if COM16_C806_EMT
        pcCU->setEmtTuIdxSubParts(0, uiAbsPartIdx, uiFullDepth);
#if JVET_C0024_QTBT
        pcCU->setTransformSkipSubParts(0, COMPONENT_Y, uiAbsPartIdx, 0);
#else
        pcCU->setTransformSkipSubParts(0, COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan);
#endif  //xIntraCodingTUBlockTM过程和xIntraCodingTUBlock大致一样,但不知道TM表示什么意思
        bSuccessful = xIntraCodingTUBlockTM(pcOrgYuv, pcPredYuv, pcResiYuv,
            uiSingleDistLuma, COMPONENT_Y, rTu DEBUG_STRING_PASS_INTO(sDebug), &uiSigNum, TMPRED0_TMPREDKLT1_ORI2);
#else
        dSingleCost = 0.0;
#if JVET_C0024_QTBT
        pcCU->setTransformSkipSubParts(0, COMPONENT_Y, uiAbsPartIdx, 0);
#else
        pcCU->setTransformSkipSubParts(0, COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan);
#endif
#if JVET_C0024_QTBT
        bSuccessful = 
#endif
        xIntraCodingTUBlockTM(pcOrgYuv, pcPredYuv, pcResiYuv,
            uiSingleDistLuma, COMPONENT_Y, rTu DEBUG_STRING_PASS_INTO(sDebug)
#if JVET_C0024_QTBT
            , TMPRED0_TMPREDKLT1_ORI2
#else
#if COM16_C983_RSAF
            , false
            , bStub
#endif
#endif
            );
#endif
        uiSingleCbfLuma = pcCU->getCbf(uiAbsPartIdx, COMPONENT_Y, uiTrDepth);//cbf/CBF表示coded block flags;

        if (bSuccessful == true && uiSingleCbfLuma) //assume only cbf being nonzero, can use TM mode
        {
            //----- determine rate and r-d cost ,确定码率和率失真代价 
            UInt uiSingleBits = xGetIntraBitsQT(rTu, true, false, false); 
#if JVET_C0024_QTBT
            if(m_pcEncCfg->getRDpenalty() && (uiWIdx+uiHIdx+(MIN_CU_LOG2<<1)>=10) && !isIntraSlice)
#else
            if (m_pcEncCfg->getRDpenalty() && (uiLog2TrSize == 5) && !isIntraSlice)
#endif
            {
                uiSingleBits = uiSingleBits * 4;//为什么乘以4???
            }
            dSingleCost = m_pcRdCost->calcRdCost(uiSingleBits, uiSingleDistLuma); 
        }
        else
        {
            dSingleCost = MAX_DOUBLE;
        }
		//代价更新
        if (dSingleCostBackUp <= dSingleCost)
        {
            dSingleCost = dSingleCostBackUp;
            uiSingleCbfLuma = uiSingleCbfYBackUp;
            uiSingleDistLuma = uiSingleDistYBackUp;
            pcCU->setKLTFlagSubParts(0, COMPONENT_Y, uiAbsPartIdx, uiFullDepth);
#if COM16_C806_EMT
            pcCU->setEmtTuIdxSubParts(bestTrIdx, uiAbsPartIdx, uiFullDepth);
#endif
#if JVET_C0024_QTBT
            pcCU->setTransformSkipSubParts(bestModeId[COMPONENT_Y], COMPONENT_Y, uiAbsPartIdx, 0); //1.30.2016  uiFullDepth);
#else
            pcCU->setTransformSkipSubParts(bestModeId[COMPONENT_Y], COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan); //1.30.2016  uiFullDepth);
#endif
            xLoadIntraResultQT(COMPONENT_Y, rTu); 
            pcCU->setCbfSubParts(uiSingleCbfLuma << uiTrDepth, COMPONENT_Y, uiAbsPartIdx, uiFullDepth);
#if JVET_C0024_QTBT
            m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_TEMP_BEST]);
#else
            m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiFullDepth][CI_TEMP_BEST]);
#endif
        }
        else//dSingleCostBackUp > dSingleCost
        {
#if !JVET_C0024_QTBT
            bestTMKLT = 1;
#endif
            bestModeId[COMPONENT_Y] = 0;
#if JVET_C0024_QTBT && COM16_C806_EMT
            bestTrIdx = 0;
#endif
#if COM16_C806_EMT
            pcCU->setEmtTuIdxSubParts(0, uiAbsPartIdx, uiFullDepth);
#endif
        }
    }
#endif
  }

#if !JVET_C0024_QTBT
  if( bCheckSplit )
  {
    //----- store full entropy coding status, load original entropy coding status -----
    if( bCheckFull )
    {
      m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_TEST ] );
      m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
    }
    else
    {
      m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
    }
    //----- code splitted block -----
    Double     dSplitCost      = 0.0;
    Distortion uiSplitDistLuma = 0;
    UInt       uiSplitCbfLuma  = 0;
#if COM16_C806_EMT
    Bool    bSplitSelected = true;
#endif

    TComTURecurse tuRecurseChild(rTu, false);
    DEBUG_STRING_NEW(sSplit)
    do
    {
      DEBUG_STRING_NEW(sChild)
#if HHI_RQT_INTRA_SPEEDUP
      xRecurIntraCodingLumaQT( pcOrgYuv, pcPredYuv, pcResiYuv, 
#if COM16_C806_LARGE_CTU
        m_resiSplitBuffer[uiLog2TrSize],
#else
        resiLumaSplit, 
#endif
        uiSplitDistLuma, bCheckFirst, dSplitCost, tuRecurseChild DEBUG_STRING_PASS_INTO(sChild) );
#else
      xRecurIntraCodingLumaQT( pcOrgYuv, pcPredYuv, pcResiYuv, 
#if COM16_C806_LARGE_CTU
        m_resiSplitBuffer[uiLog2TrSize],
#else
        resiLumaSplit, 
#endif
        uiSplitDistLuma, dSplitCost, tuRecurseChild DEBUG_STRING_PASS_INTO(sChild) );
#endif
      DEBUG_STRING_APPEND(sSplit, sChild)
      uiSplitCbfLuma |= pcCU->getCbf( tuRecurseChild.GetAbsPartIdxTU(), COMPONENT_Y, tuRecurseChild.GetTransformDepthRel() );
#if COM16_C806_EMT
      if( dSplitCost>dSingleCost && m_pcEncCfg->getUseFastIntraEMT() )
      {
        bSplitSelected = false;
        break;
      }
#endif
    } while (tuRecurseChild.nextSection(rTu) );

#if COM16_C806_EMT
    if( bSplitSelected )
    {
#endif
    UInt    uiPartsDiv     = rTu.GetAbsPartIdxNumParts();
    {
      if (uiSplitCbfLuma)
      {
        const UInt flag=1<<uiTrDepth;
        UChar *pBase=pcCU->getCbf( COMPONENT_Y );
        for( UInt uiOffs = 0; uiOffs < uiPartsDiv; uiOffs++ )
        {
          pBase[ uiAbsPartIdx + uiOffs ] |= flag;
        }
      }
    }
    //----- restore context states -----
    m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_ROOT ] );
    
    //----- determine rate and r-d cost -----
    UInt uiSplitBits = xGetIntraBitsQT( rTu, true, false, false );
    dSplitCost       = m_pcRdCost->calcRdCost( uiSplitBits, uiSplitDistLuma );
#if COM16_C806_EMT
    }
#endif

    //===== compare and set best =====
    if( dSplitCost < dSingleCost )
    {
      //--- update cost ---
      DEBUG_STRING_SWAP(sSplit, sDebug)
      ruiDistY += uiSplitDistLuma;
      dRDCost  += dSplitCost;

      if (pcCU->getSlice()->getPPS()->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag())
      {
        const Int xOffset = rTu.getRect( COMPONENT_Y ).x0;
        const Int yOffset = rTu.getRect( COMPONENT_Y ).y0;
        for (UInt storedResidualIndex = 0; storedResidualIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; storedResidualIndex++)
        {
          if (bMaintainResidual[storedResidualIndex])
          {
            xStoreCrossComponentPredictionResult(resiLuma[storedResidualIndex], 
#if COM16_C806_LARGE_CTU
              m_resiSplitBuffer[uiLog2TrSize][storedResidualIndex],
#else
              resiLumaSplit[storedResidualIndex], 
#endif
              rTu, xOffset, yOffset, MAX_CU_SIZE, MAX_CU_SIZE);
          }
        }
      }

      return;
    }

    //----- set entropy coding status -----
    m_pcRDGoOnSbacCoder->load ( m_pppcRDSbacCoder[ uiFullDepth ][ CI_QT_TRAFO_TEST ] );

    //--- set transform index and Cbf values ---
    pcCU->setTrIdxSubParts( uiTrDepth, uiAbsPartIdx, uiFullDepth );
    const TComRectangle &tuRect=rTu.getRect(COMPONENT_Y);
    pcCU->setCbfSubParts  ( uiSingleCbfLuma << uiTrDepth, COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan );
    pcCU ->setTransformSkipSubParts  ( bestModeId[COMPONENT_Y], COMPONENT_Y, uiAbsPartIdx, totalAdjustedDepthChan );
#if COM16_C806_EMT
    pcCU->setEmtTuIdxSubParts( bestTrIdx, uiAbsPartIdx, uiFullDepth );
#endif
#if VCEG_AZ08_INTRA_KLT
    pcCU->setKLTFlagSubParts(bestTMKLT, COMPONENT_Y, uiAbsPartIdx, uiFullDepth);
#endif

    //--- set reconstruction for next intra prediction blocks ---
    const UInt  uiQTLayer   = pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() - uiLog2TrSize;
    const UInt  uiZOrder    = pcCU->getZorderIdxInCtu() + uiAbsPartIdx;
    const UInt  uiWidth     = tuRect.width;
    const UInt  uiHeight    = tuRect.height;
    Pel*  piSrc       = m_pcQTTempTComYuv[ uiQTLayer ].getAddr( COMPONENT_Y, uiAbsPartIdx );
    UInt  uiSrcStride = m_pcQTTempTComYuv[ uiQTLayer ].getStride  ( COMPONENT_Y );
    Pel*  piDes       = pcCU->getPic()->getPicYuvRec()->getAddr( COMPONENT_Y, pcCU->getCtuRsAddr(), uiZOrder );
    UInt  uiDesStride = pcCU->getPic()->getPicYuvRec()->getStride  ( COMPONENT_Y );

    for( UInt uiY = 0; uiY < uiHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride )
    {
      for( UInt uiX = 0; uiX < uiWidth; uiX++ )
      {
        piDes[ uiX ] = piSrc[ uiX ];
      }
    }
  }
#endif

  ruiDistY += uiSingleDistLuma;//累加失真
  dRDCost  += dSingleCost;//累加代价
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值