欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-17 14:58:27
...

作者:66

(转载请注明出处)

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

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

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

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];
    }
  }
}