+void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init )
+{
+ x264_ratecontrol_t *rc = h->rc;
+ if( !b_init && rc->b_2pass )
+ return;
+
+ if( h->param.rc.i_rc_method == X264_RC_CRF )
+ {
+ /* Arbitrary rescaling to make CRF somewhat similar to QP.
+ * Try to compensate for MB-tree's effects as well. */
+ double base_cplx = h->mb.i_mb_count * (h->param.i_bframe ? 120 : 80);
+ double mbtree_offset = h->param.rc.b_mb_tree ? (1.0-h->param.rc.f_qcompress)*13.5 : 0;
+ rc->rate_factor_constant = pow( base_cplx, 1 - rc->qcompress )
+ / qp2qscale( h->param.rc.f_rf_constant + mbtree_offset );
+ }
+
+ if( h->param.rc.i_vbv_max_bitrate > 0 && h->param.rc.i_vbv_buffer_size > 0 )
+ {
+ if( h->param.rc.i_vbv_buffer_size < (int)(h->param.rc.i_vbv_max_bitrate / rc->fps) )
+ {
+ h->param.rc.i_vbv_buffer_size = h->param.rc.i_vbv_max_bitrate / rc->fps;
+ x264_log( h, X264_LOG_WARNING, "VBV buffer size cannot be smaller than one frame, using %d kbit\n",
+ h->param.rc.i_vbv_buffer_size );
+ }
+
+ /* We don't support changing the ABR bitrate right now,
+ so if the stream starts as CBR, keep it CBR. */
+ if( rc->b_vbv_min_rate )
+ h->param.rc.i_vbv_max_bitrate = h->param.rc.i_bitrate;
+
+ int vbv_buffer_size = h->param.rc.i_vbv_buffer_size * 1000;
+ int vbv_max_bitrate = h->param.rc.i_vbv_max_bitrate * 1000;
+
+ /* Init HRD */
+ h->sps->vui.hrd.i_bit_rate_unscaled = vbv_max_bitrate;
+ h->sps->vui.hrd.i_cpb_size_unscaled = vbv_buffer_size;
+ if( h->param.i_nal_hrd && b_init )
+ {
+ h->sps->vui.hrd.i_cpb_cnt = 1;
+ h->sps->vui.hrd.b_cbr_hrd = h->param.i_nal_hrd == X264_NAL_HRD_CBR;
+ h->sps->vui.hrd.i_time_offset_length = 0;
+
+ #define BR_SHIFT 6
+ #define CPB_SHIFT 4
+
+ int bitrate = 1000*h->param.rc.i_vbv_max_bitrate;
+ int bufsize = 1000*h->param.rc.i_vbv_buffer_size;
+
+ // normalize HRD size and rate to the value / scale notation
+ h->sps->vui.hrd.i_bit_rate_scale = x264_clip3( x264_ctz( bitrate ) - BR_SHIFT, 0, 15 );
+ h->sps->vui.hrd.i_bit_rate_value = bitrate >> ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT );
+ h->sps->vui.hrd.i_bit_rate_unscaled = h->sps->vui.hrd.i_bit_rate_value << ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT );
+ h->sps->vui.hrd.i_cpb_size_scale = x264_clip3( x264_ctz( bufsize ) - CPB_SHIFT, 0, 15 );
+ h->sps->vui.hrd.i_cpb_size_value = bufsize >> ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT );
+ h->sps->vui.hrd.i_cpb_size_unscaled = h->sps->vui.hrd.i_cpb_size_value << ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT );
+
+ #undef CPB_SHIFT
+ #undef BR_SHIFT
+
+ // arbitrary
+ #define MAX_DURATION 0.5
+
+ int max_cpb_output_delay = X264_MIN( h->param.i_keyint_max * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick, INT_MAX );
+ int max_dpb_output_delay = h->sps->vui.i_max_dec_frame_buffering * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick;
+ int max_delay = (int)(90000.0 * (double)h->sps->vui.hrd.i_cpb_size_unscaled / h->sps->vui.hrd.i_bit_rate_unscaled + 0.5);
+
+ h->sps->vui.hrd.i_initial_cpb_removal_delay_length = 2 + x264_clip3( 32 - x264_clz( max_delay ), 4, 22 );
+ h->sps->vui.hrd.i_cpb_removal_delay_length = x264_clip3( 32 - x264_clz( max_cpb_output_delay ), 4, 31 );
+ h->sps->vui.hrd.i_dpb_output_delay_length = x264_clip3( 32 - x264_clz( max_dpb_output_delay ), 4, 31 );
+
+ #undef MAX_DURATION
+
+ vbv_buffer_size = h->sps->vui.hrd.i_cpb_size_unscaled;
+ vbv_max_bitrate = h->sps->vui.hrd.i_bit_rate_unscaled;
+ }
+ else if( h->param.i_nal_hrd && !b_init )
+ {
+ x264_log( h, X264_LOG_WARNING, "VBV parameters cannot be changed when NAL HRD is in use\n" );
+ return;
+ }
+
+ rc->buffer_rate = vbv_max_bitrate / rc->fps;
+ rc->vbv_max_rate = vbv_max_bitrate;
+ rc->buffer_size = vbv_buffer_size;
+ rc->single_frame_vbv = rc->buffer_rate * 1.1 > rc->buffer_size;
+ rc->cbr_decay = 1.0 - rc->buffer_rate / rc->buffer_size
+ * 0.5 * X264_MAX(0, 1.5 - rc->buffer_rate * rc->fps / rc->bitrate);
+ if( h->param.rc.i_rc_method == X264_RC_CRF && h->param.rc.f_rf_constant_max )
+ {
+ rc->rate_factor_max_increment = h->param.rc.f_rf_constant_max - h->param.rc.f_rf_constant;
+ if( rc->rate_factor_max_increment <= 0 )
+ {
+ x264_log( h, X264_LOG_WARNING, "CRF max must be greater than CRF\n" );
+ rc->rate_factor_max_increment = 0;
+ }
+ }
+ if( b_init )
+ {
+ if( h->param.rc.f_vbv_buffer_init > 1. )
+ h->param.rc.f_vbv_buffer_init = x264_clip3f( h->param.rc.f_vbv_buffer_init / h->param.rc.i_vbv_buffer_size, 0, 1 );
+ h->param.rc.f_vbv_buffer_init = x264_clip3f( X264_MAX( h->param.rc.f_vbv_buffer_init, rc->buffer_rate / rc->buffer_size ), 0, 1);
+ rc->buffer_fill_final = rc->buffer_size * h->param.rc.f_vbv_buffer_init * h->sps->vui.i_time_scale;
+ rc->b_vbv = 1;
+ rc->b_vbv_min_rate = !rc->b_2pass
+ && h->param.rc.i_rc_method == X264_RC_ABR
+ && h->param.rc.i_vbv_max_bitrate <= h->param.rc.i_bitrate;
+ }
+ }
+}
+