函数xPredIntraAng
功能:帧内 - -角度预测、DC预测
着重关注:
1.数组的相互赋值
2.数组的含义
3.指针的位置变化
*/
// Function for deriving the angular Intra predictions
/** Function for deriving the simplified angular intra predictions.
// 重建数组参数
* \param pSrc pointer to reconstructed sample array
* \param srcStride the stride of the reconstructed sample array
// 预测数组参数
* \param rpDst reference to pointer for the prediction sample array
* \param dstStride the stride of the prediction sample array
* \param width the width of the block
* \param height the height of the block
* \param dirMode the intra prediction mode index
* \param blkAboveAvailable boolean indication if the block above is available
* \param blkLeftAvailable boolean indication if the block to the left is available
*
* This function derives the prediction samples for the angular mode based on the prediction direction indicated by
* the prediction mode index. The prediction direction is given by the displacement of the bottom row of the block and
* the reference row above the block in the case of vertical prediction or displacement of the rightmost column
* of the block and reference column left from the block in the case of the horizontal prediction. The displacement
* is signalled at 1/32 pixel accuracy. When projection of the predicted pixel falls inbetween reference samples,
* the predicted value for the pixel is linearly interpolated from the reference samples. All reference samples are taken
* from the extended main reference.
*/
Void TComPrediction::xPredIntraAng( 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 ); //确保非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;
// DC预测模式
if (modeDC)
{
// 计算dcval
Pel dcval = predIntraGetPredValDC(pSrc, srcStride, width, height, blkAboveAvailable, blkLeftAvailable);
for (k=0;k<blkSize;k++)
{
for (l=0;l<blkSize;l++)
{
// 对预测数组中的每个元素赋值dcval
pDst[k*dstStride+l] = dcval;
}
}
}
// 角度预测
else
{
Pel* refMain;// 主
Pel* refSide;// 辅
Pel refAbove[2*MAX_CU_SIZE+1];// 上 数组
Pel refLeft[2*MAX_CU_SIZE+1];// 左 数组
// 参考数组的初始化
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);
// 将refside数组“扩展”到refmain数组上
Int invAngleSum = 128; // rounding for (shift by 8)
for (k=-1; k>blkSize*intraPredAngle>>5; k--)
{
invAngleSum += invAngle;
refMain[k] = refSide[invAngleSum>>8];
}
}
//if (intraPredAngle < 0)
else //intraPredAngle>=0
{// 此过程与if过程类似
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] = Clip ( pDst[k*dstStride] + (( refSide[k+1] - refSide[0] ) >> 1) );
}
}
}
// if (intraPredAngle == 0)
else//角度不为0,此时考虑投影的问题
{
Int deltaPos=0;
Int deltaInt;
Int deltaFract;
Int refMainIndex;
//计算出“格数”deltaInt和“权重”deltaFract
for (k=0;k<blkSize;k++)
{
deltaPos += intraPredAngle;
deltaInt = deltaPos >> 5;
deltaFract = deltaPos & (32 - 1);
//如果“权重”不为0,说明未投影到像素点上,而是投影在两个像素点之间
if (deltaFract)
{
// 加权插值计算
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 );
}
}
// if (deltaFract)
else
{
// 直接进行整像素的复制
for (l=0;l<blkSize;l++)
{
pDst[k*dstStride+l] = refMain[l+deltaInt+1];
}
}
}
}
// 如果是水平模式,则进行一个翻转
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;
}
}
}
}
}