//在对P帧或B帧的宏块进行预测之前,先判断当前帧是否适宜用帧内模式,
//如果宏块的临近已编码宏块均不采用帧内模式,并且若宏块所在的slice为p的话,
//参考帧相应位置的宏块也不采用帧内模式的话,则该宏块采用帧内预测的可能性就很小。
//那么在该宏块用帧间模式得到的最小的SAD后,只要计算帧内16*16预测模式的SAD,
//将二者相比,当比值超过门限值时,即用帧间预测模式,而不用计算帧内4*4的模式了。
else if( h->sh.i_type == SLICE_TYPE_P )// P帧预测模式的选择
{
//当是P帧时,首先判断是否是skip模式,只有在左,上,左上,右上有一个是skip模式的时候,
//这时mb才 可能是skip模式:b_skip = x264_macroblock_probe_pskip( h );
//当不采用p_skip模式时,则调用x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a )
//进行帧间16*16块的分析:计算p16x16模式的运动适量及cost(其中还要考虑到参考帧部分,运动估计)。
//然后在允许16*16块分割时,进一步分析8*8,4*4,16*8,8*16块的运动矢量,并比较cost的大小。
//获得最佳的运动估计模式。得到子宏块的分割方式存储在 i_partion。随后根据i_partion进行像素细化。
int b_skip = 0;
int i_intra_cost, i_intra_type;
h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 0 );//空函数?
/* Fast P_SKIP detection */
analysis.b_try_pskip = 0;
if( h->param.analyse.b_fast_pskip )
{
if( h->param.i_threads > 1 && h->mb.cache.pskip_mv[1] > h->mb.mv_max_spel[1] )
// FIXME don't need to check this if the reference frame is done
{}
else if( h->param.analyse.i_subpel_refine >= 3 )
analysis.b_try_pskip = 1;
else if( h->mb.i_mb_type_left == P_SKIP ||
h->mb.i_mb_type_top == P_SKIP ||
h->mb.i_mb_type_topleft == P_SKIP ||
h->mb.i_mb_type_topright == P_SKIP )
b_skip = x264_macroblock_probe_pskip( h );//判断是否可以进行P_skip编码
}
h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 1 );
if( b_skip )
{
h->mb.i_type = P_SKIP;
h->mb.i_partition = D_16x16;
assert( h->mb.cache.pskip_mv[1] <= h->mb.mv_max_spel[1] || h->param.i_threads == 1 );
}
else
{
const unsigned int flags = h->param.analyse.inter;
int i_type;
int i_partition;
int i_thresh16x8;
int i_satd_inter, i_satd_intra;
x264_mb_analyse_load_costs( h, &analysis );// 载入当前MB和临近MB块的信息
x264_mb_analyse_inter_p16x16( h, &analysis );//P16x16 宏块预测模式的分析;下面是这个函数的解析
static void x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a )
{
x264_me_t m;
int i_ref, i_mvc;
DECLARE_ALIGNED_4( int16_t mvc[8][2] );
int i_halfpel_thresh = INT_MAX;
int *p_halfpel_thresh = h->mb.pic.i_fref[0]>1 ? &i_halfpel_thresh : NULL;
/* 16x16 Search on all ref frame */
m.i_pixel = PIXEL_16x16;
m.p_cost_mv = a->p_cost_mv; //初始化MV的cost
LOAD_FENC( &m, h->mb.pic.p_fenc, 0, 0 );//加载将要编码的宏块
a->l0.me16x16.cost = INT_MAX;//初始化ME的cost
for( i_ref = 0; i_ref < h->mb.pic.i_fref[0]; i_ref++ )//遍历所有的参考帧寻找最佳的参考块
{
const int i_ref_cost = REF_COST( 0, i_ref );//参考帧的cost
i_halfpel_thresh -= i_ref_cost;
m.i_ref_cost = i_ref_cost;
m.i_ref = i_ref;
/* search with ref */
LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, i_ref, 0, 0 );//加载参考帧
x264_mb_predict_mv_16x16( h, 0, i_ref, m.mvp );//确定搜索的初始位置(中值法)
x264_mb_predict_mv_ref16x16( h, 0, i_ref, mvc, &i_mvc );//寻找其它候选运动矢量。这些候选者包括:空间相邻的左、左上、上、右上块的MV;第0个参考帧中的当前块、右边块、下边快运动矢量乘以时间差权重。(时空域和空间域)
x264_me_search_ref( h, &m, mvc, i_mvc, p_halfpel_thresh );//搜索该参考帧中最佳的匹配块(亚像素搜索在里面)
/* early termination
* SSD threshold would probably be better than SATD */
if( i_ref == 0&& a->b_try_pskip && m.cost-m.cost_mv < 300*a->i_lambda
&& abs(m.mv[0]-h->mb.cache.pskip_mv[0])+ abs(m.mv[1]-h->mb.cache.pskip_mv[1]) <= 1
&& x264_macroblock_probe_pskip( h ) )
{
h->mb.i_type = P_SKIP;
x264_analyse_update_cache( h, a );
assert( h->mb.cache.pskip_mv[1] <= h->mb.mv_max_spel[1] || h->param.i_threads == 1 );
return;
}
m.cost += i_ref_cost;
i_halfpel_thresh += i_ref_cost;
if( m.cost < a->l0.me16x16.cost )
h->mc.memcpy_aligned( &a->l0.me16x16, &m, sizeof(x264_me_t) );
/* save mv for predicting neighbors */
*(uint32_t*)a->l0.mvc[i_ref][0] = *(uint32_t*)h->mb.mvr[0][i_ref][h->mb.i_mb_xy] = *(uint32_t*)m.mv;
}
x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, a->l0.me16x16.i_ref );//这里存储的P_L0的ME
assert( a->l0.me16x16.mv[1] <= h->mb.mv_max_spel[1] || h->param.i_threads == 1 );
h->mb.i_type = P_L0;
if( a->i_mbrd )
{
x264_mb_cache_fenc_satd( h );//
if( a->l0.me16x16.i_ref == 0 && *(uint32_t*)a->l0.me16x16.mv == *(uint32_t*)h->mb.cache.pskip_mv )
{
h->mb.i_partition = D_16x16;
x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, 0, a->l0.me16x16.mv );//这里存储的P_L0的MV
a->l0.i_rd16x16 = x264_rd_cost_mb( h, a->i_lambda2 );//保留cost
}
}
}
if( h->mb.i_type == P_SKIP )
return;
if( flags & X264_ANALYSE_PSUB16x16 )//P8x8预测模式的选择
{
if( h->param.analyse.b_mixed_references )
x264_mb_analyse_inter_p8x8_mixed_ref( h, &analysis );
else
x264_mb_analyse_inter_p8x8( h, &analysis );
}
/* Select best inter mode */
i_type = P_L0;
i_partition = D_16x16;
i_cost = analysis.l0.me16x16.cost;
if( ( flags & X264_ANALYSE_PSUB16x16 ) &&
analysis.l0.i_cost8x8 < analysis.l0.me16x16.cost )
{
i_type = P_8x8;
i_partition = D_8x8;
i_cost = analysis.l0.i_cost8x8;
/* Do sub 8x8 */
if( flags & X264_ANALYSE_PSUB8x8 )//4x4,8x4,4x8,帧间预测模式的选择
{
for( i = 0; i < 4; i++ )
{
x264_mb_analyse_inter_p4x4( h, &analysis, i );
if( analysis.l0.i_cost4x4[i] < analysis.l0.me8x8[i].cost )
{
int i_cost8x8 = analysis.l0.i_cost4x4[i];
h->mb.i_sub_partition[i] = D_L0_4x4;
x264_mb_analyse_inter_p8x4( h, &analysis, i );
COPY2_IF_LT( i_cost8x8, analysis.l0.i_cost8x4[i],
h->mb.i_sub_partition[i], D_L0_8x4 );//比较8*4和 i_cost8*8哪个代价低
x264_mb_analyse_inter_p4x8( h, &analysis, i );
COPY2_IF_LT( i_cost8x8, analysis.l0.i_cost4x8[i],
h->mb.i_sub_partition[i], D_L0_4x8 );//比较4*8和 i_cost8*8哪个代价低
i_cost += i_cost8x8 - analysis.l0.me8x8[i].cost;
}
x264_mb_cache_mv_p8x8( h, &analysis, i );//更新8*8的MV信息
}
analysis.l0.i_cost8x8 = i_cost;
}
}
/* Now do 16x8/8x16 */
i_thresh16x8 = analysis.l0.me8x8[1].cost_mv + analysis.l0.me8x8[2].cost_mv;
if( ( flags & X264_ANALYSE_PSUB16x16 ) &&
analysis.l0.i_cost8x8 < analysis.l0.me16x16.cost + i_thresh16x8 )
{
x264_mb_analyse_inter_p16x8( h, &analysis );
COPY3_IF_LT( i_cost, analysis.l0.i_cost16x8, i_type, P_L0, i_partition, D_16x8 );//比较16*8和16*16哪个代价低
x264_mb_analyse_inter_p8x16( h, &analysis );
COPY3_IF_LT( i_cost, analysis.l0.i_cost8x16, i_type, P_L0, i_partition, D_8x16 );//比较8*16和16*16哪个代价低
}
h->mb.i_partition = i_partition;
/* refine qpel */
//FIXME mb_type costs?
if( analysis.i_mbrd )//重新划分模式
{
/* refine later *///intra省略
}
else if( i_partition == D_16x16 )
{
x264_me_refine_qpel( h, &analysis.l0.me16x16 );
i_cost = analysis.l0.me16x16.cost;
}
else if( i_partition == D_16x8 )
{
x264_me_refine_qpel( h, &analysis.l0.me16x8[0] );
x264_me_refine_qpel( h, &analysis.l0.me16x8[1] );//半像素和1/4像素搜索
i_cost = analysis.l0.me16x8[0].cost + analysis.l0.me16x8[1].cost;//保存代价函数值
}
else if( i_partition == D_8x16 )
{
x264_me_refine_qpel( h, &analysis.l0.me8x16[0] );
x264_me_refine_qpel( h, &analysis.l0.me8x16[1] );
i_cost = analysis.l0.me8x16[0].cost + analysis.l0.me8x16[1].cost;
}
else if( i_partition == D_8x8 )
{
int i8x8;
i_cost = 0;
for( i8x8 = 0; i8x8 < 4; i8x8++ )
{
switch( h->mb.i_sub_partition[i8x8] )
{
case D_L0_8x8:
x264_me_refine_qpel( h, &analysis.l0.me8x8[i8x8] );
i_cost += analysis.l0.me8x8[i8x8].cost;
break;
case D_L0_8x4:
x264_me_refine_qpel( h, &analysis.l0.me8x4[i8x8][0] );
x264_me_refine_qpel( h, &analysis.l0.me8x4[i8x8][1] );
i_cost += analysis.l0.me8x4[i8x8][0].cost +
analysis.l0.me8x4[i8x8][1].cost;
break;
case D_L0_4x8:
x264_me_refine_qpel( h, &analysis.l0.me4x8[i8x8][0] );
x264_me_refine_qpel( h, &analysis.l0.me4x8[i8x8][1] );
i_cost += analysis.l0.me4x8[i8x8][0].cost +
analysis.l0.me4x8[i8x8][1].cost;
break;
case D_L0_4x4:
x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][0] );
x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][1] );
x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][2] );
x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][3] );
i_cost += analysis.l0.me4x4[i8x8][0].cost +
analysis.l0.me4x4[i8x8][1].cost +
analysis.l0.me4x4[i8x8][2].cost +
analysis.l0.me4x4[i8x8][3].cost;
break;
default:
x264_log( h, X264_LOG_ERROR, "internal error (!8x8 && !4x4)\n" );
break;
}
}
}
if( h->mb.b_chroma_me )//对色度进行解析
{
x264_mb_analyse_intra_chroma( h, &analysis );
x264_mb_analyse_intra( h, &analysis, i_cost - analysis.i_satd_i8x8chroma );
analysis.i_satd_i16x16 += analysis.i_satd_i8x8chroma;
analysis.i_satd_i8x8 += analysis.i_satd_i8x8chroma;
analysis.i_satd_i4x4 += analysis.i_satd_i8x8chroma;
}
else
x264_mb_analyse_intra( h, &analysis, i_cost ); //intra分析
i_satd_inter = i_cost;
i_satd_intra = X264_MIN3( analysis.i_satd_i16x16,
analysis.i_satd_i8x8,
analysis.i_satd_i4x4 );//比较I16*16,I8*8,i4*4哪个模式代价低,选择最小的
//重新划分模式
if( analysis.i_mbrd )
{
x264_mb_analyse_p_rd( h, &analysis, X264_MIN(i_satd_inter, i_satd_intra) );
i_type = P_L0;
i_partition = D_16x16;
i_cost = analysis.l0.me16x16.cost;
COPY2_IF_LT( i_cost, analysis.l0.i_cost16x8, i_partition, D_16x8 );
COPY2_IF_LT( i_cost, analysis.l0.i_cost8x16, i_partition, D_8x16 );
COPY3_IF_LT( i_cost, analysis.l0.i_cost8x8, i_partition, D_8x8, i_type, P_8x8 );
h->mb.i_type = i_type;
h->mb.i_partition = i_partition;
if( i_cost < COST_MAX )
x264_mb_analyse_transform_rd( h, &analysis, &i_satd_inter, &i_cost );
x264_intra_rd( h, &analysis, i_satd_inter * 5/4 );
}
i_intra_type = I_16x16;
i_intra_cost = analysis.i_satd_i16x16;
COPY2_IF_LT( i_intra_cost, analysis.i_satd_i8x8, i_intra_type, I_8x8 );
COPY2_IF_LT( i_intra_cost, analysis.i_satd_i4x4, i_intra_type, I_4x4 );
COPY2_IF_LT( i_intra_cost, analysis.i_satd_pcm, i_intra_type, I_PCM );
COPY2_IF_LT( i_cost, i_intra_cost, i_type, i_intra_type );//比较帧内帧间的cost
if( i_intra_cost == COST_MAX )
i_intra_cost = i_cost * i_satd_intra / i_satd_inter + 1;
h->mb.i_type = i_type;
h->stat.frame.i_intra_cost += i_intra_cost;
h->stat.frame.i_inter_cost += i_cost;
{
if( IS_INTRA( h->mb.i_type ) )
{
x264_intra_rd_refine( h, &analysis );
}
else if( i_partition == D_16x16 )
{
x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, analysis.l0.me16x16.i_ref );
x264_me_refine_qpel_rd( h, &analysis.l0.me16x16, analysis.i_lambda2, 0, 0 ); //率失真函数
}
else if( i_partition == D_16x8 )
{
h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =
h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;
x264_macroblock_cache_ref( h, 0, 0, 4, 2, 0, analysis.l0.me16x8[0].i_ref );
x264_macroblock_cache_ref( h, 0, 2, 4, 2, 0, analysis.l0.me16x8[1].i_ref );
x264_me_refine_qpel_rd( h, &analysis.l0.me16x8[0], analysis.i_lambda2, 0, 0 );
x264_me_refine_qpel_rd( h, &analysis.l0.me16x8[1], analysis.i_lambda2, 8, 0 );
}
else if( i_partition == D_8x16 )
{
h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =
h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;
x264_macroblock_cache_ref( h, 0, 0, 2, 4, 0, analysis.l0.me8x16[0].i_ref );
x264_macroblock_cache_ref( h, 2, 0, 2, 4, 0, analysis.l0.me8x16[1].i_ref );
x264_me_refine_qpel_rd( h, &analysis.l0.me8x16[0], analysis.i_lambda2, 0, 0 );
x264_me_refine_qpel_rd( h, &analysis.l0.me8x16[1], analysis.i_lambda2, 4, 0 );
}
else if( i_partition == D_8x8 )
{
int i8x8;
x264_analyse_update_cache( h, &analysis );
for( i8x8 = 0; i8x8 < 4; i8x8++ )
{
if( h->mb.i_sub_partition[i8x8] == D_L0_8x8 )
{
x264_me_refine_qpel_rd( h, &analysis.l0.me8x8[i8x8], analysis.i_lambda2, i8x8*4, 0 );
}
else if( h->mb.i_sub_partition[i8x8] == D_L0_8x4 )
{
x264_me_refine_qpel_rd( h, &analysis.l0.me8x4[i8x8[0], analysis.i_lambda2, i8x8*4+0, 0 ;
x264_me_refine_qpel_rd( h, &analysis.l0.me8x4[i8x8[1], analysis.i_lambda2, i8x8*4+2, 0 ;
}
else if( h->mb.i_sub_partition[i8x8] == D_L0_4x8 )
{
x264_me_refine_qpel_rd( h, &analysis.l0.me4x8[i8x[0], analysis.i_lambda2, i8x8*4+0, 0 );
x264_me_refine_qpel_rd( h, &analysis.l0.me4x8[i8x[1], analysis.i_lambda2, i8x8*4+1, 0 );
}
else if( h->mb.i_sub_partition[i8x8] == D_L0_4x4 )
{
x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x[0], analysis.i_lambda2, i8x8*4+0, 0 );
x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x[1], analysis.i_lambda2, i8x8*4+1, 0 );
x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x[2], analysis.i_lambda2, i8x8*4+2, 0 );
x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x[3], analysis.i_lambda2, i8x8*4+3, 0 );
}
}
}
}
}
}
//如果宏块的临近已编码宏块均不采用帧内模式,并且若宏块所在的slice为p的话,
//参考帧相应位置的宏块也不采用帧内模式的话,则该宏块采用帧内预测的可能性就很小。
//那么在该宏块用帧间模式得到的最小的SAD后,只要计算帧内16*16预测模式的SAD,
//将二者相比,当比值超过门限值时,即用帧间预测模式,而不用计算帧内4*4的模式了。
else if( h->sh.i_type == SLICE_TYPE_P )// P帧预测模式的选择
{
//当是P帧时,首先判断是否是skip模式,只有在左,上,左上,右上有一个是skip模式的时候,
//这时mb才 可能是skip模式:b_skip = x264_macroblock_probe_pskip( h );
//当不采用p_skip模式时,则调用x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a )
//进行帧间16*16块的分析:计算p16x16模式的运动适量及cost(其中还要考虑到参考帧部分,运动估计)。
//然后在允许16*16块分割时,进一步分析8*8,4*4,16*8,8*16块的运动矢量,并比较cost的大小。
//获得最佳的运动估计模式。得到子宏块的分割方式存储在 i_partion。随后根据i_partion进行像素细化。
int b_skip = 0;
int i_intra_cost, i_intra_type;
h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 0 );//空函数?
/* Fast P_SKIP detection */
analysis.b_try_pskip = 0;
if( h->param.analyse.b_fast_pskip )
{
if( h->param.i_threads > 1 && h->mb.cache.pskip_mv[1] > h->mb.mv_max_spel[1] )
// FIXME don't need to check this if the reference frame is done
{}
else if( h->param.analyse.i_subpel_refine >= 3 )
analysis.b_try_pskip = 1;
else if( h->mb.i_mb_type_left == P_SKIP ||
h->mb.i_mb_type_top == P_SKIP ||
h->mb.i_mb_type_topleft == P_SKIP ||
h->mb.i_mb_type_topright == P_SKIP )
b_skip = x264_macroblock_probe_pskip( h );//判断是否可以进行P_skip编码
}
h->mc.prefetch_ref( h->mb.pic.p_fref[0][0][h->mb.i_mb_x&3], h->mb.pic.i_stride[0], 1 );
if( b_skip )
{
h->mb.i_type = P_SKIP;
h->mb.i_partition = D_16x16;
assert( h->mb.cache.pskip_mv[1] <= h->mb.mv_max_spel[1] || h->param.i_threads == 1 );
}
else
{
const unsigned int flags = h->param.analyse.inter;
int i_type;
int i_partition;
int i_thresh16x8;
int i_satd_inter, i_satd_intra;
x264_mb_analyse_load_costs( h, &analysis );// 载入当前MB和临近MB块的信息
x264_mb_analyse_inter_p16x16( h, &analysis );//P16x16 宏块预测模式的分析;下面是这个函数的解析
static void x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a )
{
x264_me_t m;
int i_ref, i_mvc;
DECLARE_ALIGNED_4( int16_t mvc[8][2] );
int i_halfpel_thresh = INT_MAX;
int *p_halfpel_thresh = h->mb.pic.i_fref[0]>1 ? &i_halfpel_thresh : NULL;
/* 16x16 Search on all ref frame */
m.i_pixel = PIXEL_16x16;
m.p_cost_mv = a->p_cost_mv; //初始化MV的cost
LOAD_FENC( &m, h->mb.pic.p_fenc, 0, 0 );//加载将要编码的宏块
a->l0.me16x16.cost = INT_MAX;//初始化ME的cost
for( i_ref = 0; i_ref < h->mb.pic.i_fref[0]; i_ref++ )//遍历所有的参考帧寻找最佳的参考块
{
const int i_ref_cost = REF_COST( 0, i_ref );//参考帧的cost
i_halfpel_thresh -= i_ref_cost;
m.i_ref_cost = i_ref_cost;
m.i_ref = i_ref;
/* search with ref */
LOAD_HPELS( &m, h->mb.pic.p_fref[0][i_ref], 0, i_ref, 0, 0 );//加载参考帧
x264_mb_predict_mv_16x16( h, 0, i_ref, m.mvp );//确定搜索的初始位置(中值法)
x264_mb_predict_mv_ref16x16( h, 0, i_ref, mvc, &i_mvc );//寻找其它候选运动矢量。这些候选者包括:空间相邻的左、左上、上、右上块的MV;第0个参考帧中的当前块、右边块、下边快运动矢量乘以时间差权重。(时空域和空间域)
x264_me_search_ref( h, &m, mvc, i_mvc, p_halfpel_thresh );//搜索该参考帧中最佳的匹配块(亚像素搜索在里面)
/* early termination
* SSD threshold would probably be better than SATD */
if( i_ref == 0&& a->b_try_pskip && m.cost-m.cost_mv < 300*a->i_lambda
&& abs(m.mv[0]-h->mb.cache.pskip_mv[0])+ abs(m.mv[1]-h->mb.cache.pskip_mv[1]) <= 1
&& x264_macroblock_probe_pskip( h ) )
{
h->mb.i_type = P_SKIP;
x264_analyse_update_cache( h, a );
assert( h->mb.cache.pskip_mv[1] <= h->mb.mv_max_spel[1] || h->param.i_threads == 1 );
return;
}
m.cost += i_ref_cost;
i_halfpel_thresh += i_ref_cost;
if( m.cost < a->l0.me16x16.cost )
h->mc.memcpy_aligned( &a->l0.me16x16, &m, sizeof(x264_me_t) );
/* save mv for predicting neighbors */
*(uint32_t*)a->l0.mvc[i_ref][0] = *(uint32_t*)h->mb.mvr[0][i_ref][h->mb.i_mb_xy] = *(uint32_t*)m.mv;
}
x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, a->l0.me16x16.i_ref );//这里存储的P_L0的ME
assert( a->l0.me16x16.mv[1] <= h->mb.mv_max_spel[1] || h->param.i_threads == 1 );
h->mb.i_type = P_L0;
if( a->i_mbrd )
{
x264_mb_cache_fenc_satd( h );//
if( a->l0.me16x16.i_ref == 0 && *(uint32_t*)a->l0.me16x16.mv == *(uint32_t*)h->mb.cache.pskip_mv )
{
h->mb.i_partition = D_16x16;
x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, 0, a->l0.me16x16.mv );//这里存储的P_L0的MV
a->l0.i_rd16x16 = x264_rd_cost_mb( h, a->i_lambda2 );//保留cost
}
}
}
if( h->mb.i_type == P_SKIP )
return;
if( flags & X264_ANALYSE_PSUB16x16 )//P8x8预测模式的选择
{
if( h->param.analyse.b_mixed_references )
x264_mb_analyse_inter_p8x8_mixed_ref( h, &analysis );
else
x264_mb_analyse_inter_p8x8( h, &analysis );
}
/* Select best inter mode */
i_type = P_L0;
i_partition = D_16x16;
i_cost = analysis.l0.me16x16.cost;
if( ( flags & X264_ANALYSE_PSUB16x16 ) &&
analysis.l0.i_cost8x8 < analysis.l0.me16x16.cost )
{
i_type = P_8x8;
i_partition = D_8x8;
i_cost = analysis.l0.i_cost8x8;
/* Do sub 8x8 */
if( flags & X264_ANALYSE_PSUB8x8 )//4x4,8x4,4x8,帧间预测模式的选择
{
for( i = 0; i < 4; i++ )
{
x264_mb_analyse_inter_p4x4( h, &analysis, i );
if( analysis.l0.i_cost4x4[i] < analysis.l0.me8x8[i].cost )
{
int i_cost8x8 = analysis.l0.i_cost4x4[i];
h->mb.i_sub_partition[i] = D_L0_4x4;
x264_mb_analyse_inter_p8x4( h, &analysis, i );
COPY2_IF_LT( i_cost8x8, analysis.l0.i_cost8x4[i],
h->mb.i_sub_partition[i], D_L0_8x4 );//比较8*4和 i_cost8*8哪个代价低
x264_mb_analyse_inter_p4x8( h, &analysis, i );
COPY2_IF_LT( i_cost8x8, analysis.l0.i_cost4x8[i],
h->mb.i_sub_partition[i], D_L0_4x8 );//比较4*8和 i_cost8*8哪个代价低
i_cost += i_cost8x8 - analysis.l0.me8x8[i].cost;
}
x264_mb_cache_mv_p8x8( h, &analysis, i );//更新8*8的MV信息
}
analysis.l0.i_cost8x8 = i_cost;
}
}
/* Now do 16x8/8x16 */
i_thresh16x8 = analysis.l0.me8x8[1].cost_mv + analysis.l0.me8x8[2].cost_mv;
if( ( flags & X264_ANALYSE_PSUB16x16 ) &&
analysis.l0.i_cost8x8 < analysis.l0.me16x16.cost + i_thresh16x8 )
{
x264_mb_analyse_inter_p16x8( h, &analysis );
COPY3_IF_LT( i_cost, analysis.l0.i_cost16x8, i_type, P_L0, i_partition, D_16x8 );//比较16*8和16*16哪个代价低
x264_mb_analyse_inter_p8x16( h, &analysis );
COPY3_IF_LT( i_cost, analysis.l0.i_cost8x16, i_type, P_L0, i_partition, D_8x16 );//比较8*16和16*16哪个代价低
}
h->mb.i_partition = i_partition;
/* refine qpel */
//FIXME mb_type costs?
if( analysis.i_mbrd )//重新划分模式
{
/* refine later *///intra省略
}
else if( i_partition == D_16x16 )
{
x264_me_refine_qpel( h, &analysis.l0.me16x16 );
i_cost = analysis.l0.me16x16.cost;
}
else if( i_partition == D_16x8 )
{
x264_me_refine_qpel( h, &analysis.l0.me16x8[0] );
x264_me_refine_qpel( h, &analysis.l0.me16x8[1] );//半像素和1/4像素搜索
i_cost = analysis.l0.me16x8[0].cost + analysis.l0.me16x8[1].cost;//保存代价函数值
}
else if( i_partition == D_8x16 )
{
x264_me_refine_qpel( h, &analysis.l0.me8x16[0] );
x264_me_refine_qpel( h, &analysis.l0.me8x16[1] );
i_cost = analysis.l0.me8x16[0].cost + analysis.l0.me8x16[1].cost;
}
else if( i_partition == D_8x8 )
{
int i8x8;
i_cost = 0;
for( i8x8 = 0; i8x8 < 4; i8x8++ )
{
switch( h->mb.i_sub_partition[i8x8] )
{
case D_L0_8x8:
x264_me_refine_qpel( h, &analysis.l0.me8x8[i8x8] );
i_cost += analysis.l0.me8x8[i8x8].cost;
break;
case D_L0_8x4:
x264_me_refine_qpel( h, &analysis.l0.me8x4[i8x8][0] );
x264_me_refine_qpel( h, &analysis.l0.me8x4[i8x8][1] );
i_cost += analysis.l0.me8x4[i8x8][0].cost +
analysis.l0.me8x4[i8x8][1].cost;
break;
case D_L0_4x8:
x264_me_refine_qpel( h, &analysis.l0.me4x8[i8x8][0] );
x264_me_refine_qpel( h, &analysis.l0.me4x8[i8x8][1] );
i_cost += analysis.l0.me4x8[i8x8][0].cost +
analysis.l0.me4x8[i8x8][1].cost;
break;
case D_L0_4x4:
x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][0] );
x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][1] );
x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][2] );
x264_me_refine_qpel( h, &analysis.l0.me4x4[i8x8][3] );
i_cost += analysis.l0.me4x4[i8x8][0].cost +
analysis.l0.me4x4[i8x8][1].cost +
analysis.l0.me4x4[i8x8][2].cost +
analysis.l0.me4x4[i8x8][3].cost;
break;
default:
x264_log( h, X264_LOG_ERROR, "internal error (!8x8 && !4x4)\n" );
break;
}
}
}
if( h->mb.b_chroma_me )//对色度进行解析
{
x264_mb_analyse_intra_chroma( h, &analysis );
x264_mb_analyse_intra( h, &analysis, i_cost - analysis.i_satd_i8x8chroma );
analysis.i_satd_i16x16 += analysis.i_satd_i8x8chroma;
analysis.i_satd_i8x8 += analysis.i_satd_i8x8chroma;
analysis.i_satd_i4x4 += analysis.i_satd_i8x8chroma;
}
else
x264_mb_analyse_intra( h, &analysis, i_cost ); //intra分析
i_satd_inter = i_cost;
i_satd_intra = X264_MIN3( analysis.i_satd_i16x16,
analysis.i_satd_i8x8,
analysis.i_satd_i4x4 );//比较I16*16,I8*8,i4*4哪个模式代价低,选择最小的
//重新划分模式
if( analysis.i_mbrd )
{
x264_mb_analyse_p_rd( h, &analysis, X264_MIN(i_satd_inter, i_satd_intra) );
i_type = P_L0;
i_partition = D_16x16;
i_cost = analysis.l0.me16x16.cost;
COPY2_IF_LT( i_cost, analysis.l0.i_cost16x8, i_partition, D_16x8 );
COPY2_IF_LT( i_cost, analysis.l0.i_cost8x16, i_partition, D_8x16 );
COPY3_IF_LT( i_cost, analysis.l0.i_cost8x8, i_partition, D_8x8, i_type, P_8x8 );
h->mb.i_type = i_type;
h->mb.i_partition = i_partition;
if( i_cost < COST_MAX )
x264_mb_analyse_transform_rd( h, &analysis, &i_satd_inter, &i_cost );
x264_intra_rd( h, &analysis, i_satd_inter * 5/4 );
}
i_intra_type = I_16x16;
i_intra_cost = analysis.i_satd_i16x16;
COPY2_IF_LT( i_intra_cost, analysis.i_satd_i8x8, i_intra_type, I_8x8 );
COPY2_IF_LT( i_intra_cost, analysis.i_satd_i4x4, i_intra_type, I_4x4 );
COPY2_IF_LT( i_intra_cost, analysis.i_satd_pcm, i_intra_type, I_PCM );
COPY2_IF_LT( i_cost, i_intra_cost, i_type, i_intra_type );//比较帧内帧间的cost
if( i_intra_cost == COST_MAX )
i_intra_cost = i_cost * i_satd_intra / i_satd_inter + 1;
h->mb.i_type = i_type;
h->stat.frame.i_intra_cost += i_intra_cost;
h->stat.frame.i_inter_cost += i_cost;
h->stat.frame.i_mbs_analysed++;
//下面这段在实际中可以省略,因为编码时用不到
if( analysis.i_mbrd >= 2 && h->mb.i_type != I_PCM ){
if( IS_INTRA( h->mb.i_type ) )
{
x264_intra_rd_refine( h, &analysis );
}
else if( i_partition == D_16x16 )
{
x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, analysis.l0.me16x16.i_ref );
x264_me_refine_qpel_rd( h, &analysis.l0.me16x16, analysis.i_lambda2, 0, 0 ); //率失真函数
}
else if( i_partition == D_16x8 )
{
h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =
h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;
x264_macroblock_cache_ref( h, 0, 0, 4, 2, 0, analysis.l0.me16x8[0].i_ref );
x264_macroblock_cache_ref( h, 0, 2, 4, 2, 0, analysis.l0.me16x8[1].i_ref );
x264_me_refine_qpel_rd( h, &analysis.l0.me16x8[0], analysis.i_lambda2, 0, 0 );
x264_me_refine_qpel_rd( h, &analysis.l0.me16x8[1], analysis.i_lambda2, 8, 0 );
}
else if( i_partition == D_8x16 )
{
h->mb.i_sub_partition[0] = h->mb.i_sub_partition[1] =
h->mb.i_sub_partition[2] = h->mb.i_sub_partition[3] = D_L0_8x8;
x264_macroblock_cache_ref( h, 0, 0, 2, 4, 0, analysis.l0.me8x16[0].i_ref );
x264_macroblock_cache_ref( h, 2, 0, 2, 4, 0, analysis.l0.me8x16[1].i_ref );
x264_me_refine_qpel_rd( h, &analysis.l0.me8x16[0], analysis.i_lambda2, 0, 0 );
x264_me_refine_qpel_rd( h, &analysis.l0.me8x16[1], analysis.i_lambda2, 4, 0 );
}
else if( i_partition == D_8x8 )
{
int i8x8;
x264_analyse_update_cache( h, &analysis );
for( i8x8 = 0; i8x8 < 4; i8x8++ )
{
if( h->mb.i_sub_partition[i8x8] == D_L0_8x8 )
{
x264_me_refine_qpel_rd( h, &analysis.l0.me8x8[i8x8], analysis.i_lambda2, i8x8*4, 0 );
}
else if( h->mb.i_sub_partition[i8x8] == D_L0_8x4 )
{
x264_me_refine_qpel_rd( h, &analysis.l0.me8x4[i8x8[0], analysis.i_lambda2, i8x8*4+0, 0 ;
x264_me_refine_qpel_rd( h, &analysis.l0.me8x4[i8x8[1], analysis.i_lambda2, i8x8*4+2, 0 ;
}
else if( h->mb.i_sub_partition[i8x8] == D_L0_4x8 )
{
x264_me_refine_qpel_rd( h, &analysis.l0.me4x8[i8x[0], analysis.i_lambda2, i8x8*4+0, 0 );
x264_me_refine_qpel_rd( h, &analysis.l0.me4x8[i8x[1], analysis.i_lambda2, i8x8*4+1, 0 );
}
else if( h->mb.i_sub_partition[i8x8] == D_L0_4x4 )
{
x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x[0], analysis.i_lambda2, i8x8*4+0, 0 );
x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x[1], analysis.i_lambda2, i8x8*4+1, 0 );
x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x[2], analysis.i_lambda2, i8x8*4+2, 0 );
x264_me_refine_qpel_rd( h, &analysis.l0.me4x4[i8x[3], analysis.i_lambda2, i8x8*4+3, 0 );
}
}
}
}
}
}