xPredIntraAng函数进行2到66的角度模式的预测,pSrc即参考像素,pDst即需要得到的pu预测像素,dirMode为帧内预测角度模式号
Void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const UInt dirMode, const ClpRng& clpRng, const SPS& sps, const bool enableBoundaryFilter )
{
Int width =Int(pDst.width);
Int height=Int(pDst.height);
CHECK( !( dirMode > DC_IDX && dirMode < NUM_LUMA_MODE ), "Invalid intra dir" );
const Bool bIsModeVer = (dirMode >= DIA_IDX); //DIA_IDX=34,左上对角模式
const Int intraPredAngleMode = (bIsModeVer) ? (Int)dirMode - VER_IDX : -((Int)dirMode - HOR_IDX);
const Int absAngMode = abs(intraPredAngleMode);
const Int signAng = intraPredAngleMode < 0 ? -1 : 1;
#if HEVC_USE_HOR_VER_PREDFILTERING
const Bool edgeFilter = bEnableEdgeFilters && isLuma(channelType) && (width <= MAXIMUM_INTRA_FILTERED_WIDTH) && (height <= MAXIMUM_INTRA_FILTERED_HEIGHT);
#endif
// Set bitshifts and scale the angle parameter to block size 设置位移并将角度参数缩放为块大小
static const Int angTable[17] = { 0, 1, 2, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 26, 29, 32 };
static const Int invAngTable[17] = { 0, 8192, 4096, 2731, 1638, 1170, 910, 745, 630, 546, 482, 431, 390, 356, 315, 282, 256 }; // (256 * 32) / Angle
Int invAngle = invAngTable[absAngMode];
Int absAng = angTable [absAngMode];
Int intraPredAngle = signAng * absAng;
Pel* refMain;
Pel* refSide;
Pel refAbove[2 * MAX_CU_SIZE + 1]; //上侧真实会用于预测的参考像素
Pel refLeft [2 * MAX_CU_SIZE + 1];
// Initialize the Main and Left reference array.
if (intraPredAngle < 0) //大于18小于50的角度模式
{ //这时的参考像素需要同时用到左边参考像素和上边参考像素
for( Int x = 0; x < width + 1; x++ )
{
refAbove[x + height - 1] = pSrc.at( x, 0 ); //前半段留空白区域是为了refSide像素投射过来
}
for( Int y = 0; y < height + 1; y++ )
{
refLeft[y + width - 1] = pSrc.at( 0, y ); //前半段留空白区域是为了refSide像素投射过来
}
refMain = (bIsModeVer ? refAbove + height : refLeft + width ) - 1; //确定主参考像素行是上还是左
refSide = (bIsModeVer ? refLeft + width : refAbove + height) - 1;
// Extend the Main reference to the left.
Int invAngleSum = 128; // rounding for (shift by 8)
const Int refMainOffsetPreScale = bIsModeVer ? height : width;
for( Int k = -1; k > (refMainOffsetPreScale * intraPredAngle) >> 5; k-- )
{
invAngleSum += invAngle;
refMain[k] = refSide[invAngleSum>>8]; //将refSide的像素投射到refMain参考像素行上面去
}
}
else // >1且<=18,或者>=50且<=66
{
for( Int x = 0; x < width + height + 1; x++ ) //这时的参考像素只会用到左边参考像素,或者只会用到上边参考像素
{
refAbove[x] = pSrc.at(x, 0);
refLeft[x] = pSrc.at(0, x);
}
refMain = bIsModeVer ? refAbove : refLeft ;
refSide = bIsModeVer ? refLeft : refAbove;
}
//横向角度模式时,为了便于和纵向角度模式一样来计算,故将横向时的pu翻转
// swap width/height if we are doing a horizontal mode: //所以宽高互换
Pel tempArray[MAX_CU_SIZE*MAX_CU_SIZE];
const Int dstStride = bIsModeVer ? pDst.stride : MAX_CU_SIZE;
Pel *pDstBuf = bIsModeVer ? pDst.buf : tempArray; //横向模式的预测像素先存放于tempArray,预测结束后,翻转后赋给pDst
if (!bIsModeVer)
{
std::swap(width, height);
}
if( intraPredAngle == 0 ) // pure vertical or pure horizontal 18或34
{
for( Int y = 0; y < height; y++ )
{
for( Int x = 0; x < width; x++ )
{
pDstBuf[y*dstStride + x] = refMain[x + 1]; //直接copy refMain的像素
}
}
}
else
{
Pel *pDsty=pDstBuf;
for (Int y=0, deltaPos=intraPredAngle; y<height; y++, deltaPos+=intraPredAngle, pDsty+=dstStride)
{
const Int deltaInt = deltaPos >> 5; //refMain参考行上,(x,y)点垂直/水平对应点的需要进行的偏移,偏移之后就是预测像素
const Int deltaFract = deltaPos & (32 - 1);
if( absAng < 32 )
{
{
// Do linear filtering
const Pel *pRM = refMain + deltaInt + 1;
Int lastRefMainPel = *pRM++;
for( Int x = 0; x < width; pRM++, x++ )
{
Int thisRefMainPel = *pRM;
pDsty[x + 0] = ( Pel ) ( ( ( 32 - deltaFract )*lastRefMainPel + deltaFract*thisRefMainPel + 16 ) >> 5 );
lastRefMainPel = thisRefMainPel;
}
}
}
else //模式2、34、66 对角模式
{
// Just copy the integer samples
for( Int x = 0; x < width; x++ )
{
pDsty[x] = refMain[x + deltaInt + 1];
}
}
}
}
// Flip the block if this is the horizontal mode 预测结束后,将横向模式重新翻转过来
if( !bIsModeVer )
{
for( Int y = 0; y < height; y++ )
{
for( Int x = 0; x < width; x++ )
{
pDst.at( y, x ) = pDstBuf[x]; //翻转,x y赋值给y x
}
pDstBuf += dstStride;
}
}
}