VVC/JEM代码学习1:estIntraPredChromaQT函数

       现在好像关于JEM的博客还很少,正好自己学习JEM,就把自己学习到的一点东西记录下来。省的学了就忘,先给自己定个目标,一天至少一篇吧。今天学习了色度帧内预测,先记录一下。estIntraPredChromaQT函数的主要功能是进行色度分量的帧内预测,在11种备选的预测模式中根据RD cost选择cost最小的一种模式作为最优预测模式。11种备选模式中,前6种是属于CCLM预测,用重建的亮度分量预测色度分量,后面5种是和HEVC中的色度预测模式一致。

Void
TEncSearch::estIntraPredChromaQT(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))
{
#if JVET_C0024_QTBT
  const UInt    uiInitTrDepth  =  0;
  UInt uiWIdx = g_aucConvertToBit[pcCU->getWidth(0)];
  UInt uiHIdx = g_aucConvertToBit[pcCU->getHeight(0)];
#else
  const UInt    uiInitTrDepth  = pcCU->getPartitionSize(0) != SIZE_2Nx2N && enable4ChromaPUsInIntraNxNCU(pcOrgYuv->getChromaFormat()) ? 1 : 0;
#endif

  TComTURecurse tuRecurseCU(pcCU, 0);
  TComTURecurse tuRecurseWithPU(tuRecurseCU, false, (uiInitTrDepth==0)?TComTU::DONT_SPLIT : TComTU::QUAD_SPLIT);
#if !JVET_C0024_QTBT
  const UInt    uiQNumParts    = tuRecurseWithPU.GetAbsPartIdxNumParts();
#endif
  const UInt    uiDepthCU=tuRecurseWithPU.getCUDepth();
  const UInt    numberValidComponents = pcCU->getPic()->getNumberValidComponents();
  do   while大循环/
  do
  {
#if JVET_E0077_LM_MF
      UInt auiSATDModeList[LM_FILTER_NUM];
      UInt auiSATDSortedcost[LM_FILTER_NUM];

      const UInt csx = getComponentScaleX(COMPONENT_Cb, pcCU->getSlice()->getSPS()->getChromaFormatIdc());
      const UInt csy = getComponentScaleY(COMPONENT_Cb, pcCU->getSlice()->getSPS()->getChromaFormatIdc());

      Int iBlockSize = (pcCU->getHeight(0) >> csy) + (pcCU->getWidth(0) >> csx);
#endif

    UInt       uiBestMode  = 0;
    Distortion uiBestDist  = 0;
    Double     dBestCost   = MAX_DOUBLE;

    //----- init mode list -----
    if (tuRecurseWithPU.ProcessChannelSection(CHANNEL_TYPE_CHROMA))
    {
#if JVET_E0062_MULTI_DMS
      UInt uiModeList[NUM_CHROMA_MODE];
#else
      UInt uiModeList[FAST_UDI_MAX_RDMODE_NUM];
#endif

#if !JVET_C0024_QTBT
      const UInt  uiQPartNum     = uiQNumParts;
#endif
      const UInt  uiPartOffset   = tuRecurseWithPU.GetAbsPartIdxTU();
      {
        UInt  uiMinMode = 0;
        UInt  uiMaxMode = NUM_CHROMA_MODE;//11;

        //----- check chroma modes -----
#if JVET_E0077_ENHANCED_LM
        uiMaxMode =
#endif//前6种67,68,69,70,71,72应该是CCLM的6种预测模式,后5种和HEVC里的一样;
        pcCU->getAllowedChromaDir( uiPartOffset, uiModeList );//获得可用的色度预测模式,uiModeList里有11种候选模式;
#if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST
        if (DebugOptionList::ForceChromaMode.isSet())
        {
          uiMinMode=DebugOptionList::ForceChromaMode.getInt();
          if (uiModeList[uiMinMode]==34)
          {
            uiMinMode=4; // if the fixed mode has been renumbered because DM_CHROMA covers it, use DM_CHROMA.
          }
          uiMaxMode=uiMinMode+1;
        }
#endif

#if JVET_C0024_QTBT
        assert(uiPartOffset==0);     
        UInt uiShort, uiLong;
        UInt uiStr;
        if (pcCU->getHeight(0) > pcCU->getWidth(0))
        {
            uiShort = pcCU->getWidth(0);
            uiLong = pcCU->getHeight(0);
            uiStr = pcCU->getPic()->getNumPartInCtuWidth();
        }
        else
        {
            uiShort = pcCU->getHeight(0);
            uiLong = pcCU->getWidth(0);
            uiStr = 1;
        }

        UInt uiCurrDepth = g_aucConvertToBit[pcCU->getSlice()->getSPS()->getCTUSize()] - g_aucConvertToBit[uiShort];
        UInt uiCurrPartNumb = pcCU->getPic()->getNumPartitionsInCtu() >> (uiCurrDepth << 1);
        UInt uiNumPartInShort = pcCU->getPic()->getNumPartInCtuWidth() >> uiCurrDepth;
#endif
        DEBUG_STRING_NEW(sPU)

#if JVET_E0077_ENHANCED_LM
        const TComRectangle &puRect = tuRecurseWithPU.getRect(COMPONENT_Cb);
        getLumaRecPixels(tuRecurseWithPU, puRect.width, puRect.height);//得到重建的亮度采样,用于CCLM;
#if !COM16_C983_RSAF 
        initIntraPatternChType(tuRecurseWithPU, COMPONENT_Cb, false  DEBUG_STRING_PASS_INTO(sDebug));//初始过程;
        initIntraPatternChType(tuRecurseWithPU, COMPONENT_Cr, false  DEBUG_STRING_PASS_INTO(sDebug));
#else
        initIntraPatternChType(tuRecurseWithPU, COMPONENT_Cb, false, false  DEBUG_STRING_PASS_INTO(sDebug));
        initIntraPatternChType(tuRecurseWithPU, COMPONENT_Cr, false, false  DEBUG_STRING_PASS_INTO(sDebug)); 
#endif
#endif

#if JVET_E0077_LM_MF
        const UInt uiAbsPartIdx = tuRecurseWithPU.GetAbsPartIdxTU();
        DistParam distParam;
        const Bool bUseHadamard = true;
        Int iCurLMMFIdx = 0;
        //SATD checking for LMMF candidates
        const Int iLMMFinRDNum = 1;
        
        if (pcCU->getSlice()->getSPS()->getUseLMChroma() && iBlockSize >= g_aiMFLM_MinSize[pcCU->getSlice()->isIntra() ? 0 : 1])
        {    //LM_FILTER_NUM=4,为什么是从69开始的,不是67,68,69,70,71,72 6个模式吗;
            for (UInt uiMode = LM_CHROMA_F1_IDX; uiMode < LM_CHROMA_F1_IDX + LM_FILTER_NUM; uiMode++)
            {
                UInt uiSad = 0;

                Pel* piOrg = pcOrgYuv->getAddr(COMPONENT_Cb, uiAbsPartIdx);
                Pel* piPred = pcPredYuv->getAddr(COMPONENT_Cb, uiAbsPartIdx);
                UInt uiStride = pcPredYuv->getStride(COMPONENT_Cb);
                m_pcRdCost->setDistParam(distParam, pcCU->getSlice()->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA), piOrg, uiStride, piPred, uiStride, puRect.width, puRect.height, bUseHadamard);
                distParam.bApplyWeight = false;
//用亮度分量预测Cb分量;
                predLMIntraChroma(tuRecurseWithPU, COMPONENT_Cb, piPred, uiStride, puRect.width, puRect.height, uiMode);
                Pel* piOrgPred = piPred;
                Pel* piSavPred = m_pLMMFPredSaved[(uiMode - LM_CHROMA_F1_IDX) * 2];
                for (Int i = 0; i < puRect.height; i++)
                {
                    memcpy(piSavPred, piOrgPred, sizeof(Pel)* puRect.width);
                    piOrgPred += uiStride;
                    piSavPred += puRect.width;
                }

                uiSad += distParam.DistFunc(&distParam);

                piOrg = pcOrgYuv->getAddr(COMPONENT_Cr, uiAbsPartIdx);
                piPred = pcPredYuv->getAddr(COMPONENT_Cr, uiAbsPartIdx);
                uiStride = pcPredYuv->getStride(COMPONENT_Cr);
                m_pcRdCost->setDistParam(distParam, pcCU->getSlice()->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA), piOrg, uiStride, piPred, uiStride, puRect.width, puRect.height, bUseHadamard);
                distParam.bApplyWeight = false;
//用亮度分量预测色度Cr分量,过程和预测Cb分量的过程一样;
                predLMIntraChroma(tuRecurseWithPU, COMPONENT_Cr, piPred, uiStride, puRect.width, puRect.height, uiMode);

                piOrgPred = piPred;
                piSavPred = m_pLMMFPredSaved[(uiMode - LM_CHROMA_F1_IDX) * 2 + 1];
                for (Int i = 0; i < puRect.height; i++)
                {
                    memcpy(piSavPred, piOrgPred, sizeof(Pel)* puRect.width);//将piOrgPred所指内存区域中的sizeof(Pel)* puRect.width个字节赋值到piSavPred指向的内存区域;
                    piOrgPred += uiStride;
                    piSavPred += puRect.width;
                }
//计算失真;
                uiSad += distParam.DistFunc(&distParam);
//uiSad的值为Cb分量的失真与Cr分量失真的和;
                auiSATDSortedcost[iCurLMMFIdx] = uiSad;
                auiSATDModeList[iCurLMMFIdx] = uiMode;
                for (Int k = iCurLMMFIdx; k > 0 && auiSATDSortedcost[k] < auiSATDSortedcost[k - 1]; k--)
                {//对这个数组auiSATDSortedcost进行排序;
                    UInt tmp = auiSATDSortedcost[k];
                    auiSATDSortedcost[k] = auiSATDSortedcost[k - 1];
                    auiSATDSortedcost[k - 1] = tmp;
                    tmp = auiSATDModeList[k];
                    auiSATDModeList[k] = auiSATDModeList[k - 1];
                    auiSATDModeList[k - 1] = tmp;
                }
                iCurLMMFIdx++;
            }
        }//此循环结束,得到69,70,71,72 4种MMLM预测模式的代价值;
#endif

#if JVET_E0077_ENHANCED_LM
        m_iCurAngMode = 0;
#endif///遍历11种色度模式,寻找代价最小的模式//
        for( UInt uiMode = uiMinMode; uiMode < uiMaxMode; uiMode++ )//色度有11种帧内预测模式;
        {
#if COM16_C806_LMCHROMA
          if ( !pcCU->getSlice()->getSPS()->getUseLMChroma() && uiModeList[uiMode] == LM_CHROMA_IDX )
          {
            continue;
          }
#endif

#if JVET_E0077_ENHANCED_LM//67,68,69,70,71,72时IsLMMode都为true;
          if (!pcCU->getSlice()->getSPS()->getUseLMChroma() && IsLMMode(uiModeList[uiMode]))
          {
              continue;
          }
#endif

#if JVET_E0077_LM_MF//如果69<=uimode<=72;
          if (uiModeList[uiMode] >= LM_CHROMA_F1_IDX &&  uiModeList[uiMode] < LM_CHROMA_F1_IDX + LM_FILTER_NUM)
          {
              Bool bNeedRD = false;
              for (Int i = 0; i < iLMMFinRDNum; i++)//iLMMFinRDNum=1;
              {
                  if (auiSATDModeList[i] == uiModeList[uiMode])
                  {
                      bNeedRD = true;
                      break;
                  }
              }
              if (!bNeedRD)
              {
                  continue;
              }
          }
#endif

#if JVET_C0024_QTBT && COM16_C1044_NSST
          if( pcCU->getSlice()->isIntra() )
          {
            UInt uiIntraMode = uiModeList[uiMode];
#if JVET_E0062_MULTI_DMS && COM16_C806_LMCHROMA            
            if( uiIntraMode == LM_CHROMA_IDX )
            {
              uiIntraMode = PLANAR_IDX;
            }
#if JVET_E0077_ENHANCED_LM
            else if (IsLMMode(uiIntraMode))
            {
                uiIntraMode = PLANAR_IDX;
            }
#endif 
#else
            if( uiIntraMode == DM_CHROMA_IDX )
            {
              uiIntraMode = pcCU->getPic()->getCtu(pcCU->getCtuRsAddr())->getIntraDir(CHANNEL_TYPE_LUMA, pcCU->getZorderIdxInCtu()+uiPartOffset);
            }
#if COM16_C806_LMCHROMA
            else if( uiIntraMode == LM_CHROMA_IDX )
            {
              uiIntraMode = PLANAR_IDX;
            }
#endif

#if JVET_E0077_ENHANCED_LM
            else if (IsLMMode(uiIntraMode))
            {
                uiIntraMode = PLANAR_IDX;
            }
#endif 

#endif

            const Int iNumberOfPassesROT = ( uiIntraMode<=DC_IDX ) ? 3 : 4;
            if( iNumberOfPassesROT <= pcCU->getROTIdx(CHANNEL_TYPE_CHROMA, uiPartOffset) )
            {
              continue;
            }
          }
#endif

#if JVET_E0077_ENHANCED_LM
          if (!IsLMMode(uiModeList[uiMode]))//不属于LM模式,即是11种模式中的后5种模式(HEVC中的传统模式);
          {
              m_iCurAngMode++;
#if QC_LM_ANGULAR_PREDICTION
              if (numRDChecking > 1 && uiCPLEFlag == 1 && adModecost[m_iCurAngMode - 1] > adSortedcost[iSecondRDtime - 1])
              {
                  continue;
              }
#endif

#if JVET_E0077_ENHANCED_LM && JVET_E0062_MULTI_DMS
              if (m_iCurAngMode > NUM_CHROMA_MODE)
              {
                  continue;
              }
#endif
          }
#endif

          //----- restore context models -----重新存储上下文模型;
#if JVET_C0024_QTBT
          m_pcRDGoOnSbacCoder->load( m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_CURR_BEST] );
#else
          m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepthCU][CI_CURR_BEST] );
