VVC代碼 BMS 幀內預測學習之三:67個角度預測 predIntraAng()

predIntraAng()

在模式決策過程中,此函數被循環調用,其主要步驟爲:
通過上層獲取當前要預測的方向,若是Planar模式則進入函數xPredIntraPlanar(),若是DC則進入函數xPredIntraDc(), 若爲角度模式則進入xPredIntraAng()
同時,判斷是否採用PDPC,並採取相關措施。

void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, const PredictionUnit &pu, const bool useFilteredPredSamples )
{
  const ComponentID    compID       = MAP_CHROMA( compId );
  const ChannelType    channelType  = toChannelType( compID );
  const Int            iWidth       = piPred.width;
  const Int            iHeight      = piPred.height;
  const UInt           uiDirMode    = PU::getFinalIntraMode( pu, channelType );


  CHECK( g_aucLog2[iWidth] < 2 && pu.cs->pcv->noChroma2x2, "Size not allowed" );
  CHECK( g_aucLog2[iWidth] > 7, "Size not allowed" );
  CHECK( iWidth != iHeight && !pu.cs->pcv->rectCUs, "Rectangular block are only allowed with QTBT" );

  const Int  srcStride = ( iWidth + iHeight + 1 );

#if HEVC_USE_HOR_VER_PREDFILTERING
  const Bool enableEdgeFilters = !(CU::isRDPCMEnabled( *pu.cu ) && pu.cu->transQuantBypass);
#endif
//參考塊左上角首地址
  Pel *ptrSrc = getPredictorPtr( compID, useFilteredPredSamples );

//************************************************ 判斷是否使用PDPC
#if JEM_TOOLS
#if HM_PDPC_AS_IN_JEM //PM: reproducing JEM behavior (however, is boundary condition for QTBT off case really useful?)
  bool pdpcCondition = (pu.cs->sps->getSpsNext().isIntraPDPC() && pu.cu->pdpc && (pu.cs->pcv->rectCUs || (pu.cu->lumaPos().x && pu.cu->lumaPos().y))) || (pu.cs->sps->getSpsNext().isPlanarPDPC() && (uiDirMode == PLANAR_IDX));
#else
  bool pdpcCondition = ((pu.cs->sps->getSpsNext().isIntraPDPC()) && pu.cu->pdpc) || (pu.cs->sps->getSpsNext().isPlanarPDPC() && (uiDirMode == PLANAR_IDX));
#endif
//************************************************ 使用PDPC
  if( pdpcCondition )
  {
    int idxW = std::min( 4, (int)g_aucLog2[iWidth]  - 1 );
    int idxH = std::min( 4, (int)g_aucLog2[iHeight] - 1 );
#if HEVC_USE_PART_SIZE
    if( !pu.cs->pcv->only2Nx2N )
    {
      CHECK( idxW != idxH, "Non-square partitions not supported by this config" );
      if( pu.cu->partSize == SIZE_NxN && idxW == 1 ) { idxW = idxH = 0; }
    }
#endif
    const int *pPdpcParWidth;
    const int *pPdpcParHeight;
    //獲取參數
    if( pu.cs->sps->getSpsNext().isPlanarPDPC() )
    {
      pPdpcParWidth = g_pdpcParam[idxW];
      pPdpcParHeight = g_pdpcParam[idxH];
    }
    else
    {
      pPdpcParWidth = g_pdpc_pred_param[idxW][g_intraMode65to33AngMapping[uiDirMode]];
      pPdpcParHeight = g_pdpc_pred_param[idxH][g_intraMode65to33AngMapping[uiDirMode]];
    }
    const int *pPdpcParMain   = (iWidth < iHeight) ? pPdpcParHeight : pPdpcParWidth;

    const int srcStride  = iWidth + iHeight + 1;
    const int doubleSize = iWidth + iHeight;

    Pel* piRefVector = m_piTempRef + doubleSize;
    Pel* piLowpRefer = m_piFiltRef + doubleSize;
    //未濾波行/列
    for( int j = 0; j <= doubleSize; j++ ) { piRefVector[ j] = ptrSrc[j]; }
    for( int i = 1; i <= doubleSize; i++ ) { piRefVector[-i] = ptrSrc[i*srcStride]; }

    if( pPdpcParMain[5] != 0 )
    {
    //參考像素的濾波
      xReferenceFilter( doubleSize, pPdpcParMain[4], pPdpcParMain[5], piRefVector, piLowpRefer );

      // copy filtered ref. samples back to ref. buffer
      //濾波後的行/列
      for( int j = 0; j <= doubleSize; j++ ) { ptrSrc[j]           = piLowpRefer[ j]; }
      for( int i = 1; i <= doubleSize; i++ ) { ptrSrc[i*srcStride] = piLowpRefer[-i]; }
    }

    const ClpRng& clpRng( pu.cu->cs->slice->clpRng(compID) );

    switch( uiDirMode )
    {
    //HEVC的planar預測
    case( PLANAR_IDX ): xPredIntraPlanar( CPelBuf( ptrSrc, srcStride, srcStride ), piPred, *pu.cs->sps );         break;
    // including DCPredFiltering
    case( DC_IDX ):     xPredIntraDc    ( CPelBuf( ptrSrc, srcStride, srcStride ), piPred, channelType, false );  break; 
#if HEVC_USE_HOR_VER_PREDFILTERING
	//獲取由預測模式索引標識的角度模式預測方向的預測樣本,若預測像素投影在參考像素之間,需要進行線性插值
    default:            xPredIntraAng   ( CPelBuf( ptrSrc, srcStride, srcStride ), piPred, channelType,
                                         uiDirMode, clpRng, enableEdgeFilters, *pu.cs->sps, false );             break;
#else
    default:            xPredIntraAng   ( CPelBuf( ptrSrc, srcStride, srcStride ), piPred, channelType,
                                          uiDirMode, clpRng, *pu.cs->sps, false );             break;
#endif
    }
//************************************************ PDPC相關步驟
    if( pPdpcParMain[5] != 0 )
    {
    //PDPC所需未濾波數據
      // copy unfiltered ref. samples back to ref. buffer for weighted prediction
      for( int j = 0; j <= doubleSize; j++ ) { ptrSrc[j]           = piRefVector[ j]; }
      for( int i = 1; i <= doubleSize; i++ ) { ptrSrc[i*srcStride] = piRefVector[-i]; }
    }

    int scale     = (g_aucLog2[iWidth] + g_aucLog2[iHeight] < 10) ? 0 : 1;
    int parShift  = 6; //normalization factor
    int parScale  = 1 << parShift;
    int parOffset = 1 << (parShift - 1);
	
	//PDPC公式
    for( int y = 0; y < iHeight; y++ )
    {
      int shiftRow     = y >> scale;
      int coeff_Top    = pPdpcParHeight[2] >> shiftRow;
      int coeff_offset = pPdpcParHeight[3] >> shiftRow;

      for( int x = 0; x < iWidth; x++ )
      {
        int shiftCol      = x >> scale;
        int coeff_Left    =  pPdpcParWidth[0] >> shiftCol;
        int coeff_TopLeft = (pPdpcParWidth[1] >> shiftCol) + coeff_offset;
        int coeff_Cur     = parScale - coeff_Left - coeff_Top + coeff_TopLeft;

        int sampleVal = (coeff_Left* piRefVector[-y - 1] + coeff_Top * piRefVector[x + 1] - coeff_TopLeft * piRefVector[0] + coeff_Cur * piPred.at( x, y ) + parOffset) >> parShift;
        piPred.at( x, y ) = ClipPel( sampleVal, clpRng );
      }
    }
  }
  else
//************************************************ 不用PDPC
#endif
  {
    switch( uiDirMode )
    {
    case( DC_IDX ):     xPredIntraDc    ( CPelBuf( ptrSrc, srcStride, srcStride ), piPred, channelType );            break; // including DCPredFiltering
    case( PLANAR_IDX ): xPredIntraPlanar( CPelBuf( ptrSrc, srcStride, srcStride ), piPred, *pu.cs->sps );            break;
#if HEVC_USE_HOR_VER_PREDFILTERING
    default:            xPredIntraAng   ( CPelBuf( ptrSrc, srcStride, srcStride ), piPred, channelType, uiDirMode,
                                          pu.cs->slice->clpRng( compID ), enableEdgeFilters, *pu.cs->sps );          break;
#else
    default:            xPredIntraAng   ( CPelBuf( ptrSrc, srcStride, srcStride ), piPred, channelType, uiDirMode,
                                          pu.cs->slice->clpRng( compID ), *pu.cs->sps );          break;
#endif
    }   
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章