幀内角度預測函數如下
void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, const PredictionUnit &pu, const bool useFilteredPredSamples )
根據預測模式調用模式預測函數,這篇文章主要講planner和DC模式。
其他模式待更新。。。
1、planner模式
planner模式預測的參考模闆示意圖如下

這裡公式都用乘除法給出,實際程式中采用移位。圖中LB為lC(i+1)和RT為tR(j+1)。
planner模式的具體程式注釋如下
void IntraPrediction::xPredIntraPlanar( const CPelBuf &pSrc, PelBuf &pDst, const SPS& sps )
{
const uint32_t width = pDst.width;
const uint32_t height = pDst.height;
#if JVET_M0102_INTRA_SUBPARTITIONS
const uint32_t log2W = g_aucLog2[width < 2 ? 2 : width];
const uint32_t log2H = g_aucLog2[height < 2 ? 2 : height];
#else
const uint32_t log2W = g_aucLog2[ width ];
const uint32_t log2H = g_aucLog2[ height ];
#endif
int leftColumn[MAX_CU_SIZE + 1], topRow[MAX_CU_SIZE + 1], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE];
#if JVET_M0102_INTRA_SUBPARTITIONS
const uint32_t offset = 1 << (log2W + log2H);
#else
const uint32_t offset = width * height;
#endif
// Get left and above reference column and row
for( int k = 0; k < width + 1; k++ )
{
topRow[k] = pSrc.at( k + 1, 0 );//上參考
}
for( int k = 0; k < height + 1; k++ )
{
leftColumn[k] = pSrc.at( 0, k + 1 );//左參考
}
// Prepare intermediate variables used in interpolation
int bottomLeft = leftColumn[height];//左下lc(i+1)
int topRight = topRow[width];//右上tR(j+1)
for( int k = 0; k < width; k++ )
{
bottomRow[k] = bottomLeft - topRow[k];//lC(i+1)-tR(j)
topRow[k] = topRow[k] << log2H;//tR(j)*H
}
for( int k = 0; k < height; k++ )
{
rightColumn[k] = topRight - leftColumn[k];//tR(j+1)-lC(i)
leftColumn[k] = leftColumn[k] << log2W;//lC(i)*W
}
const uint32_t finalShift = 1 + log2W + log2H;//2WH
const uint32_t stride = pDst.stride;
Pel* pred = pDst.buf;
for( int y = 0; y < height; y++, pred += stride )
{
int horPred = leftColumn[y];//W*lC(i)
for( int x = 0; x < width; x++ )
{
horPred += rightColumn[y];//Ph(i,j)=W*lC(i)-j*rC(i)
topRow[x] += bottomRow[x];//Pv(i,j)=H*tR(j)-i*bR(j)
int vertPred = topRow[x];
pred[x] = ( ( horPred << log2H ) + ( vertPred << log2W ) + offset ) >> finalShift;
//P(i,j)=(Ph(i,j)*H+Pv(i,j)*W+W*H)/(2*W*H)
}
}
}
2、DC模式
根據PU的形狀,對于正方形的PU計算上邊和左邊的參考像素的均值,對于非正方形計算長長邊的均值,然後填充PU。
DC模式的具體程式注釋如下
void IntraPrediction::xPredIntraDc( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const bool enableBoundaryFilter )
{
const Pel dcval = xGetPredValDc( pSrc, pDst );//DC計算入口
pDst.fill( dcval );
#if HEVC_USE_DC_PREDFILTERING
if( enableBoundaryFilter )
{
xDCPredFiltering( pSrc, pDst, channelType );
}
#endif
}
DC值的具體計算
Pel IntraPrediction::xGetPredValDc( const CPelBuf &pSrc, const Size &dstSize )
{
CHECK( dstSize.width == 0 || dstSize.height == 0, "Empty area provided" );
int idx, sum = 0;
Pel dcVal;
const int width = dstSize.width;
const int height = dstSize.height;
const auto denom = (width == height) ? (width << 1) : std::max(width,height);//對于正方形計算所有參考像素,非正方形計算長邊
const auto divShift = g_aucLog2[denom];
const auto divOffset = (denom >> 1);//偏置
if ( width >= height )//計算上參考
{
for( idx = 0; idx < width; idx++ )
{
sum += pSrc.at( 1 + idx, 0 );
}
}
if ( width <= height )//計算左參考
{
for( idx = 0; idx < height; idx++ )
{
sum += pSrc.at( 0, 1 + idx );
}
}
dcVal = (sum + divOffset) >> divShift;//計算DC值
return dcVal;
}