VTM1.0代码阅读:xCheckRDCostMerge2Nx2N函数

xCheckRDCostMerge2Nx2N在xCompressCU函数中调用,用来进行Merge模式的计算。skip模式相较于Merge模式,不向解码端发送残差系数。
首先由getInterMergeCandidates获取merge候选模式信息,存储于mergeCtx;
如果不进行fastMerge,则跳过SATD直接进行RDO选最优;
fastMerge时,对7个merge候选模式进行SATD,分别进行MC获得pred像素,选取cost最小的4个merge候选;
对RdModeList中的merge候选进行RDO选择最优的merge模式。

void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
  const Slice &slice = *tempCS->slice;

  CHECK( slice.getSliceType() == I_SLICE, "Merge modes not available for I-slices" );

  tempCS->initStructData( encTestMode.qp, encTestMode.lossless );		//tempCS清空初始化

  MergeCtx mergeCtx;						//MergeCtx类中存放merge列表的所有信息
  const SPS &sps = *tempCS->sps;

  {
    // first get merge candidates
    CodingUnit cu( tempCS->area );			//创建cu、pu用来获得merge列表
    cu.cs       = tempCS;
    cu.partSize = SIZE_2Nx2N;
    cu.predMode = MODE_INTER;
    cu.slice    = tempCS->slice;
#if HEVC_TILES_WPP
    cu.tileIdx  = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
#endif

    PredictionUnit pu( tempCS->area );
    pu.cu = &cu;
    pu.cs = tempCS;

    PU::getInterMergeCandidates(pu, mergeCtx);		//获取merge列表,其中包含7个merge候选信息,存储于mergeCtx
  }


  bool candHasNoResidual[MRG_MAX_NUM_CANDS];		//若merge模式没有resi,则为skip模式
  for (UInt ui = 0; ui < mergeCtx.numValidMergeCand; ui++)
  {
    candHasNoResidual[ui] = false;
  }

  bool                                        bestIsSkip       = false;
  unsigned                                    uiNumMrgSATDCand = mergeCtx.numValidMergeCand;	//SATD粗选择后的merge候选数目
  PelUnitBuf                                  acMergeBuffer    [ MRG_MAX_NUM_CANDS ];	
  														//存储SATD时,7个merge候选经过MC得到的pred像素信息
  static_vector<unsigned, MRG_MAX_NUM_CANDS>  RdModeList;
  bool                                        mrgTempBufSet    = false;

  for( unsigned i = 0; i < MRG_MAX_NUM_CANDS; i++ )
  {
    RdModeList.push_back( i );			//如果不进行SATD,那么RdModeList中存放7个merge候选,直接进行最后的RDO
  }

  if( m_pcEncCfg->getUseFastMerge() )
  {
    uiNumMrgSATDCand = NUM_MRG_SATD_CAND;		//SATD粗选择后的merge候选数目,4
    bestIsSkip       = false;

    if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) )
    {
      bestIsSkip = blkCache->isSkip( tempCS->area );
    }

    static_vector<double, MRG_MAX_NUM_CANDS> candCostList;		//存放SATD时得到的7个候选的cost

    // 1. Pass: get SATD-cost for selected candidates and reduce their count
    if( !bestIsSkip )						//不是skip模式,对7个merge候选模式进行SATD粗选择
    {
      RdModeList.clear();			//RdModeList前面有压栈操作,这里清空
      mrgTempBufSet       = true;
      const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda( encTestMode.lossless );

      CodingUnit &cu      = tempCS->addCU( tempCS->area, partitioner.chType );		//tempCS添加cu和pu

      partitioner.setCUData( cu );
      cu.slice            = tempCS->slice;
#if HEVC_TILES_WPP
      cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
      cu.skip             = false;
      cu.partSize         = SIZE_2Nx2N;
    //cu.affine
      cu.predMode         = MODE_INTER;
    //cu.LICFlag
      cu.transQuantBypass = encTestMode.lossless;
      cu.chromaQpAdj      = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
      cu.qp               = encTestMode.qp;
    //cu.emtFlag  is set below

      PredictionUnit &pu  = tempCS->addPU( cu, partitioner.chType );

      DistParam distParam;
      const Bool bUseHadamard= !encTestMode.lossless;							//设置计算失真的类:distParam 的各项参数
      m_pcRdCost->setDistParam (distParam, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y(), sps.getBitDepth (CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);

      const UnitArea localUnitArea( tempCS->area.chromaFormat, Area( 0, 0, tempCS->area.Y().width, tempCS->area.Y().height) );

      for( UInt uiMergeCand = 0; uiMergeCand < mergeCtx.numValidMergeCand; uiMergeCand++ )		//7个merge候选进行SATD
      {
        acMergeBuffer[uiMergeCand] = m_acMergeBuffer[uiMergeCand].getBuf( localUnitArea );

        mergeCtx.setMergeInfo( pu, uiMergeCand );

        PU::spanMotionInfo( pu, mergeCtx );

        distParam.cur = acMergeBuffer[uiMergeCand].Y();			//计算失真时的pred像素存储于acMergeBuffer[uiMergeCand]

        m_pcInterSearch->motionCompensation( pu,  acMergeBuffer[uiMergeCand] );		//MC,得到的pred像素存储于acMergeBuffer[uiMergeCand]
        
        if( mergeCtx.interDirNeighbours[uiMergeCand] == 3 && mergeCtx.mrgTypeNeighbours[uiMergeCand] == MRG_TYPE_DEFAULT_N )
        {
          mergeCtx.mvFieldNeighbours[2*uiMergeCand].mv   = pu.mv[0];		//双向预测时
          mergeCtx.mvFieldNeighbours[2*uiMergeCand+1].mv = pu.mv[1];
        }

        UInt uiSad      = distParam.distFunc( distParam );	//对比pred和orig计算失真
        UInt uiBitsCand = uiMergeCand + 1;
        if( uiMergeCand == tempCS->slice->getMaxNumMergeCand() - 1 )
        {
          uiBitsCand--;
        }
        Double cost     = (Double)uiSad + (Double)uiBitsCand * sqrtLambdaForFirstPass;		//cost

        updateCandList( uiMergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand );	//按照cost大小将merge候选模式在RdModeList中排序

        CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" );
      }

      // Try to limit number of candidates using SATD-costs
      for( UInt i = 1; i < uiNumMrgSATDCand; i++ )		//按照1.25*min cost mode,限制SATD后选择候选的个数
      {
        if( candCostList[i] > MRG_FAST_RATIO * candCostList[0] )
        {
          uiNumMrgSATDCand = i;
          break;
        }
      }

      tempCS->initStructData( encTestMode.qp, encTestMode.lossless );	//tempCS清空
    }
  }

  const UInt iteration = encTestMode.lossless ? 1 : 2;

  // 2. Pass: check candidates using full RD test
  for( UInt uiNoResidualPass = 0; uiNoResidualPass < iteration; uiNoResidualPass++ )
  {
    for( UInt uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ )		//RDO选择RdModeList中的最优merge模式
    {
      UInt uiMergeCand = RdModeList[uiMrgHADIdx];

      if( ( (uiNoResidualPass != 0) && candHasNoResidual[uiMergeCand] )
       || ( (uiNoResidualPass == 0) && bestIsSkip ) )
      {
        continue;
      }

      // first get merge candidates
      CodingUnit &cu      = tempCS->addCU( tempCS->area, partitioner.chType );		//tempCS添加cu和pu

      partitioner.setCUData( cu );
      cu.slice            = tempCS->slice;
#if HEVC_TILES_WPP
      cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
      cu.skip             = false;
      cu.partSize         = SIZE_2Nx2N;
    //cu.affine
      cu.predMode         = MODE_INTER;
    //cu.LICFlag
      cu.transQuantBypass = encTestMode.lossless;
      cu.chromaQpAdj      = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
      cu.qp               = encTestMode.qp;
      PredictionUnit &pu  = tempCS->addPU( cu, partitioner.chType );

      mergeCtx.setMergeInfo( pu, uiMergeCand );			//将merge候选信息赋给pu以及整个tempCS
      PU::spanMotionInfo( pu, mergeCtx );

      if( mrgTempBufSet )		//如果进行了SATD,mrgTempBufSet为true,直接获取到SATD时的pred像素
      {
        tempCS->getPredBuf().copyFrom( acMergeBuffer[ uiMergeCand ]);
      }
      else
      {
        m_pcInterSearch->motionCompensation( pu );		//之前没有SATD,通过MC获取pred像素信息
        
      }
					//由orig和pred像素信息,获得resi,可得到reco像素
					//分别处理无残差的skip模式和merge模式,得到cost,最终xCheckBestMode将最优merge信息存储于bestCS
      xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, ( ( uiNoResidualPass == 0 ) ? &candHasNoResidual[uiMergeCand] : NULL ) );
      if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip )
      {
        bestIsSkip = bestCS->getCU( partitioner.chType )->rootCbf == 0;
      }
      tempCS->initStructData( encTestMode.qp, encTestMode.lossless );		//tempCS清空初始化,进行下一个merge候选
    }// end loop uiMrgHADIdx

    if( uiNoResidualPass == 0 && m_pcEncCfg->getUseEarlySkipDetection() )	//判断skip模式
    {
      const CodingUnit     &bestCU = *bestCS->getCU( partitioner.chType );
      const PredictionUnit &bestPU = *bestCS->getPU( partitioner.chType );

      if( bestCU.rootCbf == 0 )
      {
        if( bestPU.mergeFlag )
        {
          m_modeCtrl->setEarlySkipDetected();			//skip模式
        }
        else if( m_pcEncCfg->getMotionEstimationSearchMethod() != MESEARCH_SELECTIVE )
        {
          Int absolute_MV = 0;

          for( UInt uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ )
          {
            if( slice.getNumRefIdx( RefPicList( uiRefListIdx ) ) > 0 )
            {
              absolute_MV += bestPU.mvd[uiRefListIdx].getAbsHor() + bestPU.mvd[uiRefListIdx].getAbsVer();
            }
          }

          if( absolute_MV == 0 )
          {
            m_modeCtrl->setEarlySkipDetected();	
          }
        }
      }
    }
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值