VVC代码 BMS 帧内预测学习之一:帧内预测函数 xCheckRDCostIntra()

代码所在网址:
https://jvet.hhi.fraunhofer.de/svn/svn_VVCSoftware_BMS/
这些只是自己初步的学习,若有问题烦请更正,共同进步~

帧内预测的相关内容在函数xCheckRDCostIntra()中

该函数下调用了亮度预测函数及色度预测函数:estIntraPredLumaQT()及estIntraPredLumaQT()
两个函数及其调用函数分析见:
https://blog.csdn.net/yolo_life/article/details/81673741

void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
#if JEM_TOOLS
  double bestInterCost        = m_modeCtrl->getBestInterCost();
#endif
#if JEM_TOOLS
#if HEVC_USE_PART_SIZE
  bool isAllIntra             = m_pcEncCfg->getIntraPeriod() == 1;
#endif
#endif
#if JEM_TOOLS
//AMT第一个通道
  double costSize2Nx2NemtFirstPass = m_modeCtrl->getEmtSize2Nx2NFirstPassCost();
  double costSizeNxNemtFirstPass   = MAX_DOUBLE;
  bool skipSecondEmtPass           = m_modeCtrl->getSkipSecondEMTPass();
#endif
#if JEM_TOOLS
  auto slsCtrl                = dynamic_cast<SaveLoadEncInfoCtrl*>( m_modeCtrl );
  const SPS &sps              = *tempCS->sps;
#endif
  const PPS &pps              = *tempCS->pps;
  const CodingUnit *bestCU    = bestCS->getCU( partitioner.chType );
#if JEM_TOOLS
//NSST索引
  const int nsstIdx           = ( encTestMode.opts & ETO_NSST ) >> ETO_NSST_SHIFT;
#endif
#if JEM_TOOLS
  const bool usePDPC          = ( encTestMode.opts & ETO_PDPC ) != 0;
#endif
#if JEM_TOOLS
  const int maxSizeEMT        = pps.pcv->noRQT ? EMT_INTRA_MAX_CU_WITH_QTBT : EMT_INTRA_MAX_CU;
#endif
#if JEM_TOOLS

#if HM_EMT_NSST_AS_IN_JEM
//判断是帧内编码的宽高均<=maxSizeEMT的亮度块,是则使用AMT的第二通道,值为1,表示使用AMT;不是则为0,不使用AMT
  UChar considerEmtSecondPass = ( sps.getSpsNext().getUseIntraEMT() && isLuma( partitioner.chType ) && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT ) ? 1 : 0;
#else
  UChar considerEmtSecondPass = ( sps.getSpsNext().getUseIntraEMT() && isLuma( partitioner.chType ) && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT && nsstIdx == 0 ) ? 1 : 0;
#endif
  CHECK( usePDPC && sps.getSpsNext().isPlanarPDPC(), "PDPC cannot be on with Planar-PDPC" );
#endif

  Distortion interHad = m_modeCtrl->getInterHad();



#if JEM_TOOLS//AMT相关循环
  for( UChar emtCuFlag = 0; emtCuFlag <= considerEmtSecondPass; emtCuFlag++ )
#else
  for( UChar numPasses = 0; numPasses < 1; numPasses++ )
