VTM1.0代码阅读:initIntraPatternChType函数

initIntraPatternChType函数在帧内预测的过程中会被调用。
initIntraPatternChType用来准备好帧内预测过程中需要用到的当前pu左侧和上侧的参考像素。

Void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompArea &area, const Bool bFilterRefSamples)
{
  const CodingStructure& cs   = *cu.cs;

  Pel *refBufUnfiltered   = m_piYuvExt[area.compID][PRED_BUF_UNFILTERED];//获取到的未滤波参考像素
  Pel *refBufFiltered     = m_piYuvExt[area.compID][PRED_BUF_FILTERED];	//滤波后的参考像素

  // ----- Step 1: unfiltered reference samples -----		//由重建像素获取pu的参考像素
  xFillReferenceSamples( cs.picture->getRecoBuf( area ), refBufUnfiltered, area, cu );	//获取当前pu的参考像素
  // ----- Step 2: filtered reference samples -----
  if( bFilterRefSamples )	//参考像素是否滤波
  {
    xFilterReferenceSamples( refBufUnfiltered, refBufFiltered, area, *cs.sps );	//对获取到的没有滤波的参考像素进行滤波
  }
}

xFillReferenceSamples函数填充帧内预测过程中左侧和上侧的参考像素模板。
参考像素模板为当前pu的左侧、左下、上侧、右上、左上的像素信息,其中左下和右上的参考像素模板长度分别为pu.width和pu.hight,即左和上的参考像素长度,都为width+height。左上的那个参考像素,可以看做归并到上面的参考像素,长度为unitWidth,函数中有体现。

