]> git.sesse.net Git - x264/blob - input/timecode.c
Add speedcontrol file.
[x264] / input / timecode.c
1 /*****************************************************************************
2  * timecode.c: timecode file input
3  *****************************************************************************
4  * Copyright (C) 2010-2016 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  * This program is also available under a commercial proprietary license.
23  * For more information, contact us at licensing@x264.com.
24  *****************************************************************************/
25
26 #include "input.h"
27 #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "timecode", __VA_ARGS__ )
28
29 typedef struct
30 {
31     cli_input_t input;
32     hnd_t p_handle;
33     int auto_timebase_num;
34     int auto_timebase_den;
35     uint64_t timebase_num;
36     uint64_t timebase_den;
37     int stored_pts_num;
38     int64_t *pts;
39     double assume_fps;
40     double last_timecode;
41 } timecode_hnd_t;
42
43 static inline double sigexp10( double value, double *exponent )
44 {
45     /* This function separates significand and exp10 from double floating point. */
46     *exponent = pow( 10, floor( log10( value ) ) );
47     return value / *exponent;
48 }
49
50 #define DOUBLE_EPSILON 5e-6
51 #define MKV_TIMEBASE_DEN 1000000000
52
53 static double correct_fps( double fps, timecode_hnd_t *h )
54 {
55     int i = 1;
56     uint64_t fps_num, fps_den;
57     double exponent;
58     double fps_sig = sigexp10( fps, &exponent );
59     while( 1 )
60     {
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 )
66             break;
67         ++i;
68     }
69     if( h->auto_timebase_den )
70     {
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;
74     }
75     return (double)fps_num / fps_den;
76 }
77
78 static int try_mkv_timebase_den( double *fpss, timecode_hnd_t *h, int loop_num )
79 {
80     h->timebase_num = 0;
81     h->timebase_den = MKV_TIMEBASE_DEN;
82     for( int num = 0; num < loop_num; num++ )
83     {
84         uint64_t fps_den;
85         double exponent;
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" )
91     }
92     return 0;
93 }
94
95 static int parse_tcfile( FILE *tcfile_in, timecode_hnd_t *h, video_info_t *info )
96 {
97     char buff[256];
98     int ret, tcfv, num, seq_num, timecodes_num;
99     double *timecodes = NULL;
100     double *fpss = NULL;
101
102     ret = fscanf( tcfile_in, "# timecode format v%d", &tcfv );
103     FAIL_IF_ERROR( ret != 1 || (tcfv != 1 && tcfv != 2), "unsupported timecode format\n" )
104 #define NO_TIMECODE_LINE (buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r')
105     if( tcfv == 1 )
106     {
107         uint64_t file_pos;
108         double assume_fps, seq_fps;
109         int start, end = -1;
110         int prev_start = -1, prev_end = -1;
111
112         h->assume_fps = 0;
113         for( num = 2; fgets( buff, sizeof(buff), tcfile_in ) != NULL; num++ )
114         {
115             if( NO_TIMECODE_LINE )
116                 continue;
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" )
119             break;
120         }
121         FAIL_IF_ERROR( h->assume_fps <= 0, "invalid assumed fps %.6f\n", h->assume_fps )
122
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++ )
126         {
127             if( NO_TIMECODE_LINE )
128             {
129                 if( sscanf( buff, "# TDecimate Mode 3:  Last Frame = %d", &end ) == 1 )
130                     h->stored_pts_num = end + 1;
131                 continue;
132             }
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 )
137             prev_start = start;
138             prev_end = end;
139             if( h->auto_timebase_den || h->auto_timebase_num )
140                 ++seq_num;
141         }
142         if( !h->stored_pts_num )
143             h->stored_pts_num = end + 2;
144         timecodes_num = h->stored_pts_num;
145         fseek( tcfile_in, file_pos, SEEK_SET );
146
147         timecodes = malloc( timecodes_num * sizeof(double) );
148         if( !timecodes )
149             return -1;
150         if( h->auto_timebase_den || h->auto_timebase_num )
151         {
152             fpss = malloc( (seq_num + 1) * sizeof(double) );
153             if( !fpss )
154                 goto fail;
155         }
156
157         assume_fps = correct_fps( h->assume_fps, h );
158         if( assume_fps < 0 )
159             goto fail;
160         timecodes[0] = 0;
161         for( num = seq_num = 0; num < timecodes_num - 1 && fgets( buff, sizeof(buff), tcfile_in ) != NULL; )
162         {
163             if( NO_TIMECODE_LINE )
164                 continue;
165             ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
166             if( ret != 3 )
167                 start = end = timecodes_num - 1;
168             for( ; num < start && num < timecodes_num - 1; num++ )
169                 timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
170             if( num < timecodes_num - 1 )
171             {
172                 if( h->auto_timebase_den || h->auto_timebase_num )
173                     fpss[seq_num++] = seq_fps;
174                 seq_fps = correct_fps( seq_fps, h );
175                 if( seq_fps < 0 )
176                     goto fail;
177                 for( num = start; num <= end && num < timecodes_num - 1; num++ )
178                     timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
179             }
180         }
181         for( ; num < timecodes_num - 1; num++ )
182             timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
183         if( h->auto_timebase_den || h->auto_timebase_num )
184             fpss[seq_num] = h->assume_fps;
185
186         if( h->auto_timebase_num && !h->auto_timebase_den )
187         {
188             double exponent;
189             double assume_fps_sig, seq_fps_sig;
190             if( try_mkv_timebase_den( fpss, h, seq_num + 1 ) < 0 )
191                 goto fail;
192             fseek( tcfile_in, file_pos, SEEK_SET );
193             assume_fps_sig = sigexp10( h->assume_fps, &exponent );
194             assume_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / assume_fps_sig ) / exponent );
195             for( num = 0; num < timecodes_num - 1 && fgets( buff, sizeof(buff), tcfile_in ) != NULL; )
196             {
197                 if( NO_TIMECODE_LINE )
198                     continue;
199                 ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
200                 if( ret != 3 )
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;
208             }
209             for( ; num < timecodes_num - 1; num++ )
210                 timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
211         }
212         if( fpss )
213         {
214             free( fpss );
215             fpss = NULL;
216         }
217
218         h->assume_fps = assume_fps;
219         h->last_timecode = timecodes[timecodes_num - 1];
220     }
221     else    /* tcfv == 2 */
222     {
223         uint64_t file_pos = ftell( tcfile_in );
224
225         h->stored_pts_num = 0;
226         while( fgets( buff, sizeof(buff), tcfile_in ) != NULL )
227         {
228             if( NO_TIMECODE_LINE )
229             {
230                 if( !h->stored_pts_num )
231                     file_pos = ftell( tcfile_in );
232                 continue;
233             }
234             h->stored_pts_num++;
235         }
236         timecodes_num = h->stored_pts_num;
237         FAIL_IF_ERROR( !timecodes_num, "input tcfile doesn't have any timecodes!\n" )
238         fseek( tcfile_in, file_pos, SEEK_SET );
239
240         timecodes = malloc( timecodes_num * sizeof(double) );
241         if( !timecodes )
242             return -1;
243
244         num = 0;
245         if( fgets( buff, sizeof(buff), tcfile_in ) != NULL )
246         {
247             ret = sscanf( buff, "%lf", &timecodes[0] );
248             timecodes[0] *= 1e-3;         /* Timecode format v2 is expressed in milliseconds. */
249             FAIL_IF_ERROR( ret != 1, "invalid input tcfile for frame 0\n" )
250             for( num = 1; num < timecodes_num && fgets( buff, sizeof(buff), tcfile_in ) != NULL; )
251             {
252                 if( NO_TIMECODE_LINE )
253                     continue;
254                 ret = sscanf( buff, "%lf", &timecodes[num] );
255                 timecodes[num] *= 1e-3;         /* Timecode format v2 is expressed in milliseconds. */
256                 FAIL_IF_ERROR( ret != 1 || timecodes[num] <= timecodes[num - 1],
257                                "invalid input tcfile for frame %d\n", num )
258                 ++num;
259             }
260         }
261         FAIL_IF_ERROR( num < timecodes_num, "failed to read input tcfile for frame %d", num )
262
263         if( timecodes_num == 1 )
264             h->timebase_den = info->fps_num;
265         else if( h->auto_timebase_den )
266         {
267             fpss = malloc( (timecodes_num - 1) * sizeof(double) );
268             if( !fpss )
269                 goto fail;
270             for( num = 0; num < timecodes_num - 1; num++ )
271             {
272                 fpss[num] = 1 / (timecodes[num + 1] - timecodes[num]);
273                 if( h->auto_timebase_den )
274                 {
275                     int i = 1;
276                     uint64_t fps_num, fps_den;
277                     double exponent;
278                     double fps_sig = sigexp10( fpss[num], &exponent );
279                     while( 1 )
280                     {
281                         fps_den = i * h->timebase_num;
282                         fps_num = round( fps_den * fps_sig ) * exponent;
283                         if( fps_num > UINT32_MAX || fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
284                             break;
285                         ++i;
286                     }
287                     h->timebase_den = fps_num && h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
288                     if( h->timebase_den > UINT32_MAX )
289                     {
290                         h->auto_timebase_den = 0;
291                         continue;
292                     }
293                 }
294             }
295             if( h->auto_timebase_num && !h->auto_timebase_den )
296                 if( try_mkv_timebase_den( fpss, h, timecodes_num - 1 ) < 0 )
297                     goto fail;
298             free( fpss );
299             fpss = NULL;
300         }
301
302         if( timecodes_num > 1 )
303             h->assume_fps = 1 / (timecodes[timecodes_num - 1] - timecodes[timecodes_num - 2]);
304         else
305             h->assume_fps = (double)info->fps_num / info->fps_den;
306         h->last_timecode = timecodes[timecodes_num - 1];
307     }
308 #undef NO_TIMECODE_LINE
309     if( h->auto_timebase_den || h->auto_timebase_num )
310     {
311         uint64_t i = gcd( h->timebase_num, h->timebase_den );
312         h->timebase_num /= i;
313         h->timebase_den /= i;
314         x264_cli_log( "timecode", X264_LOG_INFO, "automatic timebase generation %"PRIu64"/%"PRIu64"\n", h->timebase_num, h->timebase_den );
315     }
316     else FAIL_IF_ERROR( h->timebase_den > UINT32_MAX || !h->timebase_den, "automatic timebase generation failed.\n"
317                         "                  Specify an appropriate timebase manually.\n" )
318
319     h->pts = malloc( h->stored_pts_num * sizeof(int64_t) );
320     if( !h->pts )
321         goto fail;
322     for( num = 0; num < h->stored_pts_num; num++ )
323     {
324         h->pts[num] = timecodes[num] * ((double)h->timebase_den / h->timebase_num) + 0.5;
325         FAIL_IF_ERROR( num > 0 && h->pts[num] <= h->pts[num - 1], "invalid timebase or timecode for frame %d\n", num )
326     }
327
328     free( timecodes );
329     return 0;
330
331 fail:
332     if( timecodes )
333         free( timecodes );
334     if( fpss )
335         free( fpss );
336     return -1;
337 }
338
339 #undef DOUBLE_EPSILON
340 #undef MKV_TIMEBASE_DEN
341
342 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
343 {
344     int ret = 0;
345     FILE *tcfile_in;
346     timecode_hnd_t *h = malloc( sizeof(timecode_hnd_t) );
347     FAIL_IF_ERROR( !h, "malloc failed\n" )
348     h->input = cli_input;
349     h->p_handle = *p_handle;
350     h->pts = NULL;
351     if( opt->timebase )
352     {
353         ret = sscanf( opt->timebase, "%"SCNu64"/%"SCNu64, &h->timebase_num, &h->timebase_den );
354         if( ret == 1 )
355         {
356             h->timebase_num = strtoul( opt->timebase, NULL, 10 );
357             h->timebase_den = 0; /* set later by auto timebase generation */
358         }
359         FAIL_IF_ERROR( h->timebase_num > UINT32_MAX || h->timebase_den > UINT32_MAX,
360                        "timebase you specified exceeds H.264 maximum\n" )
361     }
362     h->auto_timebase_num = !ret;
363     h->auto_timebase_den = ret < 2;
364     if( h->auto_timebase_num )
365         h->timebase_num = info->fps_den; /* can be changed later by auto timebase generation */
366     if( h->auto_timebase_den )
367         h->timebase_den = 0;             /* set later by auto timebase generation */
368
369     tcfile_in = x264_fopen( psz_filename, "rb" );
370     FAIL_IF_ERROR( !tcfile_in, "can't open `%s'\n", psz_filename )
371     else if( !x264_is_regular_file( tcfile_in ) )
372     {
373         x264_cli_log( "timecode", X264_LOG_ERROR, "tcfile input incompatible with non-regular file `%s'\n", psz_filename );
374         fclose( tcfile_in );
375         return -1;
376     }
377
378     if( parse_tcfile( tcfile_in, h, info ) < 0 )
379     {
380         if( h->pts )
381             free( h->pts );
382         fclose( tcfile_in );
383         return -1;
384     }
385     fclose( tcfile_in );
386
387     info->timebase_num = h->timebase_num;
388     info->timebase_den = h->timebase_den;
389     info->vfr = 1;
390
391     *p_handle = h;
392     return 0;
393 }
394
395 static int64_t get_frame_pts( timecode_hnd_t *h, int frame, int real_frame )
396 {
397     if( frame < h->stored_pts_num )
398         return h->pts[frame];
399     else
400     {
401         if( h->pts && real_frame )
402         {
403             x264_cli_log( "timecode", X264_LOG_INFO, "input timecode file missing data for frame %d and later\n"
404                           "                 assuming constant fps %.6f\n", frame, h->assume_fps );
405             free( h->pts );
406             h->pts = NULL;
407         }
408         double timecode = h->last_timecode + 1 / h->assume_fps;
409         if( real_frame )
410             h->last_timecode = timecode;
411         return timecode * ((double)h->timebase_den / h->timebase_num) + 0.5;
412     }
413 }
414
415 static int read_frame( cli_pic_t *pic, hnd_t handle, int frame )
416 {
417     timecode_hnd_t *h = handle;
418     if( h->input.read_frame( pic, h->p_handle, frame ) )
419         return -1;
420
421     pic->pts = get_frame_pts( h, frame, 1 );
422     pic->duration = get_frame_pts( h, frame + 1, 0 ) - pic->pts;
423
424     return 0;
425 }
426
427 static int release_frame( cli_pic_t *pic, hnd_t handle )
428 {
429     timecode_hnd_t *h = handle;
430     if( h->input.release_frame )
431         return h->input.release_frame( pic, h->p_handle );
432     return 0;
433 }
434
435 static int picture_alloc( cli_pic_t *pic, hnd_t handle, int csp, int width, int height )
436 {
437     timecode_hnd_t *h = handle;
438     return h->input.picture_alloc( pic, h->p_handle, csp, width, height );
439 }
440
441 static void picture_clean( cli_pic_t *pic, hnd_t handle )
442 {
443     timecode_hnd_t *h = handle;
444     h->input.picture_clean( pic, h->p_handle );
445 }
446
447 static int close_file( hnd_t handle )
448 {
449     timecode_hnd_t *h = handle;
450     if( h->pts )
451         free( h->pts );
452     h->input.close_file( h->p_handle );
453     free( h );
454     return 0;
455 }
456
457 const cli_input_t timecode_input = { open_file, picture_alloc, read_frame, release_frame, picture_clean, close_file };