Commit 42f27d04 authored by Fiona Glaser's avatar Fiona Glaser

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.
parent 2d5dcf8c
......@@ -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" )
......
......@@ -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 */
......
......@@ -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 )
{
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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++ )
......
......@@ -165,9 +165,8 @@ static void Help( x264_param_t *defaults, int b_longhelp )
H0( "\n" );
H0( " -I, --keyint <integer> Maximum GOP size [%d]\n", defaults->i_keyint_max );
H1( " -i, --min-keyint <integer> Minimum GOP size [%d]\n", defaults->i_keyint_min );
H1( " --no-scenecut Disable adaptive I-frame decision\n" );
H1( " --scenecut <integer> 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 <integer> 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 },
......
......@@ -35,7 +35,7 @@
#include <stdarg.h>
#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;
......
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