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

12 篇文章 4 订阅

作者:66

(转载请注明出处)

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

帧内预测用到的函数大概有十几个,先来看fillRerenceSamples( )


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

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

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

Void TComPattern::fillReferenceSamples(Int bitDepth, 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;
  Int  i, j;
  Int  iDCValue = 1 << (bitDepth - 1);//8bit像素为128,10bit像素为512

  if (iNumIntraNeighbor == 0)//相邻的参考像素不可用
  {
    // Fill border with DC value
    for (i=0; i<uiWidth; i++)//unsigned int
    {
      piAdiTemp[i] = iDCValue;//上方
    }
    for (i=1; i<uiHeight; i++)
    {
      piAdiTemp[i*uiWidth] = iDCValue;//左边界(不包括左上顶点)
    }
  }
  else if (iNumIntraNeighbor == iTotalUnits)//相邻参考像素全部可用
  {
    // 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)//默认为false
    {
      piRoiTemp --; // move to the second left column
    }

    for (i=0; i<uiCuHeight; i++)
    {
      piAdiTemp[(1+i)*uiWidth] = piRoiTemp[0];
      piRoiTemp += iPicStride;//每次往下移一行
    }

    // Fill below left border with rec. samples
    for (i=0; i<uiCuHeight; i++)
    {
      piAdiTemp[(1+uiCuHeight+i)*uiWidth] = piRoiTemp[0];
      piRoiTemp += iPicStride;
    }

    // Fill top border with rec. samples
    piRoiTemp = piRoiOrigin - iPicStride;
    for (i=0; i<uiCuWidth; i++)
    {
      piAdiTemp[1+i] = piRoiTemp[i];
    }
    
    // Fill top right border with rec. samples
    piRoiTemp = piRoiOrigin - iPicStride + uiCuWidth;
    for (i=0; i<uiCuWidth; i++)
    {
      piAdiTemp[1+uiCuWidth+i] = piRoiTemp[i];
    }
  }
  else // reference samples are partially available
  {
    Int  iNumUnits2 = iNumUnitsInCu<<1;//两个块边长的长度
    Int  iTotalSamples = iTotalUnits*iUnitSize;//iUnitSize块大小,iTotalUnits为当前pu包

含的块
    Pel  piAdiLine[5 * MAX_CU_SIZE];//临时存储参考像素值
    Pel  *piAdiLineTemp; //pi中当前指针
    Bool *pbNeighborFlags;//标记是否可用
    Int  iNext, iCurr;
    Pel  piRef = 0;

    // Initialize先全部设为DC默认值
    for (i=0; i<iTotalSamples; i++)
    {
      piAdiLine[i] = iDCValue;//全设置为默认值
    }
    //这里参考像素临时存在piAdiLine中,顺序为从左下依次到右上
    // Fill top-left sample
    piRoiTemp = piRoiOrigin - iPicStride - 1;
    piAdiLineTemp = piAdiLine + (iNumUnits2*iUnitSize);//指向该存储左上点的位置
    pbNeighborFlags = bNeighborFlags + iNumUnits2;//移到左上像素点的标志位
    if (*pbNeighborFlags)//左上可用
    {
      piAdiLineTemp[0] = piRoiTemp[0];
      for (i=1; i<iUnitSize; i++)//这里左上像素占了iUnitSize个位置,?为什么这样,估

计和后面用有关。
      {
        piAdiLineTemp[i] = piAdiLineTemp[0];
      }
    }

    // Fill left & below-left samples
    piRoiTemp += iPicStride;//下移
    if (bLMmode)
    {
      piRoiTemp --; // move the second left column
    }
    piAdiLineTemp--;
    pbNeighborFlags--;
    for (j=0; j<iNumUnits2; j++)//按块
    {
      if (*pbNeighborFlags)//每次标记一个块的像素
      {
        for (i=0; i<iUnitSize; i++)
        {
          piAdiLineTemp[-i] = piRoiTemp[i*iPicStride];
        }
      }
      piRoiTemp += iUnitSize*iPicStride;
      piAdiLineTemp -= iUnitSize;
      pbNeighborFlags--;
    }

    // Fill above & above-right samples
    piRoiTemp = piRoiOrigin - iPicStride;
    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];
        }
      }
      piRoiTemp += iUnitSize;
      piAdiLineTemp += iUnitSize;
      pbNeighborFlags++;
    }

    // Pad reference samples when necessary
    iCurr = 0;
    iNext = 1;
    piAdiLineTemp = piAdiLine;//临时矩阵开始处,指向参考像素左下角
    while (iCurr < iTotalUnits)
    {
      if (!bNeighborFlags[iCurr])//第iCurr组参考像素不可用
      {
        if(iCurr == 0)//第一组
        {
          while (iNext < iTotalUnits && !bNeighborFlags[iNext])//iCurr下一组iNext组参考

像素不可用
          {
            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;//复制左上、上、右上
    for (i=0; i<uiWidth; i++)
    {
      piAdiTemp[i] = piAdiLineTemp[i];
    }
    piAdiLineTemp = piAdiLine + uiHeight - 1;
    for (i=1; i<uiHeight; i++)//复制左、左下
    {
      piAdiTemp[i*uiWidth] = piAdiLineTemp[-i];
    }
  }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值