void x264_slicetype_analyse( x264_t *h, int intra_minigop )
{
x264_mb_analysis_t a;
x264_frame_t *frames[X264_LOOKAHEAD_MAX+3] = { NULL, };
int num_frames, orig_num_frames, keyint_limit, framecnt;
int i_mb_count = NUM_MBS;
int cost1p0, cost2p0, cost1b1, cost2p1;
// X264_LOOKAHEAD_MAX = 250
// 确定最大的搜索长度
// 在我的调试当中, h->lookahead->next.i_size = 4
int i_max_search = X264_MIN( h->lookahead->next.i_size, X264_LOOKAHEAD_MAX );
int vbv_lookahead = h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead;
/* For determinism we should limit the search to the number of frames lookahead has for sure
* in h->lookahead->next.list buffer, except at the end of stream.
* For normal calls with (intra_minigop == 0) that is h->lookahead->i_slicetype_length + 1 frames.
* And for I-frame calls (intra_minigop != 0) we already removed intra_minigop frames from there. */
// 在我的调试当中,h->param.b_deterministic = 1,
// h->lookahead->i_slicetype_length = 3
// intra_minigop = 0
if( h->param.b_deterministic )
i_max_search = X264_MIN( i_max_search, h->lookahead->i_slicetype_length + 1 - intra_minigop );
int keyframe = !!intra_minigop;
assert( h->frames.b_have_lowres );
if( !h->lookahead->last_nonb )
return;
// 让frames[0]指向上一次的非B帧
frames[0] = h->lookahead->last_nonb;
// 让frames[] 依次指向 lookahead->next链表中的帧
for( framecnt = 0; framecnt < i_max_search && h->lookahead->next.list[framecnt]->i_type == X264_TYPE_AUTO; framecnt++ )
frames[framecnt+1] = h->lookahead->next.list[framecnt];
// 见 x264_lowres_context_init
x264_lowres_context_init( h, &a );
if( !framecnt )
{
if( h->param.rc.b_mb_tree )
x264_macroblock_tree( h, &a, frames, 0, keyframe );
return;
}
keyint_limit = h->param.i_keyint_max - frames[0]->i_frame + h->lookahead->i_last_keyframe - 1;
orig_num_frames = num_frames = h->param.b_intra_refresh ? framecnt : X264_MIN( framecnt, keyint_limit );
/* This is important psy-wise: if we have a non-scenecut keyframe,
* there will be significant visual artifacts if the frames just before
* go down in quality due to being referenced less, despite it being
* more RD-optimal. */
if( (h->param.analyse.b_psy && h->param.rc.b_mb_tree) || vbv_lookahead )
num_frames = framecnt;
else if( h->param.b_open_gop && num_frames < framecnt )
num_frames++;
else if( num_frames == 0 )
{
frames[1]->i_type = X264_TYPE_I;
return;
}
int num_bframes = 0;
int num_analysed_frames = num_frames;
int reset_start;
if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames, i_max_search ) )
{
frames[1]->i_type = X264_TYPE_I;
return;
}
#if HAVE_OPENCL
x264_opencl_slicetype_prep( h, frames, num_frames, a.i_lambda );
#endif
if( h->param.i_bframe )
{
if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS )
{
if( num_frames > 1 )
{
char best_paths[X264_BFRAME_MAX+1][X264_LOOKAHEAD_MAX+1] = {"","P"};
int best_path_index = num_frames % (X264_BFRAME_MAX+1);
/* Perform the frametype analysis. */
for( int j = 2; j <= num_frames; j++ )
x264_slicetype_path( h, &a, frames, j, best_paths );
num_bframes = strspn( best_paths[best_path_index], "B" );
/* Load the results of the analysis into the frame types. */
for( int j = 1; j < num_frames; j++ )
frames[j]->i_type = best_paths[best_path_index][j-1] == 'B' ? X264_TYPE_B : X264_TYPE_P;
}
frames[num_frames]->i_type = X264_TYPE_P;
}
else if( h->param.i_bframe_adaptive == X264_B_ADAPT_FAST )
{
for( int i = 0; i <= num_frames-2; )
{
// i + 2 作为 P 帧编码的代价
cost2p1 = x264_slicetype_frame_cost( h, &a, frames, i+0, i+2, i+2, 1 );
if( frames[i+2]->i_intra_mbs[2] > i_mb_count / 2 )
{
frames[i+1]->i_type = X264_TYPE_P;
frames[i+2]->i_type = X264_TYPE_P;
i += 2;
continue;
}
#if HAVE_OPENCL
if( h->param.b_opencl )
{
int b_work_done = 0;
b_work_done |= x264_opencl_precalculate_frame_cost(h, frames, a.i_lambda, i+0, i+2, i+1 );
b_work_done |= x264_opencl_precalculate_frame_cost(h, frames, a.i_lambda, i+0, i+1, i+1 );
b_work_done |= x264_opencl_precalculate_frame_cost(h, frames, a.i_lambda, i+1, i+2, i+2 );
if( b_work_done )
x264_opencl_flush( h );
}
#endif
// i + 1 作为B帧编码的代价
cost1b1 = x264_slicetype_frame_cost( h, &a, frames, i+0, i+2, i+1, 0 );
// i + 1 作为P帧编码的代价
cost1p0 = x264_slicetype_frame_cost( h, &a, frames, i+0, i+1, i+1, 0 );
// i + 2 作为P帧编码的代价
cost2p0 = x264_slicetype_frame_cost( h, &a, frames, i+1, i+2, i+2, 0 );
if( cost1p0 + cost2p0 < cost1b1 + cost2p1 )
{ // 如果i+1作为P帧编码的代价 + i+2作为P帧编码的代价
// 小于 i+1作为B帧编码的代价 + i+2作为P帧编码的代价
// 那么i+1将作为P帧编码
frames[i+1]->i_type = X264_TYPE_P;
i += 1;
continue;
}
// arbitrary and untuned
#define INTER_THRESH 300
#define P_SENS_BIAS (50 - h->param.i_bframe_bias)
// i+1 将作为B帧编码
frames[i+1]->i_type = X264_TYPE_B;
int j;
for( j = i+2; j <= X264_MIN( i+h->param.i_bframe, num_frames-1 ); j++ )
{
int pthresh = X264_MAX(INTER_THRESH - P_SENS_BIAS * (j-i-1), INTER_THRESH/10);
// 预测j+1作为P帧编码代价
int pcost = x264_slicetype_frame_cost( h, &a, frames, i+0, j+1, j+1, 1 );
// 如果pcost 满足下述条件, 则确定了一个P帧,跳出循环
if( pcost > pthresh*i_mb_count || frames[j+1]->i_intra_mbs[j-i+1] > i_mb_count/3 )
break;
// 否则就是B帧
frames[j]->i_type = X264_TYPE_B;
}
// 将j帧确定为P帧
frames[j]->i_type = X264_TYPE_P;
// 改变循环变量i
i = j;
} // for( int i = 0; i <= num_frames-2; )
// 最后一帧确定为P帧
frames[num_frames]->i_type = X264_TYPE_P;
// 确定有多少个B帧
num_bframes = 0;
while( num_bframes < num_frames && frames[num_bframes+1]->i_type == X264_TYPE_B )
num_bframes++;
}
else
{ // neither h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS
// or h->param.i_bframe_adaptive ==X264_B_ADAPT_FAST
// 确定多少B帧
num_bframes = X264_MIN(num_frames-1, h->param.i_bframe);
// 每num_bframes + 1一个P帧, 其余皆为B帧
for( int j = 1; j < num_frames; j++ )
frames[j]->i_type = (j%(num_bframes+1)) ? X264_TYPE_B : X264_TYPE_P;
// 最后一帧为P帧
frames[num_frames]->i_type = X264_TYPE_P;
}
/* Check scenecut on the first minigop. */
// 如果B帧中, 有帧有场景切换, 则改变其为P帧
for( int j = 1; j < num_bframes+1; j++ )
if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, j, j+1, 0, orig_num_frames, i_max_search ) )
{
frames[j]->i_type = X264_TYPE_P;
num_analysed_frames = j;
break;
}
// 确定重设帧类型为 X264_TYPE_AUTO的帧索引
reset_start = keyframe ? 1 : X264_MIN( num_bframes+2, num_analysed_frames+1 );
}
else
{
// if( h->param.i_bframe ) 为 false
// 则所有的帧皆为P帧
for( int j = 1; j <= num_frames; j++ )
frames[j]->i_type = X264_TYPE_P;
// 确定重设帧类型为 X264_TYPE_AUTO的帧索引
reset_start = !keyframe + 1;
num_bframes = 0;
}
/* Perform the actual macroblock tree analysis.
* Don't go farther than the maximum keyframe interval; this helps in short GOPs. */
// 见 x264_macroblock_tree
if( h->param.rc.b_mb_tree )
x264_macroblock_tree( h, &a, frames, X264_MIN(num_frames, h->param.i_keyint_max), keyframe );
/* Enforce keyframe limit. */
if( !h->param.b_intra_refresh )
for( int i = keyint_limit+1; i <= num_frames; i += h->param.i_keyint_max )
{
// 迫使为I帧
frames[i]->i_type = X264_TYPE_I;
reset_start = X264_MIN( reset_start, i+1 );
if( h->param.b_open_gop && h->param.b_bluray_compat )
while( IS_X264_TYPE_B( frames[i-1]->i_type ) )
i--;
}
// 见 x264_vbv_lookahead
if( vbv_lookahead )
x264_vbv_lookahead( h, &a, frames, num_frames, keyframe );
/* Restore frametypes for all frames that haven't actually been decided yet. */
// for reset_start, restore frame type to X264_TYPE_AUTO
for( int j = reset_start; j <= num_frames; j++ )
frames[j]->i_type = X264_TYPE_AUTO;
#if HAVE_OPENCL
x264_opencl_slicetype_end( h );
#endif
}
static void x264_lowres_context_init( x264_t *h, x264_mb_analysis_t *a )
{
// X264_LOOKAHEAD_QP = 12
a->i_qp = X264_LOOKAHEAD_QP;
// a->i_lambda = 1
a->i_lambda = x264_lambda_tab[ a->i_qp ];
// 见 x264_mb_analyse_load_costs
x264_mb_analyse_load_costs( h, a );
// 如果需要进行子像素分析
if( h->param.analyse.i_subpel_refine > 1 )
{
// 初始化运动向量搜索方法
h->mb.i_me_method = X264_MIN( X264_ME_HEX, h->param.analyse.i_me_method );
h->mb.i_subpel_refine = 4;
}
else
{
h->mb.i_me_method = X264_ME_DIA;
h->mb.i_subpel_refine = 2;
}
h->mb.b_chroma_me = 0;
}
/* initialize an array of lambda*nbits for all possible mvs */
static void x264_mb_analyse_load_costs( x264_t *h, x264_mb_analysis_t *a )
{
// a->i_qp = 12
// 将a->p_cost_mv 指向 h->cost_mv[a->i_qp]
a->p_cost_mv = h->cost_mv[a->i_qp];
// static uint16_t x264_cost_ref[QP_MAX+1][3][33];
// 将a->p_cost_ref[0], a->p_cost_ref[1] 指向 x264_cost_ref[a->i_qp][]
a->p_cost_ref[0] = x264_cost_ref[a->i_qp][x264_clip3(h->sh.i_num_ref_idx_l0_active-1,0,2)];
a->p_cost_ref[1] = x264_cost_ref[a->i_qp][x264_clip3(h->sh.i_num_ref_idx_l1_active-1,0,2)];
}
int x264_analyse_init_costs( x264_t *h, float *logs, int qp )
{
int lambda = x264_lambda_tab[qp];
if( h->cost_mv[qp] )
return 0;
// 对每一个qp, 为h->cost_mv[qp]分配内存空间(4*4*2048 + 1) * sizeof(uint16_t)
// 将h->cost_mv[qp] 偏移到线性地址空间的中间
// 从中间向两端初始化mv的代价表。(有人说是mvd的代价表),
// 这个留待以后确定
/* factor of 4 from qpel, 2 from sign, and 2 because mv can be opposite from mvp */
CHECKED_MALLOC( h->cost_mv[qp], (4*4*2048 + 1) * sizeof(uint16_t) );
h->cost_mv[qp] += 2*4*2048;
for( int i = 0; i <= 2*4*2048; i++ )
{
h->cost_mv[qp][-i] =
h->cost_mv[qp][i] = X264_MIN( lambda * logs[i] + .5f, (1<<16)-1 );
}
x264_pthread_mutex_lock( &cost_ref_mutex );
// 初始化 x264_cost_ref 表 (参考帧代价表???)
for( int i = 0; i < 3; i++ )
for( int j = 0; j < 33; j++ )
x264_cost_ref[qp][i][j] = X264_MIN( i ? lambda * bs_size_te( i, j ) : 0, (1<<16)-1 );
x264_pthread_mutex_unlock( &cost_ref_mutex );
// 初始化整像素cost_mv表
if( h->param.analyse.i_me_method >= X264_ME_ESA && !h->cost_mv_fpel[qp][0] )
{
for( int j = 0; j < 4; j++ )
{
CHECKED_MALLOC( h->cost_mv_fpel[qp][j], (4*2048 + 1) * sizeof(uint16_t) );
h->cost_mv_fpel[qp][j] += 2*2048;
for( int i = -2*2048; i < 2*2048; i++ )
h->cost_mv_fpel[qp][j][i] = h->cost_mv[qp][i*4+j];
}
}
uint16_t *cost_i4x4_mode = (uint16_t*)ALIGN((intptr_t)x264_cost_i4x4_mode,64) + qp*32;
for( int i = 0; i < 17; i++ )
cost_i4x4_mode[i] = 3*lambda*(i!=8);
return 0;
fail:
return -1;
}