VTM3.0代码阅读:xCheckRDCostMerge2Nx2N函数

回眸只為那壹抹淺笑 提交于 2020-01-27 08:39:28

xCheckRDCostMerge2Nx2N在xCompressCU函数中调用,用来测试Merge模式、mmvd模式以及CIIP模式。
首先由getInterMergeCandidates获取merge候选模式信息,存储于,mergeCtx。同时由merge列表获取MMVD模式的两个baseMV。
如果不进行fastMerge,则跳过SATD直接进行RDO选最优
fastMerge时,对7个merge候选模式进行SATD,分别进行MC获得pred像素,选取cost最小的4个merge候选;对于MMVD模式分别以这两个mv为中心进行4方向8步长的计算,得到最优的baseMV、方向和步长。CIIP模式则选择经过SATD之后的前4个merge模式,分别于帧内模式结合,选取最优的merge模式和帧内模式。
对RdModeList中的merge候选、MMVD模式以及CIIP模式,统一进行RDO选择最优。

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;
  const SPS &sps = *tempCS->sps;

  if( sps.getSpsNext().getUseSubPuMvp() )
  {
    Size bufSize = g_miScaling.scale( tempCS->area.lumaSize() );
    mergeCtx.subPuMvpMiBuf    = MotionBuf( m_SubPuMiBuf,    bufSize );
  }

#if JVET_L0124_L0208_TRIANGLE
  setMergeBestSATDCost( MAX_DOUBLE );
#endif

  {
    // 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
#if JVET_L0054_MMVD
      , 0
#endif
    );
    PU::restrictBiPredMergeCands(pu, mergeCtx);
#if JVET_L0054_MMVD
    PU::getInterMMVDMergeCandidates(pu, mergeCtx);	//MMVD选择merge列表的前两个候选,作为baseMV
#endif
  }
  
  bool candHasNoResidual[MRG_MAX_NUM_CANDS + MMVD_ADD_NUM];		//若merge模式没有resi,则为skip模式
  for (uint32_t ui = 0; ui < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; ui++)
  {
    candHasNoResidual[ui] = false;
  }

  bool                                        bestIsSkip = false;
  bool                                        bestIsMMVDSkip = true;
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
  PelUnitBuf                                  acMergeBuffer[MRG_MAX_NUM_CANDS];	//里面存储的是:merge列表里面候选模式0~6顺序排列的各模式的pred像素
#endif
  PelUnitBuf                                  acMergeRealBuffer[MMVD_MRG_MAX_RD_BUF_NUM];//存储RDModeList前7个mode的pred像素
  PelUnitBuf *                                acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM];	//acMergeTempBuffer中始终存储的是RDModeList前几个模式的pred像素
  PelUnitBuf *                                singleMergeTempBuffer;					//这两个是指针
  int                                         insertPos;
  unsigned                                    uiNumMrgSATDCand = mergeCtx.numValidMergeCand + MMVD_ADD_NUM;

  static_vector<unsigned, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  RdModeList;
  bool                                        mrgTempBufSet = false;

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

  const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height));
  for (unsigned i = 0; i < MMVD_MRG_MAX_RD_BUF_NUM; i++)
  {
    acMergeRealBuffer[i] = m_acMergeBuffer[i].getBuf(localUnitArea);
    if (i < MMVD_MRG_MAX_RD_NUM)
    {
      acMergeTempBuffer[i] = acMergeRealBuffer + i;
    }
    else
    {
      singleMergeTempBuffer = acMergeRealBuffer + i;
    }
  }/////////////////////////////////////////////////////以上为初始化,并获取Merge列表

#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
#if JVET_L0054_MMVD
  static_vector<unsigned, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  RdModeList2; // store the Intra mode for Intrainter
#else
  static_vector<unsigned, MRG_MAX_NUM_CANDS>  RdModeList2; // store the Intra mode for Intrainter
#endif
  RdModeList2.clear();
  bool isIntrainterEnabled = sps.getSpsNext().getUseMHIntra();
  if (bestCS->area.lwidth() * bestCS->area.lheight() < 64 || bestCS->area.lwidth() >= MAX_CU_SIZE || bestCS->area.lheight() >= MAX_CU_SIZE)
  {
    isIntrainterEnabled = false;
  }
  bool isTestSkipMerge[MRG_MAX_NUM_CANDS]; // record if the merge candidate has tried skip mode 
  for (uint32_t idx = 0; idx < MRG_MAX_NUM_CANDS; idx++)
  {
    isTestSkipMerge[idx] = false;
  }
