版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/NB_vol_1/article/details/78396361
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;
}
}