#endif
  {
#if JEM_TOOLS
    //Possible early EMT tests interruptions //AMT早期中断判断
    //1) saveLoadTag code for EMT
    if( sps.getSpsNext().getUseQTBT() && slsCtrl && m_pcEncCfg->getUseSaveLoadEncInfo() )
    {
      if( m_pcEncCfg->getIntraEMT() && LOAD_ENC_INFO == slsCtrl->getSaveLoadTag( tempCS->area ) && ( emtCuFlag > 0 ) != slsCtrl->getSaveLoadEmtCuFlag( tempCS->area ) )
      {
        continue;
      }
    }
    //2) Second EMT pass. This "if clause" is necessary because of the NSST and PDPC "for loops".
    if( emtCuFlag && skipSecondEmtPass )
    {
      continue;
    }
#endif
    //3) if interHad is 0, only try further modes if some intra mode was already better than inter
    if( m_pcEncCfg->getUsePbIntraFast() && !tempCS->slice->isIntra() && bestCU && CU::isInter( *bestCS->getCU( partitioner.chType ) ) && interHad == 0 )
    {
      continue;
    }
//************************************************ 初始化
    tempCS->initStructData( encTestMode.qp, encTestMode.lossless );

    CodingUnit &cu      = tempCS->addCU( CS::getArea( *tempCS, tempCS->area, partitioner.chType ), 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;
    cu.partSize         = encTestMode.partSize;
    cu.predMode         = MODE_INTRA;
    cu.transQuantBypass = encTestMode.lossless;
#if JEM_TOOLS
    cu.pdpc             = usePDPC;
#endif
    cu.chromaQpAdj      = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
    cu.qp               = encTestMode.qp;
  //cu.ipcm             = false;
#if JEM_TOOLS
    cu.nsstIdx          = nsstIdx;
    cu.emtFlag          = emtCuFlag;
#endif

    CU::addPUs( cu );

    tempCS->interHad    = interHad;

//************************************************ 亮度帧内预测
    if( isLuma( partitioner.chType ) )
    {
      m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner );//入口函数

      if( m_pcEncCfg->getUsePbIntraFast() && tempCS->dist == MAX_UINT && tempCS->interHad == 0 )
      {
        interHad = 0;
        // JEM assumes only perfect reconstructions can from now on beat the inter mode
        m_modeCtrl->enforceInterHad( 0 );
        continue;
      }

      if( !CS::isDualITree( *tempCS ) )//isDualITree:I帧下的亮度色度分离树判断,为真表示分离树
      {
        cu.cs->picture->getRecoBuf( cu.Y() ).copyFrom( cu.cs->getRecoBuf( COMPONENT_Y ) );
      }
    }
//************************************************ 色度帧内预测
    if( tempCS->area.chromaFormat != CHROMA_400 && ( partitioner.chType == CHANNEL_TYPE_CHROMA || !CS::isDualITree( *tempCS ) ) )
    {
      m_pcIntraSearch->estIntraPredChromaQT( cu, partitioner );
    }

    cu.rootCbf = false;

    for( UInt t = 0; t < getNumberValidTBlocks( *cu.cs->pcv ); t++ )
    {
      cu.rootCbf |= cu.firstTU->cbf[t] != 0;
    }

//************************************************ Get total bits for current mode: encode CU
    m_CABACEstimator->resetBits();

    if( pps.getTransquantBypassEnabledFlag() )
    { //编码变换量化旁路情况下的标志(旁路意味着残差直接赋值给变换系数)
      m_CABACEstimator->cu_transquant_bypass_flag( cu );
    }

    if( !cu.cs->slice->isIntra() )
    { //编码非帧内下的skip标志
      m_CABACEstimator->cu_skip_flag ( cu );
    }
    //编码预测模式
    m_CABACEstimator->pred_mode      ( cu );
#if JEM_TOOLS
    //编码PDPC标志
    m_CABACEstimator->pdpc_flag      ( cu );
#endif
#if HEVC_USE_PART_SIZE //默认flase
    m_CABACEstimator->part_mode      ( cu );
#endif
    //编码CU预测数据(包括:帧内:亮度预测模式+色度预测模式;PU;IMV模式;OBMC标志;LIC标志)
    m_CABACEstimator->cu_pred_data   ( cu );
    //编码PCM数据
    m_CABACEstimator->pcm_data       ( cu );


//************************************************ Encode Coefficients
    CUCtx cuCtx;
    cuCtx.isDQPCoded = true;
    cuCtx.isChromaQpAdjCoded = true;
    m_CABACEstimator->cu_residual( cu, partitioner, cuCtx );//变换系数编码

    tempCS->fracBits = m_CABACEstimator->getEstFracBits();
    tempCS->cost     = m_pcRdCost->calcRdCost(tempCS->fracBits, tempCS->dist);

#if !HM_POSTPONE_SPLIT_BITS //宏为真,默认不进入下一个函数
    xEncodeDontSplit( *tempCS, partitioner );
#endif

//************************************************ deltaQP检测
    xCheckDQP( *tempCS, partitioner );

#if JEM_TOOLS

//************************************************ Check if secondary transform (NSST) is too expensive
    const int nonZeroCoeffThr = CS::isDualITree( *tempCS ) ? ( isLuma( partitioner.chType ) ? NSST_SIG_NZ_LUMA : NSST_SIG_NZ_CHROMA ) : NSST_SIG_NZ_LUMA + NSST_SIG_NZ_CHROMA;
    if( nsstIdx && tempCS->pcv->noRQT && cuCtx.numNonZeroCoeffNonTs <= nonZeroCoeffThr )
    {
      Bool isMDIS = false;
      if( sps.getSpsNext().isPlanarPDPC() )
      {
        CHECK( CU::getNumPUs( cu ) > 1, "PLanarPDPC: encoder MDIS condition not defined for multi PU" );
        const PredictionUnit* pu = cu.firstPU;
        isMDIS = IntraPrediction::useFilteredIntraRefSamples( COMPONENT_Y, *pu, true, *pu );
#if HM_MDIS_AS_IN_JEM
        if( pu->intraDir[0] == PLANAR_IDX ) { isMDIS |= IntraPrediction::getPlanarMDISCondition( *pu ); }
#endif
      }

      if( cuCtx.numNonZeroCoeffNonTs > 0 || isMDIS )
      {
        tempCS->cost = MAX_DOUBLE;
      }
    }
    if( nsstIdx && !tempCS->pcv->noRQT && cu.rootCbf == 0 )
    {
      tempCS->cost = MAX_DOUBLE;
    }
#endif

#if JEM_TOOLS

//************************************************保存了第一个AMT通道模式的代价
    if( !emtCuFlag ) static_cast< double& >( cu.partSize == SIZE_2Nx2N ? costSize2Nx2NemtFirstPass : costSizeNxNemtFirstPass ) = tempCS->cost;
#endif

#if WCG_EXT
    DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) );
