diff --git a/encoder/slicetype.c b/encoder/slicetype.c old mode 100644 new mode 100755 index a8c028c..b299810 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -250,6 +250,11 @@ lowres_intra_mb: (h->sps->i_mb_width - 2) * (h->sps->i_mb_height - 2) :\ h->sps->i_mb_width * h->sps->i_mb_height) +/* Evaluate cost of a candidate frame (b), using p0 as L0 + * and p1 as L1 references. + * 2 references different from b => B frame + * 1 references different from b => P frame + * 0 reference different from b => I frame */ static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1, int b, int b_intra_penalty ) @@ -470,6 +475,31 @@ static int scenecut( x264_t *h, x264_frame_t *frame, int pdist ) return res; } +/* scenecut detection, not triggered in case of single-frame flashes */ +static int scenecut_ext( x264_t *h, x264_frame_t *frames[], int pdist) +{ + int res; + + res = scenecut( h, frames[pdist], pdist ); + + if ( res ) + { + /*was previous frame a flash? */ + if (frames[pdist]->i_cost_est[2][0] != -1) + res &= scenecut( h, frames[pdist], 2 ); + } + + if ( res ) + { + /* is current frame a flash? */ + if (frames[pdist]->i_cost_est[pdist+1][pdist+1] != -1) + res &= scenecut( h, frames[pdist+1], pdist+1 ); + } + + return res; +} + + static void x264_slicetype_analyse( x264_t *h ) { x264_mb_analysis_t a; @@ -480,6 +510,7 @@ static void x264_slicetype_analyse( x264_t *h ) int i_mb_count = NUM_MBS; int cost1p0, cost2p0, cost1b1, cost2p1; int idr_frame_type; + int no_b_frames = 0; assert( h->frames.b_have_lowres ); @@ -498,77 +529,89 @@ static void x264_slicetype_analyse( x264_t *h ) if( num_frames == 1 ) { -no_b_frames: - frames[1]->i_type = X264_TYPE_P; - if( h->param.b_pre_scenecut ) - { - x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 ); - if( scenecut( h, frames[1], 1 ) ) - frames[1]->i_type = idr_frame_type; - } - return; + no_b_frames = 1; } - - if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS ) + else { - int num_bframes; - int max_bframes = X264_MIN(num_frames-1, h->param.i_bframe); - if( h->param.b_pre_scenecut ) + if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS ) { - x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 ); - if( scenecut( h, frames[1], 1 ) ) + int num_bframes; + int max_bframes = X264_MIN(num_frames-1, h->param.i_bframe); + if( h->param.b_pre_scenecut ) { - frames[1]->i_type = idr_frame_type; - return; + x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 ); + if( scenecut_ext( h, frames, 1) ) + { + frames[1]->i_type = idr_frame_type; + return; + } } - } - num_bframes = x264_slicetype_path_search( h, &a, frames, num_frames, max_bframes, num_frames-max_bframes ); - assert(num_bframes < num_frames); + num_bframes = x264_slicetype_path_search( h, &a, frames, num_frames, max_bframes, num_frames-max_bframes ); + assert(num_bframes < num_frames); - for( j = 1; j < num_bframes+1; j++ ) - { - if( h->param.b_pre_scenecut && scenecut( h, frames[j+1], j+1 ) ) + for( j = 1; j < num_bframes+1; j++ ) { - frames[j]->i_type = X264_TYPE_P; - frames[j+1]->i_type = idr_frame_type; - return; + if( h->param.b_pre_scenecut && scenecut_ext( h, frames, j+1) ) + { + frames[j]->i_type = X264_TYPE_P; + frames[j+1]->i_type = idr_frame_type; + return; + } + frames[j]->i_type = X264_TYPE_B; } - frames[j]->i_type = X264_TYPE_B; + frames[num_bframes+1]->i_type = X264_TYPE_P; } - frames[num_bframes+1]->i_type = X264_TYPE_P; - } - else - { - cost2p1 = x264_slicetype_frame_cost( h, &a, frames, 0, 2, 2, 1 ); - if( frames[2]->i_intra_mbs[2] > i_mb_count / 2 ) - goto no_b_frames; + else + { /* X264_B_ADAPT_FAST || X264_B_ADAPT_NONE */ + cost2p1 = x264_slicetype_frame_cost( h, &a, frames, 0, 2, 2, 1 ); + if( frames[2]->i_intra_mbs[2] > i_mb_count / 2 ) + no_b_frames = 1; - cost1b1 = x264_slicetype_frame_cost( h, &a, frames, 0, 2, 1, 0 ); - cost1p0 = x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 ); - cost2p0 = x264_slicetype_frame_cost( h, &a, frames, 1, 2, 2, 0 ); + if (!no_b_frames) + { + cost1b1 = x264_slicetype_frame_cost( h, &a, frames, 0, 2, 1, 0 ); + cost1p0 = x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 ); + cost2p0 = x264_slicetype_frame_cost( h, &a, frames, 1, 2, 2, 0 ); - if( cost1p0 + cost2p0 < cost1b1 + cost2p1 ) - goto no_b_frames; + if( cost1p0 + cost2p0 < cost1b1 + cost2p1 ) + no_b_frames = 1; + } - // arbitrary and untuned - #define INTER_THRESH 300 - #define P_SENS_BIAS (50 - h->param.i_bframe_bias) - frames[1]->i_type = X264_TYPE_B; + if (!no_b_frames) + { + // arbitrary and untuned + #define INTER_THRESH 300 + #define P_SENS_BIAS (50 - h->param.i_bframe_bias) + frames[1]->i_type = X264_TYPE_B; - for( j = 2; j <= X264_MIN( h->param.i_bframe, num_frames-1 ); j++ ) - { - int pthresh = X264_MAX(INTER_THRESH - P_SENS_BIAS * (j-1), INTER_THRESH/10); - int pcost = x264_slicetype_frame_cost( h, &a, frames, 0, j+1, j+1, 1 ); + for( j = 2; j <= X264_MIN( h->param.i_bframe, num_frames-1 ); j++ ) + { + int pthresh = X264_MAX(INTER_THRESH - P_SENS_BIAS * (j-1), INTER_THRESH/10); + int pcost = x264_slicetype_frame_cost( h, &a, frames, 0, j+1, j+1, 1 ); - if( pcost > pthresh*i_mb_count || frames[j+1]->i_intra_mbs[j+1] > i_mb_count/3 ) - { - frames[j]->i_type = X264_TYPE_P; - break; + if( pcost > pthresh*i_mb_count || frames[j+1]->i_intra_mbs[j+1] > i_mb_count/3 ) + { + frames[j]->i_type = X264_TYPE_P; + break; + } + else + frames[j]->i_type = X264_TYPE_B; + } } - else - frames[j]->i_type = X264_TYPE_B; } } + + if(no_b_frames) + { + frames[1]->i_type = X264_TYPE_P; + if( h->param.b_pre_scenecut ) + { + x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 ); + if( scenecut_ext( h, frames, 1) ) + frames[1]->i_type = idr_frame_type; + } + return; + } } void x264_slicetype_decide( x264_t *h )