#endif
          
          DEBUG_STRING_NEW(sMode)
          //----- chroma coding -----
          Distortion uiDist = 0;
#if JVET_E0062_MULTI_DMS
          assert(uiModeList[uiMode]<=(LM_CHROMA_IDX+NUM_DM_MODES));
#endif
          pcCU->setIntraDirSubParts  ( CHANNEL_TYPE_CHROMA, uiModeList[uiMode], uiPartOffset, uiDepthCU+uiInitTrDepth );

          //求色度分量的残差,并对残差进行变换量化熵编码等,并返回一个失真;
          xRecurIntraChromaCodingQT       ( pcOrgYuv, pcPredYuv, pcResiYuv, resiLuma, uiDist, tuRecurseWithPU DEBUG_STRING_PASS_INTO(sMode) );

          if( pcCU->getSlice()->getPPS()->getUseTransformSkip() )
          {
#if JVET_C0024_QTBT
            m_pcRDGoOnSbacCoder->load( m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_CURR_BEST] );
#else
            m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepthCU][CI_CURR_BEST] );
#endif
          }

          UInt    uiBits = xGetIntraBitsQT( tuRecurseWithPU, false, true, false );
          Double  dCost  = m_pcRdCost->calcRdCost( uiBits, uiDist );

          //----- compare -----
          if( dCost < dBestCost )//如果当前模式的代价小于最优模式的代价,则将最优模式等相关数据更新为当前模式的数据;
          {
            DEBUG_STRING_SWAP(sPU, sMode);
            dBestCost   = dCost;
            uiBestDist  = uiDist;
            uiBestMode  = uiModeList[uiMode];
            xSetIntraResultChromaQT( pcRecoYuv, tuRecurseWithPU );//保存最优模式的数据;
#if JVET_C0024_QTBT            
            UInt uiRaster = g_auiZscanToRaster[pcCU->getZorderIdxInCtu()];
            for (UInt i=0; i<uiLong; i+=uiShort)
            {
                UInt uiZorder = g_auiRasterToZscan[uiRaster] - pcCU->getZorderIdxInCtu();
                for (UInt componentIndex = COMPONENT_Cb; componentIndex < numberValidComponents; componentIndex++)
                {
                    const ComponentID compID = ComponentID(componentIndex);
                    ::memcpy(m_puhQTTempCbf[compID] + uiZorder, pcCU->getCbf( compID ) + uiZorder, uiCurrPartNumb );
                    ::memcpy(m_puhQTTempTransformSkipFlag[compID]+uiZorder, pcCU->getTransformSkip( compID ) + uiZorder, uiCurrPartNumb);
                    ::memcpy(m_phQTTempCrossComponentPredictionAlpha[compID]+uiZorder, pcCU->getCrossComponentPredictionAlpha(compID)+uiZorder, uiCurrPartNumb );
                }
                uiRaster += uiNumPartInShort * uiStr;
            }
#else
            for (UInt componentIndex = COMPONENT_Cb; componentIndex < numberValidComponents; componentIndex++)
            {
              const ComponentID compID = ComponentID(componentIndex);
              ::memcpy( m_puhQTTempCbf[compID], pcCU->getCbf( compID )+uiPartOffset, uiQPartNum * sizeof( UChar ) );
              ::memcpy( m_puhQTTempTransformSkipFlag[compID], pcCU->getTransformSkip( compID )+uiPartOffset, uiQPartNum * sizeof( UChar ) );
              ::memcpy( m_phQTTempCrossComponentPredictionAlpha[compID], pcCU->getCrossComponentPredictionAlpha(compID)+uiPartOffset, uiQPartNum * sizeof( Char ) );
            }
#endif
          }
        }
