Commit 95ed2720 authored by Fiona Glaser's avatar Fiona Glaser

Add optional more optimal B-frame decision method

This method (--b-adapt 2) uses a Viterbi algorithm somewhat similar to that used in trellis quantization.
Note that it is not fully optimized and is very slow with large --bframes values.
It also takes into account weightb, which should improve fade detection.
Additionally, changes were made to cache lowres intra results for each frame to avoid recalculating them.  This should improve performance in both B-frame decision methods.
This can also be done for motion vectors, which will dramatically improve b-adapt 2 performance when it is complete.
This patch also reads b_adapt and scenecut settings from the first pass so that the x264 header information in the output file will have correct information (since frametype decision is only done on the first pass).
parent 80458ffc
...@@ -69,7 +69,7 @@ void x264_param_default( x264_param_t *param ) ...@@ -69,7 +69,7 @@ void x264_param_default( x264_param_t *param )
param->i_keyint_min = 25; param->i_keyint_min = 25;
param->i_bframe = 0; param->i_bframe = 0;
param->i_scenecut_threshold = 40; param->i_scenecut_threshold = 40;
param->b_bframe_adaptive = 1; param->i_bframe_adaptive = X264_B_ADAPT_FAST;
param->i_bframe_bias = 0; param->i_bframe_bias = 0;
param->b_bframe_pyramid = 0; param->b_bframe_pyramid = 0;
...@@ -328,7 +328,14 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) ...@@ -328,7 +328,14 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value )
OPT("bframes") OPT("bframes")
p->i_bframe = atoi(value); p->i_bframe = atoi(value);
OPT("b-adapt") OPT("b-adapt")
p->b_bframe_adaptive = atobool(value); {
p->i_bframe_adaptive = atobool(value);
if( b_error )
{
b_error = 0;
p->i_bframe_adaptive = atoi(value);
}
}
OPT("b-bias") OPT("b-bias")
p->i_bframe_bias = atoi(value); p->i_bframe_bias = atoi(value);
OPT("b-pyramid") OPT("b-pyramid")
...@@ -835,7 +842,7 @@ char *x264_param2string( x264_param_t *p, int b_res ) ...@@ -835,7 +842,7 @@ char *x264_param2string( x264_param_t *p, int b_res )
if( p->i_bframe ) if( p->i_bframe )
{ {
s += sprintf( s, " b_pyramid=%d b_adapt=%d b_bias=%d direct=%d wpredb=%d bime=%d", s += sprintf( s, " b_pyramid=%d b_adapt=%d b_bias=%d direct=%d wpredb=%d bime=%d",
p->b_bframe_pyramid, p->b_bframe_adaptive, p->i_bframe_bias, p->b_bframe_pyramid, p->i_bframe_adaptive, p->i_bframe_bias,
p->analyse.i_direct_mv_pred, p->analyse.b_weighted_bipred, p->analyse.i_direct_mv_pred, p->analyse.b_weighted_bipred,
p->analyse.b_bidir_me ); p->analyse.b_bidir_me );
} }
......
...@@ -311,11 +311,11 @@ struct x264_t ...@@ -311,11 +311,11 @@ struct x264_t
struct struct
{ {
/* Frames to be encoded (whose types have been decided) */ /* Frames to be encoded (whose types have been decided) */
x264_frame_t *current[X264_BFRAME_MAX+3]; x264_frame_t *current[X264_BFRAME_MAX*4+3];
/* Temporary buffer (frames types not yet decided) */ /* Temporary buffer (frames types not yet decided) */
x264_frame_t *next[X264_BFRAME_MAX+3]; x264_frame_t *next[X264_BFRAME_MAX*4+3];
/* Unused frames */ /* Unused frames */
x264_frame_t *unused[X264_BFRAME_MAX + X264_THREAD_MAX*2 + 16+4]; x264_frame_t *unused[X264_BFRAME_MAX*4 + X264_THREAD_MAX*2 + 16+4];
/* For adaptive B decision */ /* For adaptive B decision */
x264_frame_t *last_nonb; x264_frame_t *last_nonb;
......
...@@ -97,6 +97,7 @@ x264_frame_t *x264_frame_new( x264_t *h ) ...@@ -97,6 +97,7 @@ x264_frame_t *x264_frame_new( x264_t *h )
CHECKED_MALLOC( frame->mb_type, i_mb_count * sizeof(int8_t)); CHECKED_MALLOC( frame->mb_type, i_mb_count * sizeof(int8_t));
CHECKED_MALLOC( frame->mv[0], 2*16 * i_mb_count * sizeof(int16_t) ); CHECKED_MALLOC( frame->mv[0], 2*16 * i_mb_count * sizeof(int16_t) );
CHECKED_MALLOC( frame->ref[0], 4 * i_mb_count * sizeof(int8_t) ); CHECKED_MALLOC( frame->ref[0], 4 * i_mb_count * sizeof(int8_t) );
CHECKED_MALLOC( frame->i_intra_cost, i_mb_count * sizeof(uint16_t) );
if( h->param.i_bframe ) if( h->param.i_bframe )
{ {
CHECKED_MALLOC( frame->mv[1], 2*16 * i_mb_count * sizeof(int16_t) ); CHECKED_MALLOC( frame->mv[1], 2*16 * i_mb_count * sizeof(int16_t) );
...@@ -909,6 +910,7 @@ x264_frame_t *x264_frame_pop_unused( x264_t *h ) ...@@ -909,6 +910,7 @@ x264_frame_t *x264_frame_pop_unused( x264_t *h )
frame = x264_frame_new( h ); frame = x264_frame_new( h );
assert( frame->i_reference_count == 0 ); assert( frame->i_reference_count == 0 );
frame->i_reference_count = 1; frame->i_reference_count = 1;
frame->b_intra_calculated = 0;
return frame; return frame;
} }
......
...@@ -79,6 +79,8 @@ typedef struct ...@@ -79,6 +79,8 @@ typedef struct
int *i_row_bits; int *i_row_bits;
int *i_row_qp; int *i_row_qp;
float *f_qp_offset; float *f_qp_offset;
int b_intra_calculated;
uint16_t *i_intra_cost;
/* threading */ /* threading */
int i_lines_completed; /* in pixels */ int i_lines_completed; /* in pixels */
......
...@@ -442,7 +442,8 @@ static int x264_validate_parameters( x264_t *h ) ...@@ -442,7 +442,8 @@ static int x264_validate_parameters( x264_t *h )
h->param.i_bframe = x264_clip3( h->param.i_bframe, 0, X264_BFRAME_MAX ); h->param.i_bframe = x264_clip3( h->param.i_bframe, 0, X264_BFRAME_MAX );
h->param.i_bframe_bias = x264_clip3( h->param.i_bframe_bias, -90, 100 ); h->param.i_bframe_bias = x264_clip3( h->param.i_bframe_bias, -90, 100 );
h->param.b_bframe_pyramid = h->param.b_bframe_pyramid && h->param.i_bframe > 1; h->param.b_bframe_pyramid = h->param.b_bframe_pyramid && h->param.i_bframe > 1;
h->param.b_bframe_adaptive = h->param.b_bframe_adaptive && h->param.i_bframe > 0; if( !h->param.i_bframe )
h->param.i_bframe_adaptive = X264_B_ADAPT_NONE;
h->param.analyse.b_weighted_bipred = h->param.analyse.b_weighted_bipred && h->param.i_bframe > 0; h->param.analyse.b_weighted_bipred = h->param.analyse.b_weighted_bipred && h->param.i_bframe > 0;
h->mb.b_direct_auto_write = h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO h->mb.b_direct_auto_write = h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO
&& h->param.i_bframe && h->param.i_bframe
...@@ -673,14 +674,17 @@ x264_t *x264_encoder_open ( x264_param_t *param ) ...@@ -673,14 +674,17 @@ x264_t *x264_encoder_open ( x264_param_t *param )
h->mb.i_mb_count = h->sps->i_mb_width * h->sps->i_mb_height; h->mb.i_mb_count = h->sps->i_mb_width * h->sps->i_mb_height;
/* Init frames. */ /* Init frames. */
h->frames.i_delay = h->param.i_bframe + h->param.i_threads - 1; if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS )
h->frames.i_delay = X264_MAX(h->param.i_bframe,3)*4 + h->param.i_threads - 1;
else
h->frames.i_delay = h->param.i_bframe + h->param.i_threads - 1;
h->frames.i_max_ref0 = h->param.i_frame_reference; h->frames.i_max_ref0 = h->param.i_frame_reference;
h->frames.i_max_ref1 = h->sps->vui.i_num_reorder_frames; h->frames.i_max_ref1 = h->sps->vui.i_num_reorder_frames;
h->frames.i_max_dpb = h->sps->vui.i_max_dec_frame_buffering; h->frames.i_max_dpb = h->sps->vui.i_max_dec_frame_buffering;
h->frames.b_have_lowres = !h->param.rc.b_stat_read h->frames.b_have_lowres = !h->param.rc.b_stat_read
&& ( h->param.rc.i_rc_method == X264_RC_ABR && ( h->param.rc.i_rc_method == X264_RC_ABR
|| h->param.rc.i_rc_method == X264_RC_CRF || h->param.rc.i_rc_method == X264_RC_CRF
|| h->param.b_bframe_adaptive || h->param.i_bframe_adaptive
|| h->param.b_pre_scenecut ); || h->param.b_pre_scenecut );
h->frames.b_have_lowres |= (h->param.rc.b_stat_read && h->param.rc.i_vbv_buffer_size > 0); h->frames.b_have_lowres |= (h->param.rc.b_stat_read && h->param.rc.i_vbv_buffer_size > 0);
...@@ -1608,7 +1612,7 @@ do_encode: ...@@ -1608,7 +1612,7 @@ do_encode:
* we can't assign an I-frame. Instead, change the previous * we can't assign an I-frame. Instead, change the previous
* B-frame to P, and rearrange coding order. */ * B-frame to P, and rearrange coding order. */
if( h->param.b_bframe_adaptive || b > 1 ) if( h->param.i_bframe_adaptive || b > 1 )
h->fenc->i_type = X264_TYPE_AUTO; h->fenc->i_type = X264_TYPE_AUTO;
x264_frame_sort_pts( h->frames.current ); x264_frame_sort_pts( h->frames.current );
x264_frame_unshift( h->frames.next, h->fenc ); x264_frame_unshift( h->frames.next, h->fenc );
......
...@@ -397,6 +397,25 @@ int x264_ratecontrol_new( x264_t *h ) ...@@ -397,6 +397,25 @@ int x264_ratecontrol_new( x264_t *h )
if( strstr( opts, "qp=0" ) && h->param.rc.i_rc_method == X264_RC_ABR ) if( strstr( opts, "qp=0" ) && h->param.rc.i_rc_method == X264_RC_ABR )
x264_log( h, X264_LOG_WARNING, "1st pass was lossless, bitrate prediction will be inaccurate\n" ); x264_log( h, X264_LOG_WARNING, "1st pass was lossless, bitrate prediction will be inaccurate\n" );
if( ( p = strstr( opts, "b_adapt=" ) ) && sscanf( p, "b_adapt=%d", &i ) && i >= X264_B_ADAPT_NONE && i <= X264_B_ADAPT_TRELLIS )
h->param.i_bframe_adaptive = i;
else
{
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 */ /* find number of pics */
...@@ -523,7 +542,10 @@ int x264_ratecontrol_new( x264_t *h ) ...@@ -523,7 +542,10 @@ int x264_ratecontrol_new( x264_t *h )
{ {
h->thread[i]->rc = rc+i; h->thread[i]->rc = rc+i;
if( i ) if( i )
{
rc[i] = rc[0]; rc[i] = rc[0];
memcpy( &h->thread[i]->param, &h->param, sizeof( x264_param_t ) );
}
} }
return 0; return 0;
...@@ -967,14 +989,14 @@ int x264_ratecontrol_slice_type( x264_t *h, int frame_num ) ...@@ -967,14 +989,14 @@ int x264_ratecontrol_slice_type( x264_t *h, int frame_num )
x264_log(h, X264_LOG_ERROR, "2nd pass has more frames than 1st pass (%d)\n", rc->num_entries); x264_log(h, X264_LOG_ERROR, "2nd pass has more frames than 1st pass (%d)\n", rc->num_entries);
x264_log(h, X264_LOG_ERROR, "continuing anyway, at constant QP=%d\n", h->param.rc.i_qp_constant); x264_log(h, X264_LOG_ERROR, "continuing anyway, at constant QP=%d\n", h->param.rc.i_qp_constant);
if( h->param.b_bframe_adaptive ) if( h->param.i_bframe_adaptive )
x264_log(h, X264_LOG_ERROR, "disabling adaptive B-frames\n"); x264_log(h, X264_LOG_ERROR, "disabling adaptive B-frames\n");
rc->b_abr = 0; rc->b_abr = 0;
rc->b_2pass = 0; rc->b_2pass = 0;
h->param.rc.i_rc_method = X264_RC_CQP; h->param.rc.i_rc_method = X264_RC_CQP;
h->param.rc.b_stat_read = 0; h->param.rc.b_stat_read = 0;
h->param.b_bframe_adaptive = 0; h->param.i_bframe_adaptive = 0;
if( h->param.i_bframe > 1 ) if( h->param.i_bframe > 1 )
h->param.i_bframe = 1; h->param.i_bframe = 1;
return X264_TYPE_P; return X264_TYPE_P;
......
...@@ -51,6 +51,7 @@ static int x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, ...@@ -51,6 +51,7 @@ static int x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a,
const int i_mb_xy = i_mb_x + i_mb_y * i_mb_stride; const int i_mb_xy = i_mb_x + i_mb_y * i_mb_stride;
const int i_stride = fenc->i_stride_lowres; const int i_stride = fenc->i_stride_lowres;
const int i_pel_offset = 8 * ( i_mb_x + i_mb_y * i_stride ); const int i_pel_offset = 8 * ( i_mb_x + i_mb_y * i_stride );
const int i_bipred_weight = h->param.analyse.b_weighted_bipred ? 64 - (dist_scale_factor>>2) : 32;
DECLARE_ALIGNED_8( uint8_t pix1[9*FDEC_STRIDE] ); DECLARE_ALIGNED_8( uint8_t pix1[9*FDEC_STRIDE] );
uint8_t *pix2 = pix1+8; uint8_t *pix2 = pix1+8;
...@@ -105,7 +106,10 @@ static int x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, ...@@ -105,7 +106,10 @@ static int x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a,
(mv0)[0], (mv0)[1], 8, 8 ); \ (mv0)[0], (mv0)[1], 8, 8 ); \
src2 = h->mc.get_ref( pix2, &stride2, m[1].p_fref, m[1].i_stride[0], \ src2 = h->mc.get_ref( pix2, &stride2, m[1].p_fref, m[1].i_stride[0], \
(mv1)[0], (mv1)[1], 8, 8 ); \ (mv1)[0], (mv1)[1], 8, 8 ); \
h->mc.avg[PIXEL_8x8]( pix1, 16, src2, stride2 ); \ if( i_bipred_weight != 32 ) \
h->mc.avg_weight[PIXEL_8x8]( pix1, 16, src2, stride2, i_bipred_weight ); \
else \
h->mc.avg[PIXEL_8x8]( pix1, 16, src2, stride2 ); \
i_cost = penalty + h->pixf.mbcmp[PIXEL_8x8]( \ i_cost = penalty + h->pixf.mbcmp[PIXEL_8x8]( \
m[0].p_fenc[0], FENC_STRIDE, pix1, 16 ); \ m[0].p_fenc[0], FENC_STRIDE, pix1, 16 ); \
if( i_bcost > i_cost ) \ if( i_bcost > i_cost ) \
...@@ -177,40 +181,42 @@ static int x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, ...@@ -177,40 +181,42 @@ static int x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a,
if( i_bcost < i_cost_bak ) if( i_bcost < i_cost_bak )
SAVE_MVS( m[0].mv, m[1].mv ); SAVE_MVS( m[0].mv, m[1].mv );
//FIXME intra part could be shared across multiple encodings of the frame
lowres_intra_mb: lowres_intra_mb:
if( !b_bidir ) // forbid intra-mbs in B-frames, because it's rare and not worth checking /* forbid intra-mbs in B-frames, because it's rare and not worth checking */
/* FIXME: Should we still forbid them now that we cache intra scores? */
if( !b_bidir )
{ {
uint8_t *pix = &pix1[8+FDEC_STRIDE - 1]; int i_icost, b_intra;
uint8_t *src = &fenc->lowres[0][i_pel_offset - 1]; if( !fenc->b_intra_calculated )
const int intra_penalty = 5; {
int satds[4], i_icost, b_intra; DECLARE_ALIGNED_16( uint8_t edge[33] );
uint8_t *pix = &pix1[8+FDEC_STRIDE - 1];
uint8_t *src = &fenc->lowres[0][i_pel_offset - 1];
const int intra_penalty = 5;
int satds[4];
memcpy( pix-FDEC_STRIDE, src-i_stride, 17 ); memcpy( pix-FDEC_STRIDE, src-i_stride, 17 );
for( i=0; i<8; i++ ) for( i=0; i<8; i++ )
pix[i*FDEC_STRIDE] = src[i*i_stride]; pix[i*FDEC_STRIDE] = src[i*i_stride];
pix++; pix++;
if( h->pixf.intra_satd_x3_8x8c && h->pixf.mbcmp[0] == h->pixf.satd[0] ) if( h->pixf.intra_satd_x3_8x8c && h->pixf.mbcmp[0] == h->pixf.satd[0] )
{
h->pixf.intra_satd_x3_8x8c( h->mb.pic.p_fenc[0], pix, satds );
h->predict_8x8c[I_PRED_CHROMA_P]( pix );
satds[I_PRED_CHROMA_P] =
h->pixf.satd[PIXEL_8x8]( pix, FDEC_STRIDE, h->mb.pic.p_fenc[0], FENC_STRIDE );
}
else
{
for( i=0; i<4; i++ )
{ {
h->predict_8x8c[i]( pix ); h->pixf.intra_satd_x3_8x8c( h->mb.pic.p_fenc[0], pix, satds );
satds[i] = h->pixf.mbcmp[PIXEL_8x8]( pix, FDEC_STRIDE, h->mb.pic.p_fenc[0], FENC_STRIDE ); h->predict_8x8c[I_PRED_CHROMA_P]( pix );
satds[I_PRED_CHROMA_P] =
h->pixf.satd[PIXEL_8x8]( pix, FDEC_STRIDE, h->mb.pic.p_fenc[0], FENC_STRIDE );
} }
} else
i_icost = X264_MIN4( satds[0], satds[1], satds[2], satds[3] ); {
for( i=0; i<4; i++ )
{
h->predict_8x8c[i]( pix );
satds[i] = h->pixf.mbcmp[PIXEL_8x8]( pix, FDEC_STRIDE, h->mb.pic.p_fenc[0], FENC_STRIDE );
}
}
i_icost = X264_MIN4( satds[0], satds[1], satds[2], satds[3] );
if( i_icost < i_bcost * 2 )
{
DECLARE_ALIGNED_16( uint8_t edge[33] );
x264_predict_8x8_filter( pix, edge, ALL_NEIGHBORS, ALL_NEIGHBORS ); x264_predict_8x8_filter( pix, edge, ALL_NEIGHBORS, ALL_NEIGHBORS );
for( i=3; i<9; i++ ) for( i=3; i<9; i++ )
{ {
...@@ -219,9 +225,12 @@ lowres_intra_mb: ...@@ -219,9 +225,12 @@ lowres_intra_mb:
satd = h->pixf.mbcmp[PIXEL_8x8]( pix, FDEC_STRIDE, h->mb.pic.p_fenc[0], FENC_STRIDE ); satd = h->pixf.mbcmp[PIXEL_8x8]( pix, FDEC_STRIDE, h->mb.pic.p_fenc[0], FENC_STRIDE );
i_icost = X264_MIN( i_icost, satd ); i_icost = X264_MIN( i_icost, satd );
} }
}
i_icost += intra_penalty; i_icost += intra_penalty;
fenc->i_intra_cost[i_mb_xy] = i_icost;
}
else
i_icost = fenc->i_intra_cost[i_mb_xy];
b_intra = i_icost < i_bcost; b_intra = i_icost < i_bcost;
if( b_intra ) if( b_intra )
i_bcost = i_icost; i_bcost = i_icost;
...@@ -330,11 +339,11 @@ static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a, ...@@ -330,11 +339,11 @@ static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a,
if( b != p1 ) if( b != p1 )
i_score = i_score * 100 / (120 + h->param.i_bframe_bias); i_score = i_score * 100 / (120 + h->param.i_bframe_bias);
else
frames[b]->b_intra_calculated = 1;
frames[b]->i_cost_est[b-p0][p1-b] = i_score; frames[b]->i_cost_est[b-p0][p1-b] = i_score;
frames[b]->i_cost_est_aq[b-p0][p1-b] = i_score_aq; frames[b]->i_cost_est_aq[b-p0][p1-b] = i_score_aq;
// fprintf( stderr, "frm %d %c(%d,%d): %6d %6d imb:%d \n", frames[b]->i_frame,
// (p1==0?'I':b<p1?'B':'P'), b-p0, p1-b, i_score, frames[b]->i_cost_est[0][0], frames[b]->i_intra_mbs[b-p0] );
x264_emms(); x264_emms();
} }
...@@ -347,6 +356,86 @@ static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a, ...@@ -347,6 +356,86 @@ static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a,
return i_score; return i_score;
} }
#define MAX_LENGTH (X264_BFRAME_MAX*4)
static int x264_slicetype_path_cost( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, char *path, int threshold )
{
int loc = 1;
int cost = 0;
int cur_p = 0;
path--; /* Since the 1st path element is really the second frame */
while( path[loc] )
{
int next_p = loc;
int next_b;
/* Find the location of the next P-frame. */
while( path[next_p] && path[next_p] != 'P' )
next_p++;
/* Return if the path doesn't end on a P-frame. */
if( path[next_p] != 'P' )
return cost;
/* Add the cost of the P-frame found above */
cost += x264_slicetype_frame_cost( h, a, frames, cur_p, next_p, next_p, 0 );
/* Early terminate if the cost we have found is larger than the best path cost so far */
if( cost > threshold )
break;
for( next_b = loc; next_b < next_p && cost < threshold; next_b++ )
cost += x264_slicetype_frame_cost( h, a, frames, cur_p, next_p, next_b, 0 );
loc = next_p + 1;
cur_p = next_p;
}
return cost;
}
/* Viterbi/trellis slicetype decision algorithm. */
/* Uses strings due to the fact that the speed of the control functions is
negligable compared to the cost of running slicetype_frame_cost, and because
it makes debugging easier. */
static void x264_slicetype_path( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int length, int max_bframes, int buffer_size, char (*best_paths)[MAX_LENGTH] )
{
char paths[X264_BFRAME_MAX+2][MAX_LENGTH] = {{0}};
int num_paths = X264_MIN(max_bframes+1, length);
int suffix_size, loc, path;
int best_cost = COST_MAX;
int best_path_index = 0;
length = X264_MIN(length,MAX_LENGTH);
/* Iterate over all currently possible paths and add suffixes to each one */
for( suffix_size = 0; suffix_size < num_paths; suffix_size++ )
{
memcpy( paths[suffix_size], best_paths[length - (suffix_size + 1)], length - (suffix_size + 1) );
for( loc = 0; loc < suffix_size; loc++ )
strcat( paths[suffix_size], "B" );
strcat( paths[suffix_size], "P" );
}
/* Calculate the actual cost of each of the current paths */
for( path = 0; path < num_paths; path++ )
{
int cost = x264_slicetype_path_cost( h, a, frames, paths[path], best_cost );
if( cost < best_cost )
{
best_cost = cost;
best_path_index = path;
}
}
/* Store the best path. */
memcpy( best_paths[length], paths[best_path_index], length );
}
static int x264_slicetype_path_search( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int length, int bframes, int buffer )
{
char best_paths[MAX_LENGTH][MAX_LENGTH] = {"","P"};
int n;
for( n = 2; n < length-1; n++ )
x264_slicetype_path( h, a, frames, n, bframes, buffer, best_paths );
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_frame_t *frame, int pdist )
{ {
int icost = frame->i_cost_est[0][0]; int icost = frame->i_cost_est[0][0];
...@@ -369,8 +458,8 @@ static int scenecut( x264_t *h, x264_frame_t *frame, int pdist ) ...@@ -369,8 +458,8 @@ static int scenecut( x264_t *h, x264_frame_t *frame, int pdist )
{ {
f_bias = f_thresh_min f_bias = f_thresh_min
+ ( f_thresh_max - f_thresh_min ) + ( f_thresh_max - f_thresh_min )
* ( i_gop_size - h->param.i_keyint_min ) * ( i_gop_size - h->param.i_keyint_min )
/ ( h->param.i_keyint_max - h->param.i_keyint_min ); / ( h->param.i_keyint_max - h->param.i_keyint_min ) ;
} }
res = pcost >= (1.0 - f_bias) * icost; res = pcost >= (1.0 - f_bias) * icost;
...@@ -389,7 +478,7 @@ static int scenecut( x264_t *h, x264_frame_t *frame, int pdist ) ...@@ -389,7 +478,7 @@ static int scenecut( x264_t *h, x264_frame_t *frame, int pdist )
static void x264_slicetype_analyse( x264_t *h ) static void x264_slicetype_analyse( x264_t *h )
{ {
x264_mb_analysis_t a; x264_mb_analysis_t a;
x264_frame_t *frames[X264_BFRAME_MAX+3] = { NULL, }; x264_frame_t *frames[X264_BFRAME_MAX*4+3] = { NULL, };
int num_frames; int num_frames;
int keyint_limit; int keyint_limit;
int j; int j;
...@@ -425,42 +514,65 @@ no_b_frames: ...@@ -425,42 +514,65 @@ no_b_frames:
return; return;
} }
cost2p1 = x264_slicetype_frame_cost( h, &a, frames, 0, 2, 2, 1 ); if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS )
if( frames[2]->i_intra_mbs[2] > i_mb_count / 2 ) {
goto no_b_frames; int num_bframes;
int max_bframes = X264_MIN(num_frames-1, h->param.i_bframe);
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;
return;
}
}
num_bframes = x264_slicetype_path_search( h, &a, frames, num_frames, max_bframes, num_frames-max_bframes );
assert(num_bframes < num_frames);
cost1b1 = x264_slicetype_frame_cost( h, &a, frames, 0, 2, 1, 0 ); for( j = 1; j < num_bframes+1; j++ )
cost1p0 = x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 ); {
cost2p0 = x264_slicetype_frame_cost( h, &a, frames, 1, 2, 2, 0 ); if( h->param.b_pre_scenecut && scenecut( h, frames[j+1], j+1 ) )
// fprintf( stderr, "PP: %d + %d <=> BP: %d + %d \n", {
// cost1p0, cost2p0, cost1b1, cost2p1 ); frames[j]->i_type = X264_TYPE_P;
if( cost1p0 + cost2p0 < cost1b1 + cost2p1 ) frames[j+1]->i_type = idr_frame_type;
goto no_b_frames; return;
}
frames[j]->i_type = X264_TYPE_B;
}
frames[num_bframes+1]->i_type = X264_TYPE_P;
}
else
{
cost2p1 = x264_slicetype_frame_cost( h, &a, frames, 0, 2, 2, 1 );
if( frames[2]->i_intra_mbs[2] > i_mb_count / 2 )
goto no_b_frames;
// arbitrary and untuned cost1b1 = x264_slicetype_frame_cost( h, &a, frames, 0, 2, 1, 0 );
#define INTER_THRESH 300 cost1p0 = x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 );
#define P_SENS_BIAS (50 - h->param.i_bframe_bias) cost2p0 = x264_slicetype_frame_cost( h, &a, frames, 1, 2, 2, 0 );
frames[1]->i_type = X264_TYPE_B;
for( j = 2; j <= X264_MIN( h->param.i_bframe, num_frames-1 ); j++ ) if( cost1p0 + cost2p0 < cost1b1 + cost2p1 )
{ goto no_b_frames;
int pthresh = X264_MAX(INTER_THRESH - P_SENS_BIAS * (j-1), INTER_THRESH/10);
int pcost = x264_slicetype_frame_cost( h, &a, frames, 0, j+1, j+1, 1 ); // arbitrary and untuned
/* if( i_mb_count ) #define INTER_THRESH 300
fprintf( stderr, "frm%d+%d: %d <=> %d, I:%d/%d \n", #define P_SENS_BIAS (50 - h->param.i_bframe_bias)
frames[0]->i_frame, j-1, pthresh, pcost/i_mb_count, frames[1]->i_type = X264_TYPE_B;
frames[j+1]->i_intra_mbs[j+1], i_mb_count );
else for( j = 2; j <= X264_MIN( h->param.i_bframe, num_frames-1 ); j++ )
fprintf( stderr, "frm%d+%d: %d <=> %d, I:%d/%d \n",
frames[0]->i_frame, j-1, pthresh, pcost,
frames[j+1]->i_intra_mbs[j+1], i_mb_count ); */
if( pcost > pthresh*i_mb_count || frames[j+1]->i_intra_mbs[j+1] > i_mb_count/3 )
{ {
frames[j]->i_type = X264_TYPE_P; int pthresh = X264_MAX(INTER_THRESH - P_SENS_BIAS * (j-1), INTER_THRESH/10);
break; int pcost = x264_slicetype_frame_cost( h, &a, frames, 0, j+1, j+1, 1 );
if( pcost > pthresh*i_mb_count || frames[j+1]->i_intra_mbs[j+1] > i_mb_count/3 )
{
frames[j]->i_type = X264_TYPE_P;
break;
}
else
frames[j]->i_type = X264_TYPE_B;
} }
else
frames[j]->i_type = X264_TYPE_B;
} }
} }
...@@ -480,7 +592,7 @@ void x264_slicetype_decide( x264_t *h ) ...@@ -480,7 +592,7 @@ void x264_slicetype_decide( x264_t *h )
h->frames.next[i]->i_type = h->frames.next[i]->i_type =
x264_ratecontrol_slice_type( h, h->frames.next[i]->i_frame ); x264_ratecontrol_slice_type( h, h->frames.next[i]->i_frame );
} }
else if( (h->param.i_bframe && h->param.b_bframe_adaptive) else if( (h->param.i_bframe && h->param.i_bframe_adaptive)
|| h->param.b_pre_scenecut ) || h->param.b_pre_scenecut )
x264_slicetype_analyse( h ); x264_slicetype_analyse( h );
...@@ -530,7 +642,7 @@ void x264_slicetype_decide( x264_t *h ) ...@@ -530,7 +642,7 @@ void x264_slicetype_decide( x264_t *h )
int x264_rc_analyse_slice( x264_t *h ) int x264_rc_analyse_slice( x264_t *h )