]> git.sesse.net Git - x264/commitdiff
Fix issues with extremely large timebases
authorFiona Glaser <fiona@x264.com>
Fri, 16 Apr 2010 18:36:43 +0000 (11:36 -0700)
committerFiona Glaser <fiona@x264.com>
Fri, 23 Apr 2010 19:40:13 +0000 (12:40 -0700)
With timebase denominators >= 2^30 , x264 would silently overflow and cause odd issues.
Now x264 will explicitly fail with timebase denominators >= 2^31 and work with timebase denominators 2^31 > x >= 2^30.

13 files changed:
common/common.c
common/common.h
common/set.h
encoder/encoder.c
encoder/ratecontrol.c
input/input.h
input/timecode.c
input/y4m.c
output/flv.c
output/matroska.c
output/mp4.c
x264.c
x264.h

index 924323a07878e5eef93d969774026f9b09cf2c92..6471c07e1b26d83f3f3f976fe596ca4912e4a101 100644 (file)
@@ -614,7 +614,7 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value )
     }
     OPT("fps")
     {
-        if( sscanf( value, "%d/%d", &p->i_fps_num, &p->i_fps_den ) == 2 )
+        if( sscanf( value, "%u/%u", &p->i_fps_num, &p->i_fps_den ) == 2 )
             ;
         else
         {
@@ -1119,11 +1119,11 @@ void x264_free( void *p )
 /****************************************************************************
  * x264_reduce_fraction:
  ****************************************************************************/
-void x264_reduce_fraction( int *n, int *d )
+void x264_reduce_fraction( uint32_t *n, uint32_t *d )
 {
-    int a = *n;
-    int b = *d;
-    int c;
+    uint32_t a = *n;
+    uint32_t b = *d;
+    uint32_t c;
     if( !a || !b )
         return;
     c = a % b;
@@ -1185,8 +1185,8 @@ char *x264_param2string( x264_param_t *p, int b_res )
     if( b_res )
     {
         s += sprintf( s, "%dx%d ", p->i_width, p->i_height );
-        s += sprintf( s, "fps=%d/%d ", p->i_fps_num, p->i_fps_den );
-        s += sprintf( s, "timebase=%d/%d ", p->i_timebase_num, p->i_timebase_den );
+        s += sprintf( s, "fps=%u/%u ", p->i_fps_num, p->i_fps_den );
+        s += sprintf( s, "timebase=%u/%u ", p->i_timebase_num, p->i_timebase_den );
     }
 
     s += sprintf( s, "cabac=%d", p->b_cabac );
index 3973558a207539088fbc961087c6d7dbe30327c8..0d7dd998e08397f57b13060d9a9eefcb14fd6034 100644 (file)
@@ -134,7 +134,7 @@ int x264_nal_encode( uint8_t *dst, x264_nal_t *nal, int b_annexb, int b_long_sta
 /* log */
 void x264_log( x264_t *h, int i_level, const char *psz_fmt, ... );
 
-void x264_reduce_fraction( int *n, int *d );
+void x264_reduce_fraction( uint32_t *n, uint32_t *d );
 void x264_init_vlc_tables();
 
 static ALWAYS_INLINE uint8_t x264_clip_uint8( int x )
index 978311873ac649486afdcedc72c71e83b8a34689..ee27d7429cfe09aef959abf7a6baca2875e2412f 100644 (file)
@@ -112,8 +112,8 @@ typedef struct
         int i_chroma_loc_bottom;
 
         int b_timing_info_present;
-        int i_num_units_in_tick;
-        int i_time_scale;
+        uint32_t i_num_units_in_tick;
+        uint32_t i_time_scale;
         int b_fixed_frame_rate;
 
         int b_nal_hrd_parameters_present;
index 197703b519a7f6edfbdf43a7a062ca7fbfb3b0ea..a48dda7187651d1c53b29f6373ee63df52e5854f 100644 (file)
@@ -817,10 +817,10 @@ static void x264_set_aspect_ratio( x264_t *h, x264_param_t *param, int initial )
     /* VUI */
     if( param->vui.i_sar_width > 0 && param->vui.i_sar_height > 0 )
     {
-        int i_w = param->vui.i_sar_width;
-        int i_h = param->vui.i_sar_height;
-        int old_w = h->param.vui.i_sar_width;
-        int old_h = h->param.vui.i_sar_height;
+        uint32_t i_w = param->vui.i_sar_width;
+        uint32_t i_h = param->vui.i_sar_height;
+        uint32_t old_w = h->param.vui.i_sar_width;
+        uint32_t old_h = h->param.vui.i_sar_height;
 
         x264_reduce_fraction( &i_w, &i_h );
 
@@ -886,21 +886,29 @@ x264_t *x264_encoder_open( x264_param_t *param )
     h->i_frame = -1;
     h->i_frame_num = 0;
     h->i_idr_pic_id = 0;
+    uint64_t new_timebase_den = h->param.i_timebase_den;
     if( h->param.b_dts_compress )
     {
         /* h->i_dts_compress_multiplier == h->frames.i_bframe_delay + 1 */
         h->i_dts_compress_multiplier = h->param.i_bframe ? (h->param.i_bframe_pyramid ? 3 : 2) : 1;
         if( h->i_dts_compress_multiplier != 1 )
         {
-            x264_log( h, X264_LOG_DEBUG, "DTS compresion changed timebase: %d/%d -> %d/%d\n",
+            new_timebase_den = h->param.i_timebase_den * h->i_dts_compress_multiplier;
+            x264_log( h, X264_LOG_DEBUG, "DTS compresion changed timebase: %u/%u -> %u/%"PRIu64"\n",
                       h->param.i_timebase_num, h->param.i_timebase_den,
-                      h->param.i_timebase_num, h->param.i_timebase_den * h->i_dts_compress_multiplier );
-            h->param.i_timebase_den *= h->i_dts_compress_multiplier;
+                      h->param.i_timebase_num, new_timebase_den );
         }
     }
     else
         h->i_dts_compress_multiplier = 1;
 
+    if( new_timebase_den * 2 > UINT32_MAX )
+    {
+        x264_log( h, X264_LOG_ERROR, "Effective timebase denominator %"PRIu64" exceeds H.264 maximum\n", new_timebase_den );
+        goto fail;
+    }
+    h->param.i_timebase_den = new_timebase_den;
+
     h->sps = &h->sps_array[0];
     x264_sps_init( h->sps, h->param.i_sps_id, &h->param );
 
index 6cc59c34713ad2591d17ab7820a3e56b859cb0ce..580829728e64791e84dabb42d806e675965a8823 100644 (file)
@@ -639,6 +639,7 @@ int x264_ratecontrol_new( x264_t *h )
         if( !strncmp( stats_buf, "#options:", 9 ) )
         {
             int i, j;
+            uint32_t k, l;
             char *opts = stats_buf;
             stats_in = strchr( stats_buf, '\n' );
             if( !stats_in )
@@ -657,15 +658,15 @@ int x264_ratecontrol_new( x264_t *h )
                 return -1;
             }
 
-            if( ( p = strstr( opts, "timebase=" ) ) && sscanf( p, "timebase=%d/%d", &i, &j ) != 2 )
+            if( ( p = strstr( opts, "timebase=" ) ) && sscanf( p, "timebase=%u/%u", &k, &l ) != 2 )
             {
                 x264_log( h, X264_LOG_ERROR, "timebase specified in stats file not valid\n" );
                 return -1;
             }
-            if( i != h->param.i_timebase_num || j != h->param.i_timebase_den )
+            if( k != h->param.i_timebase_num || l != h->param.i_timebase_den )
             {
-                x264_log( h, X264_LOG_ERROR, "timebase mismatch with 1st pass (%d/%d vs %d/%d)\n",
-                          h->param.i_timebase_num, h->param.i_timebase_den, i, j );
+                x264_log( h, X264_LOG_ERROR, "timebase mismatch with 1st pass (%u/%u vs %u/%u)\n",
+                          h->param.i_timebase_num, h->param.i_timebase_den, k, l );
                 return -1;
             }
 
index b6cd218dbc9a469bdf2ad662ac745163fc425fc5..eb62fdd441c70bb5e47351c867a30f7c503afb13 100644 (file)
@@ -38,15 +38,15 @@ typedef struct
 typedef struct
 {
     int csp; /* X264_CSP_YV12 or X264_CSP_I420 */
-    int fps_num;
-    int fps_den;
+    uint32_t fps_num;
+    uint32_t fps_den;
     int height;
     int interlaced;
-    int sar_width;
-    int sar_height;
+    uint32_t sar_width;
+    uint32_t sar_height;
     int tff;
-    int timebase_num;
-    int timebase_den;
+    uint32_t timebase_num;
+    uint32_t timebase_den;
     int vfr;
     int width;
 } video_info_t;
index 5fabe61470e81000dfeb8e213fbdca8377ab02af..a30732783013584897592cb8d5dc5a31b3c5a50a 100644 (file)
@@ -32,8 +32,8 @@ typedef struct
     int frame_total;
     int auto_timebase_num;
     int auto_timebase_den;
-    int timebase_num;
-    int timebase_den;
+    uint64_t timebase_num;
+    uint64_t timebase_den;
     int seek;
     int stored_pts_num;
     int64_t *pts;
@@ -53,15 +53,15 @@ static inline double sigexp10( double value, double *exponent )
 
 static double correct_fps( double fps, timecode_hnd_t *h )
 {
-    int64_t i = 1;
-    int64_t fps_num, fps_den;
+    int i = 1;
+    uint64_t fps_num, fps_den;
     double exponent;
     double fps_sig = sigexp10( fps, &exponent );
     while( 1 )
     {
         fps_den = i * h->timebase_num;
         fps_num = round( fps_den * fps_sig ) * exponent;
-        if( fps_num < 0 )
+        if( fps_num > UINT32_MAX )
         {
             fprintf( stderr, "timecode [error]: tcfile fps correction failed.\n"
                              "                  Specify an appropriate timebase manually or remake tcfile.\n" );
@@ -74,7 +74,7 @@ static double correct_fps( double fps, timecode_hnd_t *h )
     if( h->auto_timebase_den )
     {
         h->timebase_den = h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
-        if( h->timebase_den < 0 )
+        if( h->timebase_den > UINT32_MAX )
             h->auto_timebase_den = 0;
     }
     return (double)fps_num / fps_den;
@@ -86,12 +86,12 @@ static int try_mkv_timebase_den( double *fpss, timecode_hnd_t *h, int loop_num )
     h->timebase_den = MKV_TIMEBASE_DEN;
     for( int num = 0; num < loop_num; num++ )
     {
-        int fps_den;
+        uint64_t fps_den;
         double exponent;
         double fps_sig = sigexp10( fpss[num], &exponent );
         fps_den = round( MKV_TIMEBASE_DEN / fps_sig ) / exponent;
-        h->timebase_num = fps_den > 0 && h->timebase_num ? gcd( h->timebase_num, fps_den ) : fps_den;
-        if( h->timebase_num <= 0 )
+        h->timebase_num = fps_den && h->timebase_num ? gcd( h->timebase_num, fps_den ) : fps_den;
+        if( h->timebase_num > UINT32_MAX || !h->timebase_num )
         {
             fprintf( stderr, "timecode [error]: automatic timebase generation failed.\n"
                              "                  Specify timebase manually.\n" );
@@ -305,19 +305,19 @@ static int parse_tcfile( FILE *tcfile_in, timecode_hnd_t *h, video_info_t *info
                 if( h->timebase_den >= 0 )
                 {
                     int i = 1;
-                    int fps_num, fps_den;
+                    uint64_t fps_num, fps_den;
                     double exponent;
                     double fps_sig = sigexp10( fpss[num], &exponent );
                     while( 1 )
                     {
                         fps_den = i * h->timebase_num;
                         fps_num = round( fps_den * fps_sig ) * exponent;
-                        if( fps_num < 0 || fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
+                        if( fps_num > UINT32_MAX || fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
                             break;
                         ++i;
                     }
-                    h->timebase_den = fps_num > 0 && h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
-                    if( h->timebase_den < 0 )
+                    h->timebase_den = fps_num && h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
+                    if( h->timebase_den > UINT32_MAX )
                     {
                         h->auto_timebase_den = 0;
                         continue;
@@ -339,10 +339,12 @@ static int parse_tcfile( FILE *tcfile_in, timecode_hnd_t *h, video_info_t *info
 
     if( h->auto_timebase_den || h->auto_timebase_num )
     {
-        x264_reduce_fraction( &h->timebase_num, &h->timebase_den );
-        fprintf( stderr, "timecode [info]: automatic timebase generation %d/%d\n", h->timebase_num, h->timebase_den );
+        uint64_t i = gcd( h->timebase_num, h->timebase_den );
+        h->timebase_num /= i;
+        h->timebase_den /= i;
+        fprintf( stderr, "timecode [info]: automatic timebase generation %"PRIu64"/%"PRIu64"\n", h->timebase_num, h->timebase_den );
     }
-    else if( h->timebase_den <= 0 )
+    else if( h->timebase_den > UINT32_MAX || !h->timebase_den )
     {
         fprintf( stderr, "timecode [error]: automatic timebase generation failed.\n"
                          "                  Specify an appropriate timebase manually.\n" );
@@ -394,9 +396,16 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c
     h->frame_total = input.get_frame_total( h->p_handle );
     h->seek = opt->seek;
     if( opt->timebase )
-        ret = sscanf( opt->timebase, "%d/%d", &h->timebase_num, &h->timebase_den );
-    if( ret == 1 )
-        h->timebase_num = atoi( opt->timebase );
+    {
+        ret = sscanf( opt->timebase, "%"SCNu64"/%"SCNu64, &h->timebase_num, &h->timebase_den );
+        if( ret == 1 )
+            h->timebase_num = strtoul( opt->timebase, NULL, 10 );
+        if( h->timebase_num > UINT32_MAX || h->timebase_den > UINT32_MAX )
+        {
+            fprintf( stderr, "timecode [error]: timebase you specified exceeds H.264 maximum\n" );
+            return -1;
+        }
+    }
     h->auto_timebase_num = !ret;
     h->auto_timebase_den = ret < 2;
     if( h->auto_timebase_num )
index c34f264e16bba68523e7f5c52f835c9bbd6f9f35..842b9860d1ec6cbbea91ce08de39f354042ac11c 100644 (file)
@@ -40,7 +40,8 @@ typedef struct
 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
 {
     y4m_hnd_t *h = malloc( sizeof(y4m_hnd_t) );
-    int  i, n, d;
+    int i;
+    uint32_t n, d;
     char header[MAX_YUV4_HEADER+10];
     char *tokend, *header_end;
     int colorspace = X264_CSP_NONE;
index 04f44283508aaaa9209aeb5def8d193a6a4f2152..e441b6d405c8b896d7fa30bd47e457cdeb455006 100644 (file)
@@ -47,8 +47,8 @@ typedef struct
     int64_t i_prev_dts;
     int64_t i_prev_pts;
 
-    int i_timebase_num;
-    int i_timebase_den;
+    uint32_t i_timebase_num;
+    uint32_t i_timebase_den;
     int b_vfr_input;
 
     unsigned start;
index 47753d763de88baa8f3ef8f14a03b5b0f60fbb09..0304c847436e992fc2e893ead0666c256c055e08 100644 (file)
@@ -30,8 +30,8 @@ typedef struct
     int64_t frame_duration;
 
     char b_writing_frame;
-    int i_timebase_num;
-    int i_timebase_den;
+    uint32_t i_timebase_num;
+    uint32_t i_timebase_den;
 
 } mkv_hnd_t;
 
index cbe9f5c3de39589ea88e19db5bd162ce290f4869..f76541ed91ffc35d804b064fe5f5e60591626a12 100644 (file)
@@ -38,7 +38,7 @@ typedef struct
     GF_ISOSample *p_sample;
     int i_track;
     uint32_t i_descidx;
-    int i_time_res;
+    uint32_t i_time_res;
     int64_t i_time_inc;
     int i_numframe;
     int i_delay_time;
diff --git a/x264.c b/x264.c
index 3f46fd93ac96be5995468020984103f2f33d8a2e..8f4e372ecc6b90bd035a01f760485061762101ce 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -1205,9 +1205,9 @@ generic_option:
     }
     if( !tcfile_name && input_opt.timebase )
     {
-        int i_user_timebase_num;
-        int i_user_timebase_den;
-        int ret = sscanf( input_opt.timebase, "%d/%d", &i_user_timebase_num, &i_user_timebase_den );
+        uint64_t i_user_timebase_num;
+        uint64_t i_user_timebase_den;
+        int ret = sscanf( input_opt.timebase, "%"SCNu64"/%"SCNu64, &i_user_timebase_num, &i_user_timebase_den );
         if( !ret )
         {
             fprintf( stderr, "x264 [error]: invalid argument: timebase = %s\n", input_opt.timebase );
@@ -1216,7 +1216,12 @@ generic_option:
         else if( ret == 1 )
         {
             i_user_timebase_num = param->i_timebase_num;
-            i_user_timebase_den = atoi( input_opt.timebase );
+            i_user_timebase_den = strtoul( input_opt.timebase, NULL, 10 );
+        }
+        if( i_user_timebase_num > UINT32_MAX || i_user_timebase_den > UINT32_MAX )
+        {
+            fprintf( stderr, "x264 [error]: timebase you specified exceeds H.264 maximum\n" );
+            return -1;
         }
         opt->timebase_convert_multiplier = ((double)i_user_timebase_den / param->i_timebase_den)
                                          * ((double)param->i_timebase_num / i_user_timebase_num);
diff --git a/x264.h b/x264.h
index d30effef13c768462da6bb631e663827f4a365c1..83f087eefaaa15430dd23412b8520607585fbc1f 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -35,7 +35,7 @@
 
 #include <stdarg.h>
 
-#define X264_BUILD 93
+#define X264_BUILD 94
 
 /* x264_t:
  *      opaque handler for encoder */
@@ -208,9 +208,6 @@ typedef struct x264_param_t
         int         i_chroma_loc;    /* both top & bottom */
     } vui;
 
-    int         i_fps_num;
-    int         i_fps_den;
-
     /* Bitstream parameters */
     int         i_frame_reference;  /* Maximum number of reference frames */
     int         i_keyint_max;       /* Force an IDR keyframe at this interval */
@@ -330,8 +327,10 @@ typedef struct x264_param_t
                                  * otherwise place size (4 bytes) before NAL units. */
     int i_sps_id;               /* SPS and PPS id number */
     int b_vfr_input;            /* VFR input */
-    int i_timebase_num;         /* Timebase numerator */
-    int i_timebase_den;         /* Timebase denominator */
+    uint32_t i_fps_num;
+    uint32_t i_fps_den;
+    uint32_t i_timebase_num;    /* Timebase numerator */
+    uint32_t i_timebase_den;    /* Timebase denominator */
     int b_dts_compress;         /* DTS compression: this algorithm eliminates negative DTS
                                  * by compressing them to be less than the second PTS.
                                  * Warning: this will change the timebase! */