#endif
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
  if( m_pcEncCfg->getUseFastMerge() || isIntrainterEnabled)			// FastMerge || CIIP
#else
  if( m_pcEncCfg->getUseFastMerge() )
#endif
  {
    uiNumMrgSATDCand = NUM_MRG_SATD_CAND;		//SATD粗选择后的merge候选数目,4
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
    if (isIntrainterEnabled)
    {
      uiNumMrgSATDCand += 1;			//4加一个CIIP模式
    }
#endif
    bestIsSkip       = false;

    if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) )
    {
#if JVET_L0293_CPR
      if (slice.getSPS()->getSpsNext().getCPRMode())
      {
        ComprCUCtx cuECtx = m_modeCtrl->getComprCUCtx();
        bestIsSkip = blkCache->isSkip(tempCS->area) && cuECtx.bestCU;
      }
      else
#endif
      bestIsSkip = blkCache->isSkip( tempCS->area );
#if JVET_L0054_MMVD
      bestIsMMVDSkip = blkCache->isMMVDSkip(tempCS->area);
#endif
    }

#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
    if (isIntrainterEnabled) // always perform low complexity check
    {
      bestIsSkip = false;
    }
#endif

#if JVET_L0054_MMVD
    static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> candCostList;		//存放SATD时得到的7+64个候选的cost
#else
    static_vector<double, MRG_MAX_NUM_CANDS> candCostList;
#endif

    // 1. Pass: get SATD-cost for selected candidates and reduce their count
    if( !bestIsSkip )				//不是skip模式,对7+64个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
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
      const double sqrtLambdaForFirstPassIntra = m_pcRdCost->getMotionLambda(cu.transQuantBypass) / double(1 << SCALE_BITS);
#endif

      partitioner.setCUData( cu );
      cu.slice            = tempCS->slice;
#if HEVC_TILES_WPP
      cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
      cu.skip             = false;
#if JVET_L0054_MMVD
      cu.mmvdSkip		  = false;
#endif
#if JVET_L0124_L0208_TRIANGLE
      cu.triangle         = false;
#endif
      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;	//用来计算失真的pred像素存储在m_acMergeBuffer[0].Y()
														//设置计算失真的类: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) );
#if JVET_L0293_CPR
      uint32_t cprCand = 0;
      uint32_t numValidMv = mergeCtx.numValidMergeCand;
#endif
      for( uint32_t uiMergeCand = 0; uiMergeCand < mergeCtx.numValidMergeCand; uiMergeCand++ )	//Merge列表的loop,merge候选进行SATD
      {
#if JVET_L0293_CPR
        if ((mergeCtx.interDirNeighbours[uiMergeCand] == 1 || mergeCtx.interDirNeighbours[uiMergeCand] == 3) && tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[uiMergeCand << 1].refIdx)->getPOC() == tempCS->slice->getPOC())
        {
          cprCand++;
          numValidMv--;
          continue;
        }
#endif
#if !JVET_L0054_MMVD
        acMergeBuffer[uiMergeCand] = m_acMergeBuffer[uiMergeCand].getBuf( localUnitArea );
#endif
        mergeCtx.setMergeInfo( pu, uiMergeCand );

        PU::spanMotionInfo( pu, mergeCtx );
#if JVET_L0054_MMVD
        distParam.cur = singleMergeTempBuffer->Y();		//MMVD模式中MC得到的pred像素存储在singleMergeTempBuffer->Y()中
        m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer);		// MC
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
        acMergeBuffer[uiMergeCand] = m_acRealMergeBuffer[uiMergeCand].getBuf(localUnitArea);
        acMergeBuffer[uiMergeCand].copyFrom(*singleMergeTempBuffer);	//acMergeBuffer存储merge列表0~6的pred像素,用于最后CIIP和普通merge的处理
#endif
#else
        distParam.cur = acMergeBuffer[uiMergeCand].Y();

        m_pcInterSearch->motionCompensation( pu,  acMergeBuffer[uiMergeCand] );
#endif
        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];
#if DMVR_JVET_LOW_LATENCY_K0217
          refinedMvdL0[uiMergeCand] = pu.mvd[0];
#endif
        }

        Distortion uiSad = distParam.distFunc(distParam);		//计算失真
        uint32_t uiBitsCand = uiMergeCand + 1;
        if( uiMergeCand == tempCS->slice->getMaxNumMergeCand() - 1 )
        {
          uiBitsCand--;
        }
#if JVET_L0054_MMVD
        uiBitsCand++; // for mmvd_flag
#endif
        double cost     = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass;		//cost
#if JVET_L0054_MMVD
        insertPos = -1;
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA	//当前mode按cost大小顺序插入RdModeList
        updateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos);
#else
#if JVET_L0283_MULTI_REF_LINE
        static_vector<int, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> * nullList = nullptr;
#endif
        updateCandList(uiMergeCand, cost, RdModeList, candCostList
#if JVET_L0283_MULTI_REF_LINE
          , *nullList, -1
#endif          
          , uiNumMrgSATDCand, &insertPos);
#endif
        if (insertPos != -1)	//acMergeTempBuffer中始终存储的是RDModeList前几个模式的pred像素
        {
          if (insertPos == RdModeList.size() - 1)//若插入到vector的最后时,直接将MC得到的pred像素放到tempBuffer的最后一个
          {
            swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
          }
          else
          {
            for (uint32_t i = uint32_t(RdModeList.size()) - 1; i > insertPos; i--)
            {
              swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
            }
            swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
          }
        }
#else

#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
        updateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand);
#else
#if JVET_L0283_MULTI_REF_LINE
        static_vector<int, MRG_MAX_NUM_CANDS> * nullList = nullptr;
#endif
        updateCandList( uiMergeCand, cost, RdModeList, candCostList
#if JVET_L0283_MULTI_REF_LINE
          , *nullList, -1
#endif
          , uiNumMrgSATDCand );
#endif
#endif
#if JVET_L0293_CPR
        CHECK(std::min(uiMergeCand + 1 - cprCand, uiNumMrgSATDCand) != RdModeList.size(), "");
#else        
        CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" );
#endif
      }		//MergeCand 的loop结束,对Merge列表中的模式都进行了运动补偿,计算cost,排序
#if JVET_L0293_CPR
      if (numValidMv < uiNumMrgSATDCand)
        uiNumMrgSATDCand = numValidMv;
      if (numValidMv == 0)
        return;
#endif


#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
      if (isIntrainterEnabled)						// CIIP
      {
        int numTestIntraMode = 4;
        // prepare for Intra bits calculation
        const TempCtx ctxStart(m_CtxCache, m_CABACEstimator->getCtx());
        const TempCtx ctxStartIntraMode(m_CtxCache, SubCtx(Ctx::MHIntraPredMode, m_CABACEstimator->getCtx()));

        // for Intrainter fast, recored the best intra mode during the first round for mrege 0
        int bestMHIntraMode = -1;
        double bestMHIntraCost = MAX_DOUBLE;

        pu.mhIntraFlag = true;

        // save the to-be-tested merge candidates
        uint32_t MHIntraMergeCand[NUM_MRG_SATD_CAND];
#if JVET_L0293_CPR
        for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, (const int) uiNumMrgSATDCand); mergeCnt++)
#else
        for (uint32_t mergeCnt = 0; mergeCnt < NUM_MRG_SATD_CAND; mergeCnt++)
#endif
        {
          MHIntraMergeCand[mergeCnt] = RdModeList[mergeCnt];		//CIIP的inter模式,取SATD后的前4个MergeMode
        }
#if JVET_L0293_CPR
        for (uint32_t mergeCnt = 0; mergeCnt < std::min( std::min(NUM_MRG_SATD_CAND, (const int)uiNumMrgSATDCand), 4); mergeCnt++)
#else
        for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, 4); mergeCnt++)
#endif																		//4个mergeMode loop,选最优
        {
          uint32_t mergeCand = MHIntraMergeCand[mergeCnt];
#if JVET_L0054_MMVD
          acMergeBuffer[mergeCand] = m_acRealMergeBuffer[mergeCand].getBuf(localUnitArea);
#else
          acMergeBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea);
#endif

          // estimate merge bits
          uint32_t bitsCand = mergeCand + 1;
          if (mergeCand == pu.cs->slice->getMaxNumMergeCand() - 1)
          {
            bitsCand--;
          }

          // first round
          for (uint32_t intraCnt = 0; intraCnt < numTestIntraMode; intraCnt++)		//4个帧内预测模式loop
          {
            pu.intraDir[0] = (intraCnt < 2) ? intraCnt : ((intraCnt == 2) ? HOR_IDX : VER_IDX);

            // fast 2
            if (mergeCnt > 0 && bestMHIntraMode != pu.intraDir[0])	//只对第一个merge模式执行全面的4个intra模式的check
            {										//对于剩下的3个merge模式,只检查第一个merge模式中所选择的最优的那个intra模式
              continue;
            }
            int narrowCase = PU::getNarrowShape(pu.lwidth(), pu.lheight());
            if (narrowCase == 1 && pu.intraDir[0] == HOR_IDX)	//W >> H
            {
              continue;
            }
            if (narrowCase == 2 && pu.intraDir[0] == VER_IDX)	//H >> W
            {
              continue;
            }
            // generate intrainter Y prediction
			//只对第一个merge执行4次intra预测,预测结果保存在m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt),所以后面的3个merge模式直接取用,不用再预测
            if (mergeCnt == 0)
            {
              bool isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Y, pu, true, pu);
              m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Y(), isUseFilter);
              m_pcIntraSearch->predIntraAng(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, isUseFilter);
              m_pcIntraSearch->switchBuffer(pu, COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));
            }
            pu.cs->getPredBuf(pu).copyFrom(acMergeBuffer[mergeCand]);	//pred像素copy入merge模式像素
            m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));
																//CIIP模式中的intra和inter的加权平均
            // calculate cost
            distParam.cur = pu.cs->getPredBuf(pu).Y();	//此时pred存储的是intrainter加权像素
            Distortion sadValue = distParam.distFunc(distParam);								//计算失真和cost
            m_CABACEstimator->getCtx() = SubCtx(Ctx::MHIntraPredMode, ctxStartIntraMode);
            uint64_t fracModeBits = m_pcIntraSearch->xFracModeBitsIntra(pu, pu.intraDir[0], CHANNEL_TYPE_LUMA);
            double cost = (double)sadValue + (double)(bitsCand + 1) * sqrtLambdaForFirstPass + (double)fracModeBits * sqrtLambdaForFirstPassIntra;
#if JVET_L0054_MMVD
            insertPos = -1;			//加入RDModeList时,mergeCand的基础上加了7+64,绕开普通merge和MMVD
            updateDoubleCandList(mergeCand + MRG_MAX_NUM_CANDS + MMVD_ADD_NUM, cost, RdModeList, candCostList, RdModeList2, pu.intraDir[0], uiNumMrgSATDCand, &insertPos);
#else
            updateDoubleCandList(mergeCand + MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS, cost, RdModeList, candCostList, RdModeList2, pu.intraDir[0], uiNumMrgSATDCand);
#endif
#if JVET_L0054_MMVD
            if (insertPos != -1)
            {
              for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
              {
                swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
              }
              swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
            }
#endif
            // fast 2	记录第一个merge模式中4个intra模式最优的那个
            if (mergeCnt == 0 && cost < bestMHIntraCost)
            {
              bestMHIntraMode = pu.intraDir[0];
              bestMHIntraCost = cost;
            }
          }
        }
        pu.mhIntraFlag = false;
        m_CABACEstimator->getCtx() = ctxStart;
      }
#endif

#if JVET_L0054_MMVD									// MMVD
      cu.mmvdSkip = true;
      int tempNum = 0;
      tempNum = MMVD_ADD_NUM;
      bool allowDirection[4] = { true, true, true, true };
      for (uint32_t mergeCand = mergeCtx.numValidMergeCand; mergeCand < mergeCtx.numValidMergeCand + tempNum; mergeCand++)
      {															//64个mvd进行loop,选取最优的mvd
        const int mmvdMergeCand = mergeCand - mergeCtx.numValidMergeCand;
        int bitsBaseIdx = 0;
        int bitsRefineStep = 0;
        int bitsDirection = 2;
        int bitsCand = 0;
        int baseIdx;
        int refineStep;
        int direction;
        baseIdx = mmvdMergeCand / MMVD_MAX_REFINE_NUM;			//baseMV是第一个mergeMode还是第二个
        refineStep = (mmvdMergeCand - (baseIdx * MMVD_MAX_REFINE_NUM)) / 4;					//步长
        direction = (mmvdMergeCand - baseIdx * MMVD_MAX_REFINE_NUM - refineStep * 4) % 4; 	//mvd的方向
        if (refineStep == 0)
        {
          allowDirection[direction] = true;
        }
        if (allowDirection[direction] == false)
        {
          continue;
        }
        bitsBaseIdx = baseIdx + 1;
        if (baseIdx == MMVD_BASE_MV_NUM - 1)
        {
          bitsBaseIdx--;
        }

        bitsRefineStep = refineStep + 1;
        if (refineStep == MMVD_REFINE_STEP - 1)
        {
          bitsRefineStep--;
        }

        bitsCand = bitsBaseIdx + bitsRefineStep + bitsDirection;
        bitsCand++; // for mmvd_flag

#if !JVET_L0054_MMVD
        acMergeBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea);
#endif
        mergeCtx.setMmvdMergeCandiInfo(pu, mmvdMergeCand);		//由mmvdMergeCand获取mvd,从而得到pu的motioninfo信息

        PU::spanMotionInfo(pu, mergeCtx);
#if JVET_L0054_MMVD
        distParam.cur = singleMergeTempBuffer->Y();
        m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer);	//MC
#else
        distParam.cur = acMergeBuffer[mergeCand].Y();
        m_pcInterSearch->motionCompensation(pu, acMergeBuffer[mergeCand]);
#endif

        Distortion uiSad = distParam.distFunc(distParam);		//失真


#if !JVET_L0054_MMVD
        uint32_t bitsCand = mergeCand + 1;
        if (mergeCand == tempCS->slice->getMaxNumMergeCand() - 1)
        {
          bitsCand--;
        }
#endif
        double cost = (double)uiSad + (double)bitsCand * sqrtLambdaForFirstPass;	//cost
#if JVET_L0054_MMVD
        allowDirection[direction] = cost >  1.3 * candCostList[0] ? 0 : 1;	//只要一个方向上的8个点中有一个不达标,该方向剩下的点就不用测了
#endif
#if JVET_L0054_MMVD
        insertPos = -1;
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA		//MMVD插入RDModelList的模式是mergeCand,即7~71
        updateDoubleCandList(mergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos);
#else
#if JVET_L0283_MULTI_REF_LINE
        static_vector<int, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> * nullList = nullptr;
#endif
        updateCandList(mergeCand, cost, RdModeList, candCostList
#if JVET_L0283_MULTI_REF_LINE
          , *nullList, -1
#endif
          , uiNumMrgSATDCand, &insertPos);
#endif
        if (insertPos != -1)
        {
          for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
          {
            swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
          }
          swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
        }
#else
        updateCandList(mergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand);
#endif
#if !JVET_L0054_MMVD
        CHECK(std::min(mergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), "");
#endif
      }
#endif

      // Try to limit number of candidates using SATD-costs
      for( uint32_t i = 1; i < uiNumMrgSATDCand; i++ )
      {
        if( candCostList[i] > MRG_FAST_RATIO * candCostList[0] )
        {
          uiNumMrgSATDCand = i;
          break;
        }
      }

#if JVET_L0124_L0208_TRIANGLE
      setMergeBestSATDCost( candCostList[0] );
#endif

