HEVC 亚像素插值offset和shift推导

在调用水平亮度像素插值时,

filter<N, (isVertical)false, (isFirst)true, (isLast)false>(bitDepth, src, srcStride, dst, dstStride, width, height, coeff)

  Int row, col;

  Pel c[8];

  c[0] = coeff[0];

  c[1] = coeff[1];

  if ( N >= 4 )

  {

    c[2] = coeff[2];

    c[3] = coeff[3];

  }

  if ( N >= 6 )

  {

    c[4] = coeff[4];

    c[5] = coeff[5];

  }

  if ( N == 8 )

  {

    c[6] = coeff[6];

    c[7] = coeff[7];

  }

 

  Int cStride = ( isVertical ) ? srcStride : 1;

  src -= ( N/2 - 1 ) * cStride;

 

  Int offset;

  Pel maxVal;

  Int headRoom = std::max<Int>(2, (IF_INTERNAL_PREC - bitDepth));

  Int shift    = IF_FILTER_PREC;   // IF_FILTER_PREC=6

  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;      // shift = 6 – 4 = 2

    offset = (isFirst) ? -IF_INTERNAL_OFFS << shift : 0; //offset=-2^15=32768

    maxVal = 0;

  }

 

#if VECTOR_CODING__INTERPOLATION_FILTER && (RExt__HIGH_BIT_DEPTH_SUPPORT==0)

  if( bitDepth <= 10 )

  {

    if( N == 8 && !( width & 0x07 ) )

    {

      Short minVal = 0;

      __m128i mmOffset = _mm_set1_epi32( offset );

      __m128i mmCoeff[8];

      __m128i mmMin = _mm_set1_epi16( minVal );

      __m128i mmMax = _mm_set1_epi16( maxVal );

      for( Int n = 0 ; n < 8 ; n++ )

        mmCoeff[n] = _mm_set1_epi16( c[n] );

      for( row = 0 ; row < height ; row++ )

      {

        for( col = 0 ; col < width ; col += 8 )

        {

          __m128i mmFiltered = simdInterpolateLuma8( src + col , cStride , mmCoeff , mmOffset , shift );

          if( isLast )

          {

            mmFiltered = simdClip3( mmMin , mmMax , mmFiltered );

          }

          _mm_storeu_si128( ( __m128i * )( dst + col ) , mmFiltered );

        }

        src += srcStride;

        dst += dstStride;

      }

      return;

    }

 }

 

通过上述观察发现,水平插值后的结果为: 

 

 

在调用垂直亮度编码时:

filter<N, (isVertical)true, (isFirst)false, (isLast)true>(bitDepth, src, srcStride, dst, dstStride, width, height, coeff)

  Int row, col;

  Pel c[8];

  c[0] = coeff[0];

  c[1] = coeff[1];

  if ( N >= 4 )

  {

    c[2] = coeff[2];

    c[3] = coeff[3];

  }

  if ( N >= 6 )

  {

    c[4] = coeff[4];

    c[5] = coeff[5];

  }

  if ( N == 8 )

  {

    c[6] = coeff[6];

    c[7] = coeff[7];

  }

 

  Int cStride = ( isVertical ) ? srcStride : 1;

  src -= ( N/2 - 1 ) * cStride;

 

  Int offset;

  Pel maxVal;

  Int headRoom = std::max<Int>(2, (IF_INTERNAL_PREC - bitDepth));   // headRoom = 14 – 10 = 4

  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;  // shift = 6 + 4 = 10

    offset = 1 << (shift - 1);           // offset = 1 << 9 = 512

offset += (isFirst) ? 0 : IF_INTERNAL_OFFS << IF_FILTER_PREC;

// offset=512+2^(13+6)512=524288 + 512 = 524800

    maxVal = (1 << bitDepth) - 1;

  }

  else

  {

    shift -= (isFirst) ? headRoom : 0;

    offset = (isFirst) ? -IF_INTERNAL_OFFS << shift : 0;

    maxVal = 0;

  }

 

#if VECTOR_CODING__INTERPOLATION_FILTER && (RExt__HIGH_BIT_DEPTH_SUPPORT==0)

  if( bitDepth <= 10 )

  {

    if( N == 8 && !( width & 0x07 ) )

    {

      Short minVal = 0;

      __m128i mmOffset = _mm_set1_epi32( offset );

      __m128i mmCoeff[8];

      __m128i mmMin = _mm_set1_epi16( minVal );

      __m128i mmMax = _mm_set1_epi16( maxVal );

      for( Int n = 0 ; n < 8 ; n++ )

        mmCoeff[n] = _mm_set1_epi16( c[n] );

      for( row = 0 ; row < height ; row++ )

      {

        for( col = 0 ; col < width ; col += 8 )

        {

          __m128i mmFiltered = simdInterpolateLuma8( src + col , cStride , mmCoeff , mmOffset , shift );

          if( isLast )

          {

            mmFiltered = simdClip3( mmMin , mmMax , mmFiltered );

          }

          _mm_storeu_si128( ( __m128i * )( dst + col ) , mmFiltered );

        }

        src += srcStride;

        dst += dstStride;

      }

      return;

}

}

通过观察发现,插值的结果为

  

 

 

推导过程如下

 

 

posted @ 2022-05-11 19:34  风影旋新月  阅读(142)  评论(0编辑  收藏  举报