[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