VVC学习之五:帧内预测——帧内参考像素滤波xFilterReferenceSamples()

帧内预测过程,获取预测参考样点之后,需要判断当前单元是否满足参考样本滤波条件。如满足,则需要对参考样本进行
[1,2,1]的平滑滤波。

不需要进行平滑滤波的情况:

  • sps中规定关闭帧内参考样本平滑
  • 帧内色度信号预测不需要滤波
  • 帧内ISP预测模式参考样本不需要滤波
  • 多行预测的扩展行不需要滤波
  • 帧内预测DC模式
  • 块内样本总数大于32的块采用Planar模式预测时

滤波条件的判定函数为useFilteredIntraRefSamples(),具体代码如下如下:

bool IntraPrediction::useFilteredIntraRefSamples( const ComponentID &compID, const PredictionUnit &pu, bool modeSpecific, const UnitArea &tuArea )
{
  const SPS         &sps    = *pu.cs->sps;
  const ChannelType  chType = toChannelType( compID );

  // high level conditions
  if( sps.getSpsRangeExtension().getIntraSmoothingDisabledFlag() )                                       { return false; }
  if( !isLuma( chType ) && pu.chromaFormat != CHROMA_444 )                                               { return false; }

#if JVET_M0102_INTRA_SUBPARTITIONS
  if( pu.cu->ispMode && isLuma(compID) )                                                                 { return false; }
#endif

  if( !modeSpecific )                                                                                    { return true; }

  if (pu.multiRefIdx)                                                                                    { return false; }

  // pred. mode related conditions
  const int dirMode = PU::getFinalIntraMode( pu, chType );
  int predMode = getWideAngle(tuArea.blocks[compID].width, tuArea.blocks[compID].height, dirMode);
  if (predMode != dirMode )                                                                              { return true; }
  if (dirMode == DC_IDX)                                                                                 { return false; }
  if (dirMode == PLANAR_IDX)
  {
    return tuArea.blocks[compID].width * tuArea.blocks[compID].height > 32 ? true : false;
  }

  int diff = std::min<int>( abs( dirMode - HOR_IDX ), abs( dirMode - VER_IDX ) );
  int log2Size = ((g_aucLog2[tuArea.blocks[compID].width] + g_aucLog2[tuArea.blocks[compID].height]) >> 1);
  CHECK( log2Size >= MAX_INTRA_FILTER_DEPTHS, "Size not supported" );
  return (diff > m_aucIntraFilter[chType][log2Size]);
}

具体滤波操作由函数xFilterReferenceSamples()实现,代码如下

/**
* \param refBufUnfiltered: 已填充参考像素,待滤波
* \param refBufFiltered:  滤波像素存储首地址
**/
void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps, int multiRefIdx)
{
  if (area.compID != COMPONENT_Y) 
  {
    multiRefIdx = 0;
  }
  int whRatio          = std::max(1, int(area.width  / area.height));
  int hwRatio          = std::max(1, int(area.height / area.width));
  const int  predSize  = m_topRefLength  + (whRatio + 1) * multiRefIdx; // 上方参考样本数
  const int  predHSize = m_leftRefLength + (hwRatio + 1) * multiRefIdx; // 左侧参考样本数
  const int  predStride = predSize + 1;

 // 帧内参考样本强滤波,默认关闭
#if HEVC_USE_INTRA_SMOOTHING_T32 || HEVC_USE_INTRA_SMOOTHING_T64
  // Strong intra smoothing
  ChannelType chType = toChannelType( area.compID );
  if( sps.getUseStrongIntraSmoothing() && isLuma( chType ) )
  {
    const Pel bottomLeft = refBufUnfiltered[predStride * predHSize];
    const Pel topLeft    = refBufUnfiltered[0];
    const Pel topRight   = refBufUnfiltered[predSize];

    const int  threshold     = 1 << (sps.getBitDepth( chType ) - 5);
    const bool bilinearLeft  = abs( (bottomLeft + topLeft)  - (2 * refBufUnfiltered[predStride * tuHeight]) ) < threshold; //difference between the
    const bool bilinearAbove = abs( (topLeft    + topRight) - (2 * refBufUnfiltered[             tuWidth ]) ) < threshold; //ends and the middle

    if( tuWidth >= 32 && tuHeight >= 32 && bilinearLeft && bilinearAbove )
#if !HEVC_USE_INTRA_SMOOTHING_T32
    if( tuWidth > 32 && tuHeight > 32 )
#endif
#if !HEVC_USE_INTRA_SMOOTHING_T64
    if( tuWidth < 64 && tuHeight < 64 )
#endif
    {
      Pel *piDestPtr = refBufFiltered + (predStride * predHSize); // bottom left

      // apply strong intra smoothing
      for (int i = 0; i < predHSize; i++, piDestPtr -= predStride) //left column (bottom to top)
      {
        *piDestPtr = (((predHSize - i) * bottomLeft) + (i * topLeft) + predHSize / 2) / predHSize;
      }
      for( uint32_t i = 0; i <= predSize; i++, piDestPtr++ )            //full top row (left-to-right)
      {
        *piDestPtr = (((predSize - i) * topLeft) + (i * topRight) + predSize / 2) / predSize;
      }

      return;
    }
  }
#endif

  // Regular reference sample filter
  const Pel *piSrcPtr  = refBufUnfiltered + (predStride * predHSize); // bottom left 未滤波参考,指向移向左下第一个参考样本
        Pel *piDestPtr = refBufFiltered   + (predStride * predHSize); // bottom left 目标滤波像素

  // bottom left (not filtered)
  *piDestPtr = *piSrcPtr; // 跳过第一个像素
  piDestPtr -= predStride;
  piSrcPtr  -= predStride;
  //left column (bottom to top)
  for( int i = 1; i < predHSize; i++, piDestPtr -= predStride, piSrcPtr -= predStride)
  {
    *piDestPtr = (piSrcPtr[predStride] + 2 * piSrcPtr[0] + piSrcPtr[-predStride] + 2) >> 2; //滤波系数[1,2,1]
  }
  //top-left
  *piDestPtr = (piSrcPtr[predStride] + 2 * piSrcPtr[0] + piSrcPtr[1] + 2) >> 2;
  piDestPtr++;
  piSrcPtr++;
  //top row (left-to-right)
  for( uint32_t i=1; i < predSize; i++, piDestPtr++, piSrcPtr++ )
  {
    *piDestPtr = (piSrcPtr[1] + 2 * piSrcPtr[0] + piSrcPtr[-1] + 2) >> 2;
  }
  // top right (not filtered)
  *piDestPtr=*piSrcPtr;
}

你可能感兴趣的:(VVC/H.266学习日记)