HEVC代码学习6:filterHor和filterVer函数

帧间预测分为运动估计ME和运动补偿MV,其中用到了MV的亚像素搜索,需要使用filterHor和filterVer进行插值。
这里使用的是HM16,在之前版本中分为filterHorLuma、filterHorChroma和filterHorLuma、filterVerChroma。HM16中已经将亮度和色度插值滤波器整合。

我们来从最底层插值滤波器函数filter看起。filter函数代码如下,对同一亚像素位置(如1/4处)处进行插值,插值后的MV存在dst中。

/** 插值滤波器
 * \brief Apply FIR filter to a block of samples  
 *
 * \tparam N          Number of taps  抽头数
 * \tparam isVertical Flag indicating filtering along vertical direction
 * \tparam isFirst    Flag indicating whether it is the first filtering operation
 * \tparam isLast     Flag indicating whether it is the last filtering operation
 * \param  bitDepth   Bit depth of samples
 * \param  src        Pointer to source samples  源MV地址
 * \param  srcStride  Stride of source samples
 * \param  dst        Pointer to destination samples   插值后的MV地址
 * \param  dstStride  Stride of destination samples
 * \param  width      Width of block
 * \param  height     Height of block
 * \param  coeff      Pointer to filter taps  抽头系数
 */
template
Void TComInterpolationFilter::filter(Int bitDepth, Pel const *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, TFilterCoeff const *coeff)
{
  Int row, col;

  Pel c[8];   //系数数组
  c[0] = coeff[0];   //抽头0系数
  c[1] = coeff[1];   //抽头1系数
  if ( N >= 4 )    //N≥4时,取抽头2和3系数(UV分量)
  {
    c[2] = coeff[2];
    c[3] = coeff[3];
  }
  if ( N >= 6 )    //N≥6时,取抽头4和5系数
  {
    c[4] = coeff[4];
    c[5] = coeff[5];
  }
  if ( N == 8 )    //N=8时,取抽头6和7系数(Y分量)
  {
    c[6] = coeff[6];
    c[7] = coeff[7];
  }


  Int cStride = ( isVertical ) ? srcStride : 1;   //垂直情况下步长为srcStride,水平情况下为1
  src -= ( N/2 - 1 ) * cStride;   //找到前面N/2-1个整数点

  Int offset;
  Pel maxVal;
  Int headRoom = std::max(2, (IF_INTERNAL_PREC - bitDepth));
  Int shift    = IF_FILTER_PREC;
  // with the current settings (IF_INTERNAL_PREC = 14 and IF_FILTER_PREC = 6), though headroom can be
  // negative for bit depths greater than 14, shift will remain non-negative for bit depths of 8->20
  assert(shift >= 0);

  if ( isLast )
  {
    shift += (isFirst) ? 0 : headRoom;
    offset = 1 << (shift - 1);
    offset += (isFirst) ? 0 : IF_INTERNAL_OFFS << IF_FILTER_PREC;
    maxVal = (1 << bitDepth) - 1;
  }
  else
  {
    shift -= (isFirst) ? headRoom : 0;
    offset = (isFirst) ? -IF_INTERNAL_OFFS << shift : 0;
    maxVal = 0;
  }

  for (row = 0; row < height; row++)
  {
    for (col = 0; col < width; col++)
    {
      Int sum;

      //从N/2-1个整数点开始,取N个整数点乘对应的抽头系数求和。
      sum  = src[ col + 0 * cStride] * c[0];    
      sum += src[ col + 1 * cStride] * c[1];    
      if ( N >= 4 )
      {
        sum += src[ col + 2 * cStride] * c[2];
        sum += src[ col + 3 * cStride] * c[3];
      }
      if ( N >= 6 )
      {
        sum += src[ col + 4 * cStride] * c[4];
        sum += src[ col + 5 * cStride] * c[5];
      }
      if ( N == 8 )
      {
        sum += src[ col + 6 * cStride] * c[6];
        sum += src[ col + 7 * cStride] * c[7];
      }

      Pel val = ( sum + offset ) >> shift;  
      if ( isLast )
      {
        val = ( val < 0 ) ? 0 : val;    //保证不小于0
        val = ( val > maxVal ) ? maxVal : val;   //保证不越界
      }
      dst[col] = val;   //存储插值后的MV
    }

    src += srcStride;   
    dst += dstStride;
  }
}

再来看上一层的函数,函数代码如下。是一个分类处理,分为普通操作、第一次操作和最后一次操作,分别传入不同参数调用底层filter函数进行插值。这里直接通过N来区分是亮度插值和色度插值。

