1 /*****************************************************************************
2 * timecode.c: timecode file input
3 *****************************************************************************
4 * Copyright (C) 2010-2021 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
28 #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "timecode", __VA_ARGS__ )
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
sigexp10(double value,double * exponent)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
correct_fps(double fps,timecode_hnd_t * h)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
try_mkv_timebase_den(double * fpss,timecode_hnd_t * h,int loop_num)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
parse_tcfile(FILE * tcfile_in,timecode_hnd_t * h,video_info_t * info)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 #define NO_TIMECODE_LINE (buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r')
106 if( tcfv == 1 )
107 {
108 int64_t file_pos;
109 double assume_fps, seq_fps;
110 int start, end = -1;
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( NO_TIMECODE_LINE )
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( NO_TIMECODE_LINE )
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 + 2;
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 && fgets( buff, sizeof(buff), tcfile_in ) != NULL; )
163 {
164 if( NO_TIMECODE_LINE )
165 continue;
166 ret = sscanf( buff, "%d,%d,%lf", &start, &end, &seq_fps );
167 if( ret != 3 )
168 start = end = timecodes_num - 1;
169 for( ; num < start && num < timecodes_num - 1; num++ )
170 timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
171 if( num < timecodes_num - 1 )
172 {
173 if( h->auto_timebase_den || h->auto_timebase_num )
174 fpss[seq_num++] = seq_fps;
175 seq_fps = correct_fps( seq_fps, h );
176 if( seq_fps < 0 )
177 goto fail;
178 for( num = start; num <= end && num < timecodes_num - 1; num++ )
179 timecodes[num + 1] = timecodes[num] + 1 / seq_fps;
180 }
181 }
182 for( ; num < timecodes_num - 1; num++ )
183 timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
184 if( h->auto_timebase_den || h->auto_timebase_num )
185 fpss[seq_num] = h->assume_fps;
186
187 if( h->auto_timebase_num && !h->auto_timebase_den )
188 {
189 double exponent;
190 double assume_fps_sig, seq_fps_sig;
191 if( try_mkv_timebase_den( fpss, h, seq_num + 1 ) < 0 )
192 goto fail;
193 fseek( tcfile_in, file_pos, SEEK_SET );
194 assume_fps_sig = sigexp10( h->assume_fps, &exponent );
195 assume_fps = MKV_TIMEBASE_DEN / ( round( MKV_TIMEBASE_DEN / assume_fps_sig ) / exponent );
196 for( num = 0; num < timecodes_num - 1 && fgets( buff, sizeof(buff), tcfile_in ) != NULL; )
197 {
198 if( NO_TIMECODE_LINE )
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 for( ; num < timecodes_num - 1; num++ )
211 timecodes[num + 1] = timecodes[num] + 1 / assume_fps;
212 }
213 if( fpss )
214 {
215 free( fpss );
216 fpss = NULL;
217 }
218
219 h->assume_fps = assume_fps;
220 h->last_timecode = timecodes[timecodes_num - 1];
221 }
222 else /* tcfv == 2 */
223 {
224 int64_t file_pos = ftell( tcfile_in );
225
226 h->stored_pts_num = 0;
227 while( fgets( buff, sizeof(buff), tcfile_in ) != NULL )
228 {
229 if( NO_TIMECODE_LINE )
230 {
231 if( !h->stored_pts_num )
232 file_pos = ftell( tcfile_in );
233 continue;
234 }
235 h->stored_pts_num++;
236 }
237 timecodes_num = h->stored_pts_num;
238 FAIL_IF_ERROR( !timecodes_num, "input tcfile doesn't have any timecodes!\n" );
239 fseek( tcfile_in, file_pos, SEEK_SET );
240
241 timecodes = malloc( timecodes_num * sizeof(double) );
242 if( !timecodes )
243 return -1;
244
245 num = 0;
246 if( fgets( buff, sizeof(buff), tcfile_in ) != NULL )
247 {
248 ret = sscanf( buff, "%lf", &timecodes[0] );
249 timecodes[0] *= 1e-3; /* Timecode format v2 is expressed in milliseconds. */
250 FAIL_IF_ERROR( ret != 1, "invalid input tcfile for frame 0\n" );
251 for( num = 1; num < timecodes_num && fgets( buff, sizeof(buff), tcfile_in ) != NULL; )
252 {
253 if( NO_TIMECODE_LINE )
254 continue;
255 ret = sscanf( buff, "%lf", &timecodes[num] );
256 timecodes[num] *= 1e-3; /* Timecode format v2 is expressed in milliseconds. */
257 FAIL_IF_ERROR( ret != 1 || timecodes[num] <= timecodes[num - 1],
258 "invalid input tcfile for frame %d\n", num );
259 ++num;
260 }
261 }
262 FAIL_IF_ERROR( num < timecodes_num, "failed to read input tcfile for frame %d", num );
263
264 if( timecodes_num == 1 )
265 h->timebase_den = info->fps_num;
266 else if( h->auto_timebase_den )
267 {
268 fpss = malloc( (timecodes_num - 1) * sizeof(double) );
269 if( !fpss )
270 goto fail;
271 for( num = 0; num < timecodes_num - 1; num++ )
272 {
273 fpss[num] = 1 / (timecodes[num + 1] - timecodes[num]);
274 if( h->auto_timebase_den )
275 {
276 int i = 1;
277 uint64_t fps_num, fps_den;
278 double exponent;
279 double fps_sig = sigexp10( fpss[num], &exponent );
280 while( 1 )
281 {
282 fps_den = i * h->timebase_num;
283 fps_num = round( fps_den * fps_sig ) * exponent;
284 if( fps_num > UINT32_MAX || fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
285 break;
286 ++i;
287 }
288 h->timebase_den = fps_num && h->timebase_den ? lcm( h->timebase_den, fps_num ) : fps_num;
289 if( h->timebase_den > UINT32_MAX )
290 {
291 h->auto_timebase_den = 0;
292 continue;
293 }
294 }
295 }
296 if( h->auto_timebase_num && !h->auto_timebase_den )
297 if( try_mkv_timebase_den( fpss, h, timecodes_num - 1 ) < 0 )
298 goto fail;
299 free( fpss );
300 fpss = NULL;
301 }
302
303 if( timecodes_num > 1 )
304 h->assume_fps = 1 / (timecodes[timecodes_num - 1] - timecodes[timecodes_num - 2]);
305 else
306 h->assume_fps = (double)info->fps_num / info->fps_den;
307 h->last_timecode = timecodes[timecodes_num - 1];
308 }
309 #undef NO_TIMECODE_LINE
310 if( h->auto_timebase_den || h->auto_timebase_num )
311 {
312 uint64_t i = gcd( h->timebase_num, h->timebase_den );
313 h->timebase_num /= i;
314 h->timebase_den /= i;
315 x264_cli_log( "timecode", X264_LOG_INFO, "automatic timebase generation %"PRIu64"/%"PRIu64"\n", h->timebase_num, h->timebase_den );
316 }
317 else FAIL_IF_ERROR( h->timebase_den > UINT32_MAX || !h->timebase_den, "automatic timebase generation failed.\n"
318 " Specify an appropriate timebase manually.\n" );
319
320 h->pts = malloc( h->stored_pts_num * sizeof(int64_t) );
321 if( !h->pts )
322 goto fail;
323 for( num = 0; num < h->stored_pts_num; num++ )
324 {
325 h->pts[num] = timecodes[num] * ((double)h->timebase_den / h->timebase_num) + 0.5;
326 FAIL_IF_ERROR( num > 0 && h->pts[num] <= h->pts[num - 1], "invalid timebase or timecode for frame %d\n", num );
327 }
328
329 free( timecodes );
330 return 0;
331
332 fail:
333 if( timecodes )
334 free( timecodes );
335 if( fpss )
336 free( fpss );
337 return -1;
338 }
339
340 #undef DOUBLE_EPSILON
341 #undef MKV_TIMEBASE_DEN
342
open_file(char * psz_filename,hnd_t * p_handle,video_info_t * info,cli_input_opt_t * opt)343 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
344 {
345 int ret = 0;
346 FILE *tcfile_in;
347 timecode_hnd_t *h = malloc( sizeof(timecode_hnd_t) );
348 FAIL_IF_ERROR( !h, "malloc failed\n" );
349 h->input = cli_input;
350 h->p_handle = *p_handle;
351 h->pts = NULL;
352 if( opt->timebase )
353 {
354 ret = sscanf( opt->timebase, "%"SCNu64"/%"SCNu64, &h->timebase_num, &h->timebase_den );
355 if( ret == 1 )
356 {
357 h->timebase_num = strtoul( opt->timebase, NULL, 10 );
358 h->timebase_den = 0; /* set later by auto timebase generation */
359 }
360 FAIL_IF_ERROR( h->timebase_num > UINT32_MAX || h->timebase_den > UINT32_MAX,
361 "timebase you specified exceeds H.264 maximum\n" );
362 }
363 h->auto_timebase_num = !ret;
364 h->auto_timebase_den = ret < 2;
365 if( h->auto_timebase_num )
366 h->timebase_num = info->fps_den; /* can be changed later by auto timebase generation */
367 if( h->auto_timebase_den )
368 h->timebase_den = 0; /* set later by auto timebase generation */
369
370 tcfile_in = x264_fopen( psz_filename, "rb" );
371 FAIL_IF_ERROR( !tcfile_in, "can't open `%s'\n", psz_filename );
372 if( !x264_is_regular_file( tcfile_in ) )
373 {
374 x264_cli_log( "timecode", X264_LOG_ERROR, "tcfile input incompatible with non-regular file `%s'\n", psz_filename );
375 fclose( tcfile_in );
376 return -1;
377 }
378
379 if( parse_tcfile( tcfile_in, h, info ) < 0 )
380 {
381 if( h->pts )
382 free( h->pts );
383 fclose( tcfile_in );
384 return -1;
385 }
386 fclose( tcfile_in );
387
388 info->timebase_num = h->timebase_num;
389 info->timebase_den = h->timebase_den;
390 info->vfr = 1;
391
392 *p_handle = h;
393 return 0;
394 }
395
get_frame_pts(timecode_hnd_t * h,int frame,int real_frame)396 static int64_t get_frame_pts( timecode_hnd_t *h, int frame, int real_frame )
397 {
398 if( frame < h->stored_pts_num )
399 return h->pts[frame];
400 else
401 {
402 if( h->pts && real_frame )
403 {
404 x264_cli_log( "timecode", X264_LOG_INFO, "input timecode file missing data for frame %d and later\n"
405 " assuming constant fps %.6f\n", frame, h->assume_fps );
406 free( h->pts );
407 h->pts = NULL;
408 }
409 double timecode = h->last_timecode + 1 / h->assume_fps;
410 if( real_frame )
411 h->last_timecode = timecode;
412 return timecode * ((double)h->timebase_den / h->timebase_num) + 0.5;
413 }
414 }
415
read_frame(cli_pic_t * pic,hnd_t handle,int frame)416 static int read_frame( cli_pic_t *pic, hnd_t handle, int frame )
417 {
418 timecode_hnd_t *h = handle;
419 if( h->input.read_frame( pic, h->p_handle, frame ) )
420 return -1;
421
422 pic->pts = get_frame_pts( h, frame, 1 );
423 pic->duration = get_frame_pts( h, frame + 1, 0 ) - pic->pts;
424
425 return 0;
426 }
427
release_frame(cli_pic_t * pic,hnd_t handle)428 static int release_frame( cli_pic_t *pic, hnd_t handle )
429 {
430 timecode_hnd_t *h = handle;
431 if( h->input.release_frame )
432 return h->input.release_frame( pic, h->p_handle );
433 return 0;
434 }
435
picture_alloc(cli_pic_t * pic,hnd_t handle,int csp,int width,int height)436 static int picture_alloc( cli_pic_t *pic, hnd_t handle, int csp, int width, int height )
437 {
438 timecode_hnd_t *h = handle;
439 return h->input.picture_alloc( pic, h->p_handle, csp, width, height );
440 }
441
picture_clean(cli_pic_t * pic,hnd_t handle)442 static void picture_clean( cli_pic_t *pic, hnd_t handle )
443 {
444 timecode_hnd_t *h = handle;
445 h->input.picture_clean( pic, h->p_handle );
446 }
447
close_file(hnd_t handle)448 static int close_file( hnd_t handle )
449 {
450 timecode_hnd_t *h = handle;
451 if( h->pts )
452 free( h->pts );
453 h->input.close_file( h->p_handle );
454 free( h );
455 return 0;
456 }
457
458 const cli_input_t timecode_input = { open_file, picture_alloc, read_frame, release_frame, picture_clean, close_file };
459