Commit d48c3809 authored by Fiona Glaser's avatar Fiona Glaser

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.
parent bb1294f1
......@@ -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 );
......
......@@ -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 )
......
......@@ -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;
......
......@@ -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 );
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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 )
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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! */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment