]> git.sesse.net Git - x264/blob - input/timecode.c
Fix issues with extremely large timebases
[x264] / input / timecode.c
1 /*****************************************************************************
2  * timecode.c: x264 timecode format file input module
3  *****************************************************************************
4  * Copyright (C) 2010 x264 project
5  *
6  * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 #include "muxers.h"
24 #include <math.h>
25
26 extern cli_input_t input;
27
28 typedef struct
29 {
30     cli_input_t input;
31     hnd_t p_handle;
32     int frame_total;
33     int auto_timebase_num;
34     int auto_timebase_den;
35     uint64_t timebase_num;
36     uint64_t timebase_den;
37     int seek;
38     int stored_pts_num;
39     int64_t *pts;
40     double assume_fps;
41     double last_timecode;
42 } timecode_hnd_t;
43
44 static inline double sigexp10( double value, double *exponent )
45 {
46     /* This function separates significand and exp10 from double floating point. */
47     *exponent = pow( 10, floor( log10( value ) ) );
48     return value / *exponent;
49 }
50
51 #define DOUBLE_EPSILON 5e-6
52 #define MKV_TIMEBASE_DEN 1000000000
53
54 static double correct_fps( double fps, timecode_hnd_t *h )
55 {
56     int i = 1;
57     uint64_t fps_num, fps_den;
58     double exponent;
59     double fps_sig = sigexp10( fps, &exponent );
60     while( 1 )
61     {
62         fps_den = i * h->timebase_num;
63         fps_num = round( fps_den * fps_sig ) * exponent;
64         if( fps_num > UINT32_MAX )
65         {
66             fprintf( stderr, "timecode [error]: tcfile fps correction failed.\n"
67                              "                  Specify an appropriate timebase manually or remake tcfile.\n" );
68             return -1;
69         }
70         if( fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
71             break;
72         ++i;
73     }
74     if( h->auto_timebase_den )
75     {
76         h->timebase_den = h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
77         if( h->timebase_den > UINT32_MAX )
78             h->auto_timebase_den = 0;
79     }
80     return (double)fps_num / fps_den;
81 }
82
83 static int try_mkv_timebase_den( double *fpss, timecode_hnd_t *h, int loop_num )
84 {
85     h->timebase_num = 0;
86     h->timebase_den = MKV_TIMEBASE_DEN;
87     for( int num = 0; num < loop_num; num++ )
88     {
89         uint64_t fps_den;
90         double exponent;
91         double fps_sig = sigexp10( fpss[num], &exponent );
92         fps_den = round( MKV_TIMEBASE_DEN / fps_sig ) / exponent;
93         h->timebase_num = fps_den && h->timebase_num ? gcd( h->timebase_num, fps_den ) : fps_den;
94         if( h->timebase_num > UINT32_MAX || !h->timebase_num )
95         {
96             fprintf( stderr, "timecode [error]: automatic timebase generation failed.\n"
97                              "                  Specify timebase manually.\n" );
98             return -1;
99         }
100     }
101     return 0;
102 }
103
104 static int parse_tcfile( FILE *tcfile_in, timecode_hnd_t *h, video_info_t *info )
105 {
106     char buff[256];
107     int ret, tcfv, num, seq_num, timecodes_num;
108     int64_t pts_seek_offset;
109     double *timecodes = NULL;
110     double *fpss = NULL;
111
112     ret = fscanf( tcfile_in, "# timecode format v%d", &tcfv );
113     if( ret != 1 || (tcfv != 1 && tcfv != 2) )
114     {
115         fprintf( stderr, "timecode [error]: unsupported timecode format\n" );
116         return -1;
117     }
118
119     if( tcfv == 1 )
120     {
121         uint64_t file_pos;
122         double assume_fps, seq_fps;
123         int start, end = h->seek;
124         int prev_start = -1, prev_end = -1;
125
126         h->assume_fps = 0;
127         for( num = 2; fgets( buff, sizeof(buff), tcfile_in ) != NULL; num++ )
128         {
129             if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
130                 continue;
131             if( sscanf( buff, "assume %lf", &h->assume_fps ) != 1 && sscanf( buff, "Assume %lf", &h->assume_fps ) != 1 )
132             {
133                 fprintf( stderr, "timecode [error]: tcfile parsing error: assumed fps not found\n" );
134                 return -1;
135             }
136             break;
137         }
138         if( h->assume_fps <= 0 )
139         {
140             fprintf( stderr, "timecode [error]: invalid assumed fps %.6f\n", h->assume_fps );
141             return -1;
142         }
143
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++ )
147         {
148             if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
149             {
150                 if( sscanf( buff, "# TDecimate Mode 3:  Last Frame = %d", &end ) == 1 )
151                     h->stored_pts_num = end + 1 - h->seek;
152                 continue;
153             }
154             ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
155             if( ret != 3 && ret != EOF )
156             {
157                 fprintf( stderr, "timecode [error]: invalid input tcfile\n" );
158                 return -1;
159             }
160             if( start > end || start <= prev_start || end <= prev_end || seq_fps <= 0 )
161             {
162                 fprintf( stderr, "timecode [error]: invalid input tcfile at line %d: %s\n", num, buff );
163                 return -1;
164             }
165             prev_start = start;
166             prev_end = end;
167             if( h->auto_timebase_den || h->auto_timebase_num )
168                 ++seq_num;
169         }
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 );
174
175         timecodes = malloc( timecodes_num * sizeof(double) );
176         if( !timecodes )
177             return -1;
178         if( h->auto_timebase_den || h->auto_timebase_num )
179         {
180             fpss = malloc( (seq_num + 1) * sizeof(double) );
181             if( !fpss )
182                 goto fail;
183         }
184
185         assume_fps = correct_fps( h->assume_fps, h );
186         if( assume_fps < 0 )
187             goto fail;
188         timecodes[0] = 0;
189         for( num = seq_num = 0; num < timecodes_num - 1; )
190         {
191             fgets( buff, sizeof(buff), tcfile_in );
192             if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
193                 continue;
194             ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
195             if( ret != 3 )
196                 start = end = timecodes_num - 1;
197             for( ; num < start && num < timecodes_num - 1; num++ )
198                 timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
199             if( num < timecodes_num - 1 )
200             {
201                 if( h->auto_timebase_den || h->auto_timebase_num )
202                     fpss[seq_num++] = seq_fps;
203                 seq_fps = correct_fps( seq_fps, h );
204                 if( seq_fps < 0 )
205                     goto fail;
206                 for( num = start; num <= end && num < timecodes_num - 1; num++ )
207                     timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
208             }
209         }
210         if( h->auto_timebase_den || h->auto_timebase_num )
211             fpss[seq_num] = h->assume_fps;
212
213         if( h->auto_timebase_num && !h->auto_timebase_den )
214         {
215             double exponent;
216             double assume_fps_sig, seq_fps_sig;
217             if( try_mkv_timebase_den( fpss, h, seq_num + 1 ) < 0 )
218                 goto fail;
219             fseek( tcfile_in, file_pos, SEEK_SET );
220             assume_fps_sig = sigexp10( h->assume_fps, &exponent );
221             assume_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / assume_fps_sig ) / exponent );
222             for( num = 0; num < timecodes_num - 1; )
223             {
224                 fgets( buff, sizeof(buff), tcfile_in );
225                 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
226                     continue;
227                 ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
228                 if( ret != 3 )
229                     start = end = timecodes_num - 1;
230                 seq_fps_sig = sigexp10( seq_fps, &exponent );
231                 seq_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / seq_fps_sig ) / exponent );
232                 for( ; num < start && num < timecodes_num - 1; num++ )
233                     timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
234                 for( num = start; num <= end && num < timecodes_num - 1; num++ )
235                     timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
236             }
237         }
238         if( fpss )
239             free( fpss );
240
241         h->assume_fps = assume_fps;
242         h->last_timecode = timecodes[timecodes_num - 1];
243     }
244     else    /* tcfv == 2 */
245     {
246         uint64_t file_pos = ftell( tcfile_in );
247
248         num = h->stored_pts_num = 0;
249         while( fgets( buff, sizeof(buff), tcfile_in ) != NULL )
250         {
251             if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
252             {
253                 if( !num )
254                     file_pos = ftell( tcfile_in );
255                 continue;
256             }
257             if( num >= h->seek )
258                 ++h->stored_pts_num;
259             ++num;
260         }
261         timecodes_num = h->stored_pts_num + h->seek;
262         if( !timecodes_num )
263         {
264             fprintf( stderr, "timecode [error]: input tcfile doesn't have any timecodes!\n" );
265             return -1;
266         }
267         fseek( tcfile_in, file_pos, SEEK_SET );
268
269         timecodes = malloc( timecodes_num * sizeof(double) );
270         if( !timecodes )
271             return -1;
272
273         fgets( buff, sizeof(buff), tcfile_in );
274         ret = sscanf( buff, "%lf", &timecodes[0] );
275         if( ret != 1 )
276         {
277             fprintf( stderr, "timecode [error]: invalid input tcfile for frame 0\n" );
278             goto fail;
279         }
280         for( num = 1; num < timecodes_num; )
281         {
282             fgets( buff, sizeof(buff), tcfile_in );
283             if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
284                 continue;
285             ret = sscanf( buff, "%lf", &timecodes[num] );
286             timecodes[num] *= 1e-3;         /* Timecode format v2 is expressed in milliseconds. */
287             if( ret != 1 || timecodes[num] <= timecodes[num - 1] )
288             {
289                 fprintf( stderr, "timecode [error]: invalid input tcfile for frame %d\n", num );
290                 goto fail;
291             }
292             ++num;
293         }
294
295         if( timecodes_num == 1 )
296             h->timebase_den = info->fps_num;
297         else if( h->auto_timebase_den )
298         {
299             fpss = malloc( (timecodes_num - 1) * sizeof(double) );
300             if( !fpss )
301                 goto fail;
302             for( num = 0; num < timecodes_num - 1; num++ )
303             {
304                 fpss[num] = 1 / (timecodes[num + 1] - timecodes[num]);
305                 if( h->timebase_den >= 0 )
306                 {
307                     int i = 1;
308                     uint64_t fps_num, fps_den;
309                     double exponent;
310                     double fps_sig = sigexp10( fpss[num], &exponent );
311                     while( 1 )
312                     {
313                         fps_den = i * h->timebase_num;
314                         fps_num = round( fps_den * fps_sig ) * exponent;
315                         if( fps_num > UINT32_MAX || fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
316                             break;
317                         ++i;
318                     }
319                     h->timebase_den = fps_num && h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
320                     if( h->timebase_den > UINT32_MAX )
321                     {
322                         h->auto_timebase_den = 0;
323                         continue;
324                     }
325                 }
326             }
327             if( h->auto_timebase_num && !h->auto_timebase_den )
328                 if( try_mkv_timebase_den( fpss, h, timecodes_num - 1 ) < 0 )
329                     goto fail;
330             free( fpss );
331         }
332
333         if( timecodes_num > 1 )
334             h->assume_fps = 1 / (timecodes[timecodes_num - 1] - timecodes[timecodes_num - 2]);
335         else
336             h->assume_fps = (double)info->fps_num / info->fps_den;
337         h->last_timecode = timecodes[timecodes_num - 1];
338     }
339
340     if( h->auto_timebase_den || h->auto_timebase_num )
341     {
342         uint64_t i = gcd( h->timebase_num, h->timebase_den );
343         h->timebase_num /= i;
344         h->timebase_den /= i;
345         fprintf( stderr, "timecode [info]: automatic timebase generation %"PRIu64"/%"PRIu64"\n", h->timebase_num, h->timebase_den );
346     }
347     else if( h->timebase_den > UINT32_MAX || !h->timebase_den )
348     {
349         fprintf( stderr, "timecode [error]: automatic timebase generation failed.\n"
350                          "                  Specify an appropriate timebase manually.\n" );
351         goto fail;
352     }
353
354     h->pts = malloc( h->stored_pts_num * sizeof(int64_t) );
355     if( !h->pts )
356         goto fail;
357     pts_seek_offset = (int64_t)( timecodes[h->seek] * ((double)h->timebase_den / h->timebase_num) + 0.5 );
358     h->pts[0] = 0;
359     for( num = 1; num < h->stored_pts_num; num++ )
360     {
361         h->pts[num] = (int64_t)( timecodes[h->seek + num] * ((double)h->timebase_den / h->timebase_num) + 0.5 );
362         h->pts[num] -= pts_seek_offset;
363         if( h->pts[num] <= h->pts[num - 1] )
364         {
365             fprintf( stderr, "timecode [error]: invalid timebase or timecode for frame %d\n", num );
366             goto fail;
367         }
368     }
369
370     free( timecodes );
371     return 0;
372
373 fail:
374     if( timecodes )
375         free( timecodes );
376     if( fpss )
377         free( fpss );
378     return -1;
379 }
380
381 #undef DOUBLE_EPSILON
382 #undef MKV_TIMEBASE_DEN
383
384 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
385 {
386     int ret = 0;
387     FILE *tcfile_in;
388     timecode_hnd_t *h = malloc( sizeof(timecode_hnd_t) );
389     if( !h )
390     {
391         fprintf( stderr, "timecode [error]: malloc failed\n" );
392         return -1;
393     }
394     h->input = input;
395     h->p_handle = *p_handle;
396     h->frame_total = input.get_frame_total( h->p_handle );
397     h->seek = opt->seek;
398     if( opt->timebase )
399     {
400         ret = sscanf( opt->timebase, "%"SCNu64"/%"SCNu64, &h->timebase_num, &h->timebase_den );
401         if( ret == 1 )
402             h->timebase_num = strtoul( opt->timebase, NULL, 10 );
403         if( h->timebase_num > UINT32_MAX || h->timebase_den > UINT32_MAX )
404         {
405             fprintf( stderr, "timecode [error]: timebase you specified exceeds H.264 maximum\n" );
406             return -1;
407         }
408     }
409     h->auto_timebase_num = !ret;
410     h->auto_timebase_den = ret < 2;
411     if( h->auto_timebase_num )
412         h->timebase_num = info->fps_den; /* can be changed later by auto timebase generation */
413     if( h->auto_timebase_den )
414         h->timebase_den = 0;             /* set later by auto timebase generation */
415     timecode_input.picture_alloc = h->input.picture_alloc;
416     timecode_input.picture_clean = h->input.picture_clean;
417
418     *p_handle = h;
419
420     tcfile_in = fopen( psz_filename, "rb" );
421     if( !tcfile_in )
422     {
423         fprintf( stderr, "timecode [error]: can't open `%s'\n", psz_filename );
424         return -1;
425     }
426     else if( !x264_is_regular_file( tcfile_in ) )
427     {
428         fprintf( stderr, "timecode [error]: tcfile input incompatible with non-regular file `%s'\n", psz_filename );
429         fclose( tcfile_in );
430         return -1;
431     }
432
433     if( parse_tcfile( tcfile_in, h, info ) < 0 )
434     {
435         if( h->pts )
436             free( h->pts );
437         fclose( tcfile_in );
438         return -1;
439     }
440     fclose( tcfile_in );
441
442     info->timebase_num = h->timebase_num;
443     info->timebase_den = h->timebase_den;
444     info->vfr = 1;
445
446     return 0;
447 }
448
449 static int get_frame_total( hnd_t handle )
450 {
451     timecode_hnd_t *h = handle;
452     return h->frame_total;
453 }
454
455 static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
456 {
457     timecode_hnd_t *h = handle;
458     int ret = h->input.read_frame( p_pic, h->p_handle, i_frame );
459
460     if( i_frame - h->seek < h->stored_pts_num )
461     {
462         assert( i_frame >= h->seek );
463         p_pic->i_pts = h->pts[i_frame - h->seek];
464     }
465     else
466     {
467         if( h->pts )
468         {
469             fprintf( stderr, "timecode [info]: input timecode file missing data for frame %d and later\n"
470                              "                 assuming constant fps %.6f\n", i_frame, h->assume_fps );
471             free( h->pts );
472             h->pts = NULL;
473         }
474         h->last_timecode += 1 / h->assume_fps;
475         p_pic->i_pts = (int64_t)( h->last_timecode * ((double)h->timebase_den / h->timebase_num) + 0.5 );
476     }
477
478     return ret;
479 }
480
481 static int release_frame( x264_picture_t *pic, hnd_t handle )
482 {
483     timecode_hnd_t *h = handle;
484     if( h->input.release_frame )
485         return h->input.release_frame( pic, h->p_handle );
486     return 0;
487 }
488
489 static int close_file( hnd_t handle )
490 {
491     timecode_hnd_t *h = handle;
492     if( h->pts )
493         free( h->pts );
494     h->input.close_file( h->p_handle );
495     free( h );
496     return 0;
497 }
498
499 cli_input_t timecode_input = { open_file, get_frame_total, NULL, read_frame, release_frame, NULL, close_file };