description: Remove a redundant condition for looking for suitable samplerate.
[L-SMASH.git] / cli / timelineeditor.c
blob725b11aef02e111e445588a600707833de975cfa
1 /*****************************************************************************
2 * timelineeditor.c:
3 *****************************************************************************
4 * Copyright (C) 2011-2014 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #include "common/internal.h"
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <inttypes.h>
30 #include <math.h>
31 #include <stdarg.h>
33 #include "lsmash.h"
34 #include "cli.h"
36 #include "config.h"
38 #define LSMASH_MAX( a, b ) ((a) > (b) ? (a) : (b))
40 #define eprintf( ... ) fprintf( stderr, __VA_ARGS__ )
41 #define REFRESH_CONSOLE eprintf( " \r" )
43 typedef struct
45 int active;
46 lsmash_summary_t *summary;
47 } summary_t;
49 typedef struct
51 int active;
52 uint32_t track_ID;
53 uint32_t last_sample_delta;
54 uint32_t current_sample_number;
55 int reach_end_of_media_timeline;
56 uint32_t *summary_remap;
57 uint32_t num_summaries;
58 summary_t *summaries;
59 lsmash_track_parameters_t track_param;
60 lsmash_media_parameters_t media_param;
61 } track_t;
63 typedef struct
65 lsmash_itunes_metadata_t *itunes_metadata;
66 track_t *track;
67 lsmash_movie_parameters_t param;
68 uint32_t num_tracks;
69 uint32_t num_itunes_metadata;
70 uint32_t current_track_number;
71 } movie_t;
73 typedef struct
75 lsmash_file_t *fh;
76 lsmash_file_parameters_t param;
77 movie_t movie;
78 } file_t;
80 typedef struct
82 lsmash_root_t *root;
83 file_t file;
84 } root_t;
86 typedef struct
88 FILE *file;
89 uint64_t *ts;
90 uint32_t sample_count;
91 int auto_media_timescale;
92 int auto_media_timebase;
93 uint64_t media_timescale;
94 uint64_t media_timebase;
95 uint64_t duration;
96 uint64_t composition_delay;
97 uint64_t empty_delay;
98 } timecode_t;
100 typedef struct
102 root_t *output;
103 root_t *input;
104 timecode_t *timecode;
105 } movie_io_t;
107 typedef struct
109 uint32_t track_number;
110 uint32_t media_timescale;
111 uint32_t media_timebase;
112 uint32_t skip_duration;
113 uint32_t empty_delay;
114 int dts_compression;
115 } opt_t;
117 static void cleanup_root( root_t *h )
119 if( !h )
120 return;
121 movie_t *movie = &h->file.movie;
122 if( movie->itunes_metadata )
124 for( uint32_t i = 0; i < movie->num_itunes_metadata; i++ )
126 lsmash_itunes_metadata_t *metadata = &movie->itunes_metadata[i];
127 if( metadata->type == ITUNES_METADATA_TYPE_STRING )
129 if( metadata->value.string )
130 lsmash_free( metadata->value.string );
132 else if( metadata->type == ITUNES_METADATA_TYPE_BINARY )
133 if( metadata->value.binary.data )
134 lsmash_free( metadata->value.binary.data );
135 if( metadata->meaning )
136 lsmash_free( metadata->meaning );
137 if( metadata->name )
138 lsmash_free( metadata->name );
140 lsmash_freep( &movie->itunes_metadata );
142 if( movie->track )
143 lsmash_freep( &movie->track );
144 lsmash_close_file( &h->file.param );
145 lsmash_destroy_root( h->root );
146 h->root = NULL;
149 static void cleanup_timecode( timecode_t *timecode )
151 if( !timecode )
152 return;
153 if( timecode->file )
155 fclose( timecode->file );
156 timecode->file = NULL;
158 if( timecode->ts )
159 lsmash_freep( &timecode->ts );
162 static int error_message( const char* message, ... )
164 REFRESH_CONSOLE;
165 eprintf( "Error: " );
166 va_list args;
167 va_start( args, message );
168 vfprintf( stderr, message, args );
169 va_end( args );
170 return -1;
173 static int warning_message( const char* message, ... )
175 REFRESH_CONSOLE;
176 eprintf( "Warning: " );
177 va_list args;
178 va_start( args, message );
179 vfprintf( stderr, message, args );
180 va_end( args );
181 return -1;
184 static int timelineeditor_error( movie_io_t *io, const char *message, ... )
186 cleanup_root( io->input );
187 cleanup_root( io->output );
188 cleanup_timecode( io->timecode );
189 va_list args;
190 va_start( args, message );
191 error_message( message, args );
192 va_end( args );
193 return -1;
196 #define TIMELINEEDITOR_ERR( ... ) timelineeditor_error( &io, __VA_ARGS__ )
197 #define ERROR_MSG( ... ) error_message( __VA_ARGS__ )
198 #define WARNING_MSG( ... ) warning_message( __VA_ARGS__ )
200 static char *duplicate_string( char *src )
202 if( !src )
203 return NULL;
204 int dst_size = strlen( src ) + 1;
205 char *dst = lsmash_malloc( dst_size );
206 if( !dst )
207 return NULL;
208 memcpy( dst, src, dst_size );
209 return dst;
212 static int get_itunes_metadata( lsmash_root_t *root, uint32_t metadata_number, lsmash_itunes_metadata_t *metadata )
214 memset( metadata, 0, sizeof(lsmash_itunes_metadata_t) );
215 if( lsmash_get_itunes_metadata( root, metadata_number, metadata ) )
216 return -1;
217 lsmash_itunes_metadata_t shadow = *metadata;
218 metadata->meaning = NULL;
219 metadata->name = NULL;
220 memset( &metadata->value, 0, sizeof(lsmash_itunes_metadata_value_t) );
221 if( shadow.meaning )
223 metadata->meaning = duplicate_string( shadow.meaning );
224 if( !metadata->meaning )
225 return -1;
227 if( shadow.name )
229 metadata->name = duplicate_string( shadow.name );
230 if( !metadata->name )
231 goto fail;
233 if( shadow.type == ITUNES_METADATA_TYPE_STRING )
235 metadata->value.string = duplicate_string( shadow.value.string );
236 if( !metadata->value.string )
237 goto fail;
239 else if( shadow.type == ITUNES_METADATA_TYPE_BINARY )
241 metadata->value.binary.data = lsmash_malloc( shadow.value.binary.size );
242 if( !metadata->value.binary.data )
243 goto fail;
244 memcpy( metadata->value.binary.data, shadow.value.binary.data, shadow.value.binary.size );
246 return 0;
247 fail:
248 if( metadata->meaning )
249 lsmash_free( metadata->meaning );
250 if( metadata->name )
251 lsmash_free( metadata->name );
252 return -1;
255 static int get_summaries( root_t *input, track_t *track )
257 track->num_summaries = lsmash_count_summary( input->root, track->track_ID );
258 if( track->num_summaries == 0 )
259 return ERROR_MSG( "Failed to get find valid summaries.\n" );
260 track->summaries = lsmash_malloc( track->num_summaries * sizeof(summary_t) );
261 if( !track->summaries )
262 return ERROR_MSG( "failed to alloc input summaries.\n" );
263 memset( track->summaries, 0, track->num_summaries * sizeof(summary_t) );
264 for( uint32_t j = 0; j < track->num_summaries; j++ )
266 lsmash_summary_t *summary = lsmash_get_summary( input->root, track->track_ID, j + 1 );
267 if( !summary )
269 WARNING_MSG( "failed to get a summary.\n" );
270 continue;
272 track->summaries[j].summary = summary;
273 track->summaries[j].active = 1;
275 return 0;
278 static int get_movie( root_t *input, char *input_name )
280 if( !strcmp( input_name, "-" ) )
281 return ERROR_MSG( "Standard input not supported.\n" );
282 input->root = lsmash_create_root();
283 if( !input->root )
284 return ERROR_MSG( "failed to create a ROOT for an input file.\n" );
285 file_t *in_file = &input->file;
286 if( lsmash_open_file( input_name, 1, &in_file->param ) < 0 )
287 return ERROR_MSG( "failed to open an input file.\n" );
288 in_file->fh = lsmash_set_file( input->root, &in_file->param );
289 if( !in_file->fh )
290 return ERROR_MSG( "failed to add an input file into a ROOT.\n" );
291 if( lsmash_read_file( in_file->fh, &in_file->param ) < 0 )
292 return ERROR_MSG( "failed to read an input file\n" );
293 movie_t *movie = &in_file->movie;
294 movie->num_itunes_metadata = lsmash_count_itunes_metadata( input->root );
295 if( movie->num_itunes_metadata )
297 movie->itunes_metadata = lsmash_malloc( movie->num_itunes_metadata * sizeof(lsmash_itunes_metadata_t) );
298 if( !movie->itunes_metadata )
299 return ERROR_MSG( "failed to alloc iTunes metadata.\n" );
300 uint32_t itunes_metadata_count = 0;
301 for( uint32_t i = 1; i <= movie->num_itunes_metadata; i++ )
303 if( get_itunes_metadata( input->root, i, &movie->itunes_metadata[itunes_metadata_count] ) )
305 WARNING_MSG( "failed to get an iTunes metadata.\n" );
306 continue;
308 ++itunes_metadata_count;
310 movie->num_itunes_metadata = itunes_metadata_count;
312 lsmash_initialize_movie_parameters( &movie->param );
313 lsmash_get_movie_parameters( input->root, &movie->param );
314 movie->num_tracks = movie->param.number_of_tracks;
315 movie->current_track_number = 1;
316 /* Create tracks. */
317 track_t *track = movie->track = lsmash_malloc( movie->num_tracks * sizeof(track_t) );
318 if( !track )
319 return ERROR_MSG( "Failed to alloc input tracks.\n" );
320 memset( track, 0, movie->num_tracks * sizeof(track_t) );
321 for( uint32_t i = 0; i < movie->num_tracks; i++ )
323 track[i].track_ID = lsmash_get_track_ID( input->root, i + 1 );
324 if( !track[i].track_ID )
325 return ERROR_MSG( "Failed to get track_ID.\n" );
327 for( uint32_t i = 0; i < movie->num_tracks; i++ )
329 lsmash_initialize_track_parameters( &track[i].track_param );
330 if( lsmash_get_track_parameters( input->root, track[i].track_ID, &track[i].track_param ) )
332 WARNING_MSG( "failed to get track parameters.\n" );
333 continue;
335 lsmash_initialize_media_parameters( &track[i].media_param );
336 if( lsmash_get_media_parameters( input->root, track[i].track_ID, &track[i].media_param ) )
338 WARNING_MSG( "failed to get media parameters.\n" );
339 continue;
341 if( lsmash_construct_timeline( input->root, track[i].track_ID ) )
343 WARNING_MSG( "failed to construct timeline.\n" );
344 continue;
346 if( lsmash_get_last_sample_delta_from_media_timeline( input->root, track[i].track_ID, &track[i].last_sample_delta ) )
348 WARNING_MSG( "failed to get the last sample delta.\n" );
349 continue;
351 if( get_summaries( input, &track[i] ) )
353 WARNING_MSG( "failed to get valid summaries.\n" );
354 continue;
356 track[i].active = 1;
357 track[i].current_sample_number = 1;
359 lsmash_destroy_children( lsmash_file_as_box( in_file->fh ) );
360 return 0;
363 static inline uint64_t get_gcd( uint64_t a, uint64_t b )
365 if( !b )
366 return a;
367 while( 1 )
369 uint64_t c = a % b;
370 if( !c )
371 return b;
372 a = b;
373 b = c;
377 static inline uint64_t get_lcm( uint64_t a, uint64_t b )
379 if( !a )
380 return 0;
381 return (a / get_gcd( a, b )) * b;
384 static uint64_t get_media_timebase( lsmash_media_ts_list_t *ts_list )
386 uint64_t timebase = ts_list->timestamp[0].cts;
387 for( uint32_t i = 1; i < ts_list->sample_count; i++ )
388 timebase = get_gcd( timebase, ts_list->timestamp[i].cts );
389 for( uint32_t i = 0; i < ts_list->sample_count; i++ )
390 timebase = get_gcd( timebase, ts_list->timestamp[i].dts );
391 return timebase;
394 static inline double sigexp10( double value, double *exponent )
396 /* This function separates significand and exp10 from double floating point. */
397 *exponent = 1;
398 while( value < 1 )
400 value *= 10;
401 *exponent /= 10;
403 while( value >= 10 )
405 value /= 10;
406 *exponent *= 10;
408 return value;
411 #define DOUBLE_EPSILON 5e-6
412 #define MATROSKA_TIMESCALE 1000000000
413 #define SKIP_LINE_CHARACTER( x ) ((x) == '#' || (x) == '\n' || (x) == '\r')
415 static double correct_fps( double fps, timecode_t *timecode )
417 int i = 1;
418 uint64_t fps_num, fps_den;
419 double exponent;
420 double fps_sig = sigexp10( fps, &exponent );
421 while( 1 )
423 fps_den = i * timecode->media_timebase;
424 fps_num = round( fps_den * fps_sig ) * exponent;
425 if( fps_num > UINT32_MAX )
426 return ERROR_MSG( "framerate correction failed.\n"
427 "Specify an appropriate timebase manually or remake timecode file.\n" );
428 if( fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
429 break;
430 ++i;
432 if( timecode->auto_media_timescale )
434 timecode->media_timescale = timecode->media_timescale
435 ? get_lcm( timecode->media_timescale, fps_num )
436 : fps_num;
437 if( timecode->media_timescale > UINT32_MAX )
438 timecode->auto_media_timescale = 0;
440 return (double)fps_num / fps_den;
443 static int try_matroska_timescale( double *fps_array, timecode_t *timecode, uint32_t num_loops )
445 timecode->media_timebase = 0;
446 timecode->media_timescale = MATROSKA_TIMESCALE;
447 for( uint32_t i = 0; i < num_loops; i++ )
449 uint64_t fps_den;
450 double exponent;
451 double fps_sig = sigexp10( fps_array[i], &exponent );
452 fps_den = round( MATROSKA_TIMESCALE / fps_sig ) / exponent;
453 timecode->media_timebase = fps_den && timecode->media_timebase
454 ? get_gcd( timecode->media_timebase, fps_den )
455 : fps_den;
456 if( timecode->media_timebase > UINT32_MAX || !timecode->media_timebase )
457 return ERROR_MSG( "Automatic media timescale generation failed.\n"
458 "Specify media timescale manually.\n" );
460 return 0;
463 static int parse_timecode( timecode_t *timecode, uint32_t sample_count )
465 int tcfv;
466 int ret = fscanf( timecode->file, "# timecode format v%d", &tcfv );
467 if( ret != 1 || (tcfv != 1 && tcfv != 2) )
468 return ERROR_MSG( "Unsupported timecode format\n" );
469 char buff[256];
470 double *timecode_array = NULL;
471 if( tcfv == 1 )
473 double assume_fps = 0;
474 /* Get assumed framerate. */
475 while( fgets( buff, sizeof(buff), timecode->file ) )
477 if( SKIP_LINE_CHARACTER( buff[0] ) )
478 continue;
479 if( sscanf( buff, "assume %lf", &assume_fps ) != 1
480 && sscanf( buff, "Assume %lf", &assume_fps ) != 1 )
481 return ERROR_MSG( "Assumed fps not found\n" );
482 break;
484 if( assume_fps <= 0 )
485 return ERROR_MSG( "Invalid assumed fps\n" );
486 int64_t file_pos = lsmash_ftell( timecode->file );
487 if( file_pos < 0 )
488 return ERROR_MSG( "Failed to tell the postion of input timecode file.\n" );
489 /* Check whether valid or not and count number of sequences. */
490 uint32_t num_sequences = 0;
491 int64_t start, end;
492 int64_t prev_start = -1, prev_end = -1;
493 double sequence_fps;
494 while( fgets( buff, sizeof(buff), timecode->file ) )
496 if( SKIP_LINE_CHARACTER( buff[0] ) )
497 continue;
498 ret = sscanf( buff, "%"SCNd64",%"SCNd64",%lf", &start, &end, &sequence_fps );
499 if( ret != 3 && ret != EOF )
500 return ERROR_MSG( "Invalid input timecode file\n" );
501 if( start > end || start <= prev_start || end <= prev_end || sequence_fps <= 0 )
502 return ERROR_MSG( "Invalid input timecode file\n" );
503 prev_start = start;
504 prev_end = end;
505 if( timecode->auto_media_timescale || timecode->auto_media_timebase )
506 ++num_sequences;
508 if( lsmash_fseek( timecode->file, file_pos, SEEK_SET ) != 0 )
509 return ERROR_MSG( "Failed to seek input timecode file.\n" );
510 /* Preparation storing timecodes. */
511 double fps_array[ (timecode->auto_media_timescale || timecode->auto_media_timebase) * num_sequences + 1 ];
512 double corrected_assume_fps = correct_fps( assume_fps, timecode );
513 if( corrected_assume_fps < 0 )
514 return ERROR_MSG( "Failed to correct the assumed framerate\n" );
515 timecode_array = lsmash_malloc( sample_count * sizeof(double) );
516 if( !timecode_array )
517 return ERROR_MSG( "Failed to alloc timecodes\n" );
518 timecode_array[0] = 0;
519 num_sequences = 0;
520 uint32_t i = 0;
521 while( i < sample_count - 1 && fgets( buff, sizeof(buff), timecode->file ) )
523 if( SKIP_LINE_CHARACTER( buff[0] ) )
524 continue;
525 ret = sscanf( buff, "%"SCNd64",%"SCNd64",%lf", &start, &end, &sequence_fps );
526 if( ret != 3 )
527 start = end = sample_count - 1;
528 for( ; i < start && i < sample_count - 1; i++ )
529 timecode_array[i + 1] = timecode_array[i] + 1 / corrected_assume_fps;
530 if( i < sample_count - 1 )
532 if( timecode->auto_media_timescale || timecode->auto_media_timebase )
533 fps_array[num_sequences++] = sequence_fps;
534 sequence_fps = correct_fps( sequence_fps, timecode );
535 if( sequence_fps < 0 )
537 lsmash_free( timecode_array );
538 return ERROR_MSG( "Failed to correct the framerate of a sequence.\n" );
540 for( i = start; i <= end && i < sample_count - 1; i++ )
541 timecode_array[i + 1] = timecode_array[i] + 1 / sequence_fps;
544 for( ; i < sample_count - 1; i++ )
545 timecode_array[i + 1] = timecode_array[i] + 1 / corrected_assume_fps;
546 if( timecode->auto_media_timescale || timecode->auto_media_timebase )
547 fps_array[num_sequences] = assume_fps;
548 /* Assume matroska timebase if automatic timescale generation isn't done yet. */
549 if( timecode->auto_media_timebase && !timecode->auto_media_timescale )
551 double exponent;
552 double assume_fps_sig, sequence_fps_sig;
553 if( try_matroska_timescale( fps_array, timecode, num_sequences + 1 ) < 0 )
555 lsmash_free( timecode_array );
556 return ERROR_MSG( "Failed to try matroska timescale.\n" );
558 if( lsmash_fseek( timecode->file, file_pos, SEEK_SET ) != 0 )
559 return ERROR_MSG( "Failed to seek input timecode file.\n" );
560 assume_fps_sig = sigexp10( assume_fps, &exponent );
561 corrected_assume_fps = MATROSKA_TIMESCALE / ( round( MATROSKA_TIMESCALE / assume_fps_sig ) / exponent );
562 for( i = 0; i < sample_count - 1 && fgets( buff, sizeof(buff), timecode->file ); )
564 if( SKIP_LINE_CHARACTER( buff[0] ) )
565 continue;
566 ret = sscanf( buff, "%"SCNd64",%"SCNd64",%lf", &start, &end, &sequence_fps );
567 if( ret != 3 )
568 start = end = sample_count - 1;
569 sequence_fps_sig = sigexp10( sequence_fps, &exponent );
570 sequence_fps = MATROSKA_TIMESCALE / ( round( MATROSKA_TIMESCALE / sequence_fps_sig ) / exponent );
571 for( ; i < start && i < sample_count - 1; i++ )
572 timecode_array[i + 1] = timecode_array[i] + 1 / corrected_assume_fps;
573 for( i = start; i <= end && i < sample_count - 1; i++ )
574 timecode_array[i + 1] = timecode_array[i] + 1 / sequence_fps;
576 for( ; i < sample_count - 1; i++ )
577 timecode_array[i + 1] = timecode_array[i] + 1 / corrected_assume_fps;
580 else /* tcfv == 2 */
582 uint32_t num_timecodes = 0;
583 int64_t file_pos = lsmash_ftell( timecode->file );
584 if( file_pos < 0 )
585 return ERROR_MSG( "Failed to tell the postion of input timecode file.\n" );
586 while( fgets( buff, sizeof(buff), timecode->file ) )
588 if( SKIP_LINE_CHARACTER( buff[0] ) )
590 if( !num_timecodes )
592 file_pos = lsmash_ftell( timecode->file );
593 if( file_pos < 0 )
594 return ERROR_MSG( "Failed to tell the postion of input timecode file.\n" );
596 continue;
598 ++num_timecodes;
600 if( !num_timecodes )
601 return ERROR_MSG( "No timecodes!\n" );
602 if( sample_count > num_timecodes )
603 return ERROR_MSG( "Lack number of timecodes.\n" );
604 if( lsmash_fseek( timecode->file, file_pos, SEEK_SET ) != 0 )
605 return ERROR_MSG( "Failed to seek input timecode file.\n" );
606 timecode_array = lsmash_malloc( sample_count * sizeof(uint64_t) );
607 if( !timecode_array )
608 return ERROR_MSG( "Failed to alloc timecodes.\n" );
609 uint32_t i = 0;
610 if( fgets( buff, sizeof(buff), timecode->file ) )
612 ret = sscanf( buff, "%lf", &timecode_array[0] );
613 if( ret != 1 )
615 lsmash_free( timecode_array );
616 return ERROR_MSG( "Invalid timecode number: 0\n" );
618 timecode_array[i++] *= 1e-3; /* Timescale of timecode format v2 is 1000. */
619 while( i < sample_count && fgets( buff, sizeof(buff), timecode->file ) )
621 if( SKIP_LINE_CHARACTER( buff[0] ) )
622 continue;
623 ret = sscanf( buff, "%lf", &timecode_array[i] );
624 timecode_array[i] *= 1e-3; /* Timescale of timecode format v2 is 1000. */
625 if( ret != 1 || timecode_array[i] <= timecode_array[i - 1] )
627 lsmash_free( timecode_array );
628 return ERROR_MSG( "Invalid input timecode.\n" );
630 ++i;
633 if( i < sample_count )
635 lsmash_free( timecode_array );
636 return ERROR_MSG( "Failed to get timecodes.\n" );
638 /* Generate media timescale automatically if needed. */
639 if( sample_count != 1 && timecode->auto_media_timescale )
641 double fps_array[sample_count - 1];
642 for( i = 0; i < sample_count - 1; i++ )
644 fps_array[i] = 1 / (timecode_array[i + 1] - timecode_array[i]);
645 if( timecode->auto_media_timescale )
647 int j = 1;
648 uint64_t fps_num, fps_den;
649 double exponent;
650 double fps_sig = sigexp10( fps_array[i], &exponent );
651 while( 1 )
653 fps_den = j * timecode->media_timebase;
654 fps_num = round( fps_den * fps_sig ) * exponent;
655 if( fps_num > UINT32_MAX
656 || fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
657 break;
658 ++j;
660 timecode->media_timescale = fps_num && timecode->media_timescale
661 ? get_lcm( timecode->media_timescale, fps_num )
662 : fps_num;
663 if( timecode->media_timescale > UINT32_MAX )
665 timecode->auto_media_timescale = 0;
666 continue; /* Don't break because all framerate is needed for try_matroska_timescale. */
670 if( timecode->auto_media_timebase && !timecode->auto_media_timescale
671 && try_matroska_timescale( fps_array, timecode, sample_count - 1 ) < 0 )
673 lsmash_free( timecode_array );
674 return ERROR_MSG( "Failed to try matroska timescale.\n" );
678 if( timecode->auto_media_timescale || timecode->auto_media_timebase )
680 uint64_t reduce = get_gcd( timecode->media_timebase, timecode->media_timescale );
681 timecode->media_timebase /= reduce;
682 timecode->media_timescale /= reduce;
684 else if( timecode->media_timescale > UINT32_MAX || !timecode->media_timescale )
686 lsmash_free( timecode_array );
687 return ERROR_MSG( "Failed to generate media timescale automatically.\n"
688 "Specify an appropriate media timescale manually.\n" );
690 uint32_t timescale = timecode->media_timescale;
691 uint32_t timebase = timecode->media_timebase;
692 double delay_tc = timecode_array[0];
693 timecode->empty_delay = ((uint64_t)(delay_tc * ((double)timescale / timebase) + 0.5)) * timebase;
694 timecode->ts = lsmash_malloc( sample_count * sizeof(uint64_t) );
695 if( !timecode->ts )
697 lsmash_free( timecode_array );
698 return ERROR_MSG( "Failed to allocate timestamps.\n" );
700 timecode->ts[0] = 0;
701 for( uint32_t i = 1; i < sample_count; i++ )
703 timecode->ts[i] = ((uint64_t)((timecode_array[i] - delay_tc) * ((double)timescale / timebase) + 0.5)) * timebase;
704 if( timecode->ts[i] <= timecode->ts[i - 1] )
706 lsmash_free( timecode_array );
707 lsmash_free( timecode->ts );
708 timecode->ts = NULL;
709 return ERROR_MSG( "Invalid timecode.\n" );
712 lsmash_free( timecode_array );
713 return 0;
716 #undef DOUBLE_EPSILON
717 #undef MATROSKA_TIMESCALE
718 #undef SKIP_LINE_CHARACTER
720 static int edit_media_timeline( root_t *input, timecode_t *timecode, opt_t *opt )
722 if( !timecode->file && !opt->media_timescale && !opt->media_timebase && !opt->dts_compression )
723 return 0;
724 track_t *in_track = &input->file.movie.track[opt->track_number - 1];
725 uint32_t track_ID = in_track->track_ID;
726 lsmash_media_ts_list_t ts_list;
727 if( lsmash_get_media_timestamps( input->root, track_ID, &ts_list ) )
728 return ERROR_MSG( "Failed to get media timestamps.\n" );
729 uint64_t timebase = get_media_timebase( &ts_list );
730 if( !timebase )
731 return ERROR_MSG( "Failed to get media timebase.\n" );
732 lsmash_media_ts_t *timestamp = ts_list.timestamp;
733 uint32_t sample_count = ts_list.sample_count;
734 uint32_t orig_timebase = timebase;
735 uint32_t timescale;
736 double timebase_convert_multiplier;
737 if( opt->media_timescale || opt->media_timebase )
739 uint32_t orig_timescale = in_track->media_param.timescale;
740 timescale = opt->media_timescale ? opt->media_timescale : orig_timescale;
741 timebase = opt->media_timebase ? opt->media_timebase : orig_timebase;
742 if( !opt->media_timescale && opt->media_timebase && (timebase > orig_timebase) )
743 timescale = timescale * ((double)timebase / orig_timebase) + 0.5;
744 timebase_convert_multiplier = ((double)timescale / orig_timescale) * ((double)orig_timebase / timebase);
746 else
748 /* Reduce timescale and timebase. */
749 timescale = in_track->media_param.timescale;
750 uint64_t reduce = get_gcd( timescale, timebase );
751 timescale /= reduce;
752 timebase /= reduce;
753 timebase_convert_multiplier = 1;
755 /* Parse timecode file. */
756 if( timecode->file )
758 timecode->auto_media_timescale = !opt->media_timescale;
759 timecode->auto_media_timebase = !opt->media_timebase;
760 timecode->media_timescale = timecode->auto_media_timescale ? 0 : timescale;
761 timecode->media_timebase = timebase;
762 if( parse_timecode( timecode, sample_count ) )
763 return ERROR_MSG( "Failed to parse timecode file.\n" );
764 timescale = timecode->media_timescale;
765 timebase = timecode->media_timebase;
767 /* Get maximum composition sample delay for DTS generation. */
768 uint32_t sample_delay;
769 if( lsmash_get_max_sample_delay( &ts_list, &sample_delay ) )
770 return ERROR_MSG( "Failed to get maximum composition sample delay.\n" );
771 if( sample_delay ) /* Reorder composition order. */
772 lsmash_sort_timestamps_composition_order( &ts_list );
773 if( !timecode->file )
775 /* Genarate timestamps timescale converted. */
776 timecode->ts = lsmash_malloc( sample_count * sizeof(uint64_t) );
777 if( !timecode->ts )
778 return ERROR_MSG( "Failed to alloc timestamps\n" );
779 for( uint32_t i = 0; i < sample_count; i++ )
781 timecode->ts[i] = (timestamp[i].cts - timestamp[0].cts) / orig_timebase;
782 timecode->ts[i] = ((uint64_t)(timecode->ts[i] * timebase_convert_multiplier + 0.5)) * timebase;
783 if( i && (timecode->ts[i] <= timecode->ts[i - 1]) )
784 return ERROR_MSG( "Invalid timescale conversion.\n" );
787 if( sample_delay )
789 /* If media timescale is specified, disable DTS compression multiplier. */
790 uint32_t dts_compression_multiplier = opt->dts_compression * !opt->media_timescale * sample_delay + 1;
791 uint64_t initial_delta = timecode->ts[1];
792 timescale *= dts_compression_multiplier;
793 if( dts_compression_multiplier > 1 )
794 for( uint32_t i = 0; i < sample_count; i++ )
795 timecode->ts[i] *= dts_compression_multiplier;
796 /* Generate CTS. */
797 uint64_t sample_delay_time = timecode->composition_delay = opt->dts_compression ? 0 : timecode->ts[sample_delay];
798 for( uint32_t i = 0; i < sample_count; i++ )
799 timestamp[i].cts = timecode->ts[i] + sample_delay_time;
800 /* Reorder decode order and generate new DTS from CTS. */
801 lsmash_sort_timestamps_decoding_order( &ts_list );
802 uint64_t prev_reordered_cts[sample_delay];
803 for( uint32_t i = 0; i <= sample_delay; i++ )
805 if( !opt->dts_compression )
806 timestamp[i].dts = timecode->ts[i];
807 else
809 timestamp[i].dts = (i * initial_delta) / (!!opt->media_timescale * sample_delay + 1);
810 if( i && (timestamp[i].dts <= timestamp[i - 1].dts) )
811 return ERROR_MSG( "Failed to do DTS compression.\n" );
813 prev_reordered_cts[ i % sample_delay ] = timecode->ts[i] + sample_delay_time;
815 for( uint32_t i = sample_delay + 1; i < sample_count; i++ )
817 timestamp[i].dts = prev_reordered_cts[ (i - sample_delay) % sample_delay ];
818 prev_reordered_cts[ i % sample_delay ] = timecode->ts[i] + sample_delay_time;
821 else
822 for( uint32_t i = 0; i < sample_count; i++ )
823 timestamp[i].cts = timestamp[i].dts = timecode->ts[i];
824 if( sample_count > 1 )
826 in_track->last_sample_delta = timecode->ts[sample_count - 1] - timecode->ts[sample_count - 2];
827 timecode->duration = timecode->ts[sample_count - 1] + in_track->last_sample_delta;
829 else /* still image */
830 timecode->duration = in_track->last_sample_delta = UINT32_MAX;
831 in_track->media_param.timescale = timescale;
832 if( lsmash_set_media_timestamps( input->root, track_ID, &ts_list ) )
833 return ERROR_MSG( "Failed to set media timestamps.\n" );
834 lsmash_delete_media_timestamps( &ts_list );
835 return 0;
838 static int check_white_brand( lsmash_brand_type brand )
840 static const lsmash_brand_type brand_white_list[] =
842 ISOM_BRAND_TYPE_3G2A,
843 ISOM_BRAND_TYPE_3GG6,
844 ISOM_BRAND_TYPE_3GG9,
845 ISOM_BRAND_TYPE_3GP4,
846 ISOM_BRAND_TYPE_3GP5,
847 ISOM_BRAND_TYPE_3GP6,
848 ISOM_BRAND_TYPE_3GP7,
849 ISOM_BRAND_TYPE_3GP8,
850 ISOM_BRAND_TYPE_3GP9,
851 ISOM_BRAND_TYPE_3GR6,
852 ISOM_BRAND_TYPE_3GR9,
853 ISOM_BRAND_TYPE_M4A ,
854 ISOM_BRAND_TYPE_M4B ,
855 ISOM_BRAND_TYPE_M4V ,
856 ISOM_BRAND_TYPE_AVC1,
857 ISOM_BRAND_TYPE_DBY1,
858 ISOM_BRAND_TYPE_ISO2,
859 ISOM_BRAND_TYPE_ISO3,
860 ISOM_BRAND_TYPE_ISO4,
861 ISOM_BRAND_TYPE_ISO5,
862 ISOM_BRAND_TYPE_ISO6,
863 ISOM_BRAND_TYPE_ISOM,
864 ISOM_BRAND_TYPE_MP41,
865 ISOM_BRAND_TYPE_MP42,
866 ISOM_BRAND_TYPE_QT ,
869 for( int i = 0; brand_white_list[i]; i++ )
870 if( brand == brand_white_list[i] )
871 return 1;
872 return 0;
875 static int moov_to_front_callback( void *param, uint64_t written_movie_size, uint64_t total_movie_size )
877 eprintf( "Finalizing: [%5.2lf%%]\r", ((double)written_movie_size / total_movie_size) * 100.0 );
878 return 0;
881 static void display_version( void )
883 eprintf( "\n"
884 "L-SMASH isom/mov timeline editor rev%s %s\n"
885 "Built on %s %s\n"
886 "Copyright (C) 2011-2014 L-SMASH project\n",
887 LSMASH_REV, LSMASH_GIT_HASH, __DATE__, __TIME__ );
890 static void display_help( void )
892 display_version();
893 eprintf( "\n"
894 "Usage: timelineeditor [options] input output\n"
895 " options:\n"
896 " --help Display help\n"
897 " --version Display version information\n"
898 " --track <integer> Specify track number to edit [1]\n"
899 " --timecode <string> Specify timecode file to edit timeline\n"
900 " --media-timescale <integer> Specify media timescale to convert\n"
901 " --media-timebase <integer> Specify media timebase to convert\n"
902 " --skip <integer> Skip start of media presentation in milliseconds\n"
903 " --delay <integer> Insert blank clip before actual media presentation in milliseconds\n"
904 " --dts-compression Eliminate composition delay with DTS hack\n"
905 " Multiply media timescale and timebase automatically\n" );
908 int main( int argc, char *argv[] )
910 if ( argc < 2 )
912 display_help();
913 return -1;
915 else if( !strcasecmp( argv[1], "-h" ) || !strcasecmp( argv[1], "--help" ) )
917 display_help();
918 return 0;
920 else if( !strcasecmp( argv[1], "-v" ) || !strcasecmp( argv[1], "--version" ) )
922 display_version();
923 return 0;
925 else if( argc < 3 )
927 display_help();
928 return -1;
930 root_t output = { 0 };
931 root_t input = { 0 };
932 timecode_t timecode = { 0 };
933 movie_io_t io = { &output, &input, &timecode };
934 opt_t opt = { 1, 0, 0, 0, 0, 0 };
935 /* Parse options. */
936 lsmash_get_mainargs( &argc, &argv );
937 int argn = 1;
938 while( argn < argc - 2 )
940 if( !strcasecmp( argv[argn], "--track" ) )
942 opt.track_number = atoi( argv[++argn] );
943 if( !opt.track_number )
944 return TIMELINEEDITOR_ERR( "Invalid track number.\n" );
945 ++argn;
947 else if( !strcasecmp( argv[argn], "--timecode" ) )
949 timecode.file = lsmash_fopen( argv[++argn], "rb" );
950 if( !timecode.file )
951 return TIMELINEEDITOR_ERR( "Failed to open timecode file.\n" );
952 ++argn;
954 else if( !strcasecmp( argv[argn], "--media-timescale" ) )
956 opt.media_timescale = atoi( argv[++argn] );
957 if( !opt.media_timescale )
958 return TIMELINEEDITOR_ERR( "Invalid media timescale.\n" );
959 ++argn;
961 else if( !strcasecmp( argv[argn], "--media-timebase" ) )
963 opt.media_timebase = atoi( argv[++argn] );
964 if( !opt.media_timebase )
965 return TIMELINEEDITOR_ERR( "Invalid media timebase.\n" );
966 ++argn;
968 else if( !strcasecmp( argv[argn], "--skip" ) )
970 opt.skip_duration = atoi( argv[++argn] );
971 if( !opt.skip_duration )
972 return TIMELINEEDITOR_ERR( "Invalid skip duration.\n" );
973 ++argn;
975 else if( !strcasecmp( argv[argn], "--delay" ) )
977 opt.empty_delay = atoi( argv[++argn] );
978 if( !opt.empty_delay )
979 return TIMELINEEDITOR_ERR( "Invalid delay time.\n" );
980 ++argn;
982 else if( !strcasecmp( argv[argn], "--dts-compression" ) )
984 opt.dts_compression = 1;
985 ++argn;
987 else
988 return TIMELINEEDITOR_ERR( "Invalid option.\n" );
990 if( argn > argc - 2 )
991 return TIMELINEEDITOR_ERR( "Invalid arguments.\n" );
992 /* Get input movies. */
993 if( get_movie( &input, argv[argn++] ) )
994 return TIMELINEEDITOR_ERR( "Failed to get input movie.\n" );
995 movie_t *in_movie = &input.file.movie;
996 if( opt.track_number && (opt.track_number > in_movie->num_tracks) )
997 return TIMELINEEDITOR_ERR( "Invalid track number.\n" );
998 /* Create output movie. */
999 file_t *out_file = &output.file;
1000 output.root = lsmash_create_root();
1001 if( !output.root )
1002 return TIMELINEEDITOR_ERR( "failed to create a ROOT for an output file.\n" );
1003 if( lsmash_open_file( argv[argn], 0, &out_file->param ) < 0 )
1004 return TIMELINEEDITOR_ERR( "failed to open an output file.\n" );
1005 file_t *in_file = &input.file;
1006 out_file->param.major_brand = in_file->param.major_brand;
1007 out_file->param.minor_version = in_file->param.minor_version;
1008 out_file->param.brands = in_file->param.brands;
1009 out_file->param.brand_count = in_file->param.brand_count;
1010 out_file->param.max_chunk_duration = 0.5;
1011 out_file->param.max_async_tolerance = 2.0;
1012 out_file->param.max_chunk_size = 4*1024*1024;
1013 if( !check_white_brand( out_file->param.major_brand ) )
1015 /* Replace with whitelisted brand 'mp42'. */
1016 out_file->param.major_brand = ISOM_BRAND_TYPE_MP42;
1017 out_file->param.minor_version = 0;
1018 uint32_t i;
1019 for( i = 0; i < out_file->param.brand_count; i++ )
1020 if( out_file->param.brands[i] == ISOM_BRAND_TYPE_MP42 )
1021 break;
1022 if( i == out_file->param.brand_count )
1024 /* Add 'mp42' into the list of compatible brands. */
1025 out_file->param.brands = lsmash_malloc( (i + 1) * sizeof(lsmash_brand_type) );
1026 if( out_file->param.brands )
1028 memcpy( out_file->param.brands, in_file->param.brands, i * sizeof(lsmash_brand_type) );
1029 out_file->param.brands[i] = ISOM_BRAND_TYPE_MP42;
1033 out_file->fh = lsmash_set_file( output.root, &out_file->param );
1034 if( !out_file->fh )
1035 return TIMELINEEDITOR_ERR( "failed to add an output file into a ROOT.\n" );
1036 if( out_file->param.brands != in_file->param.brands )
1037 lsmash_freep( &out_file->param.brands );
1038 /* Set movie parameters. */
1039 movie_t *out_movie = &out_file->movie;
1040 out_movie->param = in_movie->param; /* Copy movie parameters. */
1041 if( in_movie->num_tracks == 1 )
1042 out_movie->param.timescale = in_movie->track[0].media_param.timescale;
1043 if( lsmash_set_movie_parameters( output.root, &out_movie->param ) )
1044 return TIMELINEEDITOR_ERR( "Failed to set output movie parameters.\n" );
1045 /* Set iTunes metadata. */
1046 for( uint32_t i = 0; i < in_movie->num_itunes_metadata; i++ )
1047 if( lsmash_set_itunes_metadata( output.root, in_movie->itunes_metadata[i] ) )
1049 WARNING_MSG( "failed to set an iTunes metadata.\n" );
1050 continue;
1052 /* Create tracks of the output movie. */
1053 out_movie->track = lsmash_malloc( in_movie->num_tracks * sizeof(track_t) );
1054 if( !out_movie->track )
1055 return TIMELINEEDITOR_ERR( "Failed to alloc output tracks.\n" );
1056 /* Edit timeline. */
1057 if( edit_media_timeline( &input, &timecode, &opt ) )
1058 return TIMELINEEDITOR_ERR( "Failed to edit timeline.\n" );
1059 out_movie->num_tracks = in_movie->num_tracks;
1060 out_movie->current_track_number = 1;
1061 for( uint32_t i = 0; i < in_movie->num_tracks; i++ )
1063 track_t *in_track = &in_movie->track[i];
1064 if( !in_track->active )
1066 -- out_movie->num_tracks;
1067 continue;
1069 track_t *out_track = &out_movie->track[i];
1070 out_track->summary_remap = lsmash_malloc( in_track->num_summaries * sizeof(uint32_t) );
1071 if( !out_track->summary_remap )
1072 return TIMELINEEDITOR_ERR( "failed to create summary mapping for a track.\n" );
1073 memset( out_track->summary_remap, 0, in_track->num_summaries * sizeof(uint32_t) );
1074 out_track->track_ID = lsmash_create_track( output.root, in_track->media_param.handler_type );
1075 if( !out_track->track_ID )
1076 return TIMELINEEDITOR_ERR( "Failed to create a track.\n" );
1077 /* Copy track and media parameters except for track_ID. */
1078 out_track->track_param = in_track->track_param;
1079 out_track->media_param = in_track->media_param;
1080 out_track->track_param.track_ID = out_track->track_ID;
1081 if( lsmash_set_track_parameters( output.root, out_track->track_ID, &out_track->track_param ) )
1082 return TIMELINEEDITOR_ERR( "Failed to set track parameters.\n" );
1083 if( lsmash_set_media_parameters( output.root, out_track->track_ID, &out_track->media_param ) )
1084 return TIMELINEEDITOR_ERR( "Failed to set media parameters.\n" );
1085 uint32_t valid_summary_count = 0;
1086 for( uint32_t k = 0; k < in_track->num_summaries; k++ )
1088 if( !in_track->summaries[k].active )
1090 out_track->summary_remap[k] = 0;
1091 continue;
1093 lsmash_summary_t *summary = in_track->summaries[k].summary;
1094 if( lsmash_add_sample_entry( output.root, out_track->track_ID, summary ) == 0 )
1096 WARNING_MSG( "failed to append a summary.\n" );
1097 lsmash_cleanup_summary( summary );
1098 in_track->summaries[k].summary = NULL;
1099 in_track->summaries[k].active = 0;
1100 out_track->summary_remap[k] = 0;
1101 continue;
1103 out_track->summary_remap[k] = ++valid_summary_count;
1105 if( valid_summary_count == 0 )
1106 return TIMELINEEDITOR_ERR( "failed to append all summaries.\n" );
1107 out_track->last_sample_delta = in_track->last_sample_delta;
1108 out_track->current_sample_number = 1;
1109 out_track->reach_end_of_media_timeline = 0;
1111 /* Start muxing. */
1112 double largest_dts = 0;
1113 uint32_t num_consecutive_sample_skip = 0;
1114 uint32_t num_active_input_tracks = out_movie->num_tracks;
1115 uint64_t total_media_size = 0;
1116 uint8_t sample_count = 0;
1117 while( 1 )
1119 track_t *in_track = &in_movie->track[ in_movie->current_track_number - 1 ];
1120 /* Try append a sample in an input track where we didn't reach the end of media timeline. */
1121 if( !in_track->reach_end_of_media_timeline )
1123 track_t *out_track = &out_movie->track[ out_movie->current_track_number - 1 ];
1124 uint32_t in_track_ID = in_track->track_ID;
1125 uint32_t out_track_ID = out_track->track_ID;
1126 uint32_t input_media_timescale = in_track->media_param.timescale;
1127 /* Get a DTS from a track in an input movie. */
1128 uint64_t dts;
1129 if( lsmash_get_dts_from_media_timeline( input.root, in_track_ID, in_track->current_sample_number, &dts ) )
1131 if( lsmash_check_sample_existence_in_media_timeline( input.root, in_track_ID, in_track->current_sample_number ) )
1132 return TIMELINEEDITOR_ERR( "Failed to get the DTS.\n" );
1133 else
1135 in_track->reach_end_of_media_timeline = 1;
1136 if( --num_active_input_tracks == 0 )
1137 break; /* end of muxing */
1140 /* Get and append a sample if it's good time. */
1141 else if( ((double)dts / input_media_timescale) <= largest_dts
1142 || num_consecutive_sample_skip == num_active_input_tracks )
1144 /* Get an actual sample data from a track in an input movie. */
1145 lsmash_sample_t *sample = lsmash_get_sample_from_media_timeline( input.root, in_track_ID, in_track->current_sample_number );
1146 if( !sample )
1147 return TIMELINEEDITOR_ERR( "Failed to get sample.\n" );
1148 sample->index = sample->index > in_track->num_summaries ? in_track->num_summaries
1149 : sample->index == 0 ? 1
1150 : sample->index;
1151 sample->index = out_track->summary_remap[ sample->index - 1 ];
1152 if( sample->index )
1154 /* Append sample into output movie. */
1155 uint64_t sample_size = sample->length; /* sample will be deleted internally after appending. */
1156 if( lsmash_append_sample( output.root, out_track_ID, sample ) )
1158 lsmash_delete_sample( sample );
1159 return TIMELINEEDITOR_ERR( "Failed to append a sample.\n" );
1161 largest_dts = LSMASH_MAX( largest_dts, (double)dts / input_media_timescale );
1162 total_media_size += sample_size;
1163 ++ in_track->current_sample_number;
1164 num_consecutive_sample_skip = 0;
1165 /* Print, per 256 samples, total size of imported media. */
1166 if( ++sample_count == 0 )
1167 eprintf( "Importing: %"PRIu64" bytes\r", total_media_size );
1170 else
1171 ++num_consecutive_sample_skip; /* Skip appendig sample. */
1173 /* Move the next track. */
1174 if( ++ in_movie->current_track_number > in_movie->num_tracks )
1175 in_movie->current_track_number = 1; /* Back the first track. */
1176 if( ++ out_movie->current_track_number > out_movie->num_tracks )
1177 out_movie->current_track_number = 1; /* Back the first track in the output movie. */
1179 for( uint32_t i = 0; i < out_movie->num_tracks; i++ )
1180 if( lsmash_flush_pooled_samples( output.root, out_movie->track[i].track_ID, out_movie->track[i].last_sample_delta ) )
1181 return TIMELINEEDITOR_ERR( "Failed to flush samples.\n" );
1182 /* Copy timeline maps. */
1183 for( uint32_t i = 0; i < out_movie->num_tracks; i++ )
1184 if( lsmash_copy_timeline_map( output.root, out_movie->track[i].track_ID, input.root, in_movie->track[i].track_ID ) )
1185 return TIMELINEEDITOR_ERR( "Failed to copy a timeline map.\n" );
1186 /* Edit timeline map. */
1187 if( argc > 3 )
1189 track_t *out_track = &out_movie->track[ opt.track_number - 1 ];
1190 uint32_t track_ID = out_track->track_ID;
1191 uint32_t movie_timescale = lsmash_get_movie_timescale( output.root );
1192 uint32_t media_timescale = lsmash_get_media_timescale( output.root, track_ID );
1193 uint64_t empty_delay = timecode.empty_delay + (uint64_t)(opt.empty_delay * (1e-3 * media_timescale) + 0.5);
1194 uint64_t duration = timecode.duration + empty_delay;
1195 if( lsmash_delete_explicit_timeline_map( output.root, track_ID ) )
1196 return TIMELINEEDITOR_ERR( "Failed to delete explicit timeline maps.\n" );
1197 if( timecode.empty_delay )
1199 lsmash_edit_t empty_edit;
1200 empty_edit.duration = ((double)timecode.empty_delay / media_timescale) * movie_timescale;
1201 empty_edit.start_time = ISOM_EDIT_MODE_EMPTY;
1202 empty_edit.rate = ISOM_EDIT_MODE_NORMAL;
1203 if( lsmash_create_explicit_timeline_map( output.root, track_ID, empty_edit ) )
1204 return TIMELINEEDITOR_ERR( "Failed to create a empty duration.\n" );
1205 duration = ((double)duration / media_timescale) * movie_timescale;
1206 duration -= empty_edit.duration;
1208 else
1209 duration = ((double)duration / media_timescale) * movie_timescale;
1210 lsmash_edit_t edit;
1211 edit.duration = duration;
1212 edit.start_time = timecode.composition_delay + (uint64_t)(opt.skip_duration * (1e-3 * media_timescale) + 0.5);
1213 edit.rate = ISOM_EDIT_MODE_NORMAL;
1214 if( lsmash_create_explicit_timeline_map( output.root, track_ID, edit ) )
1215 return TIMELINEEDITOR_ERR( "Failed to create a explicit timeline map.\n" );
1217 /* Finish muxing. */
1218 lsmash_adhoc_remux_t moov_to_front;
1219 moov_to_front.func = moov_to_front_callback;
1220 moov_to_front.buffer_size = 4*1024*1024;
1221 moov_to_front.param = NULL;
1222 eprintf( " \r" );
1223 if( lsmash_finish_movie( output.root, &moov_to_front )
1224 || lsmash_write_lsmash_indicator( output.root ) )
1225 return TIMELINEEDITOR_ERR( "Failed to finish output movie.\n" );
1226 cleanup_root( io.input );
1227 cleanup_root( io.output );
1228 cleanup_timecode( io.timecode );
1229 eprintf( "Timeline editing completed! \n" );
1230 return 0;