From: Fiona Glaser Date: Thu, 26 Feb 2009 22:29:50 +0000 (-0800) Subject: Remove non-pre scenecut X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=42f27d04b8fe0f9fb7e978edd38252d9d8a5af3d;p=libx264 Remove non-pre scenecut Add support for no-b-adapt + pre-scenecut (patch by BugMaster) Pre-scenecut was generally better than regular scenecut in terms of accuracy and regular scenecut didn't work in threaded mode anyways. Add no-scenecut option (scenecut=0 is now no scenecut; previously it was -1) Fix an incorrect bias towards P-frames near scenecuts with B-adapt 2. Simplify pre-scenecut code. --- diff --git a/common/common.c b/common/common.c index 18b9e1ac..d7d45d32 100644 --- a/common/common.c +++ b/common/common.c @@ -323,9 +323,14 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) p->i_keyint_max = p->i_keyint_min; } OPT("scenecut") - p->i_scenecut_threshold = atoi(value); - OPT("pre-scenecut") - p->b_pre_scenecut = atobool(value); + { + p->i_scenecut_threshold = atobool(value); + if( b_error || p->i_scenecut_threshold ) + { + b_error = 0; + p->i_scenecut_threshold = atoi(value); + } + } OPT("bframes") p->i_bframe = atoi(value); OPT("b-adapt") @@ -856,9 +861,8 @@ char *x264_param2string( x264_param_t *p, int b_res ) p->analyse.i_direct_mv_pred, p->analyse.b_weighted_bipred ); } - s += sprintf( s, " keyint=%d keyint_min=%d scenecut=%d%s", - p->i_keyint_max, p->i_keyint_min, p->i_scenecut_threshold, - p->b_pre_scenecut ? "(pre)" : "" ); + s += sprintf( s, " keyint=%d keyint_min=%d scenecut=%d", + p->i_keyint_max, p->i_keyint_min, p->i_scenecut_threshold ); s += sprintf( s, " rc=%s", p->rc.i_rc_method == X264_RC_ABR ? ( p->rc.b_stat_read ? "2pass" : p->rc.i_vbv_buffer_size ? "cbr" : "abr" ) diff --git a/common/common.h b/common/common.h index c8fb1d99..5d1123c3 100644 --- a/common/common.h +++ b/common/common.h @@ -576,11 +576,6 @@ struct x264_t int i_mb_count_8x8dct[2]; int i_mb_count_ref[2][32]; int i_mb_partition[17]; - /* Estimated (SATD) cost as Intra/Predicted frame */ - /* XXX: both omit the cost of MBs coded as P_SKIP */ - int i_intra_cost; - int i_inter_cost; - int i_mbs_analysed; /* Adaptive direct mv pred */ int i_direct_score[2]; /* Metrics */ diff --git a/encoder/analyse.c b/encoder/analyse.c index 62d51c5d..635771b0 100644 --- a/encoder/analyse.c +++ b/encoder/analyse.c @@ -2135,10 +2135,6 @@ static inline void x264_mb_analyse_transform_rd( x264_t *h, x264_mb_analysis_t * { if( *i_rd > 0 ) *i_satd = (int64_t)(*i_satd) * i_rd8 / *i_rd; - /* prevent a rare division by zero in estimated intra cost */ - if( *i_satd == 0 ) - *i_satd = 1; - *i_rd = i_rd8; } else @@ -2184,7 +2180,6 @@ void x264_macroblock_analyse( x264_t *h ) else if( h->sh.i_type == SLICE_TYPE_P ) { 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 ); @@ -2385,20 +2380,12 @@ void x264_macroblock_analyse( x264_t *h ) 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 ); - - if( i_intra_cost == COST_MAX ) - i_intra_cost = i_cost * i_satd_intra / i_satd_inter + 1; + COPY2_IF_LT( i_cost, analysis.i_satd_i16x16, i_type, I_16x16 ); + COPY2_IF_LT( i_cost, analysis.i_satd_i8x8, i_type, I_8x8 ); + COPY2_IF_LT( i_cost, analysis.i_satd_i4x4, i_type, I_4x4 ); + COPY2_IF_LT( i_cost, analysis.i_satd_pcm, i_type, I_PCM ); 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 ) { diff --git a/encoder/encoder.c b/encoder/encoder.c index 17a9a47f..55634560 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -366,9 +366,6 @@ static int x264_validate_parameters( x264_t *h ) #ifndef HAVE_PTHREAD x264_log( h, X264_LOG_WARNING, "not compiled with pthread support!\n"); h->param.i_threads = 1; -#else - if( h->param.i_scenecut_threshold >= 0 ) - h->param.b_pre_scenecut = 1; #endif } @@ -442,6 +439,8 @@ static int x264_validate_parameters( x264_t *h ) h->param.i_frame_reference = x264_clip3( h->param.i_frame_reference, 1, 16 ); if( h->param.i_keyint_max <= 0 ) h->param.i_keyint_max = 1; + if( h->param.i_scenecut_threshold < 0 ) + h->param.i_scenecut_threshold = 0; h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 ); if( !h->param.analyse.i_subpel_refine && h->param.analyse.i_direct_mv_pred > X264_DIRECT_PRED_SPATIAL ) { @@ -457,8 +456,6 @@ static int x264_validate_parameters( x264_t *h ) h->mb.b_direct_auto_write = h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO && h->param.i_bframe && ( h->param.rc.b_stat_write || !h->param.rc.b_stat_read ); - if( h->param.i_scenecut_threshold < 0 ) - h->param.b_pre_scenecut = 0; h->param.i_deblocking_filter_alphac0 = x264_clip3( h->param.i_deblocking_filter_alphac0, -6, 6 ); h->param.i_deblocking_filter_beta = x264_clip3( h->param.i_deblocking_filter_beta, -6, 6 ); @@ -709,7 +706,7 @@ x264_t *x264_encoder_open ( x264_param_t *param ) && ( h->param.rc.i_rc_method == X264_RC_ABR || h->param.rc.i_rc_method == X264_RC_CRF || h->param.i_bframe_adaptive - || h->param.b_pre_scenecut ); + || h->param.i_scenecut_threshold ); h->frames.b_have_lowres |= (h->param.rc.b_stat_read && h->param.rc.i_vbv_buffer_size > 0); h->frames.b_have_sub8x8_esa = !!(h->param.analyse.inter & X264_ANALYSE_PSUB8x8); @@ -815,7 +812,7 @@ int x264_encoder_reconfig( x264_t *h, x264_param_t *param ) #define COPY(var) h->param.var = param->var COPY( i_frame_reference ); // but never uses more refs than initially specified COPY( i_bframe_bias ); - if( h->param.i_scenecut_threshold >= 0 && param->i_scenecut_threshold >= 0 ) + if( h->param.i_scenecut_threshold ) COPY( i_scenecut_threshold ); // can't turn it on or off, only vary the threshold COPY( b_deblocking_filter ); COPY( i_deblocking_filter_alphac0 ); @@ -1465,8 +1462,6 @@ int x264_encoder_encode( x264_t *h, return 0; } -do_encode: - if( h->fenc->i_type == X264_TYPE_IDR ) { h->frames.i_last_idr = h->fenc->i_frame; @@ -1594,107 +1589,6 @@ do_encode: else x264_slices_write( h ); - /* restore CPU state (before using float again) */ - x264_emms(); - - if( h->sh.i_type == SLICE_TYPE_P && !h->param.rc.b_stat_read - && h->param.i_scenecut_threshold >= 0 - && !h->param.b_pre_scenecut ) - { - const int *mbs = h->stat.frame.i_mb_count; - int i_mb_i = mbs[I_16x16] + mbs[I_8x8] + mbs[I_4x4]; - int i_mb_p = mbs[P_L0] + mbs[P_8x8]; - int i_mb_s = mbs[P_SKIP]; - int i_mb = h->sps->i_mb_width * h->sps->i_mb_height; - int64_t i_inter_cost = h->stat.frame.i_inter_cost; - int64_t i_intra_cost = h->stat.frame.i_intra_cost; - - float f_bias; - int i_gop_size = h->fenc->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; - - /* macroblock_analyse() doesn't further analyse skipped mbs, - * so we have to guess their cost */ - if( h->stat.frame.i_mbs_analysed > 0 ) - i_intra_cost = i_intra_cost * i_mb / h->stat.frame.i_mbs_analysed; - - 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 ); - } - f_bias = X264_MIN( f_bias, 1.0 ); - - /* Bad P will be reencoded as I */ - if( h->stat.frame.i_mbs_analysed > 0 && - i_inter_cost >= (1.0 - f_bias) * i_intra_cost ) - { - int b; - - x264_log( h, X264_LOG_DEBUG, "scene cut at %d Icost:%.0f Pcost:%.0f ratio:%.4f bias:%.4f gop:%d (imb:%d pmb:%d smb:%d)\n", - h->fenc->i_frame, - (double)i_intra_cost, (double)i_inter_cost, - 1. - (double)i_inter_cost / i_intra_cost, - f_bias, i_gop_size, - i_mb_i, i_mb_p, i_mb_s ); - - /* Restore frame num */ - h->i_frame_num--; - - for( b = 0; h->frames.current[b] && IS_X264_TYPE_B( h->frames.current[b]->i_type ); b++ ); - if( b > 0 ) - { - /* If using B-frames, force GOP to be closed. - * Even if this frame is going to be I and not IDR, forcing a - * P-frame before the scenecut will probably help compression. - * - * We don't yet know exactly which frame is the scene cut, so - * we can't assign an I-frame. Instead, change the previous - * B-frame to P, and rearrange coding order. */ - - if( h->param.i_bframe_adaptive || b > 1 ) - h->fenc->i_type = X264_TYPE_AUTO; - x264_frame_sort_pts( h->frames.current ); - x264_frame_unshift( h->frames.next, h->fenc ); - h->fenc = h->frames.current[b-1]; - h->frames.current[b-1] = NULL; - h->fenc->i_type = X264_TYPE_P; - x264_frame_sort_dts( h->frames.current ); - } - /* Do IDR if needed */ - else if( i_gop_size >= h->param.i_keyint_min ) - { - /* Reset */ - h->i_frame_num = 0; - - /* Reinit field of fenc */ - h->fenc->i_type = X264_TYPE_IDR; - h->fenc->i_poc = 0; - - /* Put enqueued frames back in the pool */ - while( h->frames.current[0] ) - x264_frame_push( h->frames.next, x264_frame_shift( h->frames.current ) ); - x264_frame_sort_pts( h->frames.next ); - } - else - { - h->fenc->i_type = X264_TYPE_I; - } - goto do_encode; - } - } - x264_encoder_frame_end( thread_oldest, thread_current, pp_nal, pi_nal, pic_out ); return 0; } diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index c0a4bd76..5433c179 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -454,17 +454,6 @@ int x264_ratecontrol_new( x264_t *h ) x264_log( h, X264_LOG_ERROR, "b_adapt method specified in stats file not valid\n" ); return -1; } - - if( ( p = strstr( opts, "scenecut=" ) ) && sscanf( p, "scenecut=%d", &i ) && i >= -1 && i <= 100 ) - { - h->param.i_scenecut_threshold = i; - h->param.b_pre_scenecut = !!strstr( p, "(pre)" ); - } - else - { - x264_log( h, X264_LOG_ERROR, "scenecut method specified in stats file not valid\n" ); - return -1; - } } /* find number of pics */ @@ -1047,8 +1036,7 @@ int x264_ratecontrol_slice_type( x264_t *h, int frame_num ) h->thread[i]->param.rc.i_rc_method = X264_RC_CQP; h->thread[i]->param.rc.b_stat_read = 0; h->thread[i]->param.i_bframe_adaptive = 0; - h->thread[i]->param.b_pre_scenecut = 0; - h->thread[i]->param.i_scenecut_threshold = -1; + h->thread[i]->param.i_scenecut_threshold = 0; if( h->thread[i]->param.i_bframe > 1 ) h->thread[i]->param.i_bframe = 1; } diff --git a/encoder/slicetype.c b/encoder/slicetype.c index a1f73fa3..0dc2bef2 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -434,10 +434,13 @@ static int x264_slicetype_path_search( x264_t *h, x264_mb_analysis_t *a, x264_fr return strspn( best_paths[length-2], "B" ); } -static int scenecut( x264_t *h, x264_frame_t *frame, int pdist ) +static int scenecut( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1 ) { + x264_frame_t *frame = frames[p1]; + x264_slicetype_frame_cost( h, a, frames, p0, p1, p1, 0 ); + int icost = frame->i_cost_est[0][0]; - int pcost = frame->i_cost_est[pdist][0]; + int pcost = frame->i_cost_est[p1-p0][0]; 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; @@ -463,7 +466,7 @@ static int scenecut( x264_t *h, x264_frame_t *frame, int pdist ) res = pcost >= (1.0 - f_bias) * icost; if( res ) { - int imb = frame->i_intra_mbs[pdist]; + int imb = frame->i_intra_mbs[p1-p0]; int pmb = NUM_MBS - imb; x264_log( h, X264_LOG_DEBUG, "scene cut at %d Icost:%d Pcost:%d ratio:%.4f bias:%.4f gop:%d (imb:%d pmb:%d)\n", frame->i_frame, @@ -503,12 +506,8 @@ static void x264_slicetype_analyse( x264_t *h ) { 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; - } + if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1 ) ) + frames[1]->i_type = idr_frame_type; return; } @@ -516,31 +515,26 @@ no_b_frames: { 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_scenecut_threshold && scenecut( h, &a, frames, 0, 1 ) ) { - 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; - } + 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); for( j = 1; j < num_bframes+1; j++ ) { - if( h->param.b_pre_scenecut && scenecut( h, frames[j+1], j+1 ) ) + if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, j, 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[num_bframes+1]->i_type = X264_TYPE_P; } - else + else if( h->param.i_bframe_adaptive == X264_B_ADAPT_FAST ) { cost2p1 = x264_slicetype_frame_cost( h, &a, frames, 0, 2, 2, 1 ); if( frames[2]->i_intra_mbs[2] > i_mb_count / 2 ) @@ -572,6 +566,26 @@ no_b_frames: frames[j]->i_type = X264_TYPE_B; } } + else + { + int max_bframes = X264_MIN(num_frames-1, h->param.i_bframe); + if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1 ) ) + { + frames[1]->i_type = idr_frame_type; + return; + } + + for( j = 1; j < max_bframes+1; j++ ) + { + if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, j, j+1 ) ) + { + frames[j]->i_type = X264_TYPE_P; + return; + } + frames[j]->i_type = X264_TYPE_B; + } + frames[max_bframes+1]->i_type = X264_TYPE_P; + } } void x264_slicetype_decide( x264_t *h ) @@ -591,7 +605,7 @@ void x264_slicetype_decide( x264_t *h ) x264_ratecontrol_slice_type( h, h->frames.next[i]->i_frame ); } else if( (h->param.i_bframe && h->param.i_bframe_adaptive) - || h->param.b_pre_scenecut ) + || h->param.i_scenecut_threshold ) x264_slicetype_analyse( h ); for( bframes = 0;; bframes++ ) diff --git a/x264.c b/x264.c index da79e960..9aafc357 100644 --- a/x264.c +++ b/x264.c @@ -165,9 +165,8 @@ static void Help( x264_param_t *defaults, int b_longhelp ) H0( "\n" ); H0( " -I, --keyint Maximum GOP size [%d]\n", defaults->i_keyint_max ); H1( " -i, --min-keyint Minimum GOP size [%d]\n", defaults->i_keyint_min ); + H1( " --no-scenecut Disable adaptive I-frame decision\n" ); H1( " --scenecut How aggressively to insert extra I-frames [%d]\n", defaults->i_scenecut_threshold ); - H1( " --pre-scenecut Faster, less precise scenecut detection.\n" - " Required and implied by multi-threading.\n" ); H0( " -b, --bframes Number of B-frames between I and P [%d]\n", defaults->i_bframe ); H1( " --b-adapt Adaptive B-frame decision method [%d]\n" " Higher values may lower threading efficiency.\n" @@ -397,7 +396,7 @@ static int Parse( int argc, char **argv, { "min-keyint",required_argument,NULL,'i' }, { "keyint", required_argument, NULL, 'I' }, { "scenecut",required_argument, NULL, 0 }, - { "pre-scenecut", no_argument, NULL, 0 }, + { "no-scenecut",no_argument, NULL, 0 }, { "nf", no_argument, NULL, 0 }, { "no-deblock", no_argument, NULL, 0 }, { "filter", required_argument, NULL, 0 }, diff --git a/x264.h b/x264.h index 820185f9..3971992b 100644 --- a/x264.h +++ b/x264.h @@ -35,7 +35,7 @@ #include -#define X264_BUILD 66 +#define X264_BUILD 67 /* x264_t: * opaque handler for encoder */ @@ -188,7 +188,6 @@ typedef struct x264_param_t int i_keyint_max; /* Force an IDR keyframe at this interval */ int i_keyint_min; /* Scenecuts closer together than this are coded as I, not IDR. */ int i_scenecut_threshold; /* how aggressively to insert extra I frames */ - int b_pre_scenecut; /* compute scenecut on lowres frames */ int i_bframe; /* how many b-frame between 2 references pictures */ int i_bframe_adaptive; int i_bframe_bias;