帧内宏块预测编码模式:分别计算16X16和16个4X4块的代价,取两者中最小代价为该宏块的编码模式。
1、进行16X16模式的预测
(1)根据周围宏块的情况判断其可能的预测模式。(主要是上块TOP和左块LEFT)
(2)计算各种可能模式的编码代价
(3)取最小代价
2、进行4X4块模式的预测
(1)根据周围宏块情况判断其可能的预测模式。(可以参考其他相邻宏块)
(2)计算每个4X4块的每种预测模式的编码代价,并取代价最小
(3)将16个4X4块的最小代价相加,得到总代价和。
3、将16X16模式的代价与4X4模式的代价和进行比较,取两者最小为最后的宏块预测编码模式。
X264中的代码分析:
static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_satd_inter )//函数功能:帧内预测编码模式选择
{
const unsigned int flags = h->sh.i_type == SLICE_TYPE_I ? h->param.analyse.intra : h->param.analyse.inter;
//判断是进行I片内的宏块帧内预测编码还是P或B片(帧间片)内的帧内模式预测编码
uint8_t *p_src = h->mb.pic.p_fenc[0];
uint8_t *p_dst = h->mb.pic.p_fdec[0];
int i, idx;
int i_max;
int predict_mode[9];
int b_merged_satd = h->pixf.intra_satd_x3_16x16 && h->pixf.mbcmp[0] == h->pixf.satd[0];
/*---------------- Try all mode and calculate their score ---------------*/
/* 16x16 prediction selection */
predict_16x16_mode_available( h->mb.i_neighbour, predict_mode, &i_max );//获取16X16的可用预测编码模式
if( b_merged_satd && i_max == 4 )//如果b_merged_satd不为0且可用预测编码模式有4种,I帧时直接跳过
{
h->pixf.intra_satd_x3_16x16( p_src, p_dst, a->i_satd_i16x16_dir );
h->predict_16x16[I_PRED_16x16_P]( p_dst );
a->i_satd_i16x16_dir[I_PRED_16x16_P] =
h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE );
for( i=0; i<4; i++ )
{
int cost = a->i_satd_i16x16_dir[i] += a->i_lambda * bs_size_ue(i);
COPY2_IF_LT( a->i_satd_i16x16, cost, a->i_predict16x16, i );
}
}
else
{
for( i = 0; i < i_max; i++ )
{
int i_satd;
int i_mode = predict_mode[i];
h->predict_16x16[i_mode]( p_dst );
i_satd = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE ) +
a->i_lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] );//计算编码代价
COPY2_IF_LT( a->i_satd_i16x16, i_satd, a->i_predict16x16, i_mode );
//比较a->i_satd_i16x16与i_satd的大小,a->i_satd_i16x16的初值为COST_MAX
/* 比较大小代码如下:
#define COPY2_IF_LT(x,y,a,b)\
if((y)<(x))\
{\
(x)=(y);\
(a)=(b);\
}
如果i_satd比a->i_satd_i16x16小,则把i_satd值赋给a->i_satd_i16x16,作为当前最优代价,
同时把该次预测模式作为当前最优模式;如果a->i_satd_i16x16比i_satd小,则不赋值,只作比较.
*/
}
}
if( h->sh.i_type == SLICE_TYPE_B )//如果是进行B片内的宏块帧内预测编码,I帧时直接跳过
/* cavlc mb type prefix */
a->i_satd_i16x16 += a->i_lambda * i_mb_b_cost_table[I_16x16];//在代价上增加一个prefix
if( a->b_fast_intra && a->i_satd_i16x16 > 2*i_satd_inter )
return;
/* 8x8 prediction selection */
if( flags & X264_ANALYSE_I8x8 )
{
//省略8X8分块模式时的预测编码代价运算,一般情况下,8X8模式是关闭的.
}
/* 4x4 prediction selection */
if( flags & X264_ANALYSE_I4x4 )//进行4X4分块模式代价运算
{
int i_cost;
int i_satd_thresh = X264_MIN3( i_satd_inter, a->i_satd_i16x16, a->i_satd_i8x8 );//获得帧间,帧内16X16及8X8模式下编码的最优代价
b_merged_satd = h->pixf.intra_satd_x3_4x4 && h->pixf.mbcmp[0] == h->pixf.satd[0];
if( a->b_mbrd )
i_satd_thresh = i_satd_thresh * (10-a->b_fast_intra)/8;
i_cost = a->i_lambda * 24; /* from JVT (SATD0) */
//非RDO率失真优化模式下,宏块总代价cost_intra4*4 = 16个 4*4 小块的最佳 cost 求和 + 4 * 6 * lambda_mode.
//此处由于还未进行4X4代价计算,只是预先增加4 * 6 * lambda_mode.
//当采用4X4分块时,由于每个4X4块的最优预测编码模式都需要进行编码传输,这样,相比较于16X16模式就多了传输比特数,
//为了合理公平比较,规定每个8*8块加一个6*lambda_mode,因此就等于是加了一个 4 * 6 * lambda_mode.
if( h->sh.i_type == SLICE_TYPE_B )
i_cost += a->i_lambda * i_mb_b_cost_table[I_4x4];
for( idx = 0;; idx++ )
{
int x = block_idx_x[idx];
int y = block_idx_y[idx];//计算4X4块在所属宏块中的坐标或位置
uint8_t *p_src_by = p_src + 4*x + 4*y*FENC_STRIDE;
uint8_t *p_dst_by = p_dst + 4*x + 4*y*FDEC_STRIDE;
int i_best = COST_MAX;
int i_pred_mode = x264_mb_predict_intra4x4_mode( h, idx );
predict_4x4_mode_available( h->mb.i_neighbour4[idx], predict_mode, &i_max );//根据周围块情况,获取可用编码模式
if( (h->mb.i_neighbour4[idx] & (MB_TOPRIGHT|MB_TOP)) == MB_TOP )
/* emulate missing topright samples */
*(uint32_t*) &p_dst_by[4 - FDEC_STRIDE] = p_dst_by[3 - FDEC_STRIDE] * 0x01010101U;
if( b_merged_satd && i_max >= 6 )
{
int satd[3];
h->pixf.intra_satd_x3_4x4( p_src_by, p_dst_by, satd );
if( i_pred_mode < 3 )
satd[i_pred_mode] -= 3 * a->i_lambda;
for( i=2; i>=0; i-- )
COPY2_IF_LT( i_best, satd[i] + 4 * a->i_lambda,//非RDO率失真优化模式下, cost = SATD + 4 * lambda_mode(当前模式不是最有可能模式)
a->i_predict4x4[idx], i );//把当前编码模式下的代价与原最优代价进行比较,得出新的最优代价模式.
i = 3;
}
else
i = 0;
for( ; i<i_max; i++ )
{
int i_satd;
int i_mode = predict_mode[i];
h->predict_4x4[i_mode]( p_dst_by );
i_satd = h->pixf.mbcmp[PIXEL_4x4]( p_dst_by, FDEC_STRIDE,//进行代价计算,其中前半部分为绝对变换差和(SATD)
p_src_by, FENC_STRIDE )
+ a->i_lambda * (i_pred_mode == x264_mb_pred_mode4x4_fix(i_mode) ? 1 : 4);//
//SAD(绝对差值和)计算的差值是预测值与图像像素值的差值,为了更准确的比较每种模式的Cost值,H.264还对这些差值进行Hadamard变换,
//将差值(这些值最后要变换到频域进行编码)变换到频域求绝对差值和,这样计算得到的值叫作绝对变换差和(SATD).
COPY2_IF_LT( i_best, i_satd, a->i_predict4x4[idx], i_mode );//进行代价比较
}
i_cost += i_best;
if( i_cost > i_satd_thresh || idx == 15 )//如果4X4块的代价总和过大或者已经计算完16个4X4块,则退出循环.
break;
/* we need to encode this block now (for next ones) */
h->predict_4x4[a->i_predict4x4[idx]]( p_dst_by );
x264_mb_encode_i4x4( h, idx, a->i_qp );
h->mb.cache.intra4x4_pred_mode[x264_scan8[idx]] = a->i_predict4x4[idx];
}
if( idx == 15 )
a->i_satd_i4x4 = i_cost;//如果已经计算完16个4X4块,则得到4X4分块模式的最小代价
else
a->i_satd_i4x4 = COST_MAX;//如果4X4分块预测半路终止,则将其代价和赋值为最大,表示4X4分块模式不可用
}
}