VTM3.0代码阅读:xCheckRDCostMergeTriangle2Nx2N函数

三角预测模式,首先会获取一个三角预测单向候选模式列表,表长为5,就像普通merge模式的函数流程那样;
然后MC计算5个候选的预测像素pred,方便之后的40种三角组合模式的pred像素加权计算;
对40种三角组合模式进行SATD,计算出最优的3种组合模式;
对SATD得到的最优的三角组合预测模式,RDO得到最优的一种三角组合预测模式。

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

  CHECK( slice.getSliceType() != B_SLICE, "Triangle mode is only applied to B-slices" );	//M0329扩展到了P
  
  tempCS->initStructData( encTestMode.qp, encTestMode.lossless );		//tempCS清空
  
  bool trianglecandHasNoResidual[TRIANGLE_MAX_NUM_CANDS];
  for( int mergeCand = 0; mergeCand < TRIANGLE_MAX_NUM_CANDS; mergeCand++ )
  {
    trianglecandHasNoResidual[mergeCand] = false;
  }

#if JVET_L0293_CPR
  bool bestIsSkip;
  CodingUnit* cuTemp = bestCS->getCU(partitioner.chType);
  if (cuTemp)
    bestIsSkip = m_pcEncCfg->getUseFastDecisionForMerge() ? bestCS->getCU(partitioner.chType)->rootCbf == 0 : false;
  else
    bestIsSkip = false;
#else
  bool                  bestIsSkip             = m_pcEncCfg->getUseFastDecisionForMerge() ? bestCS->getCU( partitioner.chType )->rootCbf == 0 : false;
#endif
  uint8_t               numTriangleCandidate   = TRIANGLE_MAX_NUM_CANDS;		//40
  uint8_t               triangleNumMrgSATDCand = TRIANGLE_MAX_NUM_SATD_CANDS;		//SATD选择3个mvp
  PelUnitBuf            triangleBuffer[TRIANGLE_MAX_NUM_UNI_CANDS];	//存储构建的三角预测单向列表中5个mvp的预测像素
  PelUnitBuf            triangleWeightedBuffer[TRIANGLE_MAX_NUM_CANDS];//存储40种三角组合模式的加权像素值
  static_vector<uint8_t, TRIANGLE_MAX_NUM_CANDS> triangleRdModeList;
  static_vector<double,  TRIANGLE_MAX_NUM_CANDS> tianglecandCostList;	//modeList和costList

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

  DistParam distParam;
  const bool useHadamard = !encTestMode.lossless;
  m_pcRdCost->setDistParam( distParam, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y(), sps.getBitDepth( CHANNEL_TYPE_LUMA ), COMPONENT_Y, useHadamard );

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

  const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda(encTestMode.lossless);

  MergeCtx triangleMrgCtx;			//三角预测候选列表
  {
    CodingUnit cu( tempCS->area );
    cu.cs       = tempCS;
    cu.partSize = SIZE_2Nx2N;
    cu.predMode = MODE_INTER;
    cu.slice    = tempCS->slice;
    cu.triangle = true;
#if JVET_L0054_MMVD
    cu.mmvdSkip = false;
#endif    
#if JVET_L0646_GBI
    cu.GBiIdx   = GBI_DEFAULT;
#endif

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

    PU::getTriangleMergeCandidates( pu, triangleMrgCtx );	// 获取三角预测单向MV列表

    for( uint8_t mergeCand = 0; mergeCand < TRIANGLE_MAX_NUM_UNI_CANDS; mergeCand++ )	//对5个三角预测候选分别MC
    {
      triangleBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea);
      triangleMrgCtx.setMergeInfo( pu, mergeCand );		//给pu赋值单向三角候选的motioninfo
      PU::spanMotionInfo( pu, triangleMrgCtx );
													//直接取单向mv,通过MC得到pred像素,存储于triangleBuffer
      m_pcInterSearch->motionCompensation( pu, triangleBuffer[mergeCand] );		//MC   得到三角单向候选的pred像素,方便之后组合三角模式的计算
    }
  }

  bool tempBufSet = bestIsSkip ? false : true;
  triangleNumMrgSATDCand = bestIsSkip ? TRIANGLE_MAX_NUM_CANDS : TRIANGLE_MAX_NUM_SATD_CANDS;
  if( bestIsSkip )
  {
    for( uint8_t i = 0; i < TRIANGLE_MAX_NUM_CANDS; i++ )	//skip时需要RDO选择40个三角模式
    {
      triangleRdModeList.push_back(i);
    }
  }
  else						//SATD
  {										//SATD从40个三角模式中选出最优的3个模式
    CodingUnit &cu      = tempCS->addCU( tempCS->area, partitioner.chType );
      
    partitioner.setCUData( cu );
    cu.slice            = tempCS->slice;
    cu.skip             = false;
    cu.partSize         = SIZE_2Nx2N;
    cu.predMode         = MODE_INTER;
    cu.transQuantBypass = encTestMode.lossless;
    cu.chromaQpAdj      = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
    cu.qp               = encTestMode.qp;
    cu.triangle         = true;
#if JVET_L0054_MMVD
    cu.mmvdSkip         = false;
#endif
#if JVET_L0646_GBI
    cu.GBiIdx           = GBI_DEFAULT;
#endif

    PredictionUnit &pu  = tempCS->addPU( cu, partitioner.chType );		//tempCS添加cu pu
      
    if( abs(g_aucLog2[cu.lwidth()] - g_aucLog2[cu.lheight()]) >= 2 )
    {
      numTriangleCandidate = 30;		//当前块的长宽比,大于等于4时
    }
    else
    {
      numTriangleCandidate = TRIANGLE_MAX_NUM_CANDS;	//40
    }

    for( uint8_t mergeCand = 0; mergeCand < numTriangleCandidate; mergeCand++ )		//loop 40种三角组合模式
    {																//g_triangleCombination即为三角预测的那张表格
      bool    splitDir = g_triangleCombination[mergeCand][0];		//三角划分方向,对角反对角
      uint8_t candIdx0 = g_triangleCombination[mergeCand][1];		//第一个三角的候选idx
      uint8_t candIdx1 = g_triangleCombination[mergeCand][2];		//第二个三角的候选idx

      pu.mergeIdx  = mergeCand;
      pu.mergeFlag = true;
      triangleWeightedBuffer[mergeCand] = m_acTriangleWeightedBuffer[mergeCand].getBuf( localUnitArea );
      triangleBuffer[candIdx0] = m_acMergeBuffer[candIdx0].getBuf( localUnitArea );
      triangleBuffer[candIdx1] = m_acMergeBuffer[candIdx1].getBuf( localUnitArea );
															//三角预测的两个三角预测像素加权
      m_pcInterSearch->weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, CHANNEL_TYPE_LUMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
      
      distParam.cur = triangleWeightedBuffer[mergeCand].Y();

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

      uint32_t uiBitsCand = g_triangleIdxBins[mergeCand];

      double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass;	//一种三角组合模式的cost

#if JVET_L0283_MULTI_REF_LINE
      static_vector<int, TRIANGLE_MAX_NUM_CANDS> * nullList = nullptr;
#endif
      updateCandList( mergeCand, cost, triangleRdModeList, tianglecandCostList		//根据cost,排序各种三角组合模式
#if JVET_L0283_MULTI_REF_LINE
        , *nullList, -1
#endif
        , triangleNumMrgSATDCand );
    } //40种三角组合模式loop结束
        
    // limit number of candidates using SATD-costs
    for( uint8_t i = 0; i < triangleNumMrgSATDCand; i++ )
    {
      if( tianglecandCostList[i] > MRG_FAST_RATIO * tianglecandCostList[0] || tianglecandCostList[i] > getMergeBestSATDCost() )
      {
        triangleNumMrgSATDCand = i;
        break;
      }
    }

    // perform chroma weighting process
    for( uint8_t i = 0; i < triangleNumMrgSATDCand; i++ )		//SATD选取3个最优的三角组合模式
    {
      uint8_t  mergeCand = triangleRdModeList[i];
      bool     splitDir  = g_triangleCombination[mergeCand][0];
      uint8_t  candIdx0  = g_triangleCombination[mergeCand][1];
      uint8_t  candIdx1  = g_triangleCombination[mergeCand][2];
        
      pu.mergeIdx  = mergeCand;
      pu.mergeFlag = true;
														//计算三个最优的三角组合模式的加权预测像素
      m_pcInterSearch->weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, CHANNEL_TYPE_CHROMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
    }

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

  {
    const uint8_t iteration = encTestMode.lossless ? 1 : 2;
    for( uint8_t noResidualPass = 0; noResidualPass < iteration; noResidualPass++ )	//两次循环
    {
      for( uint8_t mrgHADIdx = 0; mrgHADIdx < triangleNumMrgSATDCand; mrgHADIdx++ )		//对SATD选择的三角组合模式进行RDO
      {
        uint8_t mergeCand = triangleRdModeList[mrgHADIdx];

        if ( ( (noResidualPass != 0) && trianglecandHasNoResidual[mergeCand] )
          || ( (noResidualPass == 0) && bestIsSkip ) )
        {
          continue;
        }

        bool    splitDir = g_triangleCombination[mergeCand][0];		//划分方向
        uint8_t candIdx0 = g_triangleCombination[mergeCand][1];		//第一个三角的候选idx
        uint8_t candIdx1 = g_triangleCombination[mergeCand][2];		//第二个三角的候选idx

        CodingUnit &cu = tempCS->addCU(tempCS->area, partitioner.chType);

        partitioner.setCUData(cu);
        cu.slice = tempCS->slice;
        cu.skip = false;
        cu.partSize = SIZE_2Nx2N;
        cu.predMode = MODE_INTER;
        cu.transQuantBypass = encTestMode.lossless;
        cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
        cu.qp = encTestMode.qp;
        cu.triangle = true;
#if JVET_L0054_MMVD
        cu.mmvdSkip = false;
#endif
#if JVET_L0646_GBI
        cu.GBiIdx   = GBI_DEFAULT;
#endif
        PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType);		//tempCS添加cu pu

        pu.mergeIdx = mergeCand;
        pu.mergeFlag = true;
									//将当前test的三角组合候选的MotionInfo赋给pu
        PU::spanTriangleMotionInfo(pu, triangleMrgCtx, mergeCand, splitDir, candIdx0, candIdx1 );

        if( tempBufSet )	//非skip模式时为true,因为此时的pred像素已在上面计算过,无需再计算
        {
          tempCS->getPredBuf().copyFrom( triangleWeightedBuffer[mergeCand] );
        }
        else
        {		// skip模式时
          triangleBuffer[candIdx0] = m_acMergeBuffer[candIdx0].getBuf( localUnitArea );
          triangleBuffer[candIdx1] = m_acMergeBuffer[candIdx1].getBuf( localUnitArea );
          PelUnitBuf predBuf         = tempCS->getPredBuf();
          m_pcInterSearch->weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, MAX_NUM_CHANNEL_TYPE, predBuf, triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
        }
												//计算cost,并将最后的模式信息给bestCS								// xEncodeInterResidual
        xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, noResidualPass, NULL, true, ( (noResidualPass == 0 ) ? &trianglecandHasNoResidual[mergeCand] : NULL ) );

        if (m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip)
        {
          bestIsSkip = bestCS->getCU(partitioner.chType)->rootCbf == 0;
        }
        tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
      }// end loop mrgHADIdx
    }   
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值