[x264-devel] [PATCH] scene-cut cost
Loren Merritt
lorenm at u.washington.edu
Sat Sep 25 21:55:28 CEST 2004
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.
--Loren Merritt
-------------- next part --------------
Index: encoder/encoder.c
===================================================================
--- encoder/encoder.c (revision 48)
+++ encoder/encoder.c (working copy)
@@ -347,10 +347,7 @@
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 @@
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 @@
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 @@
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--;
Index: encoder/analyse.c
===================================================================
--- encoder/analyse.c (revision 48)
+++ encoder/analyse.c (working copy)
@@ -859,6 +859,7 @@
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 @@
}
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 )
Index: x264.c
===================================================================
--- x264.c (revision 48)
+++ x264.c (working copy)
@@ -103,7 +103,8 @@
" -h, --help Print this help\n"
"\n"
" -I, --idrframe <integer> Each 'number' I frames are IDR frames\n"
- " -i, --iframe <integer> Frequency of I frames\n"
+ " -i, --iframe <integer> Max interval between I frames\n"
+ " --scenecut <integer> How aggresively to insert extra I frames\n"
" -b, --bframe <integer> Number of B-frames between I and P\n"
"\n"
" -c, --cabac Enable CABAC\n"
@@ -178,6 +179,7 @@
#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 @@
{ "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 @@
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;
Index: core/common.c
===================================================================
--- core/common.c (revision 48)
+++ core/common.c (working copy)
@@ -60,6 +60,7 @@
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;
Index: core/common.h
===================================================================
--- core/common.h (revision 48)
+++ core/common.h (working copy)
@@ -349,6 +349,10 @@
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 */
Index: x264.h
===================================================================
--- x264.h (revision 48)
+++ x264.h (working copy)
@@ -103,6 +103,7 @@
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;
More information about the x264-devel
mailing list