帧内预测-第一步:fillReferenceSamples函数:

来源:互联网 发布:win7内存优化软件 编辑:程序博客网 时间:2024/06/06 07:42

帧内预测:fillReferenceSamples函数:

主要功能:

是在真正进行帧内预测之前,使用重建后的Yuv图像对当前PU的相邻样点进行赋值,为接下来进行的角度预测提供参考样点值

过程:

(1)如果所有相邻点均不可用,则参考样点值均被赋值为DC值;

(2)如果所有相邻点均可用,则参考样点值都会被赋值为重建Yuv图像中与其位置相同的样点值

(3)如果不满足上述两个条件,则按照从左下往左上,从左上往右上的扫描顺序进行遍历,(如下图所示),如果第一个点不可用,则使用下一个可用点对应的重建Yuv样点值对其进行赋值;对于除第一个点外的其它邻点,如果该点不可用,则使用它的前一个样点值进行赋值(前一个步骤保证了前一个样点值一定是存在的),直到遍历完毕


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是因为赋值方向与实际存储方向是相反的
    }
  }
}