HEVC代码分析-xPredIntraAng

本文详细解析了非平面模式下的帧内预测函数实现原理。针对不同的预测方向和角度,介绍了如何利用上下左右的参考像素进行预测,特别是对于非垂直和水平方向的预测,通过角度映射、余弦插值等技术实现像素级的精准预测。同时,文章还讨论了DC模式预测和边缘滤波的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该函数进行非planar模式的预测

Void TComPrediction::xPredIntraAng(       Int bitDepth,
                                    const Pel* pSrc,     Int srcStride,
                                          Pel* pTrueDst, Int dstStrideTrue,
                                          UInt uiWidth, UInt uiHeight, ChannelType channelType,
                                          UInt dirMode, const Bool bEnableEdgeFilters
                                  )
{
  // pSrc参考块指针,pTrueDst预测块指针
  Int width=Int(uiWidth);
  Int height=Int(uiHeight);
  
  // Map the mode index to main prediction direction and angle
  assert( dirMode != PLANAR_IDX ); //no planar 当前模式不可能是planar模式
  const Bool modeDC        = dirMode==DC_IDX;

  // Do the DC prediction DC模式
  if (modeDC)
  {
	// 获取DC值
    const Pel dcval = predIntraGetPredValDC(pSrc, srcStride, width, height);
	// 对预测像素全部赋DC值
    for (Int y=height;y>0;y--, pTrueDst+=dstStrideTrue)
    {
      for (Int x=0; x<width;) // width is always a multiple of 4.
      {
        pTrueDst[x++] = dcval;
      }
    }
  }
  else // Do angular predictions 角度预测模式
  {
    const Bool       bIsModeVer         = (dirMode >= 18); //是否是垂直类模式
    const Int        intraPredAngleMode = (bIsModeVer) ? (Int)dirMode - VER_IDX :  -((Int)dirMode - HOR_IDX);	// 当前模式与水平或竖直模式的差值,可以作为后面列表的下标
    const Int        absAngMode         = abs(intraPredAngleMode); // 差值的绝对值
    const Int        signAng            = intraPredAngleMode < 0 ? -1 : 1; // 差值的符号
	// 是否需要边缘滤波,因为竖直和水平模式边缘像素需要考虑对应方向上的变化趋势
    const Bool       edgeFilter         = bEnableEdgeFilters && isLuma(channelType) && (width <= MAXIMUM_INTRA_FILTERED_WIDTH) && (height <= MAXIMUM_INTRA_FILTERED_HEIGHT);

    // Set bitshifts and scale the angle parameter to block size
    static const Int angTable[9]    = {0,    2,    5,   9,  13,  17,  21,  26,  32}; // 偏移值绝对值表
	// 32除以偏移值是角度的余切值,乘以256是为了保持精度,因此invAngTable可以看作缩放后的角度余切值列表
    static const Int invAngTable[9] = {0, 4096, 1638, 910, 630, 482, 390, 315, 256}; // (256 * 32) / Angle
    Int invAngle                    = invAngTable[absAngMode]; // 当前角度的缩放余切值
    Int absAng                      = angTable[absAngMode]; // 当前角度偏移值绝对值
    Int intraPredAngle              = signAng * absAng; // 当前角度偏移值

    Pel* refMain; // 主参考像素,垂直类模式即为上方的参考像素
    Pel* refSide; // 侧边参考像素,垂直类模式即为左侧的参考像素

    Pel  refAbove[2*MAX_CU_SIZE+1]; // 上方参考像素
    Pel  refLeft[2*MAX_CU_SIZE+1]; // 左侧参考像素

    // Initialize the Main and Left reference array.
    if (intraPredAngle < 0)
    {
	  // 对于偏移值小于零的角度,垂直类模式需要将左侧的参考像素投影到上方参考像素的左侧,水平类反之
      const Int refMainOffsetPreScale = (bIsModeVer ? height : width ) - 1;
      const Int refMainOffset         = height - 1; // 主参考像素数组向右偏移height-1存储,因为其左侧还要存储侧边参考像素
      for (Int x=0;x<width+1;x++)
      {
        refAbove[x+refMainOffset] = pSrc[x-srcStride-1]; // 填充上方参考像素
      }
      for (Int y=0;y<height+1;y++)
      {
        refLeft[y+refMainOffset] = pSrc[(y-1)*srcStride-1]; // 填充左侧参像素
      }
      refMain = (bIsModeVer ? refAbove : refLeft)  + refMainOffset; // 确定主参考像素
      refSide = (bIsModeVer ? refLeft  : refAbove) + refMainOffset; // 确定侧参考像素

      // Extend the Main reference to the left.
	  // 进行参考像素的投影
      Int invAngleSum    = 128;       // rounding for (shift by 8)
	  // (refMainOffsetPreScale+1)*intraPredAngle>>5 当前块高度乘以角度正切值,得到所需投影的最大数量
      for (Int k=-1; k>(refMainOffsetPreScale+1)*intraPredAngle>>5; k--)
      {
        invAngleSum += invAngle; // 每次加缩放余切值,相当于invAngleSum=invAngle*abs(k),开始的128为了四舍五入,不用在意
        refMain[k] = refSide[invAngleSum>>8]; // 右移8位,相当于除以256,把余切值缩放抵消。因此得到的坐标相当于是abs(k)乘以余切值,正好是投影
      }
    }
    else
    {
	  // 角度偏移值大于等于零的不需要投影
      for (Int x=0;x<2*width+1;x++)
      {
        refAbove[x] = pSrc[x-srcStride-1];
      }
      for (Int y=0;y<2*height+1;y++)
      {
        refLeft[y] = pSrc[(y-1)*srcStride-1];
      }
      refMain = bIsModeVer ? refAbove : refLeft ;
      refSide = bIsModeVer ? refLeft  : refAbove;
    }

    // swap width/height if we are doing a horizontal mode:
	// 如果是水平类模式,则先把预测像素存到tempArray里面再对称,垂直类模式则不需要最后的对称
    Pel tempArray[MAX_CU_SIZE*MAX_CU_SIZE];
    const Int dstStride = bIsModeVer ? dstStrideTrue : MAX_CU_SIZE;
    Pel *pDst = bIsModeVer ? pTrueDst : tempArray;
    if (!bIsModeVer)
    {
      std::swap(width, height);
    }

    if (intraPredAngle == 0)  // pure vertical or pure horizontal
    {
	  //竖直模式或水平模式
      for (Int y=0;y<height;y++)
      {
        for (Int x=0;x<width;x++)
        {
          pDst[y*dstStride+x] = refMain[x+1];
        }
      }

      if (edgeFilter)
      {
		// 进行边缘滤波,竖直模式对最左侧一列滤波,相应的,水平模式则是对最上方一行滤波
        for (Int y=0;y<height;y++)
        {
          pDst[y*dstStride] = Clip3 (0, ((1 << bitDepth) - 1), pDst[y*dstStride] + (( refSide[y+1] - refSide[0] ) >> 1) );
        }
      }
    }
    else
    {
	  // 非竖直或水平模式
      Pel *pDsty=pDst;

      for (Int y=0, deltaPos=intraPredAngle; y<height; y++, deltaPos+=intraPredAngle, pDsty+=dstStride)
      {
		// 遍历每一行,deltaPos为角度偏移值乘以行高,该值除以32即为参考像素相对当前像素所在列的偏移值
        const Int deltaInt   = deltaPos >> 5; // 除以32的整数部分
        const Int deltaFract = deltaPos & (32 - 1); // 余数部分

        if (deltaFract)
        {
		  // 余数不为零,说明对应的参考像素不是整像素位置,需要插值获得
          // Do linear filtering 线性插值
          const Pel *pRM=refMain+deltaInt+1; // 左侧参考像素
          Int lastRefMainPel=*pRM++; // 相邻参考像素,真正的参考位置就在他俩之间
          for (Int x=0;x<width;pRM++,x++)
          {
            Int thisRefMainPel=*pRM;
			// 两个相邻的参考像素进行线性插值得到预测值
            pDsty[x+0] = (Pel) ( ((32-deltaFract)*lastRefMainPel + deltaFract*thisRefMainPel +16) >> 5 );
            lastRefMainPel=thisRefMainPel;
          }
        }
        else
        {
		  // 余数为零,不需要插值,直接copy对应位置的参考像素即可
          // Just copy the integer samples
          for (Int x=0;x<width; x++)
          {
            pDsty[x] = refMain[x+deltaInt+1];
          }
        }
      }
    }

    // Flip the block if this is the horizontal mode
    if (!bIsModeVer)
    {
	  // 如果是水平类的模式,需要对称翻转预测值
      for (Int y=0; y<height; y++)
      {
        for (Int x=0; x<width; x++)
        {
          pTrueDst[x*dstStrideTrue] = pDst[x];
        }
        pTrueDst++;
        pDst+=dstStride;
      }
    }
  }
}
AlphaControls v14.22 100%源码版本,2019.04.19发布 AlphaControls 2019 -------------------- The Library contains skinning tool for Delphi 5/6/7/2005-2010/XE-XE8, C++ Builder 6/2006-2010/XE-XE8, RAD Studio 10 Seattle, RAD Studio 10.1 Berlin, RAD Studio 10.2 Tokyo, RAD Studio 10.3 Rio TABLE OF CONTENTS --------------- Overview Demonstration Programs Registering and Prices Feedback Overview -------- AlphaControls is a collection of standard controls with new properties added in order to enhanced program interface and add behaviors to common controls. Each control have their own properties for painting extended gradient, extended borders, alpha-blending and true blurred shadow. Graphics functions are rendered in real time, so, effects are always sharp with color scheme used. Added caption properties for position and rendering. Mouse event added provide great possiblities. Style Hints control make hints to be displayed alpha-blended and you can choose from many ways to display. Analogues of standard components provides all functionality and adds many new possibilities for application interface design and work. With AlphaControls, use a new modern way to design enhanced interfaces and make your application more attractive... while adding pleasure and fun to end users. Demonstration Programs ---------------------- Demonstration programs shows some features of AlphaControls and can help you in understanding of main conceptions of AlphaControls. Page with demo programs: http://www.alphaskins.com/ademos.php Link to compiled main demo: http://www.alphaskins.com/sfiles/askindemo.zip Registering and Prices ---------------------- The AlphaControls is a Shareware product. If you find it useful and want to receive the latest versions please register your evaluation copy. You can read detail information about registration in ORDERS page at the AlphaControls home-site. After registration you will receive fully-functional package with last versions of components. By registering the components you get the following advantages: 1. You will be notified about new versions of the package. 2. You will receive new versions of AlphaControls FREE. 3. You encourage the authors do make the components even better. Feedback -------- Contact us if you have any questions, comments or suggestions: Developer: AC Team Home page: http://www.alphaskins.com E-mails: support@alphaskins.com, sales@alphaskins.com
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值