1 /*****************************************************************************
2 * timecode.c: timecode file input
3 *****************************************************************************
4 * Copyright (C) 2010-2011 x264 project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
22 * This program is also available under a commercial proprietary license.
23 * For more information, contact us at licensing@x264.com.
24 *****************************************************************************/
27 #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "timecode", __VA_ARGS__ )
33 int auto_timebase_num;
34 int auto_timebase_den;
35 uint64_t timebase_num;
36 uint64_t timebase_den;
43 static inline double sigexp10( double value, double *exponent )
45 /* This function separates significand and exp10 from double floating point. */
46 *exponent = pow( 10, floor( log10( value ) ) );
47 return value / *exponent;
50 #define DOUBLE_EPSILON 5e-6
51 #define MKV_TIMEBASE_DEN 1000000000
53 static double correct_fps( double fps, timecode_hnd_t *h )
56 uint64_t fps_num, fps_den;
58 double fps_sig = sigexp10( fps, &exponent );
61 fps_den = i * h->timebase_num;
62 fps_num = round( fps_den * fps_sig ) * exponent;
63 FAIL_IF_ERROR( fps_num > UINT32_MAX, "tcfile fps correction failed.\n"
64 " Specify an appropriate timebase manually or remake tcfile.\n" )
65 if( fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
69 if( h->auto_timebase_den )
71 h->timebase_den = h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
72 if( h->timebase_den > UINT32_MAX )
73 h->auto_timebase_den = 0;
75 return (double)fps_num / fps_den;
78 static int try_mkv_timebase_den( double *fpss, timecode_hnd_t *h, int loop_num )
81 h->timebase_den = MKV_TIMEBASE_DEN;
82 for( int num = 0; num < loop_num; num++ )
86 double fps_sig = sigexp10( fpss[num], &exponent );
87 fps_den = round( MKV_TIMEBASE_DEN / fps_sig ) / exponent;
88 h->timebase_num = fps_den && h->timebase_num ? gcd( h->timebase_num, fps_den ) : fps_den;
89 FAIL_IF_ERROR( h->timebase_num > UINT32_MAX || !h->timebase_num, "automatic timebase generation failed.\n"
90 " Specify timebase manually.\n" )
95 static int parse_tcfile( FILE *tcfile_in, timecode_hnd_t *h, video_info_t *info )
98 int ret, tcfv, num, seq_num, timecodes_num;
99 double *timecodes = NULL;
102 ret = fscanf( tcfile_in, "# timecode format v%d", &tcfv );
103 FAIL_IF_ERROR( ret != 1 || (tcfv != 1 && tcfv != 2), "unsupported timecode format\n" )
108 double assume_fps, seq_fps;
110 int prev_start = -1, prev_end = -1;
113 for( num = 2; fgets( buff, sizeof(buff), tcfile_in ) != NULL; num++ )
115 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
117 FAIL_IF_ERROR( sscanf( buff, "assume %lf", &h->assume_fps ) != 1 && sscanf( buff, "Assume %lf", &h->assume_fps ) != 1,
118 "tcfile parsing error: assumed fps not found\n" )
121 FAIL_IF_ERROR( h->assume_fps <= 0, "invalid assumed fps %.6f\n", h->assume_fps )
123 file_pos = ftell( tcfile_in );
124 h->stored_pts_num = 0;
125 for( seq_num = 0; fgets( buff, sizeof(buff), tcfile_in ) != NULL; num++ )
127 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
129 if( sscanf( buff, "# TDecimate Mode 3: Last Frame = %d", &end ) == 1 )
130 h->stored_pts_num = end + 1;
133 ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
134 FAIL_IF_ERROR( ret != 3 && ret != EOF, "invalid input tcfile\n" )
135 FAIL_IF_ERROR( start > end || start <= prev_start || end <= prev_end || seq_fps <= 0,
136 "invalid input tcfile at line %d: %s\n", num, buff )
139 if( h->auto_timebase_den || h->auto_timebase_num )
142 if( !h->stored_pts_num )
143 h->stored_pts_num = end + 1;
144 timecodes_num = h->stored_pts_num;
145 fseek( tcfile_in, file_pos, SEEK_SET );
147 timecodes = malloc( timecodes_num * sizeof(double) );
150 if( h->auto_timebase_den || h->auto_timebase_num )
152 fpss = malloc( (seq_num + 1) * sizeof(double) );
157 assume_fps = correct_fps( h->assume_fps, h );
161 for( num = seq_num = 0; num < timecodes_num - 1; )
163 fgets( buff, sizeof(buff), tcfile_in );
164 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
166 ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
168 start = end = timecodes_num - 1;
169 for( ; num < start && num < timecodes_num - 1; num++ )
170 timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
171 if( num < timecodes_num - 1 )
173 if( h->auto_timebase_den || h->auto_timebase_num )
174 fpss[seq_num++] = seq_fps;
175 seq_fps = correct_fps( seq_fps, h );
178 for( num = start; num <= end && num < timecodes_num - 1; num++ )
179 timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
182 if( h->auto_timebase_den || h->auto_timebase_num )
183 fpss[seq_num] = h->assume_fps;
185 if( h->auto_timebase_num && !h->auto_timebase_den )
188 double assume_fps_sig, seq_fps_sig;
189 if( try_mkv_timebase_den( fpss, h, seq_num + 1 ) < 0 )
191 fseek( tcfile_in, file_pos, SEEK_SET );
192 assume_fps_sig = sigexp10( h->assume_fps, &exponent );
193 assume_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / assume_fps_sig ) / exponent );
194 for( num = 0; num < timecodes_num - 1; )
196 fgets( buff, sizeof(buff), tcfile_in );
197 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
199 ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
201 start = end = timecodes_num - 1;
202 seq_fps_sig = sigexp10( seq_fps, &exponent );
203 seq_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / seq_fps_sig ) / exponent );
204 for( ; num < start && num < timecodes_num - 1; num++ )
205 timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
206 for( num = start; num <= end && num < timecodes_num - 1; num++ )
207 timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
216 h->assume_fps = assume_fps;
217 h->last_timecode = timecodes[timecodes_num - 1];
221 uint64_t file_pos = ftell( tcfile_in );
223 h->stored_pts_num = 0;
224 while( fgets( buff, sizeof(buff), tcfile_in ) != NULL )
226 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
228 if( !h->stored_pts_num )
229 file_pos = ftell( tcfile_in );
234 timecodes_num = h->stored_pts_num;
235 FAIL_IF_ERROR( !timecodes_num, "input tcfile doesn't have any timecodes!\n" )
236 fseek( tcfile_in, file_pos, SEEK_SET );
238 timecodes = malloc( timecodes_num * sizeof(double) );
242 fgets( buff, sizeof(buff), tcfile_in );
243 ret = sscanf( buff, "%lf", &timecodes[0] );
244 timecodes[0] *= 1e-3; /* Timecode format v2 is expressed in milliseconds. */
245 FAIL_IF_ERROR( ret != 1, "invalid input tcfile for frame 0\n" )
246 for( num = 1; num < timecodes_num; )
248 fgets( buff, sizeof(buff), tcfile_in );
249 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
251 ret = sscanf( buff, "%lf", &timecodes[num] );
252 timecodes[num] *= 1e-3; /* Timecode format v2 is expressed in milliseconds. */
253 FAIL_IF_ERROR( ret != 1 || timecodes[num] <= timecodes[num - 1],
254 "invalid input tcfile for frame %d\n", num )
258 if( timecodes_num == 1 )
259 h->timebase_den = info->fps_num;
260 else if( h->auto_timebase_den )
262 fpss = malloc( (timecodes_num - 1) * sizeof(double) );
265 for( num = 0; num < timecodes_num - 1; num++ )
267 fpss[num] = 1 / (timecodes[num + 1] - timecodes[num]);
268 if( h->auto_timebase_den )
271 uint64_t fps_num, fps_den;
273 double fps_sig = sigexp10( fpss[num], &exponent );
276 fps_den = i * h->timebase_num;
277 fps_num = round( fps_den * fps_sig ) * exponent;
278 if( fps_num > UINT32_MAX || fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
282 h->timebase_den = fps_num && h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
283 if( h->timebase_den > UINT32_MAX )
285 h->auto_timebase_den = 0;
290 if( h->auto_timebase_num && !h->auto_timebase_den )
291 if( try_mkv_timebase_den( fpss, h, timecodes_num - 1 ) < 0 )
297 if( timecodes_num > 1 )
298 h->assume_fps = 1 / (timecodes[timecodes_num - 1] - timecodes[timecodes_num - 2]);
300 h->assume_fps = (double)info->fps_num / info->fps_den;
301 h->last_timecode = timecodes[timecodes_num - 1];
304 if( h->auto_timebase_den || h->auto_timebase_num )
306 uint64_t i = gcd( h->timebase_num, h->timebase_den );
307 h->timebase_num /= i;
308 h->timebase_den /= i;
309 x264_cli_log( "timecode", X264_LOG_INFO, "automatic timebase generation %"PRIu64"/%"PRIu64"\n", h->timebase_num, h->timebase_den );
311 else FAIL_IF_ERROR( h->timebase_den > UINT32_MAX || !h->timebase_den, "automatic timebase generation failed.\n"
312 " Specify an appropriate timebase manually.\n" )
314 h->pts = malloc( h->stored_pts_num * sizeof(int64_t) );
317 for( num = 0; num < h->stored_pts_num; num++ )
319 h->pts[num] = timecodes[num] * ((double)h->timebase_den / h->timebase_num) + 0.5;
320 FAIL_IF_ERROR( num > 0 && h->pts[num] <= h->pts[num - 1], "invalid timebase or timecode for frame %d\n", num )
334 #undef DOUBLE_EPSILON
335 #undef MKV_TIMEBASE_DEN
337 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
341 timecode_hnd_t *h = malloc( sizeof(timecode_hnd_t) );
342 FAIL_IF_ERROR( !h, "malloc failed\n" )
343 h->input = cli_input;
344 h->p_handle = *p_handle;
347 ret = sscanf( opt->timebase, "%"SCNu64"/%"SCNu64, &h->timebase_num, &h->timebase_den );
349 h->timebase_num = strtoul( opt->timebase, NULL, 10 );
350 FAIL_IF_ERROR( h->timebase_num > UINT32_MAX || h->timebase_den > UINT32_MAX,
351 "timebase you specified exceeds H.264 maximum\n" )
353 h->auto_timebase_num = !ret;
354 h->auto_timebase_den = ret < 2;
355 if( h->auto_timebase_num )
356 h->timebase_num = info->fps_den; /* can be changed later by auto timebase generation */
357 if( h->auto_timebase_den )
358 h->timebase_den = 0; /* set later by auto timebase generation */
359 timecode_input.picture_alloc = h->input.picture_alloc;
360 timecode_input.picture_clean = h->input.picture_clean;
364 tcfile_in = fopen( psz_filename, "rb" );
365 FAIL_IF_ERROR( !tcfile_in, "can't open `%s'\n", psz_filename )
366 else if( !x264_is_regular_file( tcfile_in ) )
368 x264_cli_log( "timecode", X264_LOG_ERROR, "tcfile input incompatible with non-regular file `%s'\n", psz_filename );
373 if( parse_tcfile( tcfile_in, h, info ) < 0 )
382 info->timebase_num = h->timebase_num;
383 info->timebase_den = h->timebase_den;
389 static int64_t get_frame_pts( timecode_hnd_t *h, int frame, int real_frame )
391 if( frame < h->stored_pts_num )
392 return h->pts[frame];
395 if( h->pts && real_frame )
397 x264_cli_log( "timecode", X264_LOG_INFO, "input timecode file missing data for frame %d and later\n"
398 " assuming constant fps %.6f\n", frame, h->assume_fps );
402 double timecode = h->last_timecode + 1 / h->assume_fps;
404 h->last_timecode = timecode;
405 return timecode * ((double)h->timebase_den / h->timebase_num) + 0.5;
409 static int read_frame( cli_pic_t *pic, hnd_t handle, int frame )
411 timecode_hnd_t *h = handle;
412 if( h->input.read_frame( pic, h->p_handle, frame ) )
415 pic->pts = get_frame_pts( h, frame, 1 );
416 pic->duration = get_frame_pts( h, frame + 1, 0 ) - pic->pts;
421 static int release_frame( cli_pic_t *pic, hnd_t handle )
423 timecode_hnd_t *h = handle;
424 if( h->input.release_frame )
425 return h->input.release_frame( pic, h->p_handle );
429 static int close_file( hnd_t handle )
431 timecode_hnd_t *h = handle;
434 h->input.close_file( h->p_handle );
439 cli_input_t timecode_input = { open_file, NULL, read_frame, release_frame, NULL, close_file };