慢慢积累

菜鸟一只,多多包涵

H.266代码学习:xCheckRDCostMerge2Nx2N函数

今天来学习一下JEM中的xCheckRDCostMerge2Nx2N函数。之前HEVC代码学习31:xCheckRDCostMerge2Nx2N函数已经学习了HEVC中的xCheckRDCostMerge2Nx2N函数,JEM中相比HM变化不大,主要是新加入了TMVP新技术。

xCheckRDCostMerge2Nx2N

xCheckRDCostMerge2Nx2N是帧间Merge模式的入口函数,其中会构造Merge候选列表,遍历列表进行运动补偿,通过比较RD cost,最终得到最优MV和最优模式信息。

JEM与HM主要区别有:
JEM中加入了ATMVP和STMVP新Merge模式(https://blog.csdn.net/lin453701006/article/details/78924053,这两个技术我也不熟悉,只是大概看了下,我也是一知半解),在xCheckRDCostMerge2Nx2N增加了这两种新模式相关的代码。

流程如下:
1. 调用getInterMergeCandidates构造候选列表。这里会同步构建一个列表eMergeCandTypeNieghors记录Merge候选类型,0-传统,1-ATMVP,2-STMVP。
2. 遍历候选列表,如果有TMVP候选,先处理子块:
(1) 调用motionCompensation进行运动补偿。
(2) 调用encodeResAndCalcRdInterCU计算残差和RD cost
并进行编码。
(3) 比较选出最优MV和最优模式信息。

代码分析:

/** check RD costs for a CU block encoded with merge
 * \param rpcBestCU
 * \param rpcTempCU
 * \param earlyDetectionSkipMode
 */
//计算2Nx2N块Merge下的RD代价
Void TEncCu::xCheckRDCostMerge2Nx2N( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU DEBUG_STRING_FN_DECLARE(sDebug), Bool *earlyDetectionSkipMode )
{
#if JVET_C0024_QTBT
  UInt uiWIdx = g_aucConvertToBit[rpcBestCU->getWidth(0)];      //宽度用bit位数表示
  UInt uiHIdx = g_aucConvertToBit[rpcBestCU->getHeight(0)];     //高度用bit位数表示
#else
#if COM16_C806_LARGE_CTU
  if( m_pcEncCfg->getUseFastLCTU() && rpcTempCU->getHeight( 0 ) * 2 > rpcTempCU->getSlice()->getSPS()->getPicHeightInLumaSamples() )
  {
    rpcTempCU->getTotalCost() = MAX_DOUBLE / 4;
    rpcTempCU->getTotalDistortion() = MAX_INT;
    xCheckBestMode(rpcBestCU, rpcTempCU, rpcTempCU->getDepth( 0 ));
    return;
  }
#endif
#endif

  assert( rpcTempCU->getSlice()->getSliceType() != I_SLICE );
  if(getFastDeltaQp())          //快速DeltaQP下不进行merge检测
  {
    return;   // never check merge in fast deltaqp mode
  }
  TComMvField  cMvFieldNeighbours[2 * MRG_MAX_NUM_CANDS]; // double length for mv of both lists     //双向候选列表
  UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS];        //参考方向
  Int numValidMergeCand = 0;        //可用候选数
  const Bool bTransquantBypassFlag = rpcTempCU->getCUTransquantBypass(0);       //跳过变换量化
#if COM16_C806_VCEG_AZ10_SUB_PU_TMVP        //子PU TMVP
  UChar  eMergeCandTypeNieghors[MRG_MAX_NUM_CANDS]; 
  memset ( eMergeCandTypeNieghors, MGR_TYPE_DEFAULT_N, sizeof(UChar)*MRG_MAX_NUM_CANDS );
#endif
#if VCEG_AZ06_IC
  Bool abICFlag[MRG_MAX_NUM_CANDS];         //IC亮度补偿
#endif
  //初始化候选列表参考方向
  for( UInt ui = 0; ui < rpcTempCU->getSlice()->getMaxNumMergeCand(); ++ui )
  {
    uhInterDirNeighbours[ui] = 0;
  }
  UChar uhDepth = rpcTempCU->getDepth( 0 );     //当前CU深度
#if !JVET_C0024_QTBT
  rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth ); // interprets depth relative to CTU level