//此循环结束,即在11中模式中选择了代价最小的一种预测模式/
        DEBUG_STRING_APPEND(sDebug, sPU)
        //----- set data -----
#if JVET_C0024_QTBT
        UInt uiRaster = g_auiZscanToRaster[pcCU->getZorderIdxInCtu()];
        for (UInt i=0; i<uiLong; i+=uiShort)
        {
            UInt uiZorder = g_auiRasterToZscan[uiRaster] - pcCU->getZorderIdxInCtu();
            for (UInt componentIndex = COMPONENT_Cb; componentIndex < numberValidComponents; componentIndex++)
            {
                const ComponentID compID = ComponentID(componentIndex);
                ::memcpy( pcCU->getCbf( compID )+uiZorder, m_puhQTTempCbf[compID]+uiZorder, uiCurrPartNumb );
                ::memcpy( pcCU->getTransformSkip( compID )+uiZorder, m_puhQTTempTransformSkipFlag[compID]+uiZorder, uiCurrPartNumb );
                ::memcpy( pcCU->getCrossComponentPredictionAlpha(compID)+uiZorder, m_phQTTempCrossComponentPredictionAlpha[compID]+uiZorder, uiCurrPartNumb );
            }
            uiRaster += uiNumPartInShort * uiStr;
        }
#else
        for (UInt componentIndex = COMPONENT_Cb; componentIndex < numberValidComponents; componentIndex++)
        {
          const ComponentID compID = ComponentID(componentIndex);
          ::memcpy( pcCU->getCbf( compID )+uiPartOffset, m_puhQTTempCbf[compID], uiQPartNum * sizeof( UChar ) );
          ::memcpy( pcCU->getTransformSkip( compID )+uiPartOffset, m_puhQTTempTransformSkipFlag[compID], uiQPartNum * sizeof( UChar ) );
          ::memcpy( pcCU->getCrossComponentPredictionAlpha(compID)+uiPartOffset, m_phQTTempCrossComponentPredictionAlpha[compID], uiQPartNum * sizeof( Char ) );
        }
#endif
      }
      if( ! tuRecurseWithPU.IsLastSection() )
      {
#if JVET_C0024_QTBT
          assert(0);
#endif
        for (UInt ch=COMPONENT_Cb; ch<numberValidComponents; ch++)
        {
          const ComponentID compID    = ComponentID(ch);
          const TComRectangle &tuRect = tuRecurseWithPU.getRect(compID);
          const UInt  uiCompWidth     = tuRect.width;
          const UInt  uiCompHeight    = tuRect.height;
          const UInt  uiZOrder        = pcCU->getZorderIdxInCtu() + tuRecurseWithPU.GetAbsPartIdxTU();
                Pel*  piDes           = pcCU->getPic()->getPicYuvRec()->getAddr( compID, pcCU->getCtuRsAddr(), uiZOrder );
          const UInt  uiDesStride     = pcCU->getPic()->getPicYuvRec()->getStride( compID);
          const Pel*  piSrc           = pcRecoYuv->getAddr( compID, uiPartOffset );
          const UInt  uiSrcStride     = pcRecoYuv->getStride( compID);
          for( UInt uiY = 0; uiY < uiCompHeight; uiY++, piSrc += uiSrcStride, piDes += uiDesStride )
          {
            for( UInt uiX = 0; uiX < uiCompWidth; uiX++ )
            {
              piDes[ uiX ] = piSrc[ uiX ];
            }
          }
        }
      }
      pcCU->setIntraDirSubParts( CHANNEL_TYPE_CHROMA, uiBestMode, uiPartOffset, uiDepthCU+uiInitTrDepth );

      pcCU->getTotalDistortion      () += uiBestDist;
    }

  } while (tuRecurseWithPU.nextSection(tuRecurseCU));
do while循环结束//
  //----- restore context models -----
#if !JVET_C0024_QTBT
  if( uiInitTrDepth != 0 )
  { // set Cbf for all blocks
    UInt uiCombCbfU = 0;
    UInt uiCombCbfV = 0;
    UInt uiPartIdx  = 0;
    for( UInt uiPart = 0; uiPart < 4; uiPart++, uiPartIdx += uiQNumParts )
    {
      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_Cb )[ uiOffs ] |= uiCombCbfU;
      pcCU->getCbf( COMPONENT_Cr )[ uiOffs ] |= uiCombCbfV;
    }
  }
#endif
#if JVET_C0024_QTBT
  m_pcRDGoOnSbacCoder->load( m_ppppcRDSbacCoder[uiWIdx][uiHIdx][CI_CURR_BEST] );
#else
  m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[uiDepthCU][CI_CURR_BEST] );
#endif
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值