VVC代码 BMS 帧内预测学习之三:67个角度预测 predIntraAng()

7 篇文章 0 订阅

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
    }   
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值