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
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章