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 )
param->i_keyint_min = 25;
param->i_bframe = 0;
param->i_scenecut_threshold = 40;
param->b_bframe_adaptive = 1;
param->i_bframe_adaptive = X264_B_ADAPT_FAST;
param->i_bframe_bias = 0;
param->b_bframe_pyramid = 0;
......@@ -328,7 +328,14 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value )
OPT("bframes")
p->i_bframe = atoi(value);
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")
p->i_bframe_bias = atoi(value);
OPT("b-pyramid")
......@@ -835,7 +842,7 @@ char *x264_param2string( x264_param_t *p, int b_res )
if( p->i_bframe )
{
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.b_bidir_me );
}
......
......@@ -311,11 +311,11 @@ struct x264_t
struct
{
/* 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) */
x264_frame_t *next[X264_BFRAME_MAX+3];
x264_frame_t *next[X264_BFRAME_MAX*4+3];
/* 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 */
x264_frame_t *last_nonb;
......
......@@ -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->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->i_intra_cost, i_mb_count * sizeof(uint16_t) );
if( h->param.i_bframe )
{
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 )
frame = x264_frame_new( h );
assert( frame->i_reference_count == 0 );
frame->i_reference_count = 1;
frame->b_intra_calculated = 0;
return frame;
}
......
......@@ -79,6 +79,8 @@ typedef struct
int *i_row_bits;
int *i_row_qp;
float *f_qp_offset;
int b_intra_calculated;
uint16_t *i_intra_cost;
/* threading */
int i_lines_completed; /* in pixels */
......
......@@ -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_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_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->mb.b_direct_auto_write = h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO
&& h->param.i_bframe
......@@ -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;
/* 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_ref1 = h->sps->vui.i_num_reorder_frames;
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->param.rc.i_rc_method == X264_RC_ABR
|| 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->frames.b_have_lowres |= (h->param.rc.b_stat_read && h->param.rc.i_vbv_buffer_size > 0);
......@@ -1608,7 +1612,7 @@ do_encode:
* we can't assign an I-frame. Instead, change the previous
* 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;
x264_frame_sort_pts( h->frames.current );
x264_frame_unshift( h->frames.next, h->fenc );
......
......@@ -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 )
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 */
......@@ -523,7 +542,10 @@ int x264_ratecontrol_new( x264_t *h )
{
h->thread[i]->rc = rc+i;
if( i )
{
rc[i] = rc[0];
memcpy( &h->thread[i]->param, &h->param, sizeof( x264_param_t ) );
}
}
return 0;
......@@ -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, "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");
rc->b_abr = 0;
rc->b_2pass = 0;
h->param.rc.i_rc_method = X264_RC_CQP;
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 )
h->param.i_bframe = 1;
return X264_TYPE_P;
......
......@@ -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_stride = fenc->i_stride_lowres;
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] );
uint8_t *pix2 = pix1+8;
......@@ -105,7 +106,10 @@ static int x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a,
(mv0)[0], (mv0)[1], 8, 8 ); \
src2 = h->mc.get_ref( pix2, &stride2, m[1].p_fref, m[1].i_stride[0], \
(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]( \
m[0].p_fenc[0], FENC_STRIDE, pix1, 16 ); \
if( i_bcost > i_cost ) \
......@@ -177,40 +181,42 @@ static int x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a,
if( i_bcost < i_cost_bak )
SAVE_MVS( m[0].mv, m[1].mv );
//FIXME intra part could be shared across multiple encodings of the frame
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];
uint8_t *src = &fenc->lowres[0][i_pel_offset - 1];
const int intra_penalty = 5;
int satds[4], i_icost, b_intra;
int i_icost, b_intra;
if( !fenc->b_intra_calculated )
{
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 );
for( i=0; i<8; i++ )
pix[i*FDEC_STRIDE] = src[i*i_stride];
pix++;
memcpy( pix-FDEC_STRIDE, src-i_stride, 17 );
for( i=0; i<8; i++ )
pix[i*FDEC_STRIDE] = src[i*i_stride];
pix++;
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++ )
if( h->pixf.intra_satd_x3_8x8c && h->pixf.mbcmp[0] == h->pixf.satd[0] )
{
h->predict_8x8c[i]( pix );
satds[i] = h->pixf.mbcmp[PIXEL_8x8]( pix, FDEC_STRIDE, h->mb.pic.p_fenc[0], FENC_STRIDE );
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 );
}
}
i_icost = X264_MIN4( satds[0], satds[1], satds[2], satds[3] );
else
{
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 );
for( i=3; i<9; i++ )
{
......@@ -219,9 +225,12 @@ lowres_intra_mb:
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 += 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;
if( b_intra )
i_bcost = i_icost;
......@@ -330,11 +339,11 @@ static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a,
if( b != p1 )
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_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();
}
......@@ -347,6 +356,86 @@ static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a,
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 )
{
int icost = frame->i_cost_est[0][0];
......@@ -369,8 +458,8 @@ static int scenecut( x264_t *h, x264_frame_t *frame, int pdist )
{
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 );
* ( i_gop_size - h->param.i_keyint_min )
/ ( h->param.i_keyint_max - h->param.i_keyint_min ) ;
}
res = pcost >= (1.0 - f_bias) * icost;
......@@ -389,7 +478,7 @@ static int scenecut( x264_t *h, x264_frame_t *frame, int pdist )
static void x264_slicetype_analyse( x264_t *h )
{
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 keyint_limit;
int j;
......@@ -425,42 +514,65 @@ no_b_frames:
return;
}
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;
if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS )
{
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 );
cost1p0 = x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 );
cost2p0 = x264_slicetype_frame_cost( h, &a, frames, 1, 2, 2, 0 );
// fprintf( stderr, "PP: %d + %d <=> BP: %d + %d \n",
// cost1p0, cost2p0, cost1b1, cost2p1 );
if( cost1p0 + cost2p0 < cost1b1 + cost2p1 )
goto no_b_frames;
for( j = 1; j < num_bframes+1; j++ )
{
if( h->param.b_pre_scenecut && scenecut( h, frames[j+1], 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
{
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
#define INTER_THRESH 300
#define P_SENS_BIAS (50 - h->param.i_bframe_bias)
frames[1]->i_type = X264_TYPE_B;
cost1b1 = x264_slicetype_frame_cost( h, &a, frames, 0, 2, 1, 0 );
cost1p0 = x264_slicetype_frame_cost( h, &a, frames, 0, 1, 1, 0 );
cost2p0 = x264_slicetype_frame_cost( h, &a, frames, 1, 2, 2, 0 );
for( j = 2; j <= X264_MIN( h->param.i_bframe, num_frames-1 ); j++ )
{
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 );
/* if( i_mb_count )
fprintf( stderr, "frm%d+%d: %d <=> %d, I:%d/%d \n",
frames[0]->i_frame, j-1, pthresh, pcost/i_mb_count,
frames[j+1]->i_intra_mbs[j+1], i_mb_count );
else
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 )
if( cost1p0 + cost2p0 < cost1b1 + cost2p1 )
goto no_b_frames;
// arbitrary and untuned
#define INTER_THRESH 300
#define P_SENS_BIAS (50 - h->param.i_bframe_bias)
frames[1]->i_type = X264_TYPE_B;
for( j = 2; j <= X264_MIN( h->param.i_bframe, num_frames-1 ); j++ )
{
frames[j]->i_type = X264_TYPE_P;
break;
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 );
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 )
h->frames.next[i]->i_type =
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 )
x264_slicetype_analyse( h );
......@@ -530,7 +642,7 @@ void x264_slicetype_decide( x264_t *h )
int x264_rc_analyse_slice( x264_t *h )
{
x264_mb_analysis_t a;
x264_frame_t *frames[X264_BFRAME_MAX+2] = { NULL, };
x264_frame_t *frames[X264_BFRAME_MAX*4+2] = { NULL, };
int p0=0, p1, b;
int cost;
......
......@@ -115,7 +115,7 @@ x264_param_t *x264_gtk_param_get (X264_Gtk *x264_gtk)
param->b_bframe_pyramid = x264_gtk->bframe_pyramid && x264_gtk->bframe;
param->analyse.b_bidir_me = x264_gtk->bidir_me;
param->b_bframe_adaptive = x264_gtk->bframe_adaptive;
param->i_bframe_adaptive = x264_gtk->bframe_adaptive;
param->analyse.b_weighted_bipred = x264_gtk->weighted_bipred;
param->i_bframe = x264_gtk->bframe;
param->i_bframe_bias = x264_gtk->bframe_bias;
......@@ -470,7 +470,7 @@ x264_default_load (GtkButton *button UNUSED, gpointer user_data)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (config->mb.bframes.bframe_pyramid), param.b_bframe_pyramid);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (config->mb.bframes.bidir_me), param.analyse.b_bidir_me);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (config->mb.bframes.bframe_adaptive), param.b_bframe_adaptive);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (config->mb.bframes.bframe_adaptive), param.i_bframe_adaptive);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (config->mb.bframes.weighted_bipred), param.analyse.b_weighted_bipred);
g_snprintf (buf, 64, "%d", param.i_bframe);
gtk_entry_set_text (GTK_ENTRY (config->mb.bframes.bframe), buf);
......@@ -602,7 +602,7 @@ x264_default_set (X264_Gtk *x264_gtk)
x264_gtk->bframe_pyramid = param.b_bframe_pyramid;
x264_gtk->bidir_me = param.analyse.b_bidir_me;
x264_gtk->bframe_adaptive = param.b_bframe_adaptive;
x264_gtk->bframe_adaptive = param.i_bframe_adaptive;
x264_gtk->weighted_bipred = param.analyse.b_weighted_bipred;
x264_gtk->bframe = param.i_bframe;
x264_gtk->bframe_bias = param.i_bframe_bias;
......
......@@ -169,7 +169,11 @@ static void Help( x264_param_t *defaults, int b_longhelp )
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( " --no-b-adapt Disable adaptive B-frame decision\n" );
H1( " --b-adapt Adaptive B-frame decision method [%d]\n"
" Higher values may lower threading efficiency.\n"
" - 0: Disabled\n"
" - 1: Fast\n"
" - 2: Optimal (slow with high --bframes)\n", defaults->i_bframe_adaptive );
H1( " --b-bias <integer> Influences how often B-frames are used [%d]\n", defaults->i_bframe_bias );
H0( " --b-pyramid Keep some B-frames as references\n" );
H0( " --no-cabac Disable CABAC\n" );
......@@ -379,6 +383,7 @@ static int Parse( int argc, char **argv,
{ "version", no_argument, NULL, 'V' },
{ "bitrate", required_argument, NULL, 'B' },
{ "bframes", required_argument, NULL, 'b' },
{ "b-adapt", required_argument, NULL, 0 },
{ "no-b-adapt", no_argument, NULL, 0 },
{ "b-bias", required_argument, NULL, 0 },
{ "b-pyramid", no_argument, NULL, 0 },
......@@ -544,7 +549,7 @@ static int Parse( int argc, char **argv,
return -1;
}
param->i_scenecut_threshold = -1;
param->b_bframe_adaptive = 0;
param->i_bframe_adaptive = X264_B_ADAPT_NONE;
break;
case OPT_THREAD_INPUT:
b_thread_input = 1;
......
......@@ -35,7 +35,7 @@
#include <stdarg.h>
#define X264_BUILD 62
#define X264_BUILD 63
/* x264_t:
* opaque handler for encoder */
......@@ -86,6 +86,9 @@ typedef struct x264_t x264_t;
#define X264_RC_ABR 2
#define X264_AQ_NONE 0
#define X264_AQ_VARIANCE 1
#define X264_B_ADAPT_NONE 0
#define X264_B_ADAPT_FAST 1
#define X264_B_ADAPT_TRELLIS 2
static const char * const x264_direct_pred_names[] = { "none", "spatial", "temporal", "auto", 0 };
static const char * const x264_motion_est_names[] = { "dia", "hex", "umh", "esa", "tesa", 0 };
......@@ -184,7 +187,7 @@ typedef struct x264_param_t
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 b_bframe_adaptive;
int i_bframe_adaptive;
int i_bframe_bias;
int b_bframe_pyramid; /* Keep some B-frames as references */
......
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