#endif


#if COM16_C806_VCEG_AZ10_SUB_PU_TMVP
#if !JVET_C0024_QTBT  
  for (Int i=0 , i2 = 0 ; i< rpcTempCU->getTotalNumPart(); i++ , i2 += 2)
  {
#if JVET_C0035_ATMVP_SIMPLIFICATION
    for (Int j=0; j < NUM_MGR_TYPE ; j++)
    {
      m_phInterDirSP[j][i] = 0;
      m_pMvFieldSP[j][i2].setRefIdx(-1);
      m_pMvFieldSP[j][i2+1].setRefIdx(-1);
    }
#else
    m_phInterDirSP[1][i] = 0;
    m_pMvFieldSP[1][i2].setRefIdx(-1);
    m_pMvFieldSP[1][i2+1].setRefIdx(-1);
#endif
  }
#endif
#endif
  //获取帧间Merge候选
  rpcTempCU->getInterMergeCandidates( 0, 0, cMvFieldNeighbours,uhInterDirNeighbours, numValidMergeCand
#if VCEG_AZ06_IC
    , abICFlag
#endif
#if COM16_C806_VCEG_AZ10_SUB_PU_TMVP
    , eMergeCandTypeNieghors        //指示Merge候选类型:0-传统,1-ATMVP,2-STMVP
    , m_pMvFieldSP
    , m_phInterDirSP
#endif
    );

  for( UInt ui = 0; ui < rpcTempCU->getSlice()->getMaxNumMergeCand(); ++ui )
  {
      printf("%d,%d ",uhInterDirNeighbours[ui],eMergeCandTypeNieghors[ui]);
  }
  printf("\n");

  //Merge候选
  Int mergeCandBuffer[MRG_MAX_NUM_CANDS];
  for( UInt ui = 0; ui < numValidMergeCand; ++ui )
  {
    mergeCandBuffer[ui] = 0;        //初始化
  }

