1 /*****************************************************************************
2 * timecode.c: timecode file input
3 *****************************************************************************
4 * Copyright (C) 2010-2017 x264 project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
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.
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.
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.
22 * This program is also available under a commercial proprietary license.
23 * For more information, contact us at licensing@x264.com.
24 *****************************************************************************/
27 #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "timecode", __VA_ARGS__ )
33 int auto_timebase_num
;
34 int auto_timebase_den
;
35 uint64_t timebase_num
;
36 uint64_t timebase_den
;
43 static inline double sigexp10( double value
, double *exponent
)
45 /* This function separates significand and exp10 from double floating point. */
46 *exponent
= pow( 10, floor( log10( value
) ) );
47 return value
/ *exponent
;
50 #define DOUBLE_EPSILON 5e-6
51 #define MKV_TIMEBASE_DEN 1000000000
53 static double correct_fps( double fps
, timecode_hnd_t
*h
)
56 uint64_t fps_num
, fps_den
;
58 double fps_sig
= sigexp10( fps
, &exponent
);
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
)
69 if( h
->auto_timebase_den
)
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;
75 return (double)fps_num
/ fps_den
;
78 static int try_mkv_timebase_den( double *fpss
, timecode_hnd_t
*h
, int loop_num
)
81 h
->timebase_den
= MKV_TIMEBASE_DEN
;
82 for( int num
= 0; num
< loop_num
; num
++ )
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" );
95 static int parse_tcfile( FILE *tcfile_in
, timecode_hnd_t
*h
, video_info_t
*info
)
98 int ret
, tcfv
, num
, seq_num
, timecodes_num
;
99 double *timecodes
= NULL
;
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')
108 double assume_fps
, seq_fps
;
110 int prev_start
= -1, prev_end
= -1;
113 for( num
= 2; fgets( buff
, sizeof(buff
), tcfile_in
) != NULL
; num
++ )
115 if( NO_TIMECODE_LINE
)
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" );
121 FAIL_IF_ERROR( h
->assume_fps
<= 0, "invalid assumed fps %.6f\n", h
->assume_fps
);
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
++ )
127 if( NO_TIMECODE_LINE
)
129 if( sscanf( buff
, "# TDecimate Mode 3: Last Frame = %d", &end
) == 1 )
130 h
->stored_pts_num
= end
+ 1;
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
);
139 if( h
->auto_timebase_den
|| h
->auto_timebase_num
)
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
);
147 timecodes
= malloc( timecodes_num
* sizeof(double) );
150 if( h
->auto_timebase_den
|| h
->auto_timebase_num
)
152 fpss
= malloc( (seq_num
+ 1) * sizeof(double) );
157 assume_fps
= correct_fps( h
->assume_fps
, h
);
161 for( num
= seq_num
= 0; num
< timecodes_num
- 1 && fgets( buff
, sizeof(buff
), tcfile_in
) != NULL
; )
163 if( NO_TIMECODE_LINE
)
165 ret
= sscanf( buff
, "%d,%d,%lf", &start
, &end
, &seq_fps
);
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 )
172 if( h
->auto_timebase_den
|| h
->auto_timebase_num
)
173 fpss
[seq_num
++] = seq_fps
;
174 seq_fps
= correct_fps( seq_fps
, h
);
177 for( num
= start
; num
<= end
&& num
< timecodes_num
- 1; num
++ )
178 timecodes
[num
+ 1] = timecodes
[num
] + 1 / seq_fps
;
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
;
186 if( h
->auto_timebase_num
&& !h
->auto_timebase_den
)
189 double assume_fps_sig
, seq_fps_sig
;
190 if( try_mkv_timebase_den( fpss
, h
, seq_num
+ 1 ) < 0 )
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
; )
197 if( NO_TIMECODE_LINE
)
199 ret
= sscanf( buff
, "%d,%d,%lf", &start
, &end
, &seq_fps
);
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
;
209 for( ; num
< timecodes_num
- 1; num
++ )
210 timecodes
[num
+ 1] = timecodes
[num
] + 1 / assume_fps
;
218 h
->assume_fps
= assume_fps
;
219 h
->last_timecode
= timecodes
[timecodes_num
- 1];
223 uint64_t file_pos
= ftell( tcfile_in
);
225 h
->stored_pts_num
= 0;
226 while( fgets( buff
, sizeof(buff
), tcfile_in
) != NULL
)
228 if( NO_TIMECODE_LINE
)
230 if( !h
->stored_pts_num
)
231 file_pos
= ftell( tcfile_in
);
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
);
240 timecodes
= malloc( timecodes_num
* sizeof(double) );
245 if( fgets( buff
, sizeof(buff
), tcfile_in
) != NULL
)
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
; )
252 if( NO_TIMECODE_LINE
)
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
);
261 FAIL_IF_ERROR( num
< timecodes_num
, "failed to read input tcfile for frame %d", num
);
263 if( timecodes_num
== 1 )
264 h
->timebase_den
= info
->fps_num
;
265 else if( h
->auto_timebase_den
)
267 fpss
= malloc( (timecodes_num
- 1) * sizeof(double) );
270 for( num
= 0; num
< timecodes_num
- 1; num
++ )
272 fpss
[num
] = 1 / (timecodes
[num
+ 1] - timecodes
[num
]);
273 if( h
->auto_timebase_den
)
276 uint64_t fps_num
, fps_den
;
278 double fps_sig
= sigexp10( fpss
[num
], &exponent
);
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
)
287 h
->timebase_den
= fps_num
&& h
->timebase_den
? lcm( h
->timebase_den
, fps_num
) : fps_num
;
288 if( h
->timebase_den
> UINT32_MAX
)
290 h
->auto_timebase_den
= 0;
295 if( h
->auto_timebase_num
&& !h
->auto_timebase_den
)
296 if( try_mkv_timebase_den( fpss
, h
, timecodes_num
- 1 ) < 0 )
302 if( timecodes_num
> 1 )
303 h
->assume_fps
= 1 / (timecodes
[timecodes_num
- 1] - timecodes
[timecodes_num
- 2]);
305 h
->assume_fps
= (double)info
->fps_num
/ info
->fps_den
;
306 h
->last_timecode
= timecodes
[timecodes_num
- 1];
308 #undef NO_TIMECODE_LINE
309 if( h
->auto_timebase_den
|| h
->auto_timebase_num
)
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
);
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" );
319 h
->pts
= malloc( h
->stored_pts_num
* sizeof(int64_t) );
322 for( num
= 0; num
< h
->stored_pts_num
; num
++ )
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
);
339 #undef DOUBLE_EPSILON
340 #undef MKV_TIMEBASE_DEN
342 static int open_file( char *psz_filename
, hnd_t
*p_handle
, video_info_t
*info
, cli_input_opt_t
*opt
)
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
;
353 ret
= sscanf( opt
->timebase
, "%"SCNu64
"/%"SCNu64
, &h
->timebase_num
, &h
->timebase_den
);
356 h
->timebase_num
= strtoul( opt
->timebase
, NULL
, 10 );
357 h
->timebase_den
= 0; /* set later by auto timebase generation */
359 FAIL_IF_ERROR( h
->timebase_num
> UINT32_MAX
|| h
->timebase_den
> UINT32_MAX
,
360 "timebase you specified exceeds H.264 maximum\n" );
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 */
369 tcfile_in
= x264_fopen( psz_filename
, "rb" );
370 FAIL_IF_ERROR( !tcfile_in
, "can't open `%s'\n", psz_filename
);
371 if( !x264_is_regular_file( tcfile_in
) )
373 x264_cli_log( "timecode", X264_LOG_ERROR
, "tcfile input incompatible with non-regular file `%s'\n", psz_filename
);
378 if( parse_tcfile( tcfile_in
, h
, info
) < 0 )
387 info
->timebase_num
= h
->timebase_num
;
388 info
->timebase_den
= h
->timebase_den
;
395 static int64_t get_frame_pts( timecode_hnd_t
*h
, int frame
, int real_frame
)
397 if( frame
< h
->stored_pts_num
)
398 return h
->pts
[frame
];
401 if( h
->pts
&& real_frame
)
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
);
408 double timecode
= h
->last_timecode
+ 1 / h
->assume_fps
;
410 h
->last_timecode
= timecode
;
411 return timecode
* ((double)h
->timebase_den
/ h
->timebase_num
) + 0.5;
415 static int read_frame( cli_pic_t
*pic
, hnd_t handle
, int frame
)
417 timecode_hnd_t
*h
= handle
;
418 if( h
->input
.read_frame( pic
, h
->p_handle
, frame
) )
421 pic
->pts
= get_frame_pts( h
, frame
, 1 );
422 pic
->duration
= get_frame_pts( h
, frame
+ 1, 0 ) - pic
->pts
;
427 static int release_frame( cli_pic_t
*pic
, hnd_t handle
)
429 timecode_hnd_t
*h
= handle
;
430 if( h
->input
.release_frame
)
431 return h
->input
.release_frame( pic
, h
->p_handle
);
435 static int picture_alloc( cli_pic_t
*pic
, hnd_t handle
, int csp
, int width
, int height
)
437 timecode_hnd_t
*h
= handle
;
438 return h
->input
.picture_alloc( pic
, h
->p_handle
, csp
, width
, height
);
441 static void picture_clean( cli_pic_t
*pic
, hnd_t handle
)
443 timecode_hnd_t
*h
= handle
;
444 h
->input
.picture_clean( pic
, h
->p_handle
);
447 static int close_file( hnd_t handle
)
449 timecode_hnd_t
*h
= handle
;
452 h
->input
.close_file( h
->p_handle
);
457 const cli_input_t timecode_input
= { open_file
, picture_alloc
, read_frame
, release_frame
, picture_clean
, close_file
};