VTM10.0xPredIntraAng函数解析

Posted 神遁克里苏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VTM10.0xPredIntraAng函数解析相关的知识,希望对你有一定的参考价值。

xPredIntraAng函数内进行角度模式的解析,获取块内的预测值。

void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const ClpRng& clpRng)
{
  int width =int(pDst.width);
  int height=int(pDst.height);

  const bool bIsModeVer     = m_ipaParam.isModeVer;
  const int  multiRefIdx    = m_ipaParam.multiRefIndex;
  const int  intraPredAngle = m_ipaParam.intraPredAngle;
  const int  absInvAngle    = m_ipaParam.absInvAngle;

  Pel* refMain;
  Pel* refSide;

  Pel  refAbove[2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX];
  Pel  refLeft [2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX];

  // Initialize the Main and Left reference array.
  //先初始化先初始化主要的和左边的参考
  //predModeIntra与intraPredAngle不同,前者才是指模式号,后者是角度
  //小于0是指18到49的角度
  if (intraPredAngle < 0)
  {//+ multiRefIdx是因为第1参考行比第0参考行多出一个,第2参考行比第0参考行多出2个像素
    for (int x = 0; x <= width + 1 + multiRefIdx; x++)
    {//buf[y * stride + x];,这里就是at(x, 0)=0*stride+x
      refAbove[x + height] = pSrc.at(x, 0);//x+height是为了预留主参考像素向左扩展的位置
    }
    for (int y = 0; y <= height + 1 + multiRefIdx; y++)
    {//buf[y * stride + x];,这里就是1*stride+y
      refLeft[y + width] = pSrc.at(y, 1);
    }//怀疑是因为pstr中存放的是两行,一行上边的一行左边的?

    
    //因为对于19到49 的角度只用refAbove + height或是refLeft + width即可预测
    //bIsModeVer表示是否是偏向垂直的预测模式,如果是则主参考行为上边,副参考行为左边。
    //如果是偏向水平的预测模式,则主参考行为左边,副参考行为上边
    //本函数后面把主参考行当成上参考行进行预测,那么偏向水平的预测模式生成的预测图像会转置,预测结束后要转置回来
    refMain = bIsModeVer ? refAbove + height : refLeft + width;
    refSide = bIsModeVer ? refLeft + width : refAbove + height;

    // Extend the Main reference to the left.
    //向左边扩展主参考行
    int sizeSide = bIsModeVer ? height : width;
    for (int k = -sizeSide; k <= -1; k++)
    {
      refMain[k] = refSide[std::min((-k * absInvAngle + 256) >> 9, sizeSide)];
    }
  }
  else//intraPredAngle>=0
  {
    for (int x = 0; x <= m_topRefLength + multiRefIdx; x++)
    {
      refAbove[x] = pSrc.at(x, 0);
    }
    for (int y = 0; y <= m_leftRefLength + multiRefIdx; y++)
    {
      refLeft[y] = pSrc.at(y, 1);
    }

    refMain = bIsModeVer ? refAbove : refLeft;
    refSide = bIsModeVer ? refLeft : refAbove;

    // Extend main reference to right using replication
    //用复制的方式,向右边扩展主参考行
    const int log2Ratio = floorLog2(width) - floorLog2(height);
    const int s         = std::max<int>(0, bIsModeVer ? log2Ratio : -log2Ratio);
    const int maxIndex  = (multiRefIdx << s) + 2;
    const int refLength = bIsModeVer ? m_topRefLength : m_leftRefLength;
    const Pel val       = refMain[refLength + multiRefIdx];
    for (int z = 1; z <= maxIndex; z++)
    {
      refMain[refLength + multiRefIdx + z] = val;
    }
  }

  // swap width/height if we are doing a horizontal mode:
  //当做偏向水平的预测模式时,把宽和长交换
  if (!bIsModeVer)
  {
    std::swap(width, height);
  }
  Pel       tempArray[MAX_CU_SIZE * MAX_CU_SIZE];
  const int dstStride = bIsModeVer ? pDst.stride : width;
  Pel *     pDstBuf   = bIsModeVer ? pDst.buf : tempArray;

  // compensate for line offset in reference line buffers
  refMain += multiRefIdx;
  refSide += multiRefIdx;

  Pel *pDsty = pDstBuf;

  if( intraPredAngle == 0 )  // pure vertical or pure horizontal, intraPredAngle等于0 表示水平或垂直模式
  {
    for( int y = 0; y < height; y++ )
    {
      for( int x = 0; x < width; x++ )
      {
        pDsty[x] = refMain[x + 1];
      }
      //PDPC,对预测值进行修正
      if (m_ipaParam.applyPDPC)
      {
        const int scale   = (floorLog2(width) + floorLog2(height) - 2) >> 2;
        const Pel topLeft = refMain[0];
        const Pel left    = refSide[1 + y];
        for (int x = 0; x < std::min(3 << scale, width); x++)
        {
          const int wL  = 32 >> (2 * x >> scale);
          const Pel val = pDsty[x];
          pDsty[x]      = ClipPel(val + ((wL * (left - topLeft) + 32) >> 6), clpRng);
        }
      }

      pDsty += dstStride;
    }
  }
  else//intraPredAngle != 0 ,其他的角度模式
  {
    for (int y = 0, deltaPos = intraPredAngle * (1 + multiRefIdx); y<height; y++, deltaPos += intraPredAngle, pDsty += dstStride)
    {
      const int deltaInt   = deltaPos >> 5;//获得整数部分
      const int deltaFract = deltaPos & 31;//获得小数部分

      if ( !isIntegerSlope( abs(intraPredAngle) ) )//如果不是整数角度
      {
        if( isLuma(channelType) )//亮度
        {
          const bool useCubicFilter = !m_ipaParam.interpolationFlag;

          //定义f,加权的权值
          const TFilterCoeff        intraSmoothingFilter[4] = {TFilterCoeff(16 - (deltaFract >> 1)), TFilterCoeff(32 - (deltaFract >> 1)), TFilterCoeff(16 + (deltaFract >> 1)), TFilterCoeff(deltaFract >> 1)};
          const TFilterCoeff* const f                       = (useCubicFilter) ? InterpolationFilter::getChromaFilterTable(deltaFract) : intraSmoothingFilter;

          for (int x = 0; x < width; x++)
          {
            Pel p[4];

            p[0] = refMain[deltaInt + x];
            p[1] = refMain[deltaInt + x + 1];
            p[2] = refMain[deltaInt + x + 2];
            p[3] = refMain[deltaInt + x + 3];

            //对这4个点进行加权
            Pel val = (f[0] * p[0] + f[1] * p[1] + f[2] * p[2] + f[3] * p[3] + 32) >> 6;

            pDsty[x] = ClipPel(val, clpRng);   // always clip even though not always needed
          }
        }
        else//色度
        {
          // Do linear filtering
          for (int x = 0; x < width; x++)
          {
            Pel p[2];

            p[0] = refMain[deltaInt + x + 1];
            p[1] = refMain[deltaInt + x + 2];

            pDsty[x] = p[0] + ((deltaFract * (p[1] - p[0]) + 16) >> 5);
          }
        }
      }
      else//如果是整数
      {
        // Just copy the integer samples
        for( int x = 0; x < width; x++ )
        {
          pDsty[x] = refMain[x + deltaInt + 1];
        }
      }
      if (m_ipaParam.applyPDPC)
      {
        const int scale       = m_ipaParam.angularScale;
        int       invAngleSum = 256;

        for (int x = 0; x < std::min(3 << scale, width); x++)
        {
          invAngleSum += absInvAngle;

          int wL   = 32 >> (2 * x >> scale);
          Pel left = refSide[y + (invAngleSum >> 9) + 1];
          pDsty[x] = pDsty[x] + ((wL * (left - pDsty[x]) + 32) >> 6);
        }
      }
    }
  }

以上是关于VTM10.0xPredIntraAng函数解析的主要内容,如果未能解决你的问题,请参考以下文章

VTM10.0predIntraAng函数解析

VTM10.0predIntraAng函数解析

VTM10.0量化之一般量化技术

VTM10.0量化之一般量化技术

VTM10.0量化之一般量化技术

VTM10.0量化之一般量化技术