HEVC中一共定义了35中帧内编码预测模式,编号分别以0-34定义。其中模式0定义为平面模式(INTRA_PLANAR),模式1定义为均值模式(INTRA_DC),模式2~34定义为角度预测模式(INTRA_ANGULAR2~INTRA_ANGULAR34),分别代表了不同的角度。
最简单的Intra_DC模式,DC模式适用于大面积平摊区域,当前预测值可由其左侧和上方(不包含左上角,左下方和右上方)参考像素的平均值得到。该模式同角度预测模式实现在同一个函数Void TComPrediction::xPredIntraAng(...)中:
1 Void TComPrediction::xPredIntraAng( Int bitDepth,2 const Pel*pSrc, Int srcStride,3 Pel*pTrueDst, Int dstStrideTrue,4 UInt uiWidth, UInt uiHeight, ChannelType channelType,5 UInt dirMode, constBool bEnableEdgeFilters6 )7 {8 Int width=Int(uiWidth);9 Int height=Int(uiHeight);10
11 //Map the mode index to main prediction direction and angle
12 assert( dirMode != PLANAR_IDX ); //no planar
13 const Bool modeDC = dirMode==DC_IDX;14
15 //Do the DC prediction
16 if(modeDC)17 {18 const Pel dcval =predIntraGetPredValDC(pSrc, srcStride, width, height);19
20 for (Int y=height;y>0;y--, pTrueDst+=dstStrideTrue)21 {22 for (Int x=0; x
23 {24 pTrueDst[x++] =dcval;25 }26 }27 }28 else //Do angular predictions
29 {30 //........31 }32 }
在这个函数中可以看到,Intra_DC模式中所有预测块的像素值都是同一个值dcval,这个值是由一个函数predIntraGetPredValDC计算得到:
1 Pel TComPrediction::predIntraGetPredValDC( const Pel*pSrc, Int iSrcStride, UInt iWidth, UInt iHeight)2 {3 assert(iWidth > 0 && iHeight > 0);4 Int iInd, iSum = 0;5 Pel pDcVal;6
7 for (iInd = 0;iInd < iWidth;iInd++)8 {9 iSum += pSrc[iInd-iSrcStride];//左列参考像素总和10 }11 for (iInd = 0;iInd < iHeight;iInd++)12 {13 iSum += pSrc[iInd*iSrcStride-1];//上方行参考像素总和14 }15
16 pDcVal = (iSum + iWidth) / (iWidth +iHeight);//取平均值17
18 returnpDcVal;19 }
其次是Planar模式,该模式定义在xPredIntraPlanar函数中。适用于像素值缓慢变化的区域,Planar使用水平和垂直方向的两个线性滤波器,并将二者的平均值作为当前像素的预测值。Planar能够使像素平缓变化,与其他模式相比能够提升视频的主管质量。
1 Void TComPrediction::xPredIntraPlanar( const Pel* pSrc, Int srcStride, Pel*rpDst, Int dstStride, UInt width, UInt height )2 {3 assert(width <=height);4
5 Int leftColumn[MAX_CU_SIZE+1], topRow[MAX_CU_SIZE+1], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE];6 UInt shift1Dhor = g_aucConvertToBit[ width ] + 2;7 UInt shift1Dver = g_aucConvertToBit[ height ] + 2;8
9 //Get left and above reference column and row
10 for(Int k=0;k
15 for (Int k=0; k < height+1; k++)//记录左列数据16 {17 leftColumn[k] = pSrc[k*srcStride-1];18 }19
20 //Prepare intermediate variables used in interpolation
21 Int bottomLeft =leftColumn[height];//左下角像素值22 Int topRight =topRow[width];//右上角像素值23 /*计算底行的数据,方法是用左下角的像素减去顶行相应位置的像素得到底行。*/
24 for(Int k=0;k
30 for(Int k=0;k
36 const UInt topRowShift = 0;37
38 //Generate prediction signal
39 for (Int y=0;y
47 Int vertPred = ((topRow[x] + topRowShift)>>topRowShift);//水平方向(x,y)预测值48 rpDst[y*dstStride+x] = ( horPred + vertPred ) >> (shift1Dhor+1);//预测像素是水平和垂直两个方向预测值得平均值49 }50 }51 }
最后是角度预测,mode=2~34时采用角度预测模式。实现的方式在xPredIntraAng中:
1 Void TComPrediction::xPredIntraAng( Int bitDepth,2 const Pel*pSrc, Int srcStride,3 Pel*pTrueDst, Int dstStrideTrue,4 UInt uiWidth, UInt uiHeight, ChannelType channelType,5 UInt dirMode, constBool bEnableEdgeFilters6 )7 {8 Int width=Int(uiWidth);9 Int height=Int(uiHeight);10
11 //Map the mode index to main prediction direction and angle
12 assert( dirMode != PLANAR_IDX ); //no planar
13 const Bool modeDC = dirMode==DC_IDX;14
15 //Do the DC prediction
16 if(modeDC)17 {18 const Pel dcval =predIntraGetPredValDC(pSrc, srcStride, width, height);19
20 for (Int y=height;y>0;y--, pTrueDst+=dstStrideTrue)21 {22 for (Int x=0; x
23 {24 pTrueDst[x++] =dcval;25 }26 }27 }28 else //Do angular predictions
29 {30 const Bool bIsModeVer = (dirMode >= 18);31 const Int intraPredAngleMode = (bIsModeVer) ? (Int)dirMode - VER_IDX : -((Int)dirMode -HOR_IDX);32 const Int absAngMode =abs(intraPredAngleMode);33 const Int signAng = intraPredAngleMode < 0 ? -1 : 1;34 const Bool edgeFilter = bEnableEdgeFilters && isLuma(channelType) && (width <= MAXIMUM_INTRA_FILTERED_WIDTH) && (height <=MAXIMUM_INTRA_FILTERED_HEIGHT);35
36 //Set bitshifts and scale the angle parameter to block size
37 static const Int angTable[9] = {0, 2, 5, 9, 13, 17, 21, 26, 32};38 static const Int invAngTable[9] = {0, 4096, 1638, 910, 630, 482, 390, 315, 256}; //(256 * 32) / Angle
39 Int invAngle =invAngTable[absAngMode];40 Int absAng =angTable[absAngMode];41 Int intraPredAngle = signAng *absAng;42
43 Pel*refMain;44 Pel*refSide;45
46 Pel refAbove[2*MAX_CU_SIZE+1];47 Pel refLeft[2*MAX_CU_SIZE+1];48
49 //Initialize the Main and Left reference array.
50 if (intraPredAngle < 0)51 {52 const Int refMainOffsetPreScale = (bIsModeVer ? height : width ) - 1;53 const Int refMainOffset = height - 1;54 for (Int x=0;x
65 //Extend the Main reference to the left.
66 Int invAngleSum = 128; //rounding for (shift by 8)
67 for (Int k=-1; k>(refMainOffsetPreScale+1)*intraPredAngle>>5; k--)68 {69 invAngleSum +=invAngle;70 refMain[k] = refSide[invAngleSum>>8];71 }72 }73 else
74 {75 for (Int x=0;x<2*width+1;x++)76 {77 refAbove[x] = pSrc[x-srcStride-1];78 }79 for (Int y=0;y<2*height+1;y++)80 {81 refLeft[y] = pSrc[(y-1)*srcStride-1];82 }83 refMain = bIsModeVer ?refAbove : refLeft ;84 refSide = bIsModeVer ?refLeft : refAbove;85 }86
87 //swap width/height if we are doing a horizontal mode:
88 Pel tempArray[MAX_CU_SIZE*MAX_CU_SIZE];89 const Int dstStride = bIsModeVer ?dstStrideTrue : MAX_CU_SIZE;90 Pel *pDst = bIsModeVer ?pTrueDst : tempArray;91 if (!bIsModeVer)92 {93 std::swap(width, height);94 }95
96 if (intraPredAngle == 0) //pure vertical or pure horizontal
97 {98 for (Int y=0;y
106 if(edgeFilter)107 {108 for (Int y=0;y> 1) );111 }112 }113 }114 else
115 {116 Pel *pDsty=pDst;117
118 for (Int y=0, deltaPos=intraPredAngle; y> 5;121 const Int deltaFract = deltaPos & (32 - 1);122
123 if(deltaFract)124 {125 //Do linear filtering
126 const Pel *pRM=refMain+deltaInt+1;127 Int lastRefMainPel=*pRM++;128 for (Int x=0;x> 5);132 lastRefMainPel=thisRefMainPel;133 }134 }135 else
136 {137 //Just copy the integer samples
138 for (Int x=0;x
146 //Flip the block if this is the horizontal mode
147 if (!bIsModeVer)148 {149 for (Int y=0; y
帧内预测是在TComPrediction::predIntraAng(...)实现:
1 Void TComPrediction::predIntraAng( const ComponentID compID, UInt uiDirMode, Pel* piOrg /*Will be null for decoding*/, UInt uiOrgStride, Pel* piPred, UInt uiStride, TComTU &rTu, const Bool bUseFilteredPredSamples, constBool bUseLosslessDPCM )2 {3 const ChannelType channelType =toChannelType(compID);4 const TComRectangle &rect = rTu.getRect(isLuma(compID) ?COMPONENT_Y : COMPONENT_Cb);5 const Int iWidth =rect.width;6 const Int iHeight =rect.height;7
8 assert( g_aucConvertToBit[ iWidth ] >= 0 ); //4x 4
9 assert( g_aucConvertToBit[ iWidth ] <= 5 ); //128x12810 //assert( iWidth == iHeight );
11
12 Pel *pDst =piPred;13
14 //get starting pixel in block
15 const Int sw = (2 * iWidth + 1);16
17 if( bUseLosslessDPCM )//如果预测方式为垂直或水平,则bUseLosslessDPCM =118 {19 const Pel *ptrSrc = getPredictorPtr( compID, false);20 //Sample Adaptive intra-Prediction (SAP)
21 if (uiDirMode==HOR_IDX)//竖直方向预测22 {23 //left column filled with reference samples24 //remaining columns filled with piOrg data (if available).
25 for(Int y=0; y
32 for(Int y=0; y
39 {40 //top row filled with reference samples41 //remaining rows filled with piOrd data (if available)
42 for(Int x=0; x
49 for(Int y=1; y
57 {58 const Pel *ptrSrc =getPredictorPtr( compID, bUseFilteredPredSamples );59
60 if ( uiDirMode ==PLANAR_IDX )61 {62 xPredIntraPlanar( ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight );63 }64 else
65 {66 //Create the prediction
67 TComDataCU *const pcCU =rTu.getCU();68 const UInt uiAbsPartIdx =rTu.GetAbsPartIdxTU();69 const Bool enableEdgeFilters = !(pcCU->isRDPCMEnabled(uiAbsPartIdx) && pcCU->getCUTransquantBypass(uiAbsPartIdx));70 #if O0043_BEST_EFFORT_DECODING
71 const Int channelsBitDepthForPrediction = rTu.getCU()->getSlice()->getSPS()->getStreamBitDepth(channelType);72 #else
73 const Int channelsBitDepthForPrediction = rTu.getCU()->getSlice()->getSPS()->getBitDepth(channelType);74 #endif
75 xPredIntraAng( channelsBitDepthForPrediction, ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, channelType, uiDirMode, enableEdgeFilters );76
77 if( uiDirMode ==DC_IDX )78 {79 xDCPredFiltering( ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, channelType );80 }81 }82 }83
84 }