H.266/VVC VTM阅读10-编码结构CodingStructure

  VTM中cs(CodingStructure)是一个常用的类,含有一个区域内的各种编码信息,例如区域所属位置(帧、片、坐标、大小)、量化参数、各参数集、用于编码端搜索的模式信息,另外cs建立了3个列表,分别储存区域内CU、PU、TU。CS可以描述一个CU的编码信息,也可以描述一帧内所有CU的编码信息,取决于CS描述区域的大小。VTM编码CU时会建立tempCS和bestCS,用于决策最佳模式,此时cu列表中应该只含有一个cu。另外picture头信息中也有cs变量储存整帧内地编码信息,可从cu列表获取整帧cu。下面记录几点cs在编码cu中的应用。

1、分割模式决策

  由于CU可以进一步划分为各种大小的CU,EncCu在创建时建立了几个CS列表来存储各种大小CU的编码结构。m_pTempCS2和m_pBestCS2用于色度不划分的情况。

void EncCu::create( EncCfg* encCfg )
{
  ...
  unsigned      numWidths     = gp_sizeIdxInfo->numWidths();
  unsigned      numHeights    = gp_sizeIdxInfo->numHeights();
  m_pTempCS = new CodingStructure**  [numWidths];
  m_pBestCS = new CodingStructure**  [numWidths];
  m_pTempCS2 = new CodingStructure** [numWidths];
  m_pBestCS2 = new CodingStructure** [numWidths];

  for( unsigned w = 0; w < numWidths; w++ )
  {
    m_pTempCS[w] = new CodingStructure*  [numHeights];
    m_pBestCS[w] = new CodingStructure*  [numHeights];
    m_pTempCS2[w] = new CodingStructure* [numHeights];
    m_pBestCS2[w] = new CodingStructure* [numHeights];

    for( unsigned h = 0; h < numHeights; h++ )
    {
      unsigned width  = gp_sizeIdxInfo->sizeFrom( w );
      unsigned height = gp_sizeIdxInfo->sizeFrom( h );

      if( gp_sizeIdxInfo->isCuSize( width ) && gp_sizeIdxInfo->isCuSize( height ) )
      {
        m_pTempCS[w][h] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
        m_pBestCS[w][h] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );

        m_pTempCS[w][h]->create(chromaFormat, Area(0, 0, width, height), false, (bool)encCfg->getPLTMode());
        m_pBestCS[w][h]->create(chromaFormat, Area(0, 0, width, height), false, (bool)encCfg->getPLTMode());

        m_pTempCS2[w][h] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
        m_pBestCS2[w][h] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );

        m_pTempCS2[w][h]->create(chromaFormat, Area(0, 0, width, height), false, (bool)encCfg->getPLTMode());
        m_pBestCS2[w][h]->create(chromaFormat, Area(0, 0, width, height), false, (bool)encCfg->getPLTMode());
      }
      else
      {
        m_pTempCS[w][h] = nullptr;
        m_pBestCS[w][h] = nullptr;
        m_pTempCS2[w][h] = nullptr;
        m_pBestCS2[w][h] = nullptr;
      }
    }
  }
  ...
}

  在编码子CU前获取对应子CS,编码子CU中得到最佳子CS,编码子CU后将最佳子CS的cost记录到当前CS,所有子CS的cost加上划分信息的cost作为当前模式的cost。

void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode, const ModeType modeTypeParent, bool &skipInterPass )
{
  ...
  do
  {
    const auto &subCUArea  = partitioner.currArea();
    if( tempCS->picture->Y().contains( subCUArea.lumaPos() ) )
    {
      const unsigned wIdx    = gp_sizeIdxInfo->idxFrom( subCUArea.lwidth () );
      const unsigned hIdx    = gp_sizeIdxInfo->idxFrom( subCUArea.lheight() );

      CodingStructure *tempSubCS = m_pTempCS[wIdx][hIdx];
      CodingStructure *bestSubCS = m_pBestCS[wIdx][hIdx];

      tempCS->initSubStructure( *tempSubCS, partitioner.chType, subCUArea, false );
      tempCS->initSubStructure( *bestSubCS, partitioner.chType, subCUArea, false );
      ...
      bool keepResi = KEEP_PRED_AND_RESI_SIGNALS;
      tempCS->useSubStructure( *bestSubCS, partitioner.chType, CS::getArea( *tempCS, subCUArea, partitioner.chType ), KEEP_PRED_AND_RESI_SIGNALS, true, keepResi, keepResi );
      ...
    }
  } while( partitioner.nextPart( *tempCS ) );

  partitioner.exitCurrSplit();
  ...
}

  另外,帧内搜索可以进一步划分CU,因此帧内搜索中的CS也存在类似用法。

