Index: common/common.h =================================================================== --- common/common.h (revision 661) +++ common/common.h (working copy) @@ -583,6 +583,12 @@ /* Adaptive direct mv pred */ int i_direct_score[2]; } frame; + + /* Previous frame stats */ + struct + { + int i_intra_cost; + } frame_prev; /* Cumulated stats */ Index: encoder/slicetype.c =================================================================== --- encoder/slicetype.c (revision 661) +++ encoder/slicetype.c (working copy) @@ -247,6 +247,11 @@ #undef TRY_BIDIR #undef SAVE_MVS +/* 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 */ 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 ) @@ -323,8 +328,48 @@ return i_score; } -static int scenecut( x264_t *h, x264_frame_t *frame, int pdist ) +/* spatial detection for scene cut */ +static int scenecut_spatial( x264_t *h, x264_frame_t *frame, int prev_icost , int new_icost ) { + int res = 0; + int idiff = abs(prev_icost - new_icost); + float f_bias; + int i_gop_size = frame->i_frame - h->frames.i_last_idr; + float f_thresh_max = h->param.i_scenecut_threshold / 100.0; + /* magic numbers pulled out of thin air */ + float f_thresh_min = f_thresh_max * h->param.i_keyint_min + / ( h->param.i_keyint_max * 4 ); + + if( h->param.i_keyint_min == h->param.i_keyint_max ) + f_thresh_min= f_thresh_max; + if( i_gop_size < h->param.i_keyint_min / 4 ) + f_bias = f_thresh_min / 4; + else if( i_gop_size <= h->param.i_keyint_min ) + f_bias = f_thresh_min * i_gop_size / h->param.i_keyint_min; + else + { + f_bias = f_thresh_min + + ( f_thresh_max - f_thresh_min ) + * ( i_gop_size - h->param.i_keyint_min ) + / ( h->param.i_keyint_max - h->param.i_keyint_min ); + } + + if (frame->i_frame < 2) + return res; + if( !(h->param.b_pre_scenecut) ) + return res; + + res = idiff >= prev_icost*.4*(1.0 - f_bias); + + + return res; +} + + + +/* temporal detection for scene cut */ +static int scenecut_temporal( x264_t *h, x264_frame_t *frame, int pdist ) +{ int icost = frame->i_cost_est[0][0]; int pcost = frame->i_cost_est[pdist][0]; float f_bias; @@ -372,6 +417,9 @@ int i_mb_count = (h->sps->i_mb_width - 2) * (h->sps->i_mb_height - 2); int cost1p0, cost2p0, cost1b1, cost2p1; int idr_frame_type; + int no_b_frames = 0; + int spacial_cut = 0; + int i_intra_cost_prev = h->stat.frame_prev.i_intra_cost; assert( h->frames.b_have_lowres ); @@ -390,29 +438,48 @@ if( num_frames == 1 ) { -no_b_frames: + no_b_frames = 1; + } + else + { + + 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; + + 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 ); +// fprintf( stderr, "PP: %d + %d <=> BP: %d + %d \n", +// cost1p0, cost2p0, cost1b1, cost2p1 ); + if( cost1p0 + cost2p0 < cost1b1 + cost2p1 ) + no_b_frames = 1; + } + } + + //save intra cost + x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 ); + h->stat.frame_prev.i_intra_cost = frames[1]->i_cost_est[0][0]; + + if ( scenecut_spatial(h, frames[1], i_intra_cost_prev, frames[1]->i_cost_est[0][0]) ) + { + no_b_frames = 1; + spacial_cut = 1; + } + + 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( h, frames[1], 1 ) ) + if( scenecut_temporal( h, frames[1], 1 ) || spacial_cut) frames[1]->i_type = idr_frame_type; } return; } - 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; - - 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 ); -// fprintf( stderr, "PP: %d + %d <=> BP: %d + %d \n", -// cost1p0, cost2p0, cost1b1, cost2p1 ); - if( cost1p0 + cost2p0 < cost1b1 + cost2p1 ) - goto no_b_frames; - // arbitrary and untuned #define INTER_THRESH 300 #define P_SENS_BIAS (50 - h->param.i_bframe_bias)