HEVC代码阅读- -fillReferenceSamples

看到这个函数的注释写的很好,所以搬运过来,日后慢慢消化吸收。

文章出处:

HEVC帧内预测之参考像素的填充代码详析(一)

HEVC学习(三) —— 帧内预测系列之一

 ------ ----- ---- ------ ------- ------以下为正文----- ----- ---- -------- ---- -----------

fillReferenceSamples( )//填充参考像素值

 

iNumIntraNeighbor标识参考像素可用块数,以iUnitSize块长为单位。

分三种情况,1.像素全部可用,往相应位置填;2.像素部分可用,不可用的填默认值;3.像素不可用,全部填默认值;

在像素全部不可用时,代码不按一个一个像素复制,而是划分为iUnitSize大小的块,长宽都按多少个块长为单位,目前不了解为什么这么设置,在后面的分析中会了解。

 
Void TComPattern::fillReferenceSamples( TComDataCU* pcCU, Pel* piRoiOrigin, Int* piAdiTemp, Bool* bNeighborFlags, Int iNumIntraNeighbor, Int iUnitSize, Int iNumUnitsInCu, Int iTotalUnits, UInt uiCuWidth, UInt uiCuHeight, UInt uiWidth, UInt uiHeight, Int iPicStride, Bool bLMmode )
{
  Pel* piRoiTemp; //!< piRoiOrgin指向重建Yuv图像对应于当前PU所在位置的首地址,piRoiTemp用于指向所感兴趣的重建Yuv的位置,piAdiTemp
  Int  i, j;
  Int  iDCValue = ( 1<<( g_uiBitDepth + g_uiBitIncrement - 1) );
 
  if (iNumIntraNeighbor == 0) // all samples are not available
  {
    // Fill border with DC value
    for (i=0; i<uiWidth; i++)  //!< AboveLeft + Above + AboveRight
    {
      piAdiTemp[i] = iDCValue;
    }
    for (i=1; i<uiHeight; i++)  //!< Left + BelowLeft
    {
      piAdiTemp[i*uiWidth] = iDCValue;
    }
  }
  else if (iNumIntraNeighbor == iTotalUnits) // all samples are available
  {
    // Fill top-left border with rec. samples
    piRoiTemp = piRoiOrigin - iPicStride - 1;  //!< 左上
    piAdiTemp[0] = piRoiTemp[0];
 
    // Fill left border with rec. samples
    piRoiTemp = piRoiOrigin - 1;  //!< 左
 
    if (bLMmode) //!< bLMmode 默认值为false
    {
      piRoiTemp --; // move to the second left column
    }
 
    for (i=0; i<uiCuHeight; i++)
    {
      piAdiTemp[(1+i)*uiWidth] = piRoiTemp[0]; //!< 每个参考样点赋值为对应位置重建Yuv样点值
      piRoiTemp += iPicStride; //!< 指向重建Yuv下一行
    }
 
    // Fill below left border with rec. samples
    for (i=0; i<uiCuHeight; i++)  //!< 左下
    {
      piAdiTemp[(1+uiCuHeight+i)*uiWidth] = piRoiTemp[0]; //!< 每个参考样点赋值为对应位置重建Yuv样点值
      piRoiTemp += iPicStride;
    }
 
    // Fill top border with rec. samples
    piRoiTemp = piRoiOrigin - iPicStride; //!< 重新指向重建Yuv的上方
    for (i=0; i<uiCuWidth; i++)
    {
      piAdiTemp[1+i] = piRoiTemp[i]; //!< 每个参考样点赋值为对应位置重建Yuv样点值
    }
    
    // Fill top right border with rec. samples
    piRoiTemp = piRoiOrigin - iPicStride + uiCuWidth; //!< 指向右上
    for (i=0; i<uiCuWidth; i++)
    {
      piAdiTemp[1+uiCuWidth+i] = piRoiTemp[i]; //!< 每个参考样点赋值为对应位置重建Yuv样点值
    }
  }
  else // reference samples are partially available
  {
    Int  iNumUnits2 = iNumUnitsInCu<<1;
    Int  iTotalSamples = iTotalUnits*iUnitSize;  //!< neighboring samples的总数,iTotalUnits以4x4块为单位,iUnitSize为块的大小
    Pel  piAdiLine[5 * MAX_CU_SIZE];
    Pel  *piAdiLineTemp; //!<临时存储用于填充neighboring samples的样点值
    Bool *pbNeighborFlags;
    Int  iNext, iCurr;
    Pel  piRef = 0; //!< 存储临时样点值
 
    // Initialize
    for (i=0; i<iTotalSamples; i++)  //!< 先将所有样点值赋值为DC值
    {
      piAdiLine[i] = iDCValue;
    }
    
    // Fill top-left sample
    piRoiTemp = piRoiOrigin - iPicStride - 1;  //!< 指向重建Yuv左上角
    piAdiLineTemp = piAdiLine + (iNumUnits2*iUnitSize); //!< piAdiLine的扫描顺序为左下到左上,再从左到右上
    pbNeighborFlags = bNeighborFlags + iNumUnits2; //!< 标记neighbor可用性的数组同样移动至左上角
    if (*pbNeighborFlags) //!< 如果左上角可用,则左上角4个像素点均赋值为重建Yuv左上角的样点值
    {
      piAdiLineTemp[0] = piRoiTemp[0];
      for (i=1; i<iUnitSize; i++)
      {
        piAdiLineTemp[i] = piAdiLineTemp[0];
      }
    }
 
    // Fill left & below-left samples
    piRoiTemp += iPicStride; //!< piRoiTemp指向重建Yuv的左边界
    if (bLMmode)
    {
      piRoiTemp --; // move the second left column
    }
    piAdiLineTemp--;  //!< 移动指针置左边界
    pbNeighborFlags--; //!< 移动指针置左边界
    for (j=0; j<iNumUnits2; j++) //!< 从左往左下扫描
    {
      if (*pbNeighborFlags)  //!< 如果可用
      {
        for (i=0; i<iUnitSize; i++) //!< 每个4x4块里的4个样点分别被赋值为对应位置的重建Yuv的样点值
        {
          piAdiLineTemp[-i] = piRoiTemp[i*iPicStride];
        }
      }
      piRoiTemp += iUnitSize*iPicStride; //!< 指针挪到下一个行(以4x4块为单位,即实际上下移了4行)
      piAdiLineTemp -= iUnitSize; //!< 指针下移
      pbNeighborFlags--; //!< 指针下移
    }
 
    // Fill above & above-right samples
    piRoiTemp = piRoiOrigin - iPicStride; //!< piRoiTemp 指向重建Yuv的上边界
    piAdiLineTemp = piAdiLine + ((iNumUnits2+1)*iUnitSize); //!< 指向上边界
    pbNeighborFlags = bNeighborFlags + iNumUnits2 + 1; //!< 指向上边界
    for (j=0; j<iNumUnits2; j++) //!< 从左扫描至右上
    {
      if (*pbNeighborFlags)
      {
        for (i=0; i<iUnitSize; i++)
        {
          piAdiLineTemp[i] = piRoiTemp[i]; //!< 每个4x4块里的4个样点分别被赋值为对应位置的重建Yuv的样点值
        }
      }
      piRoiTemp += iUnitSize; //!< 指针右移
      piAdiLineTemp += iUnitSize; //!< 指针右移
      pbNeighborFlags++; //!< 指针右移
    }
 
    // Pad reference samples when necessary
    iCurr = 0;
    iNext = 1;
    piAdiLineTemp = piAdiLine; //!< 指向左下角(纵坐标最大的那个位置,即扫描起点)
    while (iCurr < iTotalUnits) //!< 遍历所有neighboring samples
    {
      if (!bNeighborFlags[iCurr]) //!< 该点不可用
      {
        if(iCurr == 0) //!< 第一个点就不可用
        {
          while (iNext < iTotalUnits && !bNeighborFlags[iNext]) //!< 找到第1个可用点
          {
            iNext++;
          }
          piRef = piAdiLine[iNext*iUnitSize]; //!< 保存该可用点的样点值
          // Pad unavailable samples with new value
          while (iCurr < iNext) //!< 使用保存下来的第一个可用点的样点值赋值给在其之前被标记为不可用的点
          {
            for (i=0; i<iUnitSize; i++)
            {
              piAdiLineTemp[i] = piRef;
            }
            piAdiLineTemp += iUnitSize;
            iCurr++;
          }
        }
        else //!< 当前点不可用且其不是第一个点,则使用该点的前一个可用点的样点值进行赋值
        {
          piRef = piAdiLine[iCurr*iUnitSize-1];
          for (i=0; i<iUnitSize; i++)
          {
            piAdiLineTemp[i] = piRef;
          }
          piAdiLineTemp += iUnitSize;
          iCurr++;
        }
      }
      else  //!< 当前点可用,继续检查下一点
      {
        piAdiLineTemp += iUnitSize;
        iCurr++;
      }
    }
 
    // Copy processed samples
    piAdiLineTemp = piAdiLine + uiHeight + iUnitSize - 2;  //!< piAdiLineTemp = (piAdiLine + 128) + 3,跳过之前对左上角扩充的3个像素点
    for (i=0; i<uiWidth; i++)  //!< 将最终结果拷贝到左上、上、右上边界
    {
      piAdiTemp[i] = piAdiLineTemp[i];
    }
    piAdiLineTemp = piAdiLine + uiHeight - 1; //!< uiHeight = uiCUHeight2 + 1
    for (i=1; i<uiHeight; i++)  //!< 将最终结果拷贝到左和左下边界
    {
      piAdiTemp[i*uiWidth] = piAdiLineTemp[-i]; //!< piAdiLineTemp下标为-i是因为赋值方向与实际存储方向是相反的
    }
  }
}
 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值