]> git.sesse.net Git - x264/blob - input/timecode.c
Make the #if'd out naive ESA actually match the real implementation
[x264] / input / timecode.c
1 /*****************************************************************************
2  * timecode.c: timecode file input
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  * 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 #include <math.h>
29
30 typedef struct
31 {
32     cli_input_t input;
33     hnd_t p_handle;
34     int auto_timebase_num;
35     int auto_timebase_den;
36     uint64_t timebase_num;
37     uint64_t timebase_den;
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         FAIL_IF_ERROR( fps_num > UINT32_MAX, "tcfile fps correction failed.\n"
65                        "                  Specify an appropriate timebase manually or remake tcfile.\n" )
66         if( fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
67             break;
68         ++i;
69     }
70     if( h->auto_timebase_den )
71     {
72         h->timebase_den = h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
73         if( h->timebase_den > UINT32_MAX )
74             h->auto_timebase_den = 0;
75     }
76     return (double)fps_num / fps_den;
77 }
78
79 static int try_mkv_timebase_den( double *fpss, timecode_hnd_t *h, int loop_num )
80 {
81     h->timebase_num = 0;
82     h->timebase_den = MKV_TIMEBASE_DEN;
83     for( int num = 0; num < loop_num; num++ )
84     {
85         uint64_t fps_den;
86         double exponent;
87         double fps_sig = sigexp10( fpss[num], &exponent );
88         fps_den = round( MKV_TIMEBASE_DEN / fps_sig ) / exponent;
89         h->timebase_num = fps_den && h->timebase_num ? gcd( h->timebase_num, fps_den ) : fps_den;
90         FAIL_IF_ERROR( h->timebase_num > UINT32_MAX || !h->timebase_num, "automatic timebase generation failed.\n"
91                        "                  Specify timebase manually.\n" )
92     }
93     return 0;
94 }
95
96 static int parse_tcfile( FILE *tcfile_in, timecode_hnd_t *h, video_info_t *info )
97 {
98     char buff[256];
99     int ret, tcfv, num, seq_num, timecodes_num;
100     double *timecodes = NULL;
101     double *fpss = NULL;
102
103     ret = fscanf( tcfile_in, "# timecode format v%d", &tcfv );
104     FAIL_IF_ERROR( ret != 1 || (tcfv != 1 && tcfv != 2), "unsupported timecode format\n" )
105
106     if( tcfv == 1 )
107     {
108         uint64_t file_pos;
109         double assume_fps, seq_fps;
110         int start, end;
111         int prev_start = -1, prev_end = -1;
112
113         h->assume_fps = 0;
114         for( num = 2; fgets( buff, sizeof(buff), tcfile_in ) != NULL; num++ )
115         {
116             if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
117                 continue;
118             FAIL_IF_ERROR( sscanf( buff, "assume %lf", &h->assume_fps ) != 1 && sscanf( buff, "Assume %lf", &h->assume_fps ) != 1,
119                            "tcfile parsing error: assumed fps not found\n" )
120             break;
121         }
122         FAIL_IF_ERROR( h->assume_fps <= 0, "invalid assumed fps %.6f\n", h->assume_fps )
123
124         file_pos = ftell( tcfile_in );
125         h->stored_pts_num = 0;
126         for( seq_num = 0; fgets( buff, sizeof(buff), tcfile_in ) != NULL; num++ )
127         {
128             if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
129             {
130                 if( sscanf( buff, "# TDecimate Mode 3:  Last Frame = %d", &end ) == 1 )
131                     h->stored_pts_num = end + 1;
132                 continue;
133             }
134             ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
135             FAIL_IF_ERROR( ret != 3 && ret != EOF, "invalid input tcfile\n" )
136             FAIL_IF_ERROR( start > end || start <= prev_start || end <= prev_end || seq_fps <= 0,
137                            "invalid input tcfile at line %d: %s\n", num, buff )
138             prev_start = start;
139             prev_end = end;
140             if( h->auto_timebase_den || h->auto_timebase_num )
141                 ++seq_num;
142         }
143         if( !h->stored_pts_num )
144             h->stored_pts_num = end + 1;
145         timecodes_num = h->stored_pts_num;
146         fseek( tcfile_in, file_pos, SEEK_SET );
147
148         timecodes = malloc( timecodes_num * sizeof(double) );
149         if( !timecodes )
150             return -1;
151         if( h->auto_timebase_den || h->auto_timebase_num )
152         {
153             fpss = malloc( (seq_num + 1) * sizeof(double) );
154             if( !fpss )
155                 goto fail;
156         }
157
158         assume_fps = correct_fps( h->assume_fps, h );
159         if( assume_fps < 0 )
160             goto fail;
161         timecodes[0] = 0;
162         for( num = seq_num = 0; num < timecodes_num - 1; )
163         {
164             fgets( buff, sizeof(buff), tcfile_in );
165             if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
166                 continue;
167             ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
168             if( ret != 3 )
169                 start = end = timecodes_num - 1;
170             for( ; num < start && num < timecodes_num - 1; num++ )
171                 timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
172             if( num < timecodes_num - 1 )
173             {
174                 if( h->auto_timebase_den || h->auto_timebase_num )
175                     fpss[seq_num++] = seq_fps;
176                 seq_fps = correct_fps( seq_fps, h );
177                 if( seq_fps < 0 )
178                     goto fail;
179                 for( num = start; num <= end && num < timecodes_num - 1; num++ )
180                     timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
181             }
182         }
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; )
196             {
197                 fgets( buff, sizeof(buff), tcfile_in );
198                 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
199                     continue;
200                 ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
201                 if( ret != 3 )
202                     start = end = timecodes_num - 1;
203                 seq_fps_sig = sigexp10( seq_fps, &exponent );
204                 seq_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / seq_fps_sig ) / exponent );
205                 for( ; num < start && num < timecodes_num - 1; num++ )
206                     timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
207                 for( num = start; num <= end && num < timecodes_num - 1; num++ )
208                     timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
209             }
210         }
211         if( fpss )
212             free( fpss );
213
214         h->assume_fps = assume_fps;
215         h->last_timecode = timecodes[timecodes_num - 1];
216     }
217     else    /* tcfv == 2 */
218     {
219         uint64_t file_pos = ftell( tcfile_in );
220
221         h->stored_pts_num = 0;
222         while( fgets( buff, sizeof(buff), tcfile_in ) != NULL )
223         {
224             if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
225             {
226                 if( !h->stored_pts_num )
227                     file_pos = ftell( tcfile_in );
228                 continue;
229             }
230             h->stored_pts_num++;
231         }
232         timecodes_num = h->stored_pts_num;
233         FAIL_IF_ERROR( !timecodes_num, "input tcfile doesn't have any timecodes!\n" )
234         fseek( tcfile_in, file_pos, SEEK_SET );
235
236         timecodes = malloc( timecodes_num * sizeof(double) );
237         if( !timecodes )
238             return -1;
239
240         fgets( buff, sizeof(buff), tcfile_in );
241         ret = sscanf( buff, "%lf", &timecodes[0] );
242         FAIL_IF_ERROR( ret != 1, "invalid input tcfile for frame 0\n" )
243         for( num = 1; num < timecodes_num; )
244         {
245             fgets( buff, sizeof(buff), tcfile_in );
246             if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
247                 continue;
248             ret = sscanf( buff, "%lf", &timecodes[num] );
249             timecodes[num] *= 1e-3;         /* Timecode format v2 is expressed in milliseconds. */
250             FAIL_IF_ERROR( ret != 1 || timecodes[num] <= timecodes[num - 1],
251                            "invalid input tcfile for frame %d\n", num )
252             ++num;
253         }
254
255         if( timecodes_num == 1 )
256             h->timebase_den = info->fps_num;
257         else if( h->auto_timebase_den )
258         {
259             fpss = malloc( (timecodes_num - 1) * sizeof(double) );
260             if( !fpss )
261                 goto fail;
262             for( num = 0; num < timecodes_num - 1; num++ )
263             {
264                 fpss[num] = 1 / (timecodes[num + 1] - timecodes[num]);
265                 if( h->timebase_den >= 0 )
266                 {
267                     int i = 1;
268                     uint64_t fps_num, fps_den;
269                     double exponent;
270                     double fps_sig = sigexp10( fpss[num], &exponent );
271                     while( 1 )
272                     {
273                         fps_den = i * h->timebase_num;
274                         fps_num = round( fps_den * fps_sig ) * exponent;
275                         if( fps_num > UINT32_MAX || fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
276                             break;
277                         ++i;
278                     }
279                     h->timebase_den = fps_num && h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
280                     if( h->timebase_den > UINT32_MAX )
281                     {
282                         h->auto_timebase_den = 0;
283                         continue;
284                     }
285                 }
286             }
287             if( h->auto_timebase_num && !h->auto_timebase_den )
288                 if( try_mkv_timebase_den( fpss, h, timecodes_num - 1 ) < 0 )
289                     goto fail;
290             free( fpss );
291         }
292
293         if( timecodes_num > 1 )
294             h->assume_fps = 1 / (timecodes[timecodes_num - 1] - timecodes[timecodes_num - 2]);
295         else
296             h->assume_fps = (double)info->fps_num / info->fps_den;
297         h->last_timecode = timecodes[timecodes_num - 1];
298     }
299
300     if( h->auto_timebase_den || h->auto_timebase_num )
301     {
302         uint64_t i = gcd( h->timebase_num, h->timebase_den );
303         h->timebase_num /= i;
304         h->timebase_den /= i;
305         x264_cli_log( "timecode", X264_LOG_INFO, "automatic timebase generation %"PRIu64"/%"PRIu64"\n", h->timebase_num, h->timebase_den );
306     }
307     else FAIL_IF_ERROR( h->timebase_den > UINT32_MAX || !h->timebase_den, "automatic timebase generation failed.\n"
308                         "                  Specify an appropriate timebase manually.\n" )
309
310     h->pts = malloc( h->stored_pts_num * sizeof(int64_t) );
311     if( !h->pts )
312         goto fail;
313     h->pts[0] = 0;
314     for( num = 1; num < h->stored_pts_num; num++ )
315     {
316         h->pts[num] = timecodes[num] * ((double)h->timebase_den / h->timebase_num) + 0.5;
317         FAIL_IF_ERROR( h->pts[num] <= h->pts[num - 1], "invalid timebase or timecode for frame %d\n", num )
318     }
319
320     free( timecodes );
321     return 0;
322
323 fail:
324     if( timecodes )
325         free( timecodes );
326     if( fpss )
327         free( fpss );
328     return -1;
329 }
330
331 #undef DOUBLE_EPSILON
332 #undef MKV_TIMEBASE_DEN
333
334 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
335 {
336     int ret = 0;
337     FILE *tcfile_in;
338     timecode_hnd_t *h = malloc( sizeof(timecode_hnd_t) );
339     FAIL_IF_ERROR( !h, "malloc failed\n" )
340     h->input = input;
341     h->p_handle = *p_handle;
342     if( opt->timebase )
343     {
344         ret = sscanf( opt->timebase, "%"SCNu64"/%"SCNu64, &h->timebase_num, &h->timebase_den );
345         if( ret == 1 )
346             h->timebase_num = strtoul( opt->timebase, NULL, 10 );
347         FAIL_IF_ERROR( h->timebase_num > UINT32_MAX || h->timebase_den > UINT32_MAX,
348                        "timebase you specified exceeds H.264 maximum\n" )
349     }
350     h->auto_timebase_num = !ret;
351     h->auto_timebase_den = ret < 2;
352     if( h->auto_timebase_num )
353         h->timebase_num = info->fps_den; /* can be changed later by auto timebase generation */
354     if( h->auto_timebase_den )
355         h->timebase_den = 0;             /* set later by auto timebase generation */
356     timecode_input.picture_alloc = h->input.picture_alloc;
357     timecode_input.picture_clean = h->input.picture_clean;
358
359     *p_handle = h;
360
361     tcfile_in = fopen( psz_filename, "rb" );
362     FAIL_IF_ERROR( !tcfile_in, "can't open `%s'\n", psz_filename )
363     else if( !x264_is_regular_file( tcfile_in ) )
364     {
365         x264_cli_log( "timecode", X264_LOG_ERROR, "tcfile input incompatible with non-regular file `%s'\n", psz_filename );
366         fclose( tcfile_in );
367         return -1;
368     }
369
370     if( parse_tcfile( tcfile_in, h, info ) < 0 )
371     {
372         if( h->pts )
373             free( h->pts );
374         fclose( tcfile_in );
375         return -1;
376     }
377     fclose( tcfile_in );
378
379     info->timebase_num = h->timebase_num;
380     info->timebase_den = h->timebase_den;
381     info->vfr = 1;
382
383     return 0;
384 }
385
386 static int64_t get_frame_pts( timecode_hnd_t *h, int frame, int real_frame )
387 {
388     if( frame < h->stored_pts_num )
389         return h->pts[frame];
390     else
391     {
392         if( h->pts && real_frame )
393         {
394             x264_cli_log( "timecode", X264_LOG_INFO, "input timecode file missing data for frame %d and later\n"
395                           "                 assuming constant fps %.6f\n", frame, h->assume_fps );
396             free( h->pts );
397             h->pts = NULL;
398         }
399         double timecode = h->last_timecode + 1 / h->assume_fps;
400         if( real_frame )
401             h->last_timecode = timecode;
402         return timecode * ((double)h->timebase_den / h->timebase_num) + 0.5;
403     }
404 }
405
406 static int read_frame( cli_pic_t *pic, hnd_t handle, int frame )
407 {
408     timecode_hnd_t *h = handle;
409     int ret = h->input.read_frame( pic, h->p_handle, frame );
410
411     pic->pts = get_frame_pts( h, frame, 1 );
412     pic->duration = get_frame_pts( h, frame + 1, 0 ) - pic->pts;
413
414     return ret;
415 }
416
417 static int release_frame( cli_pic_t *pic, hnd_t handle )
418 {
419     timecode_hnd_t *h = handle;
420     if( h->input.release_frame )
421         return h->input.release_frame( pic, h->p_handle );
422     return 0;
423 }
424
425 static int close_file( hnd_t handle )
426 {
427     timecode_hnd_t *h = handle;
428     if( h->pts )
429         free( h->pts );
430     h->input.close_file( h->p_handle );
431     free( h );
432     return 0;
433 }
434
435 cli_input_t timecode_input = { open_file, NULL, read_frame, release_frame, NULL, close_file };