#if JVET_C0024_FAST_MRG
  //跳过
  Bool bestIsSkip = rpcBestCU->getPic()->getSkiped(rpcBestCU->getZorderIdxInCtu(), rpcBestCU->getWidth(0), rpcBestCU->getHeight(0));
  UInt uiNumMrgSATDCand = NUM_MRG_SATD_CAND;        //SATD判断候选数
  UInt uiRdModeList[MRG_MAX_NUM_CANDS];     //RD模式列表
  Double CandCostList[MRG_MAX_NUM_CANDS];       //候选代价列表
  for (UInt i=0; i<MRG_MAX_NUM_CANDS; i++)
  {
    uiRdModeList[i] = i;
    CandCostList[i] = MAX_DOUBLE;
  }

  Bool bMrgTempBufSet = false;
  if (!bestIsSkip)      //不跳过
  {
#if JVET_D0123_ME_CTX_LUT_BITS
    UInt uiMrgIdxBits[MRG_MAX_NUM_CANDS];
    m_pcPredSearch->getMrgCandBits(rpcBestCU, 0, uiMrgIdxBits);     //计算候选bit数
#endif
    bMrgTempBufSet = true;
    //遍历候选
    for( UInt uiMergeCand = 0; uiMergeCand < numValidMergeCand; ++uiMergeCand )
    {
      // set MC parameters  设置MC参数
      rpcTempCU->setPredModeSubParts( MODE_INTER, 0, uhDepth ); // interprets depth relative to CTU level   
      rpcTempCU->setCUTransquantBypassSubParts( bTransquantBypassFlag, 0, uhDepth );    
      rpcTempCU->setChromaQpAdjSubParts( bTransquantBypassFlag ? 0 : m_cuChromaQpOffsetIdxPlus1, 0, uhDepth );

      rpcTempCU->setMergeFlagSubParts( true, 0, 0, uhDepth ); // interprets depth relative to CTU level
      rpcTempCU->setMergeIndexSubParts( uiMergeCand, 0, 0, uhDepth ); // interprets depth relative to CTU level
#if COM16_C806_OBMC
      rpcTempCU->setOBMCFlagSubParts( true, 0, uhDepth );
#endif
#if VCEG_AZ06_IC
      rpcTempCU->setICFlagSubParts( rpcTempCU->getSlice()->getApplyIC() ? abICFlag[uiMergeCand] : 0, 0, uhDepth );
#endif
#if COM16_C806_VCEG_AZ10_SUB_PU_TMVP
      rpcTempCU->setMergeTypeSubParts(eMergeCandTypeNieghors[uiMergeCand] , 0, 0, uhDepth ); 
      if( eMergeCandTypeNieghors[uiMergeCand])      //如果使用ATMVP或STMVP
      {
        UInt uiSPAddr;
        Int iWidth = rpcTempCU->getWidth(0);    //宽度
        Int iHeight = rpcTempCU->getHeight(0);      //高度

        Int iNumSPInOneLine, iNumSP, iSPWidth, iSPHeight;
#if JVET_C0035_ATMVP_SIMPLIFICATION
        UInt uiSPListIndex = eMergeCandTypeNieghors[uiMergeCand];
#else
        UInt uiSPListIndex = eMergeCandTypeNieghors[uiMergeCand] == MGR_TYPE_SUBPU_TMVP?0:1;
#endif
        rpcTempCU->getSPPara(iWidth, iHeight, iNumSP, iNumSPInOneLine, iSPWidth, iSPHeight);        //获取分块数量
        //遍历分块设置分块MV
        for (Int iPartitionIdx = 0; iPartitionIdx < iNumSP; iPartitionIdx++)
        {
          rpcTempCU->getSPAbsPartIdx(0, iSPWidth, iSPHeight, iPartitionIdx, iNumSPInOneLine, uiSPAddr);
          rpcTempCU->setInterDirSP(m_phInterDirSP[uiSPListIndex][iPartitionIdx], uiSPAddr, iSPWidth, iSPHeight);
          rpcTempCU->getCUMvField( REF_PIC_LIST_0 )->setMvFieldSP(rpcTempCU, uiSPAddr, m_pMvFieldSP[uiSPListIndex][2*iPartitionIdx], iSPWidth, iSPHeight);
          rpcTempCU->getCUMvField( REF_PIC_LIST_1 )->setMvFieldSP(rpcTempCU, uiSPAddr, m_pMvFieldSP[uiSPListIndex][2*iPartitionIdx + 1], iSPWidth, iSPHeight);
        }
      }
      else
      {
#endif
        rpcTempCU->setInterDirSubParts( uhInterDirNeighbours[uiMergeCand], 0, 0, uhDepth ); // interprets depth relative to CTU level
        rpcTempCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMvFieldNeighbours[0 + 2*uiMergeCand], SIZE_2Nx2N, 0, 0 ); // interprets depth relative to rpcTempCU level
        rpcTempCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMvFieldNeighbours[1 + 2*uiMergeCand], SIZE_2Nx2N, 0, 0 ); // interprets depth relative to rpcTempCU level
#if COM16_C806_VCEG_AZ10_SUB_PU_TMVP
      }
#endif

      m_pcMrgPredTempYuv[uiMergeCand]->setWidth(rpcBestCU->getWidth(0));
      m_pcMrgPredTempYuv[uiMergeCand]->setHeight(rpcBestCU->getHeight(0));
      //运动补偿
      m_pcPredSearch->motionCompensation ( rpcTempCU, m_pcMrgPredTempYuv[uiMergeCand] );
#if COM16_C806_OBMC
      //子块重叠块运动补偿
      m_pcPredSearch->subBlockOBMC( rpcTempCU, 0, m_pcMrgPredTempYuv[uiMergeCand], m_pppcTmpYuv1[uiWIdx][uiHIdx], m_pppcTmpYuv2[uiWIdx][uiHIdx] );
#endif
#if JVET_E0052_DMVR
// the mv may be changed in the mv refinement during the MC
  //重新设置MV
  if (uhInterDirNeighbours[uiMergeCand]==3 && eMergeCandTypeNieghors[uiMergeCand]== MGR_TYPE_DEFAULT_N)
  {
      cMvFieldNeighbours[0 + 2*uiMergeCand].getMv() = rpcTempCU->getCUMvField(REF_PIC_LIST_0)->getMv(0);
      cMvFieldNeighbours[1 + 2*uiMergeCand].getMv() = rpcTempCU->getCUMvField(REF_PIC_LIST_1)->getMv(0);
  }
  else if (eMergeCandTypeNieghors[uiMergeCand] != MGR_TYPE_DEFAULT_N)
  {
      UInt uiSPAddr;
      Int iWidth = rpcTempCU->getWidth(0);
      Int iHeight = rpcTempCU->getHeight(0);

      Int iNumSPInOneLine, iNumSP, iSPWidth, iSPHeight;
#if JVET_C0035_ATMVP_SIMPLIFICATION
      UInt uiSPListIndex = eMergeCandTypeNieghors[uiMergeCand];
#else
      UInt uiSPListIndex = eMergeCandTypeNieghors[uiMergeCand] == MGR_TYPE_SUBPU_TMVP ? 0 : 1;
#endif
      rpcTempCU->getSPPara(iWidth, iHeight, iNumSP, iNumSPInOneLine, iSPWidth, iSPHeight);

    for (Int iPartitionIdx = 0; iPartitionIdx < iNumSP; iPartitionIdx++)
    {
      if (m_phInterDirSP[uiSPListIndex][iPartitionIdx] == 3)
      {
        rpcTempCU->getSPAbsPartIdx(0, iSPWidth, iSPHeight, iPartitionIdx, iNumSPInOneLine, uiSPAddr);
        m_pMvFieldSP[uiSPListIndex][2 * iPartitionIdx].getMv() = rpcTempCU->getCUMvField(REF_PIC_LIST_0)->getMv(uiSPAddr);
        m_pMvFieldSP[uiSPListIndex][2 * iPartitionIdx + 1].getMv() = rpcTempCU->getCUMvField(REF_PIC_LIST_1)->getMv(uiSPAddr);
      }
    }
  }   
#endif
      // use hadamard transform here    使用HAD变换
      DistParam distParam;
      const Bool bUseHadamard=rpcTempCU->getCUTransquantBypass(0) == 0;     //是否使用HAD变换
      //初始化失真
      m_pcRdCost->setDistParam(distParam, rpcTempCU->getSlice()->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA), m_pppcOrigYuv[uiWIdx][uiHIdx]->getAddr(COMPONENT_Y)
        , m_pppcOrigYuv[uiWIdx][uiHIdx]->getStride(COMPONENT_Y)
        , m_pcMrgPredTempYuv[uiMergeCand]->getAddr(COMPONENT_Y), m_pcMrgPredTempYuv[uiMergeCand]->getStride(COMPONENT_Y)
        , rpcTempCU->getWidth(0), rpcTempCU->getHeight(0), bUseHadamard);
      distParam.bApplyWeight = false;

      UInt uiSad = distParam.DistFunc(&distParam);      //计算失真
#if JVET_D0123_ME_CTX_LUT_BITS
      UInt uiBitsCand = uiMrgIdxBits[uiMergeCand];      //bit数
      Double cost  = (Double)uiSad + (Double)uiBitsCand/((Double)EPBIT) * m_pcRdCost->getSqrtLambda();      //计算率失真代价
#else
      UInt uiBitsCand = uiMergeCand + 1;                                         
      if (uiMergeCand == rpcTempCU->getSlice()->getMaxNumMergeCand() -1)
      {
        uiBitsCand--;
      }   
      Double cost      = (Double)uiSad + (Double)uiBitsCand * m_pcRdCost->getSqrtLambda();
#endif
      TEncSearch::updateCandList( uiMergeCand, cost, uiNumMrgSATDCand, uiRdModeList, CandCostList );        //更新Merge候选列表
    }
    //初始化SATD候选列表
    for (UInt i=1; i<uiNumMrgSATDCand; i++)
    {
      if (CandCostList[i] > MRG_FAST_RATIO*CandCostList[0])
      {
        uiNumMrgSATDCand = i;
        break;
      }
    }
  }
#else
  Bool bestIsSkip = false;
#endif

  UInt iteration;
  //默认为false,iteration = 2
  if ( rpcTempCU->isLosslessCoded(0))
  {
    iteration = 1;
  }
  else
  {
    iteration = 2;
  }
  DEBUG_STRING_NEW(bestStr)
  //遍历两次,第一次无残差编码,第二次对残差编码
  for( UInt uiNoResidual = 0; uiNoResidual < iteration; ++uiNoResidual )
  {
#if JVET_C0024_FAST_MRG
      for( UInt uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; ++uiMrgHADIdx )
      {
        UInt uiMergeCand = uiRdModeList[uiMrgHADIdx];
#else
    for( UInt uiMergeCand = 0; uiMergeCand < numValidMergeCand; ++uiMergeCand )
    {
#endif
        //当uiNoResidual==0或mergeCandBuffer[uiMergeCand]==0时成立
      if(!(uiNoResidual==1 && mergeCandBuffer[uiMergeCand]==1))
      {
          //当bestIsSkip为false或uiNoResidual==1时成立
        if( !(bestIsSkip && uiNoResidual == 0) )
        {
          DEBUG_STRING_NEW(tmpStr)
          // set MC parameters 设置MC参数
          rpcTempCU->setPredModeSubParts( MODE_INTER, 0, uhDepth ); // interprets depth relative to CTU level
          rpcTempCU->setCUTransquantBypassSubParts( bTransquantBypassFlag, 0, uhDepth );
          rpcTempCU->setChromaQpAdjSubParts( bTransquantBypassFlag ? 0 : m_cuChromaQpOffsetIdxPlus1, 0, uhDepth );
#if !JVET_C0024_QTBT
          rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth ); // interprets depth relative to CTU level
#endif
          rpcTempCU->setMergeFlagSubParts( true, 0, 0, uhDepth ); // interprets depth relative to CTU level
          rpcTempCU->setMergeIndexSubParts( uiMergeCand, 0, 0, uhDepth ); // interprets depth relative to CTU level
#if COM16_C806_OBMC
          rpcTempCU->setOBMCFlagSubParts( true, 0, uhDepth );
#endif
#if VCEG_AZ06_IC
          rpcTempCU->setICFlagSubParts( rpcTempCU->getSlice()->getApplyIC() ? abICFlag[uiMergeCand] : 0, 0, uhDepth );
#endif
#if COM16_C806_VCEG_AZ10_SUB_PU_TMVP //TMVP
          rpcTempCU->setMergeTypeSubParts(eMergeCandTypeNieghors[uiMergeCand] , 0, 0, uhDepth ); 
          if( eMergeCandTypeNieghors[uiMergeCand])
          {
            UInt uiSPAddr;
            Int iWidth = rpcTempCU->getWidth(0);
            Int iHeight = rpcTempCU->getHeight(0);

            Int iNumSPInOneLine, iNumSP, iSPWidth, iSPHeight;
#if JVET_C0035_ATMVP_SIMPLIFICATION
            UInt uiSPListIndex = eMergeCandTypeNieghors[uiMergeCand];
#else
            UInt uiSPListIndex = eMergeCandTypeNieghors[uiMergeCand] == MGR_TYPE_SUBPU_TMVP?0:1;
#endif
            rpcTempCU->getSPPara(iWidth, iHeight, iNumSP, iNumSPInOneLine, iSPWidth, iSPHeight);

            for (Int iPartitionIdx = 0; iPartitionIdx < iNumSP; iPartitionIdx++)
            {
              rpcTempCU->getSPAbsPartIdx(0, iSPWidth, iSPHeight, iPartitionIdx, iNumSPInOneLine, uiSPAddr);
              rpcTempCU->setInterDirSP(m_phInterDirSP[uiSPListIndex][iPartitionIdx], uiSPAddr, iSPWidth, iSPHeight);
              rpcTempCU->getCUMvField( REF_PIC_LIST_0 )->setMvFieldSP(rpcTempCU, uiSPAddr, m_pMvFieldSP[uiSPListIndex][2*iPartitionIdx], iSPWidth, iSPHeight);
              rpcTempCU->getCUMvField( REF_PIC_LIST_1 )->setMvFieldSP(rpcTempCU, uiSPAddr, m_pMvFieldSP[uiSPListIndex][2*iPartitionIdx + 1], iSPWidth, iSPHeight);
            }
          }
          else
          {
#endif
          rpcTempCU->setInterDirSubParts( uhInterDirNeighbours[uiMergeCand], 0, 0, uhDepth ); // interprets depth relative to CTU level
          rpcTempCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMvFieldNeighbours[0 + 2*uiMergeCand], SIZE_2Nx2N, 0, 0 ); // interprets depth relative to rpcTempCU level
          rpcTempCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMvFieldNeighbours[1 + 2*uiMergeCand], SIZE_2Nx2N, 0, 0 ); // interprets depth relative to rpcTempCU level
#if COM16_C806_VCEG_AZ10_SUB_PU_TMVP
          }
#endif
          // do MC 运动补偿
#if JVET_C0024_QTBT
#if JVET_C0024_FAST_MRG
            if (bMrgTempBufSet)
            {
              m_pcMrgPredTempYuv[uiMergeCand]->copyToPartYuv(m_pppcPredYuvTemp[uiWIdx][uiHIdx], 0);
            }
            else
            {
              m_pcPredSearch->motionCompensation ( rpcTempCU, m_pppcPredYuvTemp[uiWIdx][uiHIdx] );
#if COM16_C806_OBMC
              m_pcPredSearch->subBlockOBMC( rpcTempCU, 0, m_pppcPredYuvTemp[uiWIdx][uiHIdx], m_pppcTmpYuv1[uiWIdx][uiHIdx], m_pppcTmpYuv2[uiWIdx][uiHIdx] );
#endif
            }
#else
            m_pcPredSearch->motionCompensation ( rpcTempCU, m_pppcPredYuvTemp[uiWIdx][uiHIdx] );
#if COM16_C806_OBMC
            m_pcPredSearch->subBlockOBMC( rpcTempCU, 0, m_pppcPredYuvTemp[uiWIdx][uiHIdx], m_pppcTmpYuv1[uiWIdx][uiHIdx], m_pppcTmpYuv2[uiWIdx][uiHIdx] );
#endif
#endif
            // estimate residual and encode everything 计算残差和RD cost,并进行编码
            m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU,
              m_pppcOrigYuv    [uiWIdx][uiHIdx],
              m_pppcPredYuvTemp[uiWIdx][uiHIdx],
              m_pppcResiYuvTemp[uiWIdx][uiHIdx],
              m_pppcResiYuvBest[uiWIdx][uiHIdx],
              m_pppcRecoYuvTemp[uiWIdx][uiHIdx],
              (uiNoResidual != 0) 
#if COM16_C806_EMT
              , rpcBestCU->getTotalCost()
#endif
              DEBUG_STRING_PASS_INTO(tmpStr) );

#if DEBUG_STRING
            DebugInterPredResiReco(tmpStr, *(m_ppcPredYuvTemp[uhDepth]), *(m_ppcResiYuvBest[uhDepth]), *(m_ppcRecoYuvTemp[uhDepth]), DebugStringGetPredModeMask(rpcTempCU->getPredictionMode(0)));
#endif
#else
          m_pcPredSearch->motionCompensation ( rpcTempCU, m_ppcPredYuvTemp[uhDepth] );
#if COM16_C806_OBMC
          m_pcPredSearch->subBlockOBMC( rpcTempCU, 0, m_ppcPredYuvTemp[uhDepth], m_ppcTmpYuv1[uhDepth], m_ppcTmpYuv2[uhDepth] );
#endif
          // estimate residual and encode everything
          m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU,
                                                     m_ppcOrigYuv    [uhDepth],
                                                     m_ppcPredYuvTemp[uhDepth],
                                                     m_ppcResiYuvTemp[uhDepth],
                                                     m_ppcResiYuvBest[uhDepth],
                                                     m_ppcRecoYuvTemp[uhDepth],
                                                     (uiNoResidual != 0) 
#if COM16_C806_EMT
                                                     , rpcBestCU->getTotalCost()
#endif
                                                     DEBUG_STRING_PASS_INTO(tmpStr) );