#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
      if (isIntrainterEnabled)							// CIIP   帧内色度模式
      {
        pu.mhIntraFlag = true;
        for (uint32_t mergeCnt = 0; mergeCnt < uiNumMrgSATDCand; mergeCnt++)
        {
#if JVET_L0054_MMVD
          if (RdModeList[mergeCnt] >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
#else
          if (RdModeList[mergeCnt] >= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS))
#endif
          {
            pu.intraDir[0] = RdModeList2[mergeCnt];
            pu.intraDir[1] = DM_CHROMA_IDX;
            uint32_t bufIdx = (pu.intraDir[0] > 1) ? (pu.intraDir[0] == HOR_IDX ? 2 : 3) : pu.intraDir[0];
            bool isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Cb, pu, true, pu);			//Cb
            m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cb(), isUseFilter);
            m_pcIntraSearch->predIntraAng(COMPONENT_Cb, pu.cs->getPredBuf(pu).Cb(), pu, isUseFilter);
            m_pcIntraSearch->switchBuffer(pu, COMPONENT_Cb, pu.cs->getPredBuf(pu).Cb(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cb, bufIdx));
            isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Cr, pu, true, pu);				//Cr
            m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cr(), isUseFilter);
            m_pcIntraSearch->predIntraAng(COMPONENT_Cr, pu.cs->getPredBuf(pu).Cr(), pu, isUseFilter);
            m_pcIntraSearch->switchBuffer(pu, COMPONENT_Cr, pu.cs->getPredBuf(pu).Cr(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cr, bufIdx));
          }
        }
        pu.mhIntraFlag = false;
      }
#endif

      tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
    }
    else				// bestIsSkip = true
	{
#if JVET_L0054_MMVD
      if (bestIsMMVDSkip)
      {
        uiNumMrgSATDCand = mergeCtx.numValidMergeCand + MMVD_ADD_NUM;
      }
      else
      {
        uiNumMrgSATDCand = mergeCtx.numValidMergeCand;
      }
#else
      uiNumMrgSATDCand = mergeCtx.numValidMergeCand;
#endif
    }
  }

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

  // 2. Pass: check candidates using full RD test
  for( uint32_t uiNoResidualPass = 0; uiNoResidualPass < iteration; uiNoResidualPass++ )
  {
    for( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ )
    {
      uint32_t uiMergeCand = RdModeList[uiMrgHADIdx];	//对RdModeList中的所有模式,进行计算选最优(普通merge CIIP和MMVD平等竞争)

#if JVET_L0293_CPR
#if JVET_L0054_MMVD
      if(uiMergeCand < mergeCtx.numValidMergeCand)
#endif
        if ((mergeCtx.interDirNeighbours[uiMergeCand] == 1 || mergeCtx.interDirNeighbours[uiMergeCand] == 3) && tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[uiMergeCand << 1].refIdx)->getPOC() == tempCS->slice->getPOC())
        {
          continue;				//一些特殊情况,该模式跳过
        }
#endif

#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
#if JVET_L0054_MMVD
      if (uiNoResidualPass != 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)) // intrainter does not support skip mode
#else
      if (uiNoResidualPass != 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS)) // intrainter does not support skip mode
#endif
      {
#if JVET_L0054_MMVD
        uiMergeCand -= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM); // for skip, map back to normal merge candidate idx and try RDO
#else
        uiMergeCand -= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS); // for skip, map back to normal merge candidate idx and try RDO
#endif
        if (isTestSkipMerge[uiMergeCand])
        {
          continue;				//一些特殊情况,该模式跳过
        }
      }
#endif

#if JVET_L0054_MMVD
      if (((uiNoResidualPass != 0) && candHasNoResidual[uiMrgHADIdx])
#else
      if( ( (uiNoResidualPass != 0) && candHasNoResidual[uiMergeCand] )
#endif
       || ( (uiNoResidualPass == 0) && bestIsSkip ) )
      {
        continue;				//一些特殊情况,该模式跳过
      }

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

      partitioner.setCUData( cu );
      cu.slice            = tempCS->slice;
#if HEVC_TILES_WPP
      cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endif
      cu.skip             = false;
#if JVET_L0054_MMVD
      cu.mmvdSkip = false;
#endif
#if JVET_L0124_L0208_TRIANGLE
      cu.triangle         = false;
#endif
      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 );
											//下面分CIIP、MMVD和普通merge三种情况分别对pu进行设置
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
#if JVET_L0054_MMVD							// CIIP
      if (uiNoResidualPass == 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
#else
      if (uiNoResidualPass == 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS))
#endif
      {
#if JVET_L0054_MMVD
        uiMergeCand -= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM);
        cu.mmvdSkip = false;
        mergeCtx.setMergeInfo(pu, uiMergeCand);
