Commit e3ae8a7d authored by Laurent Aimar's avatar Laurent Aimar

* 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
parent 79a2bb78
......@@ -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;
......
......@@ -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 */
......
......@@ -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 )
......
......@@ -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--;
......
......@@ -103,7 +103,8 @@ static void Help( void )
" -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 @@ 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;
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment