From e3ae8a7d1a3953c0f261cba6e1b161cfc7f1b0d6 Mon Sep 17 00:00:00 2001 From: Laurent Aimar Date: Wed, 29 Sep 2004 16:02:18 +0000 Subject: [PATCH] * all: Patch by Loren Merritt. " This patch makes scene-cut detection based on the relative cost of I-frame vs P-frame, rather than just on the number of I-blocks used. It also makes the scene-cut threshold configurable. This doesn't have a very large effect: Most scene cuts are obvious to either algorithm. But I think this way is better in some less clear cut cases, and sometimes finds a better spot for an I-frame than just waiting for the max I-frame interval." git-svn-id: svn://svn.videolan.org/x264/trunk@49 df754926-b1dd-0310-bc7b-ec298dee348c --- core/common.c | 1 + core/common.h | 4 ++++ encoder/analyse.c | 19 +++++++++++++------ encoder/encoder.c | 37 +++++++++++++++++++++++++------------ x264.c | 8 +++++++- x264.h | 3 ++- 6 files changed, 52 insertions(+), 20 deletions(-) diff --git a/core/common.c b/core/common.c index 403c0764..ea33e069 100644 --- a/core/common.c +++ b/core/common.c @@ -60,6 +60,7 @@ void x264_param_default( x264_param_t *param ) param->i_idrframe = 2; param->i_iframe = 60; param->i_bframe = 0; + param->i_scenecut_threshold = 40; param->b_deblocking_filter = 1; param->i_deblocking_filter_alphac0 = 0; diff --git a/core/common.h b/core/common.h index 087778cc..048ad2a1 100644 --- a/core/common.h +++ b/core/common.h @@ -349,6 +349,10 @@ struct x264_t int i_misc_bits; /* MB type counts */ int i_mb_count[18]; + /* 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; } frame; /* Cummulated stats */ diff --git a/encoder/analyse.c b/encoder/analyse.c index 41c561d9..7e1871c2 100644 --- a/encoder/analyse.c +++ b/encoder/analyse.c @@ -859,6 +859,7 @@ void x264_macroblock_analyse( x264_t *h ) int b_skip = 0; int i_cost; + int i_intra_cost, i_intra_type; /* Fast P_SKIP detection */ if( ( (i_neighbour&MB_LEFT) && h->mb.type[h->mb.i_mb_xy - 1] == P_SKIP ) || @@ -1017,17 +1018,23 @@ void x264_macroblock_analyse( x264_t *h ) } x264_mb_analyse_intra( h, &analysis ); - if( analysis.i_sad_i16x16 >= 0 && analysis.i_sad_i16x16 < i_cost ) + i_intra_type = I_16x16; + i_intra_cost = analysis.i_sad_i16x16; + + if( analysis.i_sad_i4x4 >=0 && analysis.i_sad_i4x4 < i_intra_cost ) { - h->mb.i_type = I_16x16; - i_cost = analysis.i_sad_i16x16; + i_intra_type = I_4x4; + i_intra_cost = analysis.i_sad_i4x4; } - if( analysis.i_sad_i4x4 >=0 && analysis.i_sad_i4x4 < i_cost ) + if( i_intra_cost >= 0 && i_intra_cost < i_cost ) { - h->mb.i_type = I_4x4; - i_cost = analysis.i_sad_i4x4; + h->mb.i_type = i_intra_type; + i_cost = i_intra_cost; } + + h->stat.frame.i_intra_cost += i_intra_cost; + h->stat.frame.i_inter_cost += i_cost; } } else if( h->sh.i_type == SLICE_TYPE_B ) diff --git a/encoder/encoder.c b/encoder/encoder.c index 517d730a..9ac2b340 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -347,10 +347,7 @@ x264_t *x264_encoder_open ( x264_param_t *param ) h->param.i_cabac_init_idc = x264_clip3( h->param.i_cabac_init_idc, -1, 2 ); - if( param->analyse.i_subpel_refine < 0 ) - param->analyse.i_subpel_refine = 0; - if( param->analyse.i_subpel_refine > 5 ) - param->analyse.i_subpel_refine = 5; + param->analyse.i_subpel_refine = x264_clip3( param->analyse.i_subpel_refine, 0, 5 ); /* VUI */ if( h->param.vui.i_sar_width > 0 && h->param.vui.i_sar_height > 0 ) @@ -732,7 +729,9 @@ static inline void x264_slice_write( x264_t *h, int i_nal_type, int i_nal_ref_id h->stat.frame.i_hdr_bits = h->stat.frame.i_itex_bits = h->stat.frame.i_ptex_bits = - h->stat.frame.i_misc_bits = 0; + h->stat.frame.i_misc_bits = + h->stat.frame.i_intra_cost = + h->stat.frame.i_inter_cost = 0; for( i = 0; i < 17; i++ ) h->stat.frame.i_mb_count[i] = 0; @@ -1127,20 +1126,34 @@ do_encode: x264_slice_write( h, i_nal_type, i_nal_ref_idc ); /* XXX: this scene cut won't work with B frame (it may never create IDR -> bad) */ - if( i_slice_type != SLICE_TYPE_I && !h->param.rc.b_stat_read ) + if( i_slice_type != SLICE_TYPE_I && !h->param.rc.b_stat_read + && h->param.i_scenecut_threshold >= 0 ) { int i_bias; int i_mb_i = h->stat.frame.i_mb_count[I_4x4] + h->stat.frame.i_mb_count[I_16x16]; + int i_mb_p = h->stat.frame.i_mb_count[P_L0] + h->stat.frame.i_mb_count[P_8x8]; + int i_mb_s = h->stat.frame.i_mb_count[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; + + /* macroblock_analyse() doesn't further analyse skipped mbs, + * so we have to guess their cost */ + if( i_mb_s < i_mb ) + i_intra_cost = i_intra_cost * i_mb / (i_mb - i_mb_s); + if( h->param.i_iframe > 0 ) - i_bias = 30 * X264_MIN( 3*h->frames.i_last_i, h->param.i_iframe ) / h->param.i_iframe; + i_bias = h->param.i_scenecut_threshold * h->frames.i_last_i / h->param.i_iframe; else i_bias = 15; + i_bias = X264_MIN( i_bias, 100 ); /* Bad P will be reencoded as I */ if( i_slice_type == SLICE_TYPE_P && - 100 * i_mb_i >= (100 - i_bias) * i_mb ) + i_mb_s < i_mb && + 100 * i_inter_cost >= (100 - i_bias) * i_intra_cost ) + /* 100 * i_mb_i >= (100 - i_bias) * i_mb ) */ /* h->out.nal[h->out.i_nal-1].i_payload > h->i_last_intra_size + h->i_last_intra_size * (3+h->i_last_intra_qp - i_global_qp) / 16 && @@ -1149,13 +1162,13 @@ do_encode: h->frames.i_last_i > 4)*/ { - x264_log( h, X264_LOG_DEBUG, "scene cut at %d size=%d last I:%d last P:%d Intra:%d Inter=%d Ratio=%d Bias=%d (Skip:%d PL0:%d)\n", + x264_log( h, X264_LOG_DEBUG, "scene cut at %d size=%d last I:%d last P:%d Intra:%lld Inter:%lld Ratio:%lld Bias=%d (I:%d P:%d Skip:%d)\n", h->i_frame - 1, h->out.nal[h->out.i_nal-1].i_payload, h->i_last_intra_size, h->i_last_inter_size, - i_mb_i, i_mb - i_mb_i, 100 * i_mb_i / i_mb, i_bias, - h->stat.frame.i_mb_count[P_SKIP], - h->stat.frame.i_mb_count[P_L0] ); + i_intra_cost, i_inter_cost, + 100 * i_inter_cost / i_intra_cost, + i_bias, i_mb_i, i_mb_p, i_mb_s ); /* Restore frame num */ h->i_frame_num--; diff --git a/x264.c b/x264.c index 4c662d8e..e34b27ce 100644 --- a/x264.c +++ b/x264.c @@ -103,7 +103,8 @@ static void Help( void ) " -h, --help Print this help\n" "\n" " -I, --idrframe Each 'number' I frames are IDR frames\n" - " -i, --iframe Frequency of I frames\n" + " -i, --iframe Max interval between I frames\n" + " --scenecut How aggresively to insert extra I frames\n" " -b, --bframe Number of B-frames between I and P\n" "\n" " -c, --cabac Enable CABAC\n" @@ -178,6 +179,7 @@ static int Parse( int argc, char **argv, #define OPT_NOPSNR 267 #define OPT_QUIET 268 #define OPT_SUBME 269 +#define OPT_SCENECUT 270 static struct option long_options[] = { @@ -186,6 +188,7 @@ static int Parse( int argc, char **argv, { "bframe", required_argument, NULL, 'b' }, { "iframe", required_argument, NULL, 'i' }, { "idrframe",required_argument, NULL, 'I' }, + { "scenecut",required_argument, NULL, OPT_SCENECUT }, { "nf", no_argument, NULL, 'n' }, { "filter", required_argument, NULL, 'f' }, { "cabac", no_argument, NULL, 'c' }, @@ -244,6 +247,9 @@ static int Parse( int argc, char **argv, case 'I': param->i_idrframe = atol( optarg ); break; + case OPT_SCENECUT: + param->i_scenecut_threshold = atol( optarg ); + break; case 'n': param->b_deblocking_filter = 0; break; diff --git a/x264.h b/x264.h index 8da79c82..8a3d0615 100644 --- a/x264.h +++ b/x264.h @@ -24,7 +24,7 @@ #ifndef _X264_H #define _X264_H 1 -#define X264_BUILD 0x000a +#define X264_BUILD 0x000b /* x264_t: * opaque handler for decoder and encoder */ @@ -103,6 +103,7 @@ typedef struct int i_frame_reference; /* Maximum number of reference frames */ int i_idrframe; /* every i_idrframe I frame are marked as IDR */ int i_iframe; /* every i_iframe are intra */ + int i_scenecut_threshold; /* how aggressively to insert extra I frames */ int i_bframe; /* how many b-frame between 2 references pictures */ int b_deblocking_filter; -- 2.40.0