#if DEBUG_STRING
          DebugInterPredResiReco(tmpStr, *(m_ppcPredYuvTemp[uhDepth]), *(m_ppcResiYuvBest[uhDepth]), *(m_ppcRecoYuvTemp[uhDepth]), DebugStringGetPredModeMask(rpcTempCU->getPredictionMode(0)));
#endif
#endif
          //第一次迭代时执行
          if ((uiNoResidual == 0) && (rpcTempCU->getQtRootCbf(0) == 0))
          {
            // If no residual when allowing for one, then set mark to not try case where residual is forced to 0
            mergeCandBuffer[uiMergeCand] = 1;
          }

          Int orgQP = rpcTempCU->getQP( 0 );
          xCheckDQP( rpcTempCU );
          xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth DEBUG_STRING_PASS_INTO(bestStr) DEBUG_STRING_PASS_INTO(tmpStr));

          rpcTempCU->initEstData( uhDepth, orgQP, bTransquantBypassFlag );

          if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip )
          {
            bestIsSkip = rpcBestCU->getQtRootCbf(0) == 0;
          }
        }
      }
    }
    //如果开启earlyDetectionSkip时,第一次迭代执行
    if(uiNoResidual == 0 && m_pcEncCfg->getUseEarlySkipDetection())
    {
      if(rpcBestCU->getQtRootCbf( 0 ) == 0)
      {
        if( rpcBestCU->getMergeFlag( 0 ))
        {
          *earlyDetectionSkipMode = true;
        }
        else if(m_pcEncCfg->getFastSearch() != SELECTIVE)
        {
          Int absoulte_MV=0;
          for ( UInt uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ )
          {
            if ( rpcBestCU->getSlice()->getNumRefIdx( RefPicList( uiRefListIdx ) ) > 0 )
            {
              TComCUMvField* pcCUMvField = rpcBestCU->getCUMvField(RefPicList( uiRefListIdx ));
              Int iHor = pcCUMvField->getMvd( 0 ).getAbsHor();
              Int iVer = pcCUMvField->getMvd( 0 ).getAbsVer();
              absoulte_MV+=iHor+iVer;
            }
          }

          if(absoulte_MV == 0)
          {
            *earlyDetectionSkipMode = true;
          }
        }
      }
    }
  }
  DEBUG_STRING_APPEND(sDebug, bestStr)
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lin453701006/article/details/80690126
个人分类: H.266/VVC
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