1 /*****************************************************************************
2 * timecode.c: x264 timecode format file input module
3 *****************************************************************************
4 * Copyright (C) 2010 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.
21 *****************************************************************************/
26 extern cli_input_t input;
33 int auto_timebase_num;
34 int auto_timebase_den;
44 static inline double sigexp10( double value, double *exponent )
46 /* This function separates significand and exp10 from double floating point. */
47 *exponent = pow( 10, floor( log10( value ) ) );
48 return value / *exponent;
51 #define DOUBLE_EPSILON 5e-6
52 #define MKV_TIMEBASE_DEN 1000000000
54 static double correct_fps( double fps, timecode_hnd_t *h )
57 int64_t fps_num, fps_den;
59 double fps_sig = sigexp10( fps, &exponent );
62 fps_den = i * h->timebase_num;
63 fps_num = round( fps_den * fps_sig ) * exponent;
66 fprintf( stderr, "timecode [error]: tcfile fps correction failed.\n"
67 " Specify an appropriate timebase manually or remake tcfile.\n" );
70 if( fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
74 if( h->auto_timebase_den )
76 h->timebase_den = h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
77 if( h->timebase_den < 0 )
78 h->auto_timebase_den = 0;
80 return (double)fps_num / fps_den;
83 static int try_mkv_timebase_den( double *fpss, timecode_hnd_t *h, int loop_num )
86 h->timebase_den = MKV_TIMEBASE_DEN;
87 for( int num = 0; num < loop_num; num++ )
91 double fps_sig = sigexp10( fpss[num], &exponent );
92 fps_den = round( MKV_TIMEBASE_DEN / fps_sig ) / exponent;
93 h->timebase_num = fps_den > 0 && h->timebase_num ? gcd( h->timebase_num, fps_den ) : fps_den;
94 if( h->timebase_num <= 0 )
96 fprintf( stderr, "timecode [error]: automatic timebase generation failed.\n"
97 " Specify timebase manually.\n" );
104 static int parse_tcfile( FILE *tcfile_in, timecode_hnd_t *h, video_info_t *info )
107 int ret, tcfv, num, seq_num, timecodes_num;
108 int64_t pts_seek_offset;
109 double *timecodes = NULL;
112 ret = fscanf( tcfile_in, "# timecode format v%d", &tcfv );
113 if( ret != 1 || (tcfv != 1 && tcfv != 2) )
115 fprintf( stderr, "timecode [error]: unsupported timecode format\n" );
122 double assume_fps, seq_fps;
123 int start, end = h->seek;
124 int prev_start = -1, prev_end = -1;
127 for( num = 2; fgets( buff, sizeof(buff), tcfile_in ) != NULL; num++ )
129 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
131 if( sscanf( buff, "assume %lf", &h->assume_fps ) != 1 && sscanf( buff, "Assume %lf", &h->assume_fps ) != 1 )
133 fprintf( stderr, "timecode [error]: tcfile parsing error: assumed fps not found\n" );
138 if( h->assume_fps <= 0 )
140 fprintf( stderr, "timecode [error]: invalid assumed fps %.6f\n", h->assume_fps );
144 file_pos = ftell( tcfile_in );
145 h->stored_pts_num = 0;
146 for( seq_num = 0; fgets( buff, sizeof(buff), tcfile_in ) != NULL; num++ )
148 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
150 if( sscanf( buff, "# TDecimate Mode 3: Last Frame = %d", &end ) == 1 )
151 h->stored_pts_num = end + 1 - h->seek;
154 ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
155 if( ret != 3 && ret != EOF )
157 fprintf( stderr, "timecode [error]: invalid input tcfile\n" );
160 if( start > end || start <= prev_start || end <= prev_end || seq_fps <= 0 )
162 fprintf( stderr, "timecode [error]: invalid input tcfile at line %d: %s\n", num, buff );
167 if( h->auto_timebase_den || h->auto_timebase_num )
170 if( !h->stored_pts_num )
171 h->stored_pts_num = end + 1 - h->seek;
172 timecodes_num = h->stored_pts_num + h->seek;
173 fseek( tcfile_in, file_pos, SEEK_SET );
175 timecodes = malloc( timecodes_num * sizeof(double) );
178 if( h->auto_timebase_den || h->auto_timebase_num )
180 fpss = malloc( (seq_num + 1) * sizeof(double) );
185 assume_fps = correct_fps( h->assume_fps, h );
189 for( num = seq_num = 0; num < timecodes_num - 1; )
191 fgets( buff, sizeof(buff), tcfile_in );
192 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
194 ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
196 start = end = timecodes_num - 1;
197 if( h->auto_timebase_den || h->auto_timebase_num )
198 fpss[seq_num++] = seq_fps;
199 seq_fps = correct_fps( seq_fps, h );
202 for( ; num < start && num < timecodes_num - 1; num++ )
203 timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
204 for( num = start; num <= end && num < timecodes_num - 1; num++ )
205 timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
207 if( h->auto_timebase_den || h->auto_timebase_num )
208 fpss[seq_num] = h->assume_fps;
210 if( h->auto_timebase_num && !h->auto_timebase_den )
213 double assume_fps_sig, seq_fps_sig;
214 if( try_mkv_timebase_den( fpss, h, seq_num + 1 ) < 0 )
216 fseek( tcfile_in, file_pos, SEEK_SET );
217 assume_fps_sig = sigexp10( h->assume_fps, &exponent );
218 assume_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / assume_fps_sig ) / exponent );
219 for( num = 0; num < timecodes_num - 1; )
221 fgets( buff, sizeof(buff), tcfile_in );
222 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
224 ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
226 start = end = timecodes_num - 1;
227 seq_fps_sig = sigexp10( seq_fps, &exponent );
228 seq_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / seq_fps_sig ) / exponent );
229 for( ; num < start && num < timecodes_num - 1; num++ )
230 timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
231 for( num = start; num <= end && num < timecodes_num - 1; num++ )
232 timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
238 h->assume_fps = assume_fps;
239 h->last_timecode = timecodes[timecodes_num - 1];
243 uint64_t file_pos = ftell( tcfile_in );
245 num = h->stored_pts_num = 0;
246 while( fgets( buff, sizeof(buff), tcfile_in ) != NULL )
248 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
251 file_pos = ftell( tcfile_in );
258 timecodes_num = h->stored_pts_num + h->seek;
261 fprintf( stderr, "timecode [error]: input tcfile doesn't have any timecodes!\n" );
264 fseek( tcfile_in, file_pos, SEEK_SET );
266 timecodes = malloc( timecodes_num * sizeof(double) );
270 fgets( buff, sizeof(buff), tcfile_in );
271 ret = sscanf( buff, "%lf", &timecodes[0] );
274 fprintf( stderr, "timecode [error]: invalid input tcfile for frame 0\n" );
277 for( num = 1; num < timecodes_num; )
279 fgets( buff, sizeof(buff), tcfile_in );
280 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
282 ret = sscanf( buff, "%lf", &timecodes[num] );
283 timecodes[num] *= 1e-3; /* Timecode format v2 is expressed in milliseconds. */
284 if( ret != 1 || timecodes[num] <= timecodes[num - 1] )
286 fprintf( stderr, "timecode [error]: invalid input tcfile for frame %d\n", num );
292 if( timecodes_num == 1 )
293 h->timebase_den = info->fps_num;
294 else if( h->auto_timebase_den )
296 fpss = malloc( (timecodes_num - 1) * sizeof(double) );
299 for( num = 0; num < timecodes_num - 1; num++ )
301 fpss[num] = 1 / (timecodes[num + 1] - timecodes[num]);
302 if( h->timebase_den >= 0 )
305 int fps_num, fps_den;
307 double fps_sig = sigexp10( fpss[num], &exponent );
310 fps_den = i * h->timebase_num;
311 fps_num = round( fps_den * fps_sig ) * exponent;
312 if( fps_num < 0 || fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
316 h->timebase_den = fps_num > 0 && h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
317 if( h->timebase_den < 0 )
319 h->auto_timebase_den = 0;
324 if( h->auto_timebase_num && !h->auto_timebase_den )
325 if( try_mkv_timebase_den( fpss, h, timecodes_num - 1 ) < 0 )
330 if( timecodes_num > 1 )
331 h->assume_fps = 1 / (timecodes[timecodes_num - 1] - timecodes[timecodes_num - 2]);
333 h->assume_fps = (double)info->fps_num / info->fps_den;
334 h->last_timecode = timecodes[timecodes_num - 1];
337 if( h->auto_timebase_den || h->auto_timebase_num )
339 x264_reduce_fraction( &h->timebase_num, &h->timebase_den );
340 fprintf( stderr, "timecode [info]: automatic timebase generation %d/%d\n", h->timebase_num, h->timebase_den );
342 else if( h->timebase_den <= 0 )
344 fprintf( stderr, "timecode [error]: automatic timebase generation failed.\n"
345 " Specify an appropriate timebase manually.\n" );
349 h->pts = malloc( h->stored_pts_num * sizeof(int64_t) );
352 pts_seek_offset = (int64_t)( timecodes[h->seek] * ((double)h->timebase_den / h->timebase_num) + 0.5 );
354 for( num = 1; num < h->stored_pts_num; num++ )
356 h->pts[num] = (int64_t)( timecodes[h->seek + num] * ((double)h->timebase_den / h->timebase_num) + 0.5 );
357 h->pts[num] -= pts_seek_offset;
358 if( h->pts[num] <= h->pts[num - 1] )
360 fprintf( stderr, "timecode [error]: invalid timebase or timecode for frame %d\n", num );
376 #undef DOUBLE_EPSILON
377 #undef MKV_TIMEBASE_DEN
379 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
383 timecode_hnd_t *h = malloc( sizeof(timecode_hnd_t) );
386 fprintf( stderr, "timecode [error]: malloc failed\n" );
390 h->p_handle = *p_handle;
391 h->frame_total = input.get_frame_total( h->p_handle );
394 ret = sscanf( opt->timebase, "%d/%d", &h->timebase_num, &h->timebase_den );
396 h->timebase_num = atoi( opt->timebase );
397 h->auto_timebase_num = !ret;
398 h->auto_timebase_den = ret < 2;
399 if( h->auto_timebase_num )
400 h->timebase_num = info->fps_den; /* can be changed later by auto timebase generation */
401 if( h->auto_timebase_den )
402 h->timebase_den = 0; /* set later by auto timebase generation */
403 timecode_input.picture_alloc = h->input.picture_alloc;
404 timecode_input.picture_clean = h->input.picture_clean;
408 tcfile_in = fopen( psz_filename, "rb" );
411 fprintf( stderr, "timecode [error]: can't open `%s'\n", psz_filename );
414 else if( !x264_is_regular_file( tcfile_in ) )
416 fprintf( stderr, "timecode [error]: tcfile input incompatible with non-regular file `%s'\n", psz_filename );
421 if( parse_tcfile( tcfile_in, h, info ) < 0 )
430 info->timebase_num = h->timebase_num;
431 info->timebase_den = h->timebase_den;
437 static int get_frame_total( hnd_t handle )
439 timecode_hnd_t *h = handle;
440 return h->frame_total;
443 static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
445 timecode_hnd_t *h = handle;
446 int ret = h->input.read_frame( p_pic, h->p_handle, i_frame );
448 if( i_frame - h->seek < h->stored_pts_num )
450 assert( i_frame >= h->seek );
451 p_pic->i_pts = h->pts[i_frame - h->seek];
457 fprintf( stderr, "timecode [info]: input timecode file missing data for frame %d and later\n"
458 " assuming constant fps %.6f\n", i_frame, h->assume_fps );
462 h->last_timecode += 1 / h->assume_fps;
463 p_pic->i_pts = (int64_t)( h->last_timecode * ((double)h->timebase_den / h->timebase_num) + 0.5 );
469 static int release_frame( x264_picture_t *pic, hnd_t handle )
471 timecode_hnd_t *h = handle;
472 if( h->input.release_frame )
473 return h->input.release_frame( pic, h->p_handle );
477 static int close_file( hnd_t handle )
479 timecode_hnd_t *h = handle;
482 h->input.close_file( h->p_handle );
487 cli_input_t timecode_input = { open_file, get_frame_total, NULL, read_frame, release_frame, NULL, close_file };