[x264-devel] [RFC PATCH 1/1] encoder: decouple VUI timing signaling from internal RC/HRD timebase
Alex Konovalov
alexcon314 at gmail.com
Fri Jul 10 12:29:52 UTC 2026
From: alexcon <a.konovalov at erlyvideo.org>
---
encoder/ratecontrol.c | 38 +++++++++++++++++++-------------------
encoder/set.c | 6 +++---
encoder/slicetype.c | 14 +++++++-------
3 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c
index 109ba8ff..d1661cc5 100644
--- a/encoder/ratecontrol.c
+++ b/encoder/ratecontrol.c
@@ -732,7 +732,7 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init )
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_fill_final_min = rc->buffer_size * h->param.rc.f_vbv_buffer_init * h->sps->vui.i_time_scale;
+ rc->buffer_fill_final_min = rc->buffer_size * h->param.rc.f_vbv_buffer_init * (h->param.i_timebase_den * 2);
rc->b_vbv = 1;
rc->b_vbv_min_rate = !rc->b_2pass
&& h->param.rc.i_rc_method == X264_RC_ABR
@@ -1458,7 +1458,7 @@ void x264_ratecontrol_start( x264_t *h, int i_force_qp, int overhead )
memset( h->fdec->f_row_qp, 0, h->mb.i_mb_height * sizeof(float) );
memset( h->fdec->f_row_qscale, 0, h->mb.i_mb_height * sizeof(float) );
rc->row_pred = rc->row_preds[h->sh.i_type];
- rc->buffer_rate = h->fenc->i_cpb_duration * rc->vbv_max_rate * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
+ rc->buffer_rate = h->fenc->i_cpb_duration * rc->vbv_max_rate * h->param.i_timebase_num / (h->param.i_timebase_den * 2);
update_vbv_plan( h, overhead );
const x264_level_t *l = x264_levels;
@@ -1486,7 +1486,7 @@ void x264_ratecontrol_start( x264_t *h, int i_force_qp, int overhead )
else
{
//384 * MaxMBPS * ( tr( n ) - tr( n - 1 ) ) / MinCR
- rc->frame_size_maximum = 384 * BIT_DEPTH * ((double)h->fenc->i_cpb_duration * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale) * l->mbps / mincr;
+ rc->frame_size_maximum = 384 * BIT_DEPTH * ((double)h->fenc->i_cpb_duration * h->param.i_timebase_num / (h->param.i_timebase_den * 2)) * l->mbps / mincr;
}
}
}
@@ -1960,7 +1960,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler )
else
{
h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (double)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) *
- h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
+ h->param.i_timebase_num / (h->param.i_timebase_den * 2);
if( h->fenc->b_keyframe )
{
@@ -1983,7 +1983,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler )
h->fenc->hrd_timing.cpb_final_arrival_time = rc->previous_cpb_final_arrival_time = h->fenc->hrd_timing.cpb_initial_arrival_time +
(double)(bits + filler_bits) / h->sps->vui.hrd.i_bit_rate_unscaled;
- h->fenc->hrd_timing.dpb_output_time = (double)h->fenc->i_dpb_output_delay * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale +
+ h->fenc->hrd_timing.dpb_output_time = (double)h->fenc->i_dpb_output_delay * h->param.i_timebase_num / (h->param.i_timebase_den * 2) +
h->fenc->hrd_timing.cpb_removal_time;
}
@@ -2007,7 +2007,7 @@ static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor
double q;
if( h->param.rc.b_mb_tree )
{
- double timescale = (double)h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
+ double timescale = (double)h->param.i_timebase_num / (h->param.i_timebase_den * 2);
q = pow( BASE_FRAME_DURATION / CLIP_DURATION(rce->i_duration * timescale), 1 - h->param.rc.f_qcompress );
}
else
@@ -2140,7 +2140,7 @@ static int update_vbv( x264_t *h, int bits )
int bitrate = h->sps->vui.hrd.i_bit_rate_unscaled;
x264_ratecontrol_t *rcc = h->rc;
x264_ratecontrol_t *rct = h->thread[0]->rc;
- int64_t buffer_size = (int64_t)h->sps->vui.hrd.i_cpb_size_unscaled * h->sps->vui.i_time_scale;
+ int64_t buffer_size = (int64_t)h->sps->vui.hrd.i_cpb_size_unscaled * (h->param.i_timebase_den * 2);
if( rcc->last_satd >= h->mb.i_mb_count )
update_predictor( &rct->pred[h->sh.i_type], qp2qscale( rcc->qpa_rc ), rcc->last_satd, bits );
@@ -2148,13 +2148,13 @@ static int update_vbv( x264_t *h, int bits )
if( !rcc->b_vbv )
return filler;
- uint64_t buffer_diff = (uint64_t)bits * h->sps->vui.i_time_scale;
+ uint64_t buffer_diff = (uint64_t)bits * (h->param.i_timebase_den * 2);
rct->buffer_fill_final -= buffer_diff;
rct->buffer_fill_final_min -= buffer_diff;
if( rct->buffer_fill_final_min < 0 )
{
- double underflow = (double)rct->buffer_fill_final_min / h->sps->vui.i_time_scale;
+ double underflow = (double)rct->buffer_fill_final_min / (h->param.i_timebase_den * 2);
if( rcc->rate_factor_max_increment && rcc->qpm >= rcc->qp_novbv + rcc->rate_factor_max_increment )
x264_log( h, X264_LOG_DEBUG, "VBV underflow due to CRF-max (frame %d, %.0f bits)\n", h->i_frame, underflow );
else
@@ -2166,7 +2166,7 @@ static int update_vbv( x264_t *h, int bits )
if( h->param.i_avcintra_class )
buffer_diff = buffer_size;
else
- buffer_diff = (uint64_t)bitrate * h->sps->vui.i_num_units_in_tick * h->fenc->i_cpb_duration;
+ buffer_diff = (uint64_t)bitrate * h->param.i_timebase_num * h->fenc->i_cpb_duration;
rct->buffer_fill_final += buffer_diff;
rct->buffer_fill_final_min += buffer_diff;
@@ -2174,10 +2174,10 @@ static int update_vbv( x264_t *h, int bits )
{
if( h->param.rc.b_filler )
{
- int64_t scale = (int64_t)h->sps->vui.i_time_scale * 8;
+ int64_t scale = (int64_t)(h->param.i_timebase_den * 2) * 8;
filler = (rct->buffer_fill_final - buffer_size + scale - 1) / scale;
bits = h->param.i_avcintra_class ? filler * 8 : X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), filler ) * 8;
- buffer_diff = (uint64_t)bits * h->sps->vui.i_time_scale;
+ buffer_diff = (uint64_t)bits * (h->param.i_timebase_den * 2);
rct->buffer_fill_final -= buffer_diff;
rct->buffer_fill_final_min -= buffer_diff;
}
@@ -2194,16 +2194,16 @@ static int update_vbv( x264_t *h, int bits )
void x264_hrd_fullness( x264_t *h )
{
x264_ratecontrol_t *rct = h->thread[0]->rc;
- uint64_t denom = (uint64_t)h->sps->vui.hrd.i_bit_rate_unscaled * h->sps->vui.i_time_scale / rct->hrd_multiply_denom;
+ uint64_t denom = (uint64_t)h->sps->vui.hrd.i_bit_rate_unscaled * (h->param.i_timebase_den * 2) / rct->hrd_multiply_denom;
uint64_t cpb_state = rct->buffer_fill_final;
- uint64_t cpb_size = (uint64_t)h->sps->vui.hrd.i_cpb_size_unscaled * h->sps->vui.i_time_scale;
+ uint64_t cpb_size = (uint64_t)h->sps->vui.hrd.i_cpb_size_unscaled * (h->param.i_timebase_den * 2);
uint64_t multiply_factor = 90000 / rct->hrd_multiply_denom;
if( rct->buffer_fill_final < 0 || rct->buffer_fill_final > (int64_t)cpb_size )
{
x264_log( h, X264_LOG_WARNING, "CPB %s: %.0f bits in a %.0f-bit buffer\n",
rct->buffer_fill_final < 0 ? "underflow" : "overflow",
- (double)rct->buffer_fill_final / h->sps->vui.i_time_scale, (double)cpb_size / h->sps->vui.i_time_scale );
+ (double)rct->buffer_fill_final / (h->param.i_timebase_den * 2), (double)cpb_size / (h->param.i_timebase_den * 2) );
}
h->initial_cpb_removal_delay = (multiply_factor * cpb_state) / denom;
@@ -2217,7 +2217,7 @@ void x264_hrd_fullness( x264_t *h )
static void update_vbv_plan( x264_t *h, int overhead )
{
x264_ratecontrol_t *rcc = h->rc;
- rcc->buffer_fill = h->thread[0]->rc->buffer_fill_final_min / h->sps->vui.i_time_scale;
+ rcc->buffer_fill = h->thread[0]->rc->buffer_fill_final_min / (h->param.i_timebase_den * 2);
if( h->i_thread_frames > 1 )
{
int j = rcc - h->thread[0]->rc;
@@ -2273,7 +2273,7 @@ static double vbv_pass1( x264_t *h, int pict_type, double q )
{
double q0 = q;
double fenc_cpb_duration = (double)h->fenc->i_cpb_duration *
- h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
+ h->param.i_timebase_num / (h->param.i_timebase_den * 2);
/* Lookahead VBV: raise the quantizer as necessary such that no frames in
* the lookahead overflow and such that the buffer is in a reasonable state
* by the end of the lookahead. */
@@ -2815,7 +2815,7 @@ static int find_underflow( x264_t *h, double *fills, int *t0, int *t1, int over
int start = -1, end = -1;
for( int i = *t0; i < rcc->num_entries; i++ )
{
- fill += (rcc->entry_out[i]->i_cpb_duration * rcc->vbv_max_rate * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale -
+ fill += (rcc->entry_out[i]->i_cpb_duration * rcc->vbv_max_rate * h->param.i_timebase_num / (h->param.i_timebase_den * 2) -
qscale2bits( rcc->entry_out[i], rcc->entry_out[i]->new_qscale )) * parity;
fill = x264_clip3f(fill, 0, rcc->buffer_size);
fills[i] = fill;
@@ -2933,7 +2933,7 @@ static int init_pass2( x264_t *h )
{
x264_ratecontrol_t *rcc = h->rc;
uint64_t all_const_bits = 0;
- double timescale = (double)h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
+ double timescale = (double)h->param.i_timebase_num / (h->param.i_timebase_den * 2);
double duration = 0;
for( int i = 0; i < rcc->num_entries; i++ )
duration += rcc->entry[i].i_duration;
diff --git a/encoder/set.c b/encoder/set.c
index 70c67aee..e5909077 100644
--- a/encoder/set.c
+++ b/encoder/set.c
@@ -216,12 +216,12 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param )
sps->vui.i_chroma_loc_bottom = param->vui.i_chroma_loc;
}
- sps->vui.b_timing_info_present = param->i_timebase_num > 0 && param->i_timebase_den > 0;
+ sps->vui.b_timing_info_present = param->i_fps_num > 0 && param->i_fps_den > 0;
if( sps->vui.b_timing_info_present )
{
- sps->vui.i_num_units_in_tick = param->i_timebase_num;
- sps->vui.i_time_scale = param->i_timebase_den * 2;
+ sps->vui.i_num_units_in_tick = param->i_fps_den;
+ sps->vui.i_time_scale = param->i_fps_num * 2;
sps->vui.b_fixed_frame_rate = !param->b_vfr_input;
}
diff --git a/encoder/slicetype.c b/encoder/slicetype.c
index 278a8fde..88b07c43 100644
--- a/encoder/slicetype.c
+++ b/encoder/slicetype.c
@@ -1251,10 +1251,10 @@ static void vbv_lookahead( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **fram
if( prev_frame )
{
frames[next_nonb]->f_planned_cpb_duration[prev_frame_idx] = (double)prev_frame->i_cpb_duration *
- h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
+ h->param.i_timebase_num / (h->param.i_timebase_den * 2);
}
frames[next_nonb]->f_planned_cpb_duration[idx] = (double)frames[cur_nonb]->i_cpb_duration *
- h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
+ h->param.i_timebase_num / (h->param.i_timebase_den * 2);
prev_frame = frames[cur_nonb];
prev_frame_idx = idx;
idx++;
@@ -1270,10 +1270,10 @@ static void vbv_lookahead( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **fram
if( prev_frame )
{
frames[next_nonb]->f_planned_cpb_duration[prev_frame_idx] = (double)prev_frame->i_cpb_duration *
- h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
+ h->param.i_timebase_num / (h->param.i_timebase_den * 2);
}
frames[next_nonb]->f_planned_cpb_duration[idx] = (double)frames[i]->i_cpb_duration *
- h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
+ h->param.i_timebase_num / (h->param.i_timebase_den * 2);
prev_frame = frames[i];
prev_frame_idx = idx;
}
@@ -1767,8 +1767,8 @@ void x264_slicetype_decide( x264_t *h )
h->lookahead->next.list[i]->i_duration = delta_tfi_divisor[h->lookahead->next.list[i]->i_pic_struct];
h->i_prev_duration = h->lookahead->next.list[i]->i_duration;
h->lookahead->next.list[i]->f_duration = (double)h->lookahead->next.list[i]->i_duration
- * h->sps->vui.i_num_units_in_tick
- / h->sps->vui.i_time_scale;
+ * h->param.i_timebase_num / (h->param.i_timebase_den * 2);
+
if( h->lookahead->next.list[i]->i_frame > h->i_disp_fields_last_frame && lookahead_size > 0 )
{
@@ -1966,7 +1966,7 @@ void x264_slicetype_decide( x264_t *h )
{
calculate_durations( h, h->lookahead->next.list[i], h->lookahead->next.list[i-1], &h->i_cpb_delay, &h->i_coded_fields );
h->lookahead->next.list[0]->f_planned_cpb_duration[i-1] = (double)h->lookahead->next.list[i]->i_cpb_duration *
- h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
+ h->param.i_timebase_num / (h->param.i_timebase_den * 2);
}
else
calculate_durations( h, h->lookahead->next.list[i], NULL, &h->i_cpb_delay, &h->i_coded_fields );
--
2.47.3
More information about the x264-devel
mailing list