Index: encoder/ratecontrol.h =================================================================== --- encoder/ratecontrol.h (revision 538) +++ encoder/ratecontrol.h (working copy) @@ -27,6 +27,7 @@ int x264_ratecontrol_new ( x264_t * ); void x264_ratecontrol_delete( x264_t * ); +void x264_ratecontrol_pre( x264_t * ); void x264_ratecontrol_start( x264_t *, int i_slice_type, int i_force_qp ); void x264_ratecontrol_threads_start( x264_t * ); int x264_ratecontrol_slice_type( x264_t *, int i_frame ); Index: encoder/encoder.c =================================================================== --- encoder/encoder.c (revision 538) +++ encoder/encoder.c (working copy) @@ -341,7 +341,7 @@ } #endif - if( h->param.rc.i_rc_method < 0 || h->param.rc.i_rc_method > 2 ) + if( h->param.rc.i_rc_method < 0 || h->param.rc.i_rc_method > 3 ) { x264_log( h, X264_LOG_ERROR, "invalid RC method\n" ); return -1; @@ -350,6 +350,10 @@ h->param.rc.i_qp_constant = x264_clip3( h->param.rc.i_qp_constant, 0, 51 ); if( h->param.rc.i_rc_method == X264_RC_CRF ) h->param.rc.i_qp_constant = h->param.rc.i_rf_constant; + if( h->param.rc.i_rc_method == X264_RC_RD ) + h->param.rc.i_rcrd_range = x264_clip3( h->param.rc.i_rcrd_range, 1, X264_RDRC_MAX ); + else + h->param.rc.i_rcrd_range = 0; if( (h->param.rc.i_rc_method == X264_RC_CQP || h->param.rc.i_rc_method == X264_RC_CRF) && h->param.rc.i_qp_constant == 0 ) { @@ -547,10 +551,10 @@ 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->frames.i_delay = h->param.i_bframe + h->param.rc.i_rcrd_range; 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 + 1; + h->frames.i_max_dpb = h->sps->vui.i_max_dec_frame_buffering + 1 + h->param.rc.i_rcrd_range; 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 @@ -964,7 +968,7 @@ const int i_mb_y = mb_xy / h->sps->i_mb_width; const int i_mb_x = mb_xy % h->sps->i_mb_width; - int mb_spos = bs_pos(&h->out.bs); + int mb_spos = bs_pos(&h->out.bs) + (h->cabac.f8_bits_encoded >> 8); /* load cache */ x264_macroblock_cache_load( h, i_mb_x, i_mb_y ); @@ -994,7 +998,10 @@ { if( h->sh.i_type != SLICE_TYPE_I ) x264_cabac_mb_skip( h, 0 ); - x264_macroblock_write_cabac( h, &h->cabac ); + if( h->param.b_write_bitstream ) + x264_macroblock_write_cabac( h, &h->cabac ); + else + x264_macroblock_size_cabac( h, &h->cabac ); } } else @@ -1047,7 +1054,7 @@ } if( h->mb.b_variable_qp ) - x264_ratecontrol_mb(h, bs_pos(&h->out.bs) - mb_spos); + x264_ratecontrol_mb(h, bs_pos(&h->out.bs) + (h->cabac.f8_bits_encoded >> 8) - mb_spos); } if( h->param.b_cabac ) @@ -1080,13 +1087,14 @@ - h->stat.frame.i_ptex_bits - h->stat.frame.i_hdr_bits; + if( !h->param.b_write_bitstream ) + h->stat.frame.i_ptex_bits += (h->cabac.f8_bits_encoded + 128) >> 8; + return 0; } static inline int x264_slices_write( x264_t *h ) { - int i_frame_size; - #if VISUALIZE if( h->param.b_visualize ) x264_visualize_init( h ); @@ -1096,7 +1104,6 @@ { x264_ratecontrol_threads_start( h ); x264_slice_write( h ); - i_frame_size = h->out.nal[h->out.i_nal-1].i_payload; } else { @@ -1135,13 +1142,11 @@ #endif /* merge contexts */ - i_frame_size = h->out.nal[i_nal].i_payload; for( i = 1; i < h->param.i_threads; i++ ) { int j; x264_t *t = h->thread[i]; h->out.nal[i_nal+i] = t->out.nal[i_nal+i]; - i_frame_size += t->out.nal[i_nal+i].i_payload; // all entries in stat.frame are ints for( j = 0; j < sizeof(h->stat.frame) / sizeof(int); j++ ) ((int*)&h->stat.frame)[j] += ((int*)&t->stat.frame)[j]; @@ -1157,7 +1162,10 @@ } #endif - return i_frame_size; + return ( h->stat.frame.i_hdr_bits + + h->stat.frame.i_itex_bits + + h->stat.frame.i_ptex_bits + + h->stat.frame.i_misc_bits + 7 ) >> 3; } /**************************************************************************** @@ -1189,10 +1197,16 @@ int i_global_qp; char psz_message[80]; + x264_picture_t dummy_pic_out; /* no data out */ - *pi_nal = 0; - *pp_nal = NULL; + if( pp_nal && pi_nal ) + { + *pi_nal = 0; + *pp_nal = NULL; + } + if( !pic_out ) + pic_out = &dummy_pic_out; /* ------------------- Setup new frame from picture -------------------- */ @@ -1223,6 +1237,8 @@ } } + x264_ratecontrol_pre( h ); + if( h->frames.current[0] == NULL ) { int bframes = 0; @@ -1487,8 +1503,11 @@ } /* End bitstream, set output */ - *pi_nal = h->out.i_nal; - *pp_nal = h->out.nal; + if( pp_nal && pi_nal ) + { + *pi_nal = h->out.i_nal; + *pp_nal = h->out.nal; + } /* Set output picture properties */ if( i_slice_type == SLICE_TYPE_I ) @@ -1533,7 +1552,7 @@ /* ---------------------- Compute/Print statistics --------------------- */ /* Slice stat */ h->stat.i_slice_count[i_slice_type]++; - h->stat.i_slice_size[i_slice_type] += i_frame_size + NALU_OVERHEAD; + h->stat.i_slice_size[i_slice_type] += i_frame_size + NALU_OVERHEAD * h->param.i_threads; h->stat.i_slice_qp[i_slice_type] += i_global_qp; for( i = 0; i < 19; i++ ) Index: encoder/macroblock.h =================================================================== --- encoder/macroblock.h (revision 538) +++ encoder/macroblock.h (working copy) @@ -38,6 +38,8 @@ void x264_macroblock_encode ( x264_t *h ); void x264_macroblock_write_cabac ( x264_t *h, x264_cabac_t *cb ); void x264_macroblock_write_cavlc ( x264_t *h, bs_t *s ); +void x264_macroblock_size_cabac ( x264_t *h, x264_cabac_t *cb ); +void x264_macroblock_size_cavlc ( x264_t *h, bs_t *s ); void x264_macroblock_encode_p8x8( x264_t *h, int i8 ); Index: encoder/ratecontrol.c =================================================================== --- encoder/ratecontrol.c (revision 538) +++ encoder/ratecontrol.c (working copy) @@ -120,6 +120,7 @@ double rate_factor_constant; double ip_offset; double pb_offset; + double qp_type_offset[6]; /* 2pass stuff */ FILE *p_stat_file_out; @@ -150,14 +151,20 @@ int bframes; /* # consecutive B-frames before this P-frame */ int bframe_bits; /* total cost of those frames */ + /* RCRD stuff */ + x264_t *h_bak; /* backup from before processing the current frame */ + int rcrd_prev_dir[5]; + predictor_t rcrd_qp_offset[5]; + int i_zones; x264_zone_t *zones; }; static int parse_zones( x264_t *h ); -static int init_pass2(x264_t *); +static int init_pass2( x264_t *h ); static float rate_estimate_qscale( x264_t *h, int pict_type ); +static int rcrd_get_qp( x264_t *h ); static void update_vbv( x264_t *h, int bits ); static double predict_size( predictor_t *p, double q, double var ); static void update_predictor( predictor_t *p, double q, double var, double bits ); @@ -175,6 +182,10 @@ { return 12.0 + 6.0 * log(qscale/0.85) / log(2.0); } +static inline int qscale2iqp(double qscale) +{ + return x264_clip3( qscale2qp(qscale) + 0.5, 0, 51 ); +} /* Texture bitrate is not quite inversely proportional to qscale, * probably due the the changing number of SKIP blocks. @@ -220,6 +231,16 @@ x264_log(h, X264_LOG_ERROR, "constant rate-factor is incompatible with 2pass.\n"); return -1; } + if( h->param.rc.i_rc_method == X264_RC_RD && !h->param.rc.b_stat_read ) + { + x264_log(h, X264_LOG_ERROR, "rcrd requires 2pass.\n"); + return -1; + } + if( h->param.rc.i_rc_method == X264_RC_RD && h->param.rc.f_rcrd_lambda <= 0 ) + { + x264_log(h, X264_LOG_ERROR, "rcrd-lambda must be > 0.\n"); + return -1; + } if( h->param.rc.i_vbv_buffer_size ) { if( h->param.rc.i_rc_method == X264_RC_CQP ) @@ -281,6 +302,11 @@ rc->qp_constant[SLICE_TYPE_P] = h->param.rc.i_qp_constant; rc->qp_constant[SLICE_TYPE_I] = x264_clip3( h->param.rc.i_qp_constant - rc->ip_offset + 0.5, 0, 51 ); rc->qp_constant[SLICE_TYPE_B] = x264_clip3( h->param.rc.i_qp_constant + rc->pb_offset + 0.5, 0, 51 ); + rc->qp_type_offset[X264_TYPE_IDR] = rc->ip_offset; + rc->qp_type_offset[X264_TYPE_I] = rc->ip_offset; + rc->qp_type_offset[X264_TYPE_B] = rc->pb_offset; + rc->qp_type_offset[X264_TYPE_BREF] = rc->pb_offset / 2; + rc->qp_type_offset[X264_TYPE_P] = 0; rc->lstep = exp2f(h->param.rc.i_qp_step / 6.0); rc->last_qscale = qp2qscale(26); @@ -295,6 +321,9 @@ rc->row_preds[i].coeff= .25; rc->row_preds[i].count= 1.0; rc->row_preds[i].decay= 0.5; + rc->rcrd_qp_offset[i].coeff= 0.0; + rc->rcrd_qp_offset[i].count= 1.0; + rc->rcrd_qp_offset[i].decay= 0.75; } rc->pred_b_from_p = rc->pred[0]; @@ -463,6 +492,11 @@ x264_free( p ); } + if( h->param.rc.i_rc_method == X264_RC_RD ) + { + rc->h_bak = x264_malloc( sizeof(x264_t) ); + } + return 0; } @@ -523,6 +557,18 @@ return 0; } +static x264_zone_t *get_zone( x264_ratecontrol_t *rc, int i_frame ) +{ + int i; + for( i = rc->i_zones-1; i >= 0; i-- ) + { + x264_zone_t *z = &rc->zones[i]; + if( i_frame >= z->i_start && i_frame <= z->i_end ) + return z; + } + return NULL; +} + void x264_ratecontrol_summary( x264_t *h ) { x264_ratecontrol_t *rc = h->rc; @@ -552,6 +598,7 @@ } x264_free( rc->entry ); x264_free( rc->zones ); + x264_free( rc->h_bak ); x264_free( rc ); } @@ -599,16 +646,19 @@ { rc->qpm = rc->qp = i_force_qp - 1; } + else if( h->param.rc.i_rc_method == X264_RC_RD ) + { + rc->qpm = rc->qp = rcrd_get_qp( h ); + rc->slice_type = i_slice_type; // got clobbered by the trial encodes + } else if( rc->b_abr ) { - rc->qpm = rc->qp = - x264_clip3( (int)(qscale2qp( rate_estimate_qscale( h, i_slice_type ) ) + .5), 0, 51 ); + rc->qpm = rc->qp = qscale2iqp( rate_estimate_qscale( h, i_slice_type ) ); } else if( rc->b_2pass ) { rce->new_qscale = rate_estimate_qscale( h, i_slice_type ); - rc->qpm = rc->qp = rce->new_qp = - x264_clip3( (int)(qscale2qp(rce->new_qscale) + 0.5), 0, 51 ); + rc->qpm = rc->qp = rce->new_qp = qscale2iqp( rce->new_qscale ); } else /* CQP */ { @@ -731,8 +781,8 @@ h->param.rc.i_qp_constant = (h->stat.i_slice_count[SLICE_TYPE_P] == 0) ? 24 : 1 + h->stat.i_slice_qp[SLICE_TYPE_P] / h->stat.i_slice_count[SLICE_TYPE_P]; rc->qp_constant[SLICE_TYPE_P] = x264_clip3( h->param.rc.i_qp_constant, 0, 51 ); - rc->qp_constant[SLICE_TYPE_I] = x264_clip3( (int)( qscale2qp( qp2qscale( h->param.rc.i_qp_constant ) / fabs( h->param.rc.f_ip_factor )) + 0.5 ), 0, 51 ); - rc->qp_constant[SLICE_TYPE_B] = x264_clip3( (int)( qscale2qp( qp2qscale( h->param.rc.i_qp_constant ) * fabs( h->param.rc.f_pb_factor )) + 0.5 ), 0, 51 ); + rc->qp_constant[SLICE_TYPE_I] = qscale2iqp( qp2qscale( h->param.rc.i_qp_constant ) / fabs( h->param.rc.f_ip_factor ) ); + rc->qp_constant[SLICE_TYPE_B] = qscale2iqp( qp2qscale( h->param.rc.i_qp_constant ) * fabs( h->param.rc.f_pb_factor ) ); 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); @@ -883,8 +933,8 @@ { x264_ratecontrol_t *rcc= h->rc; const int pict_type = rce->pict_type; + x264_zone_t *z; double q; - int i; double const_values[]={ rce->i_tex_bits * rce->qscale, @@ -948,17 +998,13 @@ rcc->last_qscale = q; } - for( i = rcc->i_zones-1; i >= 0; i-- ) + z = get_zone( rcc, frame_num ); + if( z ) { - x264_zone_t *z = &rcc->zones[i]; - if( frame_num >= z->i_start && frame_num <= z->i_end ) - { - if( z->b_force_qp ) - q = qp2qscale(z->i_qp); - else - q /= z->f_bitrate_factor; - break; - } + if( z->b_force_qp ) + q = qp2qscale(z->i_qp); + else + q /= z->f_bitrate_factor; } return q; @@ -1504,4 +1550,149 @@ return 0; } +void x264_ratecontrol_pre( x264_t *h ) +{ + if( h->param.rc.i_rc_method == X264_RC_RD ) + *h->rc->h_bak = *h; +} +static void rcrd_set_options( x264_t *t ) +{ + x264_param_t *p = &t->param; + + p->rc.i_rc_method = X264_RC_CQP; + p->rc.b_stat_write = 0; + p->b_write_bitstream = 0; + p->i_log_level = X264_MIN( X264_LOG_ERROR, p->i_log_level ); + t->mb.b_direct_auto_write = 0; + + p->analyse.inter &= ~X264_ANALYSE_PSUB8x8; + p->analyse.i_me_method = X264_ME_DIA; + p->analyse.i_subpel_refine = X264_MIN( 3, p->analyse.i_subpel_refine ); + p->analyse.i_trellis = 0; + p->analyse.b_bidir_me = 0; + p->analyse.b_fast_pskip = 1; + p->analyse.b_mixed_references = 0; + p->analyse.b_transform_8x8 = 0; + t->frames.i_max_ref0 = + p->i_frame_reference = X264_MIN( 2, p->i_frame_reference ); +} + +static float rcrd_try_encode( x264_t *h, x264_t *t, int qp, float lambda ) +{ + /* TODO + * adapt range based on number of B-frames or % intra blocks? + * try a larger search range for I-frames? + * try stopping at all I-frames, not just IDR? + * use rcrd_qp_offset[] for the dependent frames too? + * use different lambda for B-frames? + * decide which dependent frames to code? e.g. this + next P + 2 nearest Bs, instead of just the next N frames in encode order. + * reuse motion vectors between candidate encodes? loses too much quality. just init the motion search? + * map lambda onto some intuitive scale, like crf. + * plug lambda into the normal ratecontrol algo, to allow target bitrate. + */ + float rd; + int i; + int range = (h->fenc->i_type == X264_TYPE_B) ? 1 : h->param.rc.i_rcrd_range; + + if( qp < 0 || qp > 51 ) + return 1e30; + + *t = *h->rc->h_bak; + h->fenc->i_qpplus1 = qp + 1; + for( i = 0; i < range; i++ ) + { + int next_type; + x264_encoder_encode( t, NULL, NULL, NULL, NULL ); + next_type = t->frames.current[0] ? t->frames.current[0]->i_type : + t->frames.next[0] ? t->frames.next[0]->i_type : -1; + if( next_type == X264_TYPE_IDR ) + break; + } + + rd = 0; + for( i = 0; i < 5; i++ ) + rd += t->stat.i_sqe_global[i] + t->stat.i_slice_size[i] * lambda; + return rd; +} + +static int rcrd_get_qp( x264_t *h ) +{ + x264_ratecontrol_t *rcc = h->rc; + x264_frame_t **fp; + x264_zone_t *z; + x264_t t; + int base_qp, best_qp, pred_qp; + float best_rd; + int i, dir; + int *p_dir; + float lambda = h->param.rc.f_rcrd_lambda; + + z = get_zone( rcc, h->fenc->i_frame ); + if( z ) + { + if( z->b_force_qp ) + return x264_clip3( z->i_qp + rcc->qp_type_offset[h->fenc->i_type] + .5, 0, 51 ); + else + lambda *= pow( z->f_bitrate_factor, -1.5 ); + } + + /* assume the following frames use the same qp as they did in the previous pass */ + for( fp = h->frames.current; *fp; fp++ ) + (*fp)->i_qpplus1 = qscale2iqp( rcc->entry[(*fp)->i_frame].qscale ) + 1; + for( fp = h->frames.next; *fp; fp++ ) + (*fp)->i_qpplus1 = qscale2iqp( rcc->entry[(*fp)->i_frame].qscale ) + 1; + + rcrd_set_options( rcc->h_bak ); + memset( rcc->h_bak->stat.i_slice_size, 0, sizeof(rcc->h_bak->stat.i_slice_size) ); + memset( rcc->h_bak->stat.i_sqe_global, 0, sizeof(rcc->h_bak->stat.i_sqe_global) ); + + /* predict the qp of the current frame based on how much we have + * changed the qps of other frames of the same type. + * but limit the prediction, because otherwise there's feedback. */ + base_qp = qscale2iqp( rcc->rce->qscale ); + pred_qp = base_qp + x264_clip3( predict_size( &rcc->rcrd_qp_offset[h->fenc->i_type-1], 1, 1 ) + .5, -1, 1 ); + best_qp = pred_qp; + best_rd = rcrd_try_encode( h, &t, pred_qp, lambda ); + + /* not sure if this is actually better/faster than just searching one direction first always */ + p_dir = &rcc->rcrd_prev_dir[h->fenc->i_type-1]; + if( *p_dir == 0 ) + *p_dir = 1; + dir = *p_dir; + for( i = 1; i < 20; i++ ) + { + int qp = pred_qp + i*dir; + float rd = rcrd_try_encode( h, &t, qp, lambda ); + if( best_rd > rd ) + { + best_rd = rd; + best_qp = qp; + *p_dir = dir; + } + else if( i == 1 && dir == *p_dir ) + { + dir = -dir; + i = 0; + } + else + break; + } + + update_predictor( &rcc->rcrd_qp_offset[h->fenc->i_type-1], 1, 1, best_qp - base_qp ); + + for( fp = h->frames.current; *fp; fp++ ) + (*fp)->i_qpplus1 = 0; + for( fp = h->frames.next; *fp; fp++ ) + (*fp)->i_qpplus1 = 0; + h->fenc->i_qpplus1 = 0; + + for( fp = h->frames.reference; *fp; fp++ ) + { + if( (*fp)->i_frame_num > h->fdec->i_frame_num ) + (*fp)->i_poc = -1; + } + + return best_qp; +} + Index: x264.c =================================================================== --- x264.c (revision 538) +++ x264.c (working copy) @@ -169,6 +169,8 @@ " --qpmax Set max QP [%d]\n" " --qpstep Set max QP step [%d]\n" " --ratetol Allowed variance of average bitrate [%.1f]\n" + " --rcrd-lambda Enable RD ratecontrol, and select quality [%.1f]\n" + " --rcrd-range RD search range [%d]\n" " --vbv-maxrate Max local bitrate [%d]\n" " --vbv-bufsize Size of VBV buffer [%d]\n" " --vbv-init Initial VBV buffer occupancy [%.1f]\n" @@ -304,6 +306,8 @@ defaults->rc.i_qp_max, defaults->rc.i_qp_step, defaults->rc.f_rate_tolerance, + defaults->rc.f_rcrd_lambda, + defaults->rc.i_rcrd_range, defaults->rc.i_vbv_max_bitrate, defaults->rc.i_vbv_buffer_size, defaults->rc.f_vbv_buffer_init, @@ -455,6 +459,8 @@ #define OPT_NO_DCT_DECIMATE 321 #define OPT_SPS_ID 322 #define OPT_QPFILE 323 +#define OPT_RDRC_RANGE 324 +#define OPT_RDRC_LAMBDA 325 static struct option long_options[] = { @@ -475,6 +481,8 @@ { "qpmax", required_argument, NULL, OPT_QPMAX }, { "qpstep", required_argument, NULL, OPT_QPSTEP }, { "crf", required_argument, NULL, OPT_CRF }, + { "rcrd-range", required_argument, NULL, OPT_RDRC_RANGE }, + { "rcrd-lambda", required_argument, NULL, OPT_RDRC_LAMBDA }, { "ref", required_argument, NULL, 'r' }, { "no-asm", no_argument, NULL, 'C' }, { "sar", required_argument, NULL, OPT_SAR }, @@ -570,6 +578,13 @@ param->rc.i_rf_constant = atol( optarg ); param->rc.i_rc_method = X264_RC_CRF; break; + case OPT_RDRC_RANGE: + param->rc.i_rcrd_range = atol( optarg ); + break; + case OPT_RDRC_LAMBDA: + param->rc.f_rcrd_lambda = atof( optarg ); + param->rc.i_rc_method = X264_RC_RD; + break; case 'b': param->i_bframe = atol( optarg ); break; Index: common/common.c =================================================================== --- common/common.c (revision 538) +++ common/common.c (working copy) @@ -93,6 +93,8 @@ param->rc.i_qp_step = 4; param->rc.f_ip_factor = 1.4; param->rc.f_pb_factor = 1.3; + param->rc.i_rcrd_range = 4; + param->rc.f_rcrd_lambda = 0.0; param->rc.b_stat_write = 0; param->rc.psz_stat_out = "x264_2pass.log"; @@ -132,6 +134,7 @@ memset( param->cqm_8iy, 16, 64 ); memset( param->cqm_8py, 16, 64 ); + param->b_write_bitstream = 1; param->b_repeat_headers = 1; param->b_aud = 0; } @@ -494,9 +497,10 @@ 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" ) - : p->rc.i_rc_method == X264_RC_CRF ? "crf" : "cqp" ); + s += sprintf( s, " rc=%s", p->rc.i_rc_method == X264_RC_RD ? "rd" : + p->rc.i_rc_method == X264_RC_ABR ? + ( p->rc.b_stat_read ? "2pass" : p->rc.i_vbv_buffer_size ? "cbr" : "abr" ) : + p->rc.i_rc_method == X264_RC_CRF ? "crf" : "cqp" ); if( p->rc.i_rc_method == X264_RC_ABR || p->rc.i_rc_method == X264_RC_CRF ) { if( p->rc.i_rc_method == X264_RC_CRF ) @@ -514,6 +518,9 @@ s += sprintf( s, " vbv_maxrate=%d vbv_bufsize=%d", p->rc.i_vbv_max_bitrate, p->rc.i_vbv_buffer_size ); } + else if( p->rc.i_rc_method == X264_RC_RD ) + s += sprintf( s, " rc_range=%d rc_lambda=%.2f", + p->rc.i_rcrd_range, p->rc.f_rcrd_lambda ); else if( p->rc.i_rc_method == X264_RC_CQP ) s += sprintf( s, " qp=%d", p->rc.i_qp_constant ); if( !(p->rc.i_rc_method == X264_RC_CQP && p->rc.i_qp_constant == 0) ) Index: common/cabac.c =================================================================== --- common/cabac.c (revision 538) +++ common/cabac.c (working copy) @@ -908,6 +908,7 @@ cb->i_low = 0; cb->i_range = 0x01FE; cb->i_bits_outstanding = 0; + cb->f8_bits_encoded = 0; cb->s = s; s->i_left++; // the first bit will be shifted away and not written } Index: common/common.h =================================================================== --- common/common.h (revision 538) +++ common/common.h (working copy) @@ -90,6 +90,7 @@ #define X264_BFRAME_MAX 16 #define X264_SLICE_MAX 4 #define X264_NAL_MAX (4 + X264_SLICE_MAX) +#define X264_RDRC_MAX 32 /**************************************************************************** * Includes @@ -317,14 +318,14 @@ /* Frames to be encoded (whose types have been decided) */ x264_frame_t *current[X264_BFRAME_MAX+3]; /* Temporary buffer (frames types not yet decided) */ - x264_frame_t *next[X264_BFRAME_MAX+3]; + x264_frame_t *next[X264_BFRAME_MAX+X264_RDRC_MAX+3]; /* Unused frames */ - x264_frame_t *unused[X264_BFRAME_MAX+3]; + x264_frame_t *unused[X264_BFRAME_MAX+X264_RDRC_MAX+3]; /* For adaptive B decision */ x264_frame_t *last_nonb; /* frames used for reference +1 for decoding + sentinels */ - x264_frame_t *reference[16+2+1+2]; + x264_frame_t *reference[16+2+1+2+X264_RDRC_MAX]; int i_last_idr; /* Frame number of the last IDR */ @@ -345,9 +346,9 @@ /* references lists */ int i_ref0; - x264_frame_t *fref0[16+3]; /* ref list 0 */ + x264_frame_t *fref0[16+3+X264_RDRC_MAX]; /* ref list 0 */ int i_ref1; - x264_frame_t *fref1[16+3]; /* ref list 1 */ + x264_frame_t *fref1[16+3+X264_RDRC_MAX]; /* ref list 1 */ int b_ref_reorder[2]; Index: x264.h =================================================================== --- x264.h (revision 538) +++ x264.h (working copy) @@ -35,7 +35,7 @@ #include -#define X264_BUILD 48 +#define X264_BUILD 49 /* x264_t: * opaque handler for decoder and encoder */ @@ -76,6 +76,7 @@ #define X264_RC_CQP 0 #define X264_RC_CRF 1 #define X264_RC_ABR 2 +#define X264_RC_RD 3 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", 0 }; @@ -232,6 +233,9 @@ float f_ip_factor; float f_pb_factor; + int i_rcrd_range; + float f_rcrd_lambda; + /* 2pass */ int b_stat_write; /* Enable stat writing in psz_stat_out */ char *psz_stat_out; @@ -249,6 +253,8 @@ } rc; /* Muxing parameters */ + int b_write_bitstream; /* if not set, then x264 will only analyse, not generate an output file. + * doesn't yet work for normal 1st pass; internal use only. */ int b_aud; /* generate access unit delimiters */ int b_repeat_headers; /* put SPS/PPS before each keyframe */ int i_sps_id; /* SPS and PPS id number */