#else
        uiMergeCand -= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS);
#endif
        pu.mhIntraFlag = true;
        pu.intraDir[0] = RdModeList2[uiMrgHADIdx];
        CHECK(pu.intraDir[0]<0 || pu.intraDir[0]>(NUM_LUMA_MODE - 1), "out of intra mode");
        pu.intraDir[1] = DM_CHROMA_IDX;
      }
#endif

#if JVET_L0054_MMVD
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA		// MMVD
      else if (uiMergeCand >= mergeCtx.numValidMergeCand && uiMergeCand < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)
#else
      if (uiMergeCand >= mergeCtx.numValidMergeCand)
#endif
      {
        cu.mmvdSkip = true;
        mergeCtx.setMmvdMergeCandiInfo(pu, uiMergeCand - mergeCtx.numValidMergeCand);
      }
      else
      {
        cu.mmvdSkip = false;				//普通merge
        mergeCtx.setMergeInfo(pu, uiMergeCand);
      }
#else
      mergeCtx.setMergeInfo( pu, uiMergeCand );
#endif
      PU::spanMotionInfo( pu, mergeCtx );

      if( mrgTempBufSet )	//bestIsSkip为false时,mrgTempBufSet为true
      {						//skip为false,表明已经进行过上面各种模式的pred像素的计算,所以不用下面else的MC
#if DMVR_JVET_LOW_LATENCY_K0217
        pu.mvd[0] = refinedMvdL0[uiMergeCand];
#endif
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
        if (pu.mhIntraFlag)				//CIIP	分别对YUV的inter和inter加权平均,存入tempCS的predBuf
        {
          uint32_t bufIdx = (pu.intraDir[0] > 1) ? (pu.intraDir[0] == HOR_IDX ? 2 : 3) : pu.intraDir[0];
          PelBuf tmpBuf = tempCS->getPredBuf(pu).Y();
          tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Y());
          m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, bufIdx));
          tmpBuf = tempCS->getPredBuf(pu).Cb();
          tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Cb());
          m_pcIntraSearch->geneWeightedPred(COMPONENT_Cb, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cb, bufIdx));
          tmpBuf = tempCS->getPredBuf(pu).Cr();
          tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Cr());
          m_pcIntraSearch->geneWeightedPred(COMPONENT_Cr, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cr, bufIdx));
        }
        else
        {
#if JVET_L0054_MMVD		//MMVD只需在tempCS的predBuf中存储inter像素
          if (uiNoResidualPass != 0 && uiMergeCand < mergeCtx.numValidMergeCand && RdModeList[uiMrgHADIdx] >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
          {
            tempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]);			//普通merge
          }
          else
          {
            tempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx]);		//MMVD
          }
#else
          tempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]);
#endif
        }
#else
#if JVET_L0054_MMVD
        tempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx]);
#else
        tempCS->getPredBuf().copyFrom( acMergeBuffer[ uiMergeCand ]);
#endif
#endif
      }
      else				//如果上面执行的是skip模式,那么就需要MC来计算pred像素
      {
        m_pcInterSearch->motionCompensation( pu );	//MC,skip模式时才进行MC,由运动信息获取pred像素
        
      }
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
#if JVET_L0054_MMVD
      if (!cu.mmvdSkip && !pu.mhIntraFlag && uiNoResidualPass != 0)
#else
      if (!pu.mhIntraFlag && uiNoResidualPass != 0)
#endif
      {
        CHECK(uiMergeCand >= mergeCtx.numValidMergeCand, "out of normal merge");
        isTestSkipMerge[uiMergeCand] = true;
      }
#endif

#if JVET_L0054_MMVD					//由orig和pred像素信息,获得resi,可得到reco像素
									//分别处理无残差的skip模式和merge模式,得到cost,最终xCheckBestMode将最优merge信息存储于bestCS
      xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass
        , NULL
        , 1
        , uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL);
#else
      xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass
        , NULL
        , 1
        , uiNoResidualPass == 0 ? &candHasNoResidual[uiMergeCand] : NULL );
#endif

#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
      if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip && !pu.mhIntraFlag)
#else
      if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip )
#endif
      {
        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( uint32_t 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();
          }
        }
      }
    }
  }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!