#else
    DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda() );
#endif

//************************************************ 最优模式的检测及设置
    xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );


#if JEM_TOOLS

//************************************************ now we check whether the second pass of SIZE_2Nx2N and the whole Intra SIZE_NxN should be skipped or not
    if( !emtCuFlag && !tempCS->slice->isIntra() && bestCU && bestCU->predMode != MODE_INTRA && cu.partSize == SIZE_2Nx2N && m_pcEncCfg->getFastInterEMT() && ( m_pcEncCfg->getUseSaveLoadEncInfo() ? ( bestInterCost < MAX_DOUBLE ) : true ) )
    {
      const double thEmtInterFastSkipIntra = 1.4; // Skip checking Intra if "2Nx2N using DCT2" is worse than best Inter mode
      if( costSize2Nx2NemtFirstPass > thEmtInterFastSkipIntra * bestInterCost )
      //对应AMT中跳过第二个通道的相关判断操作
      {
        skipSecondEmtPass = true;
        m_modeCtrl->setSkipSecondEMTPass( true );
        break;
      }
    }

#if HEVC_USE_PART_SIZE //默认flase
    //now we check whether the second pass of EMT with SIZE_NxN should be skipped or not
    if( !emtCuFlag && isAllIntra && cu.partSize == SIZE_NxN && m_pcEncCfg->getFastIntraEMT() )
    {
      costSize2Nx2NemtFirstPass = m_modeCtrl->getEmtSize2Nx2NFirstPassCost();
      const double thEmtIntraFastSkipNxN = 1.2; // Skip checking "NxN using EMT" if "NxN using DCT2" is worse than "2Nx2N using DCT2"
      if( costSizeNxNemtFirstPass > thEmtIntraFastSkipNxN * costSize2Nx2NemtFirstPass )
      {
        break;
      }
    }
#endif
#endif
  } //for emtCuFlag
}

猜你喜欢

转载自blog.csdn.net/yolo_life/article/details/81664540