]> git.sesse.net Git - x264/blob - input/timecode.c
Add TFF/BFF detection to all demuxers
[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     int timebase_num;
36     int 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     int64_t i = 1;
57     int64_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 < 0 )
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 < 0 )
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         int 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 > 0 && h->timebase_num ? gcd( h->timebase_num, fps_den ) : fps_den;
94         if( h->timebase_num <= 0 )
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             if( h->auto_timebase_den || h->auto_timebase_num )
198                 fpss[seq_num++] = seq_fps;
199             seq_fps = correct_fps( seq_fps, h );
200             if( seq_fps < 0 )
201                 goto fail;
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;
206         }
207         if( h->auto_timebase_den || h->auto_timebase_num )
208             fpss[seq_num] = h->assume_fps;
209
210         if( h->auto_timebase_num && !h->auto_timebase_den )
211         {
212             double exponent;
213             double assume_fps_sig, seq_fps_sig;
214             if( try_mkv_timebase_den( fpss, h, seq_num + 1 ) < 0 )
215                 goto fail;
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; )
220             {
221                 fgets( buff, sizeof(buff), tcfile_in );
222                 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
223                     continue;
224                 ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
225                 if( ret != 3 )
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;
233             }
234         }
235         if( fpss )
236             free( fpss );
237
238         h->assume_fps = assume_fps;
239         h->last_timecode = timecodes[timecodes_num - 1];
240     }
241     else    /* tcfv == 2 */
242     {
243         uint64_t file_pos = ftell( tcfile_in );
244
245         num = h->stored_pts_num = 0;
246         while( fgets( buff, sizeof(buff), tcfile_in ) != NULL )
247         {
248             if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
249             {
250                 if( !num )
251                     file_pos = ftell( tcfile_in );
252                 continue;
253             }
254             if( num >= h->seek )
255                 ++h->stored_pts_num;
256             ++num;
257         }
258         timecodes_num = h->stored_pts_num + h->seek;
259         if( !timecodes_num )
260         {
261             fprintf( stderr, "timecode [error]: input tcfile doesn't have any timecodes!\n" );
262             return -1;
263         }
264         fseek( tcfile_in, file_pos, SEEK_SET );
265
266         timecodes = malloc( timecodes_num * sizeof(double) );
267         if( !timecodes )
268             return -1;
269
270         fgets( buff, sizeof(buff), tcfile_in );
271         ret = sscanf( buff, "%lf", &timecodes[0] );
272         if( ret != 1 )
273         {
274             fprintf( stderr, "timecode [error]: invalid input tcfile for frame 0\n" );
275             goto fail;
276         }
277         for( num = 1; num < timecodes_num; )
278         {
279             fgets( buff, sizeof(buff), tcfile_in );
280             if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
281                 continue;
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] )
285             {
286                 fprintf( stderr, "timecode [error]: invalid input tcfile for frame %d\n", num );
287                 goto fail;
288             }
289             ++num;
290         }
291
292         if( timecodes_num == 1 )
293             h->timebase_den = info->fps_num;
294         else if( h->auto_timebase_den )
295         {
296             fpss = malloc( (timecodes_num - 1) * sizeof(double) );
297             if( !fpss )
298                 goto fail;
299             for( num = 0; num < timecodes_num - 1; num++ )
300             {
301                 fpss[num] = 1 / (timecodes[num + 1] - timecodes[num]);
302                 if( h->timebase_den >= 0 )
303                 {
304                     int i = 1;
305                     int fps_num, fps_den;
306                     double exponent;
307                     double fps_sig = sigexp10( fpss[num], &exponent );
308                     while( 1 )
309                     {
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 )
313                             break;
314                         ++i;
315                     }
316                     h->timebase_den = fps_num > 0 && h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
317                     if( h->timebase_den < 0 )
318                     {
319                         h->auto_timebase_den = 0;
320                         continue;
321                     }
322                 }
323             }
324             if( h->auto_timebase_num && !h->auto_timebase_den )
325                 if( try_mkv_timebase_den( fpss, h, timecodes_num - 1 ) < 0 )
326                     goto fail;
327             free( fpss );
328         }
329
330         if( timecodes_num > 1 )
331             h->assume_fps = 1 / (timecodes[timecodes_num - 1] - timecodes[timecodes_num - 2]);
332         else
333             h->assume_fps = (double)info->fps_num / info->fps_den;
334         h->last_timecode = timecodes[timecodes_num - 1];
335     }
336
337     if( h->auto_timebase_den || h->auto_timebase_num )
338     {
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 );
341     }
342     else if( h->timebase_den <= 0 )
343     {
344         fprintf( stderr, "timecode [error]: automatic timebase generation failed.\n"
345                          "                  Specify an appropriate timebase manually.\n" );
346         goto fail;
347     }
348
349     h->pts = malloc( h->stored_pts_num * sizeof(int64_t) );
350     if( !h->pts )
351         goto fail;
352     pts_seek_offset = (int64_t)( timecodes[h->seek] * ((double)h->timebase_den / h->timebase_num) + 0.5 );
353     h->pts[0] = 0;
354     for( num = 1; num < h->stored_pts_num; num++ )
355     {
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] )
359         {
360             fprintf( stderr, "timecode [error]: invalid timebase or timecode for frame %d\n", num );
361             goto fail;
362         }
363     }
364
365     free( timecodes );
366     return 0;
367
368 fail:
369     if( timecodes )
370         free( timecodes );
371     if( fpss )
372         free( fpss );
373     return -1;
374 }
375
376 #undef DOUBLE_EPSILON
377 #undef MKV_TIMEBASE_DEN
378
379 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
380 {
381     int ret = 0;
382     FILE *tcfile_in;
383     timecode_hnd_t *h = malloc( sizeof(timecode_hnd_t) );
384     if( !h )
385     {
386         fprintf( stderr, "timecode [error]: malloc failed\n" );
387         return -1;
388     }
389     h->input = input;
390     h->p_handle = *p_handle;
391     h->frame_total = input.get_frame_total( h->p_handle );
392     h->seek = opt->seek;
393     if( opt->timebase )
394         ret = sscanf( opt->timebase, "%d/%d", &h->timebase_num, &h->timebase_den );
395     if( ret == 1 )
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;
405
406     *p_handle = h;
407
408     tcfile_in = fopen( psz_filename, "rb" );
409     if( !tcfile_in )
410     {
411         fprintf( stderr, "timecode [error]: can't open `%s'\n", psz_filename );
412         return -1;
413     }
414     else if( !x264_is_regular_file( tcfile_in ) )
415     {
416         fprintf( stderr, "timecode [error]: tcfile input incompatible with non-regular file `%s'\n", psz_filename );
417         fclose( tcfile_in );
418         return -1;
419     }
420
421     if( parse_tcfile( tcfile_in, h, info ) < 0 )
422     {
423         if( h->pts )
424             free( h->pts );
425         fclose( tcfile_in );
426         return -1;
427     }
428     fclose( tcfile_in );
429
430     info->timebase_num = h->timebase_num;
431     info->timebase_den = h->timebase_den;
432     info->vfr = 1;
433
434     return 0;
435 }
436
437 static int get_frame_total( hnd_t handle )
438 {
439     timecode_hnd_t *h = handle;
440     return h->frame_total;
441 }
442
443 static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
444 {
445     timecode_hnd_t *h = handle;
446     int ret = h->input.read_frame( p_pic, h->p_handle, i_frame );
447
448     if( i_frame - h->seek < h->stored_pts_num )
449     {
450         assert( i_frame >= h->seek );
451         p_pic->i_pts = h->pts[i_frame - h->seek];
452     }
453     else
454     {
455         if( h->pts )
456         {
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 );
459             free( h->pts );
460             h->pts = NULL;
461         }
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 );
464     }
465
466     return ret;
467 }
468
469 static int release_frame( x264_picture_t *pic, hnd_t handle )
470 {
471     timecode_hnd_t *h = handle;
472     if( h->input.release_frame )
473         return h->input.release_frame( pic, h->p_handle );
474     return 0;
475 }
476
477 static int close_file( hnd_t handle )
478 {
479     timecode_hnd_t *h = handle;
480     if( h->pts )
481         free( h->pts );
482     h->input.close_file( h->p_handle );
483     free( h );
484     return 0;
485 }
486
487 cli_input_t timecode_input = { open_file, get_frame_total, NULL, read_frame, release_frame, NULL, close_file };