33、編碼一個CU(幀內部分)2、幀內預測各種模式的實現
阿新 • • 發佈:2019-01-25
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);
- }
- elseif (bAbove)
- {
- pDcVal = (iSum + iWidth/2) / iWidth;
- }
- elseif (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指標指向的資料又是如何獲取的?且聽下回。