void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBufUnfiltered, const CompArea &area, const CodingUnit &cu )
{
  const ChannelType      chType = toChannelType( area.compID );
  const CodingStructure &cs     = *cu.cs;
  const SPS             &sps    = *cs.sps;
  const PreCalcValues   &pcv    = *cs.pcv;

  const int  tuWidth            = area.width;
  const int  tuHeight           = area.height;
  const int  predSize           = tuWidth + tuHeight;
  const int  predStride         = predSize + 1;				//参考像素的stride,为tuWidth+tuHeight+1,因为多了左侧一列

  const bool noShift            = pcv.noChroma2x2 && area.width == 4; // don't shift on the lowest level (chroma not-split)
  const int  unitWidth          = pcv.minCUWidth  >> (noShift ? 0 : getComponentScaleX( area.compID, sps.getChromaFormatIdc() ));//VTM处理的最小块大小
  const int  unitHeight         = pcv.minCUHeight >> (noShift ? 0 : getComponentScaleY( area.compID, sps.getChromaFormatIdc() ));//亮度4x4,色度2x2

  const int  totalAboveUnits    = (predSize + (unitWidth - 1)) / unitWidth;		//上侧参考像素可以划分的最小块数目
  const int  totalLeftUnits     = (predSize + (unitHeight - 1)) / unitHeight;	//左侧参考像素可以划分的最小块数目
  const int  totalUnits         = totalAboveUnits + totalLeftUnits + 1; //+1 for top-left	//参考像素可以划分的总计最小块数目
  const int  numAboveUnits      = std::max<int>( tuWidth / unitWidth, 1 );
  const int  numLeftUnits       = std::max<int>( tuHeight / unitHeight, 1 );
  const int  numAboveRightUnits = totalAboveUnits - numAboveUnits;				//上、左、右上、左下参考像素可以划分的最小块数
  const int  numLeftBelowUnits  = totalLeftUnits - numLeftUnits;

  CHECK( numAboveUnits <= 0 || numLeftUnits <= 0 || numAboveRightUnits <= 0 || numLeftBelowUnits <= 0, "Size not supported" );

  // ----- Step 1: analyze neighborhood -----
  const Position posLT          = area;
  const Position posRT          = area.topRight();
  const Position posLB          = area.bottomLeft();

  bool  neighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1];	//用来标记参考像素各位置的pu是否可用,起点左下第一个块,终点右上最后一个块
  int   numIntraNeighbor = 0;					//参考像素处的可用小块数目

  memset( neighborFlags, 0, totalUnits );		//初始化为参考处的pu都不可用

  neighborFlags[totalLeftUnits] = isAboveLeftAvailable( cu, chType, posLT );
  numIntraNeighbor += neighborFlags[totalLeftUnits] ? 1 : 0;					//判断并标记左上块是否可用
  numIntraNeighbor += isAboveAvailable     ( cu, chType, posLT, numAboveUnits,      unitWidth,  (neighborFlags + totalLeftUnits + 1) );
  numIntraNeighbor += isAboveRightAvailable( cu, chType, posRT, numAboveRightUnits, unitWidth,  (neighborFlags + totalLeftUnits + 1 + numAboveUnits) );
  numIntraNeighbor += isLeftAvailable      ( cu, chType, posLT, numLeftUnits,       unitHeight, (neighborFlags + totalLeftUnits - 1) );
  numIntraNeighbor += isBelowLeftAvailable ( cu, chType, posLB, numLeftBelowUnits,  unitHeight, (neighborFlags + totalLeftUnits - 1 - numLeftUnits) );
											//以上的各isAvailable函数中,最后一个参数用来记录标记各个位置处最小块是否可用
  
  // ----- Step 2: fill reference samples (depending on neighborhood) -----
  CHECK( predStride * predStride > m_iYuvExtSize, "Reference sample area not supported" );

  const Pel*  srcBuf    = recoBuf.buf;			//参考像素,即cs的重建像素
  const int   srcStride = recoBuf.stride;		//stride一般为整个picture的width
        Pel*  ptrDst    = refBufUnfiltered;		//计算存储参考像素
  const Pel*  ptrSrc;
  const Pel   valueDC   = 1 << (sps.getBitDepth( chType ) - 1);		//default填充像素值


  if( numIntraNeighbor == 0 )			//如果参考像素位置没有一个小块可用
  {
    // Fill border with DC value
    for( int j = 0; j <= predSize; j++ ) { ptrDst[j]            = valueDC; }
    for( int i = 1; i <= predSize; i++ ) { ptrDst[i*predStride] = valueDC; }		//参考像素全部填充default值
  }
  else if( numIntraNeighbor == totalUnits )		//如果参考像素位置所有的小块都可用,参考像素直接copy
  {
    // Fill top-left border and top and top right with rec. samples
    ptrSrc = srcBuf - srcStride - 1;
    for( int j = 0; j <= predSize; j++ ) { ptrDst[j] = ptrSrc[j]; }		//左上、上、右上区域的copy
    // Fill left and below left border with rec. samples
    ptrSrc = srcBuf - 1;
    for( int i = 1; i <= predSize; i++ ) { ptrDst[i*predStride] = *(ptrSrc); ptrSrc += srcStride; }	//左、左下区域的copy
  }
  else // reference samples are partially available		//参考像素部分可用,那么由可用的值填充没有用的值
  {
    // BB: old implementation using tmpLineBuf
    // ---------------------------------------
    Pel  tmpLineBuf[5 * MAX_CU_SIZE];		//一维的参考像素存储,方便padding操作
    Pel* ptrTmp;
    int  unitIdx;

    // Initialize
    const int totalSamples = (totalLeftUnits * unitHeight) + ((totalAboveUnits + 1) * unitWidth); // all above units have "unitWidth" samples each, all left/below-left units have "unitHeight" samples each
    for( int k = 0; k < totalSamples; k++ ) { tmpLineBuf[k] = valueDC; }

    // Fill top-left sample
    ptrSrc = srcBuf - srcStride - 1;					//对可用的参考像素信息直接copy,先不用notAvailable的像素
    ptrTmp = tmpLineBuf + (totalLeftUnits * unitHeight);
    unitIdx = totalLeftUnits;
    if( neighborFlags[unitIdx] )
    {
      Pel topLeftVal = ptrSrc[0];
      for( int j = 0; j < unitWidth; j++ ) { ptrTmp[j] = topLeftVal; }	//左上可用时copy
    }

    // Fill left & below-left samples (downwards)
    ptrSrc += srcStride;
    ptrTmp--;
    unitIdx--;

    for( int k = 0; k < totalLeftUnits; k++ )
    {
      if( neighborFlags[unitIdx] )					//左边可用像素copy
      {
        for( int i = 0; i < unitHeight; i++ ) { ptrTmp[-i] = ptrSrc[i*srcStride]; }
      }
      ptrSrc += unitHeight*srcStride;
      ptrTmp -= unitHeight;
      unitIdx--;
    }

    // Fill above & above-right samples (left-to-right) (each unit has "unitWidth" samples)
    ptrSrc = srcBuf - srcStride;
    ptrTmp = tmpLineBuf + (totalLeftUnits * unitHeight) + unitWidth; // offset line buffer by totalLeftUnits*unitHeight (for left/below-left) + unitWidth (for above-left)
    unitIdx = totalLeftUnits + 1;
    for( int k = 0; k < totalAboveUnits; k++ )
    {
      if( neighborFlags[unitIdx] )
      {
        for( int j = 0; j < unitWidth; j++ ) { ptrTmp[j] = ptrSrc[j]; }	//上边可用像素copy
      }
      ptrSrc += unitWidth;
      ptrTmp += unitWidth;
      unitIdx++;
    }

    // Pad reference samples when necessary			//padding操作,用可用像素补全notAvailable的像素
    int  currUnit       = 0;
    Pel* ptrTmpCurrUnit = tmpLineBuf;

    if( !neighborFlags[0] )						//如果起点开始就不可用,那么一直查找到可用点,用可用点像素补全前面的所有像素
    {
      int nextUnit = 1;
      while( nextUnit < totalUnits && !neighborFlags[nextUnit] )	//查找起点开始第一个有用的点
      {
        nextUnit++;
      }
      Pel* ptrTmpRef = tmpLineBuf + ((nextUnit < totalLeftUnits) ? (nextUnit * unitHeight) : ((totalLeftUnits * (unitHeight - unitWidth)) + (nextUnit * unitWidth)));
      const Pel refSample = *ptrTmpRef;
      // Pad unavailable samples with new value
      // fill left column
      while( currUnit < std::min<int>( nextUnit, totalLeftUnits ) )
      {
        for( int i = 0; i < unitHeight; i++ ) { ptrTmpCurrUnit[i] = refSample; }
        ptrTmpCurrUnit += unitHeight;
        currUnit++;
      }
      // fill top row
      while( currUnit < nextUnit )		//如果第一个可用点一直查找到上边了,还要补全上面的一些点像素
      {
        for( int j = 0; j < unitWidth; j++ ) { ptrTmpCurrUnit[j] = refSample; }
        ptrTmpCurrUnit += unitWidth;
        currUnit++;
      }
    }

    // pad all other reference samples.
    while( currUnit < totalUnits )		//如果有一点不可用,用它前面的可用点补全
    {
      const int numSamplesInCurrUnit = (currUnit >= totalLeftUnits) ? unitWidth : unitHeight;
      if( !neighborFlags[currUnit] ) // samples not available
      {
        const Pel refSample = *(ptrTmpCurrUnit - 1);
        for( int k = 0; k < numSamplesInCurrUnit; k++ ) { ptrTmpCurrUnit[k] = refSample; }

      }
      ptrTmpCurrUnit += numSamplesInCurrUnit;
      currUnit++;
    }

    // Copy processed samples			//获取到的参考像素模板,存储在tmpLineBuf中,现在copy到refBufUnfiltered中返回,用于接下来的滤波或者预测
    ptrTmp = tmpLineBuf + (totalLeftUnits * unitHeight) + (unitWidth - 1);
    for( int j = 0; j <= predSize; j++ ) { ptrDst[j] = ptrTmp[j]; } // top left, top and top right samples

    ptrTmp = tmpLineBuf + (totalLeftUnits * unitHeight);
    for( int i = 1; i <= predSize; i++ ) { ptrDst[i*predStride] = ptrTmp[-i]; }
  }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值