/**
 * \brief Filter a block of samples (horizontal)
 *
 * \tparam N          Number of taps 抽头数:Y-8,UV-4
 * \param  bitDepth   Bit depth of samples
 * \param  src        Pointer to source samples
 * \param  srcStride  Stride of source samples
 * \param  dst        Pointer to destination samples
 * \param  dstStride  Stride of destination samples
 * \param  width      Width of block
 * \param  height     Height of block
 * \param  isLast     Flag indicating whether it is the last filtering operation
 * \param  coeff      Pointer to filter taps 抽头系数
 */
template     //插值
Void TComInterpolationFilter::filterHor(Int bitDepth, Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Bool isLast, TFilterCoeff const *coeff)
{
  if ( isLast )
  {
    filterfalse, true, true>(bitDepth, src, srcStride, dst, dstStride, width, height, coeff);
  }
  else
  {
    filterfalse, true, false>(bitDepth, src, srcStride, dst, dstStride, width, height, coeff);
  }
}

template
Void TComInterpolationFilter::filterVer(Int bitDepth, Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Bool isFirst, Bool isLast, TFilterCoeff const *coeff)
{
  if ( isFirst && isLast )
  {
    filtertrue, true, true>(bitDepth, src, srcStride, dst, dstStride, width, height, coeff);
  }
  else if ( isFirst && !isLast )
  {
    filtertrue, true, false>(bitDepth, src, srcStride, dst, dstStride, width, height, coeff);
  }
  else if ( !isFirst && isLast )
  {
    filtertrue, false, true>(bitDepth, src, srcStride, dst, dstStride, width, height, coeff);
  }
  else
  {
    filtertrue, false, false>(bitDepth, src, srcStride, dst, dstStride, width, height, coeff);
  }
}

最后来看最上层的filterHor和filterVer,代码如下,也是一个分类处理,调用下层函数处理。分了三种情况:frac = 0、亮度和色度。frac = 0,即整数,不需要插值。

/**
 * \brief Filter a block of Luma/Chroma samples (horizontal)    
 *
 * \param  compID     Chroma component ID
 * \param  src        Pointer to source samples
 * \param  srcStride  Stride of source samples
 * \param  dst        Pointer to destination samples
 * \param  dstStride  Stride of destination samples
 * \param  width      Width of block
 * \param  height     Height of block
 * \param  frac       Fractional sample offset  分数偏移
 * \param  isLast     Flag indicating whether it is the last filtering operation
 * \param  fmt        Chroma format
 * \param  bitDepth   Bit depth
 */
Void TComInterpolationFilter::filterHor(const ComponentID compID, Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Int frac, Bool isLast, const ChromaFormat fmt, const Int bitDepth )
{
  if ( frac == 0 )   //整数直接复制
  {
    filterCopy(bitDepth, src, srcStride, dst, dstStride, width, height, true, isLast );
  }
  else if (isLuma(compID))   //Y分量小数插值
  {
    assert(frac >= 0 && frac < LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS);
    filterHor(bitDepth, src, srcStride, dst, dstStride, width, height, isLast, m_lumaFilter[frac]);
  }
  else
  {
    const UInt csx = getComponentScaleX(compID, fmt);
    assert(frac >=0 && csx<2 && (frac<<(1-csx)) < CHROMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS);
    filterHor(bitDepth, src, srcStride, dst, dstStride, width, height, isLast, m_chromaFilter[frac<<(1-csx)]);
  }
}

Void TComInterpolationFilter::filterVer(const ComponentID compID, Pel *src, Int srcStride, Pel *dst, Int dstStride, Int width, Int height, Int frac, Bool isFirst, Bool isLast, const ChromaFormat fmt, const Int bitDepth )
{
  if ( frac == 0 )
  {
    filterCopy(bitDepth, src, srcStride, dst, dstStride, width, height, isFirst, isLast );
  }
  else if (isLuma(compID))
  {
    assert(frac >= 0 && frac < LUMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS);
    filterVer(bitDepth, src, srcStride, dst, dstStride, width, height, isFirst, isLast, m_lumaFilter[frac]);
  }
  else
  {
    const UInt csy = getComponentScaleY(compID, fmt);
    assert(frac >=0 && csy<2 && (frac<<(1-csy)) < CHROMA_INTERPOLATION_FILTER_SUB_SAMPLE_POSITIONS);
    filterVer(bitDepth, src, srcStride, dst, dstStride, width, height, isFirst, isLast, m_chromaFilter[frac<<(1-csy)]);
  }
}

你可能感兴趣的:(HEVC,HM,HEVC代码学习)