x264幀內預測
理論
1、宏塊大小是 16x16,每個宏塊包含一個 16x16 大小的亮度塊和兩個 8x8 的色度塊
2、亮度分量
對於亮度分量而言,幀內預測只針對 16x16 的塊或者 4x4 的小塊,換句話說,對於亮度分量而言,進行幀內預測的時候,它只能被劃分爲 16x16(即不進行劃分)的塊,或者 4x4 的小塊。
2.1、16x16 亮度塊
有4種幀內預測模式:DC、H(水平模式)、V(垂直模式)、plane(平面模式)。對於的序號分別是:0、1、2、3.
2.2、4x4 亮度塊
有 9 種幀內預測模式:模式 0(垂直),模式 1(水平),模式 2(DC),模式3(45°),模式 4(135°),模式 5(116.6°),模式 6(153.4°),模式 7(63.4°),模式 8(26.6°)
2.3、額外補充
按照理論上,亮度分量只支持 16x16 和 4x4 的塊,但是後來增加了 8x8 的DCT,它要求提供 8x8 的幀內預測,因此,x264 提供了 8x8 塊的幀內預測。它的模式和 4x4 小塊的模式是一樣的。
3、色度分量對於色度分量,幀內預測只支持 8x8 的色度分量,也就是說宏塊對應的色度分量不用劃分,直接進行預測。它使用的預測方式和 16x16 的亮度塊一樣。
4、處理過程
先計算宏塊下每個 4x4 小塊的最優模式,把所有 4x4 小塊的最優代價相加(假設爲 sum),然後計算 16x16 的塊的最優模式,與 sum 進行比較,決定使用哪一個作爲最優模式。
代碼
1、入口函數 x264_mb_analyse_intra
2、處理步驟
2.1、進行 16x16 亮度塊的幀內預測
(1)調用函數 predict_16x16_mode_available,選出 16x16 亮度塊可用的幀內模式(要根據鄰居塊是否存在來判別哪些模式可用)
(2) 遍 歷 所 有 可 用 的 16x16 亮 度 塊 的 模 式 , 調 用 函 數 指 針predict_16x16[...]進行預測,然後計算 sad,最後選出 16x16 塊的最優模式
2.2、進行 8x8 色度塊的幀內預測
(1) 如 果 使 用 了 rdo 模 式 ( 可 以 由 用 戶 設 置 ), 那 麼 調 用x264_mb_analyse_intra_chroma 函數,進行下面處理:調用 predict_8x8chroma_mode_available 函數,選取 8x8 色度塊可用的幀內預測模式2)遍歷所有的 8x8 色度塊的預測模式,進行做魚操作,計算 sad,選出最優的模式
(2)如果沒有使用 rdo 模式,那麼計算一些額外的 sad(相當於是 8x8色度塊的 sad),它們的模式應該和對應的 16x16 亮度塊的模式一樣,不用另外計算。
2.3、進行 4x4 亮度塊的幀內預測,遍歷宏塊下所有的 4x4 小塊,對於每一個小塊,進行下面操作
(1)調用 x264_mb_predict_intra4x4_mode 函數,得到一個從鄰居塊預測來的模式 pred_mode,用於後面 sad 的計算。
(2)調用 predict_4x4_mode_available 函數,選取可用的 4x4 亮度塊的預測模式。
(3)遍歷所有可用的預測模式,進行預測操作,選取最優的模式
(4)對於最優的模式,調用 x264_mb_encode_i4x4,計算比特率
(5)把所有的 4x4 小塊最優模式的代價相加,就得到了宏塊下 4x4 劃分的最優模式的代價
2.4、如果有必要(使用 8x8 的 DCT 時),那麼進行 8x8 亮度塊的幀內預測
(1)宏塊由 4 個 8x8 塊構成,因此要依次處理這 4 個塊。
(2)對於每一個 8x8 可用的模式(由於 8x8 亮度預測模式和 4x4 的一樣,因此實際調用 predict_4x4_mode_available 函數來得到可用的預測模式),遍歷這些可用模式,進行 8x8 的預測操作,選出最優的模式,然後調用x264_mb_encode_i8x8 計算該最優模式的比特率。
(3)累加宏塊下 8x8 小塊的最優代價,即爲 8x8 幀內預測模式的最優代價
3、具體代碼實現,抽取了幾個典型的函數作爲例子:
/* 幀內預測主函數 */
static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_cost_inter )
{
const unsigned int flags = h->sh.i_type == SLICE_TYPE_I ? h->param.analyse.intra :
h->param.analyse.inter;
const int i_stride = h->mb.pic.i_stride[0];
uint8_t *p_src = h->mb.pic.p_fenc[0];
uint8_t *p_dst = h->mb.pic.p_fdec[0];
int
f8_satd_rd_ratio = 0;
int i, idx;
int i_max;
int predict_mode[9];
const int i_satd_thresh = a->i_best_satd * 5/4 + a->i_lambda * 10;
/*---------------- Try all mode and calculate their score ---------------*/
/* 16x16 prediction selection */
/* 16x16亮度 預測 */
predict_16x16_mode_available( h->mb.i_neighbour, predict_mode, &i_max );
for( i = 0; i < i_max; i++ )
{
int i_sad;
int i_mode;
i_mode = predict_mode[i];
h->predict_16x16[i_mode]( p_dst, i_stride );
i_sad = h->pixf.mbcmp[PIXEL_16x16]( p_dst, i_stride, p_src, i_stride ) +
a->i_lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] );
if( a->i_sad_i16x16 > i_sad )
{
a->i_predict16x16 = i_mode;
a->i_sad_i16x16
}
}
= i_sad;/* 8x8色度預測 */
if( a->b_mbrd )
{
f8_satd_rd_ratio = ((unsigned)i_cost_inter << 8) / a->i_best_satd + 1;
x264_mb_analyse_intra_chroma( h, a );
if( h->mb.b_chroma_me )
a->i_sad_i16x16 += a->i_sad_i8x8chroma;
if( a->i_sad_i16x16 < i_satd_thresh )
{
h->mb.i_type = I_16x16;
h->mb.i_intra16x16_pred_mode = a->i_predict16x16;
a->i_sad_i16x16 = x264_rd_cost_mb( h, a->i_lambda2 );
}
else
a->i_sad_i16x16 = a->i_sad_i16x16 * f8_satd_rd_ratio >> 8;
}
else
{
if( h->sh.i_type == SLICE_TYPE_B )
/* cavlc mb type prefix */
a->i_sad_i16x16 += a->i_lambda * i_mb_b_cost_table[I_16x16];
if( a->b_fast_intra && a->i_sad_i16x16 > 2*i_cost_inter )
return;
}
/* 4x4 prediction selection */
/* 4x4亮度預測 */
if( flags & X264_ANALYSE_I4x4 )
{
a->i_sad_i4x4 = 0;
for( idx = 0; idx < 16; idx++ )
{
uint8_t *p_src_by;
uint8_t *p_dst_by;
int
i_best;
int x, y;
int i_pred_mode;
i_pred_mode= x264_mb_predict_intra4x4_mode( h, idx );
x = block_idx_x[idx];
y = block_idx_y[idx];
p_src_by = p_src + 4 * x + 4 * y * i_stride;
p_dst_by = p_dst + 4 * x + 4 * y * i_stride;i_best = COST_MAX;
predict_4x4_mode_available( h->mb.i_neighbour4[idx], predict_mode,
&i_max );
for( i = 0; i < i_max; i++ )
{
int i_sad;
int i_mode;
i_mode = predict_mode[i];
h->predict_4x4[i_mode]( p_dst_by, i_stride );
i_sad = h->pixf.mbcmp[PIXEL_4x4]( p_dst_by, i_stride,
p_src_by, i_stride )
+ a->i_lambda * (i_pred_mode ==
x264_mb_pred_mode4x4_fix(i_mode) ? 1 : 4);
if( i_best > i_sad )
{
a->i_predict4x4[x][y] = i_mode;
i_best = i_sad;
}
}
a->i_sad_i4x4 += i_best;
/* we need to encode this block now (for next ones) */
h->predict_4x4[a->i_predict4x4[x][y]]( p_dst_by, i_stride );
/* 計算該最優模式下的比特率 */
x264_mb_encode_i4x4( h, idx, a->i_qp );
h->mb.cache.intra4x4_pred_mode[x264_scan8[idx]] = a->i_predict4x4[x][y];
}
a->i_sad_i4x4 += a->i_lambda * 24;
/* from JVT (SATD0) */
if( a->b_mbrd )
{
if( h->mb.b_chroma_me )
a->i_sad_i4x4 += a->i_sad_i8x8chroma;
if( a->i_sad_i4x4 < i_satd_thresh )
{
h->mb.i_type = I_4x4;
a->i_sad_i4x4 = x264_rd_cost_mb( h, a->i_lambda2 );
}
elsea->i_sad_i4x4 = a->i_sad_i4x4 * f8_satd_rd_ratio >> 8;
}
else
{
if( h->sh.i_type == SLICE_TYPE_B )
a->i_sad_i4x4 += a->i_lambda * i_mb_b_cost_table[I_4x4];
}
}
/* 8x8 prediction selection */
/* 如果有必要,那麼進行8x8的亮度預測 */
if( flags & X264_ANALYSE_I8x8 )
{
a->i_sad_i8x8 = 0;
for( idx = 0; idx < 4; idx++ )
{
uint8_t *p_src_by;
uint8_t *p_dst_by;
int
i_best;
int x, y;
int i_pred_mode;
i_pred_mode= x264_mb_predict_intra4x4_mode( h, 4*idx );
x = idx&1;
y = idx>>1;
p_src_by = p_src + 8 * x + 8 * y * i_stride;
p_dst_by = p_dst + 8 * x + 8 * y * i_stride;
i_best = COST_MAX;
predict_4x4_mode_available( h->mb.i_neighbour8[idx], predict_mode,
&i_max );
for( i = 0; i < i_max; i++ )
{
int i_sad;
int i_mode;
i_mode = predict_mode[i];
h->predict_8x8[i_mode]( p_dst_by, i_stride, h->mb.i_neighbour );
/* could use sa8d, but it doesn't seem worth the speed cost (without
mmx at least) */
i_sad = h->pixf.mbcmp[PIXEL_8x8]( p_dst_by, i_stride,
p_src_by, i_stride )+ a->i_lambda * (i_pred_mode ==
x264_mb_pred_mode4x4_fix(i_mode) ? 1 : 4);
if( i_best > i_sad )
{
a->i_predict8x8[x][y] = i_mode;
i_best = i_sad;
}
}
a->i_sad_i8x8 += i_best;
/* we need to encode this block now (for next ones) */
h->predict_8x8[a->i_predict8x8[x][y]]( p_dst_by, i_stride,
h->mb.i_neighbour );
x264_mb_encode_i8x8( h, idx, a->i_qp );
x264_macroblock_cache_intra8x8_pred( h, 2*x, 2*y, a->i_predict8x8[x][y] );
}
if( a->b_mbrd )
{
if( h->mb.b_chroma_me )
a->i_sad_i8x8 += a->i_sad_i8x8chroma;
if( a->i_sad_i8x8 < i_satd_thresh )
{
h->mb.i_type = I_8x8;
a->i_sad_i8x8 = x264_rd_cost_mb( h, a->i_lambda2 );
}
else
a->i_sad_i8x8 = a->i_sad_i8x8 * f8_satd_rd_ratio >> 8;
}
else
{
// FIXME some bias like in i4x4?
if( h->sh.i_type == SLICE_TYPE_B )
a->i_sad_i8x8 += a->i_lambda * i_mb_b_cost_table[I_8x8];
}
}
}
/* 選取 16x16 亮度塊,可用的幀內預測模式 */
static void predict_16x16_mode_available( unsigned int i_neighbour, int *mode, int
*pi_count ){
if( i_neighbour & MB_TOPLEFT )
{
/* top and left avaible */
*mode++ = I_PRED_16x16_V;
*mode++ = I_PRED_16x16_H;
*mode++ = I_PRED_16x16_DC;
*mode++ = I_PRED_16x16_P;
*pi_count = 4;
}
else if( i_neighbour & MB_LEFT )
{
/* left available*/
*mode++ = I_PRED_16x16_DC_LEFT;
*mode++ = I_PRED_16x16_H;
*pi_count = 2;
}
else if( i_neighbour & MB_TOP )
{
/* top available*/
*mode++ = I_PRED_16x16_DC_TOP;
*mode++ = I_PRED_16x16_V;
*pi_count = 2;
}
else
{
/* none avaible */
*mode = I_PRED_16x16_DC_128;
*pi_count = 1;
}
}
/* 從附近塊中預測出一個模式 pred_mode */
int x264_mb_predict_intra4x4_mode( x264_t *h, int idx )
{
const int ma = h->mb.cache.intra4x4_pred_mode[x264_scan8[idx] - 1];
const int mb = h->mb.cache.intra4x4_pred_mode[x264_scan8[idx] - 8];
const int m = X264_MIN( x264_mb_pred_mode4x4_fix(ma),
x264_mb_pred_mode4x4_fix(mb) );
if( m < 0 )
return I_PRED_4x4_DC;
return m;}
/* 4x4(8x8)亮度塊,可用的預測模式 */
static void predict_4x4_mode_available( unsigned int i_neighbour,
int *mode, int *pi_count )
{
/* FIXME even when b_tr == 0 there is some case where missing pixels
* are emulated and thus more mode are available TODO
* analysis and encode should be fixed too */
int b_l = i_neighbour & MB_LEFT;
int b_t = i_neighbour & MB_TOP;
int b_tr = i_neighbour & MB_TOPRIGHT;
if( b_l && b_t )
{
*mode++ = I_PRED_4x4_DC;
*mode++ = I_PRED_4x4_H;
*mode++ = I_PRED_4x4_V;
*mode++ = I_PRED_4x4_DDR;
*mode++ = I_PRED_4x4_VR;
*mode++ = I_PRED_4x4_HD;
*mode++ = I_PRED_4x4_HU;
*pi_count = 7;
}
else if( b_l )
{
*mode++ = I_PRED_4x4_DC_LEFT;
*mode++ = I_PRED_4x4_H;
*mode++ = I_PRED_4x4_HU;
*pi_count = 3;
}
else if( b_t )
{
*mode++ = I_PRED_4x4_DC_TOP;
*mode++ = I_PRED_4x4_V;
*pi_count = 2;
}
else
{
*mode++ = I_PRED_4x4_DC_128;
*pi_count = 1;
}
if( b_t && b_tr ){
*mode++ = I_PRED_4x4_DDL;
*mode++ = I_PRED_4x4_VL;
(*pi_count) += 2;
}
}
/* 編碼/計算某個模式的比特率(爲了選取最優模式) */
void x264_mb_encode_i4x4( x264_t *h, int idx, int i_qscale )
{
const int i_stride = h->mb.pic.i_stride[0];
const int i_offset = 4 * block_idx_x[idx] + 4 * block_idx_y[idx] * i_stride;
uint8_t *p_src = &h->mb.pic.p_fenc[0][i_offset];
uint8_t *p_dst = &h->mb.pic.p_fdec[0][i_offset];
int16_t dct4x4[4][4];
if( h->mb.b_lossless )
{
sub_zigzag_4x4full( h->dct.block[idx].luma4x4, p_src, p_dst, i_stride );
return;
}
h->dctf.sub4x4_dct( dct4x4, p_src, i_stride, p_dst, i_stride );
quant_4x4( dct4x4, h->quant4_mf[CQM_4IY], i_qscale, 1 );
scan_zigzag_4x4full( h->dct.block[idx].luma4x4, dct4x4 );
x264_mb_dequant_4x4( dct4x4, h->dequant4_mf[CQM_4IY], i_qscale );
/* output samples to fdec */
h->dctf.add4x4_idct( p_dst, i_stride, dct4x4 );
}
/* 16x16 亮度塊水平預測 */
static void predict_16x16_h( uint8_t *src, int i_stride )
{
int i,j;
for( i = 0; i < 16; i++ )
{
uint8_t v;
v = src[-1];
for( j = 0; j < 16; j++ )
{src[j] = v;
}
src += i_stride;
}
}