From d48c3809d24e8cc7caff2c39ae1544a957452787 Mon Sep 17 00:00:00 2001 From: Fiona Glaser Date: Fri, 16 Apr 2010 11:36:43 -0700 Subject: [PATCH] Fix issues with extremely large timebases 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. --- common/common.c | 14 ++++++------- common/common.h | 2 +- common/set.h | 4 ++-- encoder/encoder.c | 22 +++++++++++++------- encoder/ratecontrol.c | 9 +++++---- input/input.h | 12 +++++------ input/timecode.c | 47 ++++++++++++++++++++++++++----------------- input/y4m.c | 3 ++- output/flv.c | 4 ++-- output/matroska.c | 4 ++-- output/mp4.c | 2 +- x264.c | 13 ++++++++---- x264.h | 11 +++++----- 13 files changed, 85 insertions(+), 62 deletions(-) diff --git a/common/common.c b/common/common.c index 924323a0..6471c07e 100644 --- a/common/common.c +++ b/common/common.c @@ -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 ); diff --git a/common/common.h b/common/common.h index 3973558a..0d7dd998 100644 --- a/common/common.h +++ b/common/common.h @@ -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 ) diff --git a/common/set.h b/common/set.h index 97831187..ee27d742 100644 --- a/common/set.h +++ b/common/set.h @@ -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; diff --git a/encoder/encoder.c b/encoder/encoder.c index 197703b5..a48dda71 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -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 ); diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 6cc59c34..58082972 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -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; } diff --git a/input/input.h b/input/input.h index b6cd218d..eb62fdd4 100644 --- a/input/input.h +++ b/input/input.h @@ -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; diff --git a/input/timecode.c b/input/timecode.c index 5fabe614..a3073278 100644 --- a/input/timecode.c +++ b/input/timecode.c @@ -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 ) diff --git a/input/y4m.c b/input/y4m.c index c34f264e..842b9860 100644 --- a/input/y4m.c +++ b/input/y4m.c @@ -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; diff --git a/output/flv.c b/output/flv.c index 04f44283..e441b6d4 100644 --- a/output/flv.c +++ b/output/flv.c @@ -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; diff --git a/output/matroska.c b/output/matroska.c index 47753d76..0304c847 100644 --- a/output/matroska.c +++ b/output/matroska.c @@ -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; diff --git a/output/mp4.c b/output/mp4.c index cbe9f5c3..f76541ed 100644 --- a/output/mp4.c +++ b/output/mp4.c @@ -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 3f46fd93..8f4e372e 100644 --- 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 d30effef..83f087ee 100644 --- a/x264.h +++ b/x264.h @@ -35,7 +35,7 @@ #include -#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! */ -- 2.40.0