2、根据cs信息建立cu
void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
  ...
  for( int bcwLoopIdx = 0; bcwLoopIdx < bcwLoopNum; bcwLoopIdx++ )
  {
	  ...
	  CodingUnit &cu      = tempCS->addCU( tempCS->area, partitioner.chType );
	
	  partitioner.setCUData( cu );
	  cu.slice            = tempCS->slice;
	  cu.tileIdx          = tempCS->pps->getTileIdx( tempCS->area.lumaPos() );
	  cu.skip             = false;
	  cu.mmvdSkip = false;
	//cu.affine
	  cu.predMode         = MODE_INTER;
	  cu.chromaQpAdj      = m_cuChromaQpOffsetIdxPlus1;
	  cu.qp               = encTestMode.qp;
	  CU::addPUs( cu );
	
	  cu.BcwIdx = g_BcwSearchOrder[bcwLoopIdx];
	  uint8_t bcwIdx = cu.BcwIdx;
	  bool  testBcw = (bcwIdx != BCW_DEFAULT);
	
	  m_pcInterSearch->predInterSearch( cu, partitioner );
	  ...
  }
  ...
}

3、更新最佳cs
bool EncCu::xCheckBestMode( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
  bool bestCSUpdated = false;

  if( !tempCS->cus.empty() )
  {
    if( tempCS->cus.size() == 1 )
    {
      const CodingUnit& cu = *tempCS->cus.front();
      CHECK( cu.skip && !cu.firstPU->mergeFlag, "Skip flag without a merge flag is not allowed!" );
    }

#if WCG_EXT
    DTRACE_BEST_MODE( tempCS, bestCS, m_pcRdCost->getLambda( true ) );
#else
    DTRACE_BEST_MODE( tempCS, bestCS, m_pcRdCost->getLambda() );
#endif

    if( m_modeCtrl->useModeResult( encTestMode, tempCS, partitioner ) )
    {
      std::swap( tempCS, bestCS );
      // store temp best CI for next CU coding
      m_CurrCtx->best = m_CABACEstimator->getCtx();
      m_bestModeUpdated = true;
      bestCSUpdated = true;
    }
  }
  // reset context states
  m_CABACEstimator->getCtx() = m_CurrCtx->start;
  return bestCSUpdated;
}

函数中调用了useModeResult函数。useModeResult函数注意分为两部分,首先是根据当前模式对CU的上下文进行更新,然后是判断当前的rd cost是否是小于最佳的rd cost。

bool EncModeCtrlMTnoRQT::useModeResult( const EncTestMode& encTestmode, CodingStructure*& tempCS, Partitioner& partitioner )
{
  xExtractFeatures( encTestmode, *tempCS );
  ComprCUCtx& cuECtx = m_ComprCUCtxList.back();
  if(      encTestmode.type == ETM_SPLIT_BT_H )
  {
    cuECtx.set( BEST_HORZ_SPLIT_COST, tempCS->cost );
  }
  else if( encTestmode.type == ETM_SPLIT_BT_V )
  {
    cuECtx.set( BEST_VERT_SPLIT_COST, tempCS->cost );
  }
  else if( encTestmode.type == ETM_SPLIT_TT_H )
  {
    ...
  }
 ...
  // for now just a simple decision based on RD-cost or choose tempCS if bestCS is not yet coded
  if( tempCS->features[ENC_FT_RD_COST] != MAX_DOUBLE && ( !cuECtx.bestCS || ( ( tempCS->features[ENC_FT_RD_COST] + ( tempCS->useDbCost ? tempCS->costDbOffset : 0 ) ) < ( cuECtx.bestCS->features[ENC_FT_RD_COST] + ( tempCS->useDbCost ? cuECtx.bestCS->costDbOffset : 0 ) ) ) ) )
  {
    cuECtx.bestCS = tempCS;
    cuECtx.bestCU = tempCS->cus[0];
    cuECtx.bestTU = cuECtx.bestCU->firstTU;
    if( isModeInter( encTestmode ) )
    {
      //Here we take the best cost of both inter modes. We are assuming only the inter modes (and all of them) have come before the intra modes!!!
      cuECtx.bestInterCost = cuECtx.bestCS->cost;
    }
    return true;
  }
  else
  {
    return false;
  }
}

你可能感兴趣的:(H.266/VVC,视频编码)