HEVC中一共定义了35中帧内编码预测模式,编号分别以0-34定义。其中模式0定义为平面模式(INTRA_PLANAR),模式1定义为均值模式(INTRA_DC),模式2~34定义为角度预测模式(INTRA_ANGULAR2~INTRA_ANGULAR34),分别代表了不同的角度。具体的示意图如标准文档的图8-1所示:
这三大类的预测方法均有实现的代码。首先看最简单的Intra_DC模式,该模式同角度预测模式实现在同一个函数Void TComPrediction::xPredIntraAng(...)中:
- Void TComPrediction::xPredIntraAng(Int bitDepth, Int* pSrc, Int srcStride, Pel*& rpDst, Int dstStride, UInt width, UInt height, UInt dirMode, Bool blkAboveAvailable, Bool blkLeftAvailable, Bool bFilter )
- {
- //......
- // Do the DC prediction
- if (modeDC)
- {
- Pel dcval = predIntraGetPredValDC(pSrc, srcStride, width, height, blkAboveAvailable, blkLeftAvailable);
- for (k=0;k<blkSize;k++)
- {
- for (l=0;l<blkSize;l++)
- {
- pDst[k*dstStride+l] = dcval;
- }
- }
- }
- //......
- }
- Pel TComPrediction::predIntraGetPredValDC( Int* pSrc, Int iSrcStride, UInt iWidth, UInt iHeight, Bool bAbove, Bool bLeft )
- {
- Int iInd, iSum = 0;
- Pel pDcVal;
- if (bAbove)
- {
- for (iInd = 0;iInd < iWidth;iInd++)
- {
- iSum += pSrc[iInd-iSrcStride];
- }
- }
- if (bLeft)
- {
- for (iInd = 0;iInd < iHeight;iInd++)
- {
- iSum += pSrc[iInd*iSrcStride-1];
- }
- }
- if (bAbove && bLeft)
- {
- pDcVal = (iSum + iWidth) / (iWidth + iHeight);
- }
- else if (bAbove)
- {
- pDcVal = (iSum + iWidth/2) / iWidth;
- }
- else if (bLeft)
- {
- pDcVal = (iSum + iHeight/2) / iHeight;
- }
- else
- {
- pDcVal = pSrc[-1]; // Default DC value already calculated and placed in the prediction array if no neighbors are available
- }
- return pDcVal;
- }
第二种预测模式时平面模式,该模式定义在xPredIntraPlanar函数中。
- Void TComPrediction::xPredIntraPlanar( Int* pSrc, Int srcStride, Pel* rpDst, Int dstStride, UInt width, UInt height )
- {
- assert(width == height);
- Int k, l, bottomLeft, topRight;
- Int horPred;
- Int leftColumn[MAX_CU_SIZE], topRow[MAX_CU_SIZE], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE];
- UInt blkSize = width;
- UInt offset2D = width;
- UInt shift1D = g_aucConvertToBit[ width ] + 2;
- UInt shift2D = shift1D + 1;
- // Get left and above reference column and row
- for(k=0;k<blkSize+1;k++)
- {
- topRow[k] = pSrc[k-srcStride];
- leftColumn[k] = pSrc[k*srcStride-1];
- }
- // Prepare intermediate variables used in interpolation
- bottomLeft = leftColumn[blkSize];
- topRight = topRow[blkSize];
- for (k=0;k<blkSize;k++)
- {
- bottomRow[k] = bottomLeft - topRow[k];
- rightColumn[k] = topRight - leftColumn[k];
- topRow[k] <<= shift1D;
- leftColumn[k] <<= shift1D;
- }
- // Generate prediction signal
- for (k=0;k<blkSize;k++)
- {
- horPred = leftColumn[k] + offset2D;
- for (l=0;l<blkSize;l++)
- {
- horPred += rightColumn[k];
- topRow[l] += bottomRow[l];
- rpDst[k*dstStride+l] = ( (horPred + topRow[l]) >> shift2D );
- }
- }
- }
第三种预测模式,即mode=2~34时采用角度预测模式。实现的方式在xPredIntraAng中:
- Void TComPrediction::xPredIntraAng(Int bitDepth, Int* pSrc, Int srcStride, Pel*& rpDst, Int dstStride, UInt width, UInt height, UInt dirMode, Bool blkAboveAvailable, Bool blkLeftAvailable, Bool bFilter )
- {
- Int k,l;
- Int blkSize = width;
- Pel* pDst = rpDst;
- // Map the mode index to main prediction direction and angle
- assert( dirMode > 0 ); //no planar
- Bool modeDC = dirMode < 2;
- Bool modeHor = !modeDC && (dirMode < 18);
- Bool modeVer = !modeDC && !modeHor;
- Int intraPredAngle = modeVer ? (Int)dirMode - VER_IDX : modeHor ? -((Int)dirMode - HOR_IDX) : 0;//计算当前模式同水平/垂直模式之间的角度差
- Int absAng = abs(intraPredAngle);
- Int signAng = intraPredAngle < 0 ? -1 : 1;
- // Set bitshifts and scale the angle parameter to block size
- Int angTable[9] = {0, 2, 5, 9, 13, 17, 21, 26, 32};
- Int invAngTable[9] = {0, 4096, 1638, 910, 630, 482, 390, 315, 256}; // (256 * 32) / Angle
- Int invAngle = invAngTable[absAng];
- absAng = angTable[absAng];
- intraPredAngle = signAng * absAng;
- // ......
- // Do angular predictions
- else
- {
- Pel* refMain;
- Pel* refSide;
- Pel refAbove[2*MAX_CU_SIZE+1];
- Pel refLeft[2*MAX_CU_SIZE+1];
- // Initialise the Main and Left reference array.
- if (intraPredAngle < 0)
- {
- for (k=0;k<blkSize+1;k++)
- {
- refAbove[k+blkSize-1] = pSrc[k-srcStride-1];
- }
- for (k=0;k<blkSize+1;k++)
- {
- refLeft[k+blkSize-1] = pSrc[(k-1)*srcStride-1];
- }
- refMain = (modeVer ? refAbove : refLeft) + (blkSize-1);
- refSide = (modeVer ? refLeft : refAbove) + (blkSize-1);
- // Extend the Main reference to the left.
- Int invAngleSum = 128; // rounding for (shift by 8)
- for (k=-1; k>blkSize*intraPredAngle>>5; k--)
- {
- invAngleSum += invAngle;
- refMain[k] = refSide[invAngleSum>>8];
- }
- }
- else
- {
- for (k=0;k<2*blkSize+1;k++)
- {
- refAbove[k] = pSrc[k-srcStride-1];
- }
- for (k=0;k<2*blkSize+1;k++)
- {
- refLeft[k] = pSrc[(k-1)*srcStride-1];
- }
- refMain = modeVer ? refAbove : refLeft;
- refSide = modeVer ? refLeft : refAbove;
- }
- if (intraPredAngle == 0)
- {
- for (k=0;k<blkSize;k++)
- {
- for (l=0;l<blkSize;l++)
- {
- pDst[k*dstStride+l] = refMain[l+1];
- }
- }
- if ( bFilter )
- {
- for (k=0;k<blkSize;k++)
- {
- pDst[k*dstStride] = Clip3(0, (1<<bitDepth)-1, pDst[k*dstStride] + (( refSide[k+1] - refSide[0] ) >> 1) );
- }
- }
- }
- else
- {
- Int deltaPos=0;
- Int deltaInt;
- Int deltaFract;
- Int refMainIndex;
- for (k=0;k<blkSize;k++)
- {
- deltaPos += intraPredAngle;
- deltaInt = deltaPos >> 5;
- deltaFract = deltaPos & (32 - 1);
- if (deltaFract)
- {
- // Do linear filtering
- for (l=0;l<blkSize;l++)
- {
- refMainIndex = l+deltaInt+1;
- pDst[k*dstStride+l] = (Pel) ( ((32-deltaFract)*refMain[refMainIndex]+deltaFract*refMain[refMainIndex+1]+16) >> 5 );
- }
- }
- else
- {
- // Just copy the integer samples
- for (l=0;l<blkSize;l++)
- {
- pDst[k*dstStride+l] = refMain[l+deltaInt+1];
- }
- }
- }
- }
- // Flip the block if this is the horizontal mode
- if (modeHor)
- {
- Pel tmp;
- for (k=0;k<blkSize-1;k++)
- {
- for (l=k+1;l<blkSize;l++)
- {
- tmp = pDst[k*dstStride+l];
- pDst[k*dstStride+l] = pDst[l*dstStride+k];
- pDst[l*dstStride+k] = tmp;
- }
- }
- }
- }
- }
除此之外,这个函数还实现了对小于16×16尺寸块实现滤波操作,以及水平模式时将预测矩阵进行转置操作。
大致上Intra预测块的生成方法就这样了,下一个问题在于,参考像素是如何来的?pSrc指针指向的数据又是如何获取的?且听下回。