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")
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" )
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 */
{
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
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 );
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 )
{
#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
}
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 )
{
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 );
&& ( 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);
#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 );
return 0;
}
-do_encode:
-
if( h->fenc->i_type == X264_TYPE_IDR )
{
h->frames.i_last_idr = h->fenc->i_frame;
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;
}
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 */
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;
}
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;
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,
{
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;
}
{
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 )
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 )
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++ )
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"
{ "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 },
#include <stdarg.h>
-#define X264_BUILD 66
+#define X264_BUILD 67
/* x264_t:
* opaque handler for encoder */
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;