cli: Update copyright dates.
[L-SMASH.git] / cli / timelineeditor.c
blobe24aea7f0221b93a2a69053c4fd86d1952630f8d
1 /*****************************************************************************
2 * timelineeditor.c:
3 *****************************************************************************
4 * Copyright (C) 2011-2015 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 "cli.h"
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <inttypes.h>
29 #include <math.h>
30 #include <stdarg.h>
32 #define LSMASH_MAX( a, b ) ((a) > (b) ? (a) : (b))
34 #define eprintf( ... ) fprintf( stderr, __VA_ARGS__ )
35 #define REFRESH_CONSOLE eprintf( " \r" )
37 typedef struct
39 int active;
40 lsmash_summary_t *summary;
41 } summary_t;
43 typedef struct
45 int active;
46 uint32_t track_ID;
47 uint32_t last_sample_delta;
48 uint32_t current_sample_number;
49 int reach_end_of_media_timeline;
50 uint32_t *summary_remap;
51 uint32_t num_summaries;
52 summary_t *summaries;
53 lsmash_track_parameters_t track_param;
54 lsmash_media_parameters_t media_param;
55 } track_t;
57 typedef struct
59 lsmash_itunes_metadata_t *itunes_metadata;
60 track_t *track;
61 lsmash_movie_parameters_t param;
62 uint32_t num_tracks;
63 uint32_t num_itunes_metadata;
64 uint32_t current_track_number;
65 } movie_t;
67 typedef struct
69 lsmash_file_t *fh;
70 lsmash_file_parameters_t param;
71 movie_t movie;
72 } file_t;
74 typedef struct
76 lsmash_root_t *root;
77 file_t file;
78 } root_t;
80 typedef struct
82 FILE *file;
83 uint64_t *ts;
84 uint32_t sample_count;
85 int auto_media_timescale;
86 int auto_media_timebase;
87 uint64_t media_timescale;
88 uint64_t media_timebase;
89 uint64_t duration;
90 uint64_t composition_delay;
91 uint64_t empty_delay;
92 } timecode_t;
94 typedef struct
96 root_t *output;
97 root_t *input;
98 timecode_t *timecode;
99 } movie_io_t;
101 typedef struct
103 uint32_t track_number;
104 uint32_t media_timescale;
105 uint32_t media_timebase;
106 uint32_t skip_duration;
107 uint32_t empty_delay;
108 int dts_compression;
109 } opt_t;
111 static void cleanup_root( root_t *h )
113 if( !h )
114 return;
115 movie_t *movie = &h->file.movie;
116 if( movie->itunes_metadata )
118 for( uint32_t i = 0; i < movie->num_itunes_metadata; i++ )
120 lsmash_itunes_metadata_t *metadata = &movie->itunes_metadata[i];
121 if( metadata->type == ITUNES_METADATA_TYPE_STRING )
123 if( metadata->value.string )
124 lsmash_free( metadata->value.string );
126 else if( metadata->type == ITUNES_METADATA_TYPE_BINARY )
127 if( metadata->value.binary.data )
128 lsmash_free( metadata->value.binary.data );
129 if( metadata->meaning )
130 lsmash_free( metadata->meaning );
131 if( metadata->name )
132 lsmash_free( metadata->name );
134 lsmash_freep( &movie->itunes_metadata );
136 if( movie->track )
137 lsmash_freep( &movie->track );
138 lsmash_close_file( &h->file.param );
139 lsmash_destroy_root( h->root );
140 h->root = NULL;
143 static void cleanup_timecode( timecode_t *timecode )
145 if( !timecode )
146 return;
147 if( timecode->file )
149 fclose( timecode->file );
150 timecode->file = NULL;
152 if( timecode->ts )
153 lsmash_freep( &timecode->ts );
156 static int error_message( const char* message, ... )
158 REFRESH_CONSOLE;
159 eprintf( "Error: " );
160 va_list args;
161 va_start( args, message );
162 vfprintf( stderr, message, args );
163 va_end( args );
164 return -1;
167 static int warning_message( const char* message, ... )
169 REFRESH_CONSOLE;
170 eprintf( "Warning: " );
171 va_list args;
172 va_start( args, message );
173 vfprintf( stderr, message, args );
174 va_end( args );
175 return -1;
178 static int timelineeditor_error( movie_io_t *io, const char *message, ... )
180 cleanup_root( io->input );
181 cleanup_root( io->output );
182 cleanup_timecode( io->timecode );
183 va_list args;
184 va_start( args, message );
185 error_message( message, args );
186 va_end( args );
187 return -1;
190 #define TIMELINEEDITOR_ERR( ... ) timelineeditor_error( &io, __VA_ARGS__ )
191 #define ERROR_MSG( ... ) error_message( __VA_ARGS__ )
192 #define WARNING_MSG( ... ) warning_message( __VA_ARGS__ )
194 static char *duplicate_string( char *src )
196 if( !src )
197 return NULL;
198 int dst_size = strlen( src ) + 1;
199 char *dst = lsmash_malloc( dst_size );
200 if( !dst )
201 return NULL;
202 memcpy( dst, src, dst_size );
203 return dst;
206 static int get_itunes_metadata( lsmash_root_t *root, uint32_t metadata_number, lsmash_itunes_metadata_t *metadata )
208 memset( metadata, 0, sizeof(lsmash_itunes_metadata_t) );
209 if( lsmash_get_itunes_metadata( root, metadata_number, metadata ) )
210 return -1;
211 lsmash_itunes_metadata_t shadow = *metadata;
212 metadata->meaning = NULL;
213 metadata->name = NULL;
214 memset( &metadata->value, 0, sizeof(lsmash_itunes_metadata_value_t) );
215 if( shadow.meaning )
217 metadata->meaning = duplicate_string( shadow.meaning );
218 if( !metadata->meaning )
219 return -1;
221 if( shadow.name )
223 metadata->name = duplicate_string( shadow.name );
224 if( !metadata->name )
225 goto fail;
227 if( shadow.type == ITUNES_METADATA_TYPE_STRING )
229 metadata->value.string = duplicate_string( shadow.value.string );
230 if( !metadata->value.string )
231 goto fail;
233 else if( shadow.type == ITUNES_METADATA_TYPE_BINARY )
235 metadata->value.binary.data = lsmash_malloc( shadow.value.binary.size );
236 if( !metadata->value.binary.data )
237 goto fail;
238 memcpy( metadata->value.binary.data, shadow.value.binary.data, shadow.value.binary.size );
240 return 0;
241 fail:
242 if( metadata->meaning )
243 lsmash_free( metadata->meaning );
244 if( metadata->name )
245 lsmash_free( metadata->name );
246 return -1;
249 static int get_summaries( root_t *input, track_t *track )
251 track->num_summaries = lsmash_count_summary( input->root, track->track_ID );
252 if( track->num_summaries == 0 )
253 return ERROR_MSG( "Failed to get find valid summaries.\n" );
254 track->summaries = lsmash_malloc( track->num_summaries * sizeof(summary_t) );
255 if( !track->summaries )
256 return ERROR_MSG( "failed to alloc input summaries.\n" );
257 memset( track->summaries, 0, track->num_summaries * sizeof(summary_t) );
258 for( uint32_t j = 0; j < track->num_summaries; j++ )
260 lsmash_summary_t *summary = lsmash_get_summary( input->root, track->track_ID, j + 1 );
261 if( !summary )
263 WARNING_MSG( "failed to get a summary.\n" );
264 continue;
266 track->summaries[j].summary = summary;
267 track->summaries[j].active = 1;
269 return 0;
272 static int get_movie( root_t *input, char *input_name )
274 if( !strcmp( input_name, "-" ) )
275 return ERROR_MSG( "Standard input not supported.\n" );
276 input->root = lsmash_create_root();
277 if( !input->root )
278 return ERROR_MSG( "failed to create a ROOT for an input file.\n" );
279 file_t *in_file = &input->file;
280 if( lsmash_open_file( input_name, 1, &in_file->param ) < 0 )
281 return ERROR_MSG( "failed to open an input file.\n" );
282 in_file->fh = lsmash_set_file( input->root, &in_file->param );
283 if( !in_file->fh )
284 return ERROR_MSG( "failed to add an input file into a ROOT.\n" );
285 if( lsmash_read_file( in_file->fh, &in_file->param ) < 0 )
286 return ERROR_MSG( "failed to read an input file\n" );
287 movie_t *movie = &in_file->movie;
288 movie->num_itunes_metadata = lsmash_count_itunes_metadata( input->root );
289 if( movie->num_itunes_metadata )
291 movie->itunes_metadata = lsmash_malloc( movie->num_itunes_metadata * sizeof(lsmash_itunes_metadata_t) );
292 if( !movie->itunes_metadata )
293 return ERROR_MSG( "failed to alloc iTunes metadata.\n" );
294 uint32_t itunes_metadata_count = 0;
295 for( uint32_t i = 1; i <= movie->num_itunes_metadata; i++ )
297 if( get_itunes_metadata( input->root, i, &movie->itunes_metadata[itunes_metadata_count] ) )
299 WARNING_MSG( "failed to get an iTunes metadata.\n" );
300 continue;
302 ++itunes_metadata_count;
304 movie->num_itunes_metadata = itunes_metadata_count;
306 lsmash_initialize_movie_parameters( &movie->param );
307 lsmash_get_movie_parameters( input->root, &movie->param );
308 movie->num_tracks = movie->param.number_of_tracks;
309 movie->current_track_number = 1;
310 /* Create tracks. */
311 track_t *track = movie->track = lsmash_malloc( movie->num_tracks * sizeof(track_t) );
312 if( !track )
313 return ERROR_MSG( "Failed to alloc input tracks.\n" );
314 memset( track, 0, movie->num_tracks * sizeof(track_t) );
315 for( uint32_t i = 0; i < movie->num_tracks; i++ )
317 track[i].track_ID = lsmash_get_track_ID( input->root, i + 1 );
318 if( !track[i].track_ID )
319 return ERROR_MSG( "Failed to get track_ID.\n" );
321 for( uint32_t i = 0; i < movie->num_tracks; i++ )
323 lsmash_initialize_track_parameters( &track[i].track_param );
324 if( lsmash_get_track_parameters( input->root, track[i].track_ID, &track[i].track_param ) )
326 WARNING_MSG( "failed to get track parameters.\n" );
327 continue;
329 lsmash_initialize_media_parameters( &track[i].media_param );
330 if( lsmash_get_media_parameters( input->root, track[i].track_ID, &track[i].media_param ) )
332 WARNING_MSG( "failed to get media parameters.\n" );
333 continue;
335 if( lsmash_construct_timeline( input->root, track[i].track_ID ) )
337 WARNING_MSG( "failed to construct timeline.\n" );
338 continue;
340 if( lsmash_get_last_sample_delta_from_media_timeline( input->root, track[i].track_ID, &track[i].last_sample_delta ) )
342 WARNING_MSG( "failed to get the last sample delta.\n" );
343 continue;
345 if( get_summaries( input, &track[i] ) )
347 WARNING_MSG( "failed to get valid summaries.\n" );
348 continue;
350 track[i].active = 1;
351 track[i].current_sample_number = 1;
353 lsmash_destroy_children( lsmash_file_as_box( in_file->fh ) );
354 return 0;
357 static inline uint64_t get_gcd( uint64_t a, uint64_t b )
359 if( !b )
360 return a;
361 while( 1 )
363 uint64_t c = a % b;
364 if( !c )
365 return b;
366 a = b;
367 b = c;
371 static inline uint64_t get_lcm( uint64_t a, uint64_t b )
373 if( !a )
374 return 0;
375 return (a / get_gcd( a, b )) * b;
378 static uint64_t get_media_timebase( lsmash_media_ts_list_t *ts_list )
380 uint64_t timebase = ts_list->timestamp[0].cts;
381 for( uint32_t i = 1; i < ts_list->sample_count; i++ )
382 timebase = get_gcd( timebase, ts_list->timestamp[i].cts );
383 for( uint32_t i = 0; i < ts_list->sample_count; i++ )
384 timebase = get_gcd( timebase, ts_list->timestamp[i].dts );
385 return timebase;
388 static inline double sigexp10( double value, double *exponent )
390 /* This function separates significand and exp10 from double floating point. */
391 *exponent = 1;
392 while( value < 1 )
394 value *= 10;
395 *exponent /= 10;
397 while( value >= 10 )
399 value /= 10;
400 *exponent *= 10;
402 return value;
405 #define DOUBLE_EPSILON 5e-6
406 #define MATROSKA_TIMESCALE 1000000000
407 #define SKIP_LINE_CHARACTER( x ) ((x) == '#' || (x) == '\n' || (x) == '\r')
409 static double correct_fps( double fps, timecode_t *timecode )
411 int i = 1;
412 uint64_t fps_num, fps_den;
413 double exponent;
414 double fps_sig = sigexp10( fps, &exponent );
415 while( 1 )
417 fps_den = i * timecode->media_timebase;
418 fps_num = round( fps_den * fps_sig ) * exponent;
419 if( fps_num > UINT32_MAX )
420 return ERROR_MSG( "framerate correction failed.\n"
421 "Specify an appropriate timebase manually or remake timecode file.\n" );
422 if( fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
423 break;
424 ++i;
426 if( timecode->auto_media_timescale )
428 timecode->media_timescale = timecode->media_timescale
429 ? get_lcm( timecode->media_timescale, fps_num )
430 : fps_num;
431 if( timecode->media_timescale > UINT32_MAX )
432 timecode->auto_media_timescale = 0;
434 return (double)fps_num / fps_den;
437 static int try_matroska_timescale( double *fps_array, timecode_t *timecode, uint32_t num_loops )
439 timecode->media_timebase = 0;
440 timecode->media_timescale = MATROSKA_TIMESCALE;
441 for( uint32_t i = 0; i < num_loops; i++ )
443 uint64_t fps_den;
444 double exponent;
445 double fps_sig = sigexp10( fps_array[i], &exponent );
446 fps_den = round( MATROSKA_TIMESCALE / fps_sig ) / exponent;
447 timecode->media_timebase = fps_den && timecode->media_timebase
448 ? get_gcd( timecode->media_timebase, fps_den )
449 : fps_den;
450 if( timecode->media_timebase > UINT32_MAX || !timecode->media_timebase )
451 return ERROR_MSG( "Automatic media timescale generation failed.\n"
452 "Specify media timescale manually.\n" );
454 return 0;
457 static int parse_timecode( timecode_t *timecode, uint32_t sample_count )
459 #define FAILED_PARSE_TIMECODE( ... ) \
460 do \
462 lsmash_free( fps_array ); \
463 lsmash_free( timecode_array ); \
464 return ERROR_MSG( __VA_ARGS__ ); \
466 while( 0 )
467 int tcfv;
468 int ret = fscanf( timecode->file, "# timecode format v%d", &tcfv );
469 if( ret != 1 || (tcfv != 1 && tcfv != 2) )
470 return ERROR_MSG( "Unsupported timecode format\n" );
471 char buff[256];
472 double *timecode_array = NULL;
473 if( tcfv == 1 )
475 double assume_fps = 0;
476 /* Get assumed framerate. */
477 while( fgets( buff, sizeof(buff), timecode->file ) )
479 if( SKIP_LINE_CHARACTER( buff[0] ) )
480 continue;
481 if( sscanf( buff, "assume %lf", &assume_fps ) != 1
482 && sscanf( buff, "Assume %lf", &assume_fps ) != 1 )
483 return ERROR_MSG( "Assumed fps not found\n" );
484 break;
486 if( assume_fps <= 0 )
487 return ERROR_MSG( "Invalid assumed fps\n" );
488 int64_t file_pos = lsmash_ftell( timecode->file );
489 if( file_pos < 0 )
490 return ERROR_MSG( "Failed to tell the postion of input timecode file.\n" );
491 /* Check whether valid or not and count number of sequences. */
492 uint32_t num_sequences = 0;
493 int64_t start, end;
494 int64_t prev_start = -1, prev_end = -1;
495 double sequence_fps;
496 while( fgets( buff, sizeof(buff), timecode->file ) )
498 if( SKIP_LINE_CHARACTER( buff[0] ) )
499 continue;
500 ret = sscanf( buff, "%"SCNd64",%"SCNd64",%lf", &start, &end, &sequence_fps );
501 if( ret != 3 && ret != EOF )
502 return ERROR_MSG( "Invalid input timecode file\n" );
503 if( start > end || start <= prev_start || end <= prev_end || sequence_fps <= 0 )
504 return ERROR_MSG( "Invalid input timecode file\n" );
505 prev_start = start;
506 prev_end = end;
507 if( timecode->auto_media_timescale || timecode->auto_media_timebase )
508 ++num_sequences;
510 if( lsmash_fseek( timecode->file, file_pos, SEEK_SET ) != 0 )
511 return ERROR_MSG( "Failed to seek input timecode file.\n" );
512 /* Preparation storing timecodes. */
513 double *fps_array = lsmash_malloc( ((timecode->auto_media_timescale || timecode->auto_media_timebase) * num_sequences + 1) * sizeof(double) );
514 if( !fps_array )
515 return ERROR_MSG( "Failed to allocate fps array\n" );
516 double corrected_assume_fps = correct_fps( assume_fps, timecode );
517 if( corrected_assume_fps < 0 )
518 FAILED_PARSE_TIMECODE( "Failed to correct the assumed framerate\n" );
519 timecode_array = lsmash_malloc( sample_count * sizeof(double) );
520 if( !timecode_array )
521 FAILED_PARSE_TIMECODE( "Failed to alloc timecodes\n" );
522 timecode_array[0] = 0;
523 num_sequences = 0;
524 uint32_t i = 0;
525 while( i < sample_count - 1 && fgets( buff, sizeof(buff), timecode->file ) )
527 if( SKIP_LINE_CHARACTER( buff[0] ) )
528 continue;
529 ret = sscanf( buff, "%"SCNd64",%"SCNd64",%lf", &start, &end, &sequence_fps );
530 if( ret != 3 )
531 start = end = sample_count - 1;
532 for( ; i < start && i < sample_count - 1; i++ )
533 timecode_array[i + 1] = timecode_array[i] + 1 / corrected_assume_fps;
534 if( i < sample_count - 1 )
536 if( timecode->auto_media_timescale || timecode->auto_media_timebase )
537 fps_array[num_sequences++] = sequence_fps;
538 sequence_fps = correct_fps( sequence_fps, timecode );
539 if( sequence_fps < 0 )
540 FAILED_PARSE_TIMECODE( "Failed to correct the framerate of a sequence.\n" );
541 for( i = start; i <= end && i < sample_count - 1; i++ )
542 timecode_array[i + 1] = timecode_array[i] + 1 / sequence_fps;
545 for( ; i < sample_count - 1; i++ )
546 timecode_array[i + 1] = timecode_array[i] + 1 / corrected_assume_fps;
547 if( timecode->auto_media_timescale || timecode->auto_media_timebase )
548 fps_array[num_sequences] = assume_fps;
549 /* Assume matroska timebase if automatic timescale generation isn't done yet. */
550 if( timecode->auto_media_timebase && !timecode->auto_media_timescale )
552 double exponent;
553 double assume_fps_sig, sequence_fps_sig;
554 if( try_matroska_timescale( fps_array, timecode, num_sequences + 1 ) < 0 )
555 FAILED_PARSE_TIMECODE( "Failed to try matroska timescale.\n" );
556 if( lsmash_fseek( timecode->file, file_pos, SEEK_SET ) != 0 )
557 FAILED_PARSE_TIMECODE( "Failed to seek input timecode file.\n" );
558 assume_fps_sig = sigexp10( assume_fps, &exponent );
559 corrected_assume_fps = MATROSKA_TIMESCALE / ( round( MATROSKA_TIMESCALE / assume_fps_sig ) / exponent );
560 for( i = 0; i < sample_count - 1 && fgets( buff, sizeof(buff), timecode->file ); )
562 if( SKIP_LINE_CHARACTER( buff[0] ) )
563 continue;
564 ret = sscanf( buff, "%"SCNd64",%"SCNd64",%lf", &start, &end, &sequence_fps );
565 if( ret != 3 )
566 start = end = sample_count - 1;
567 sequence_fps_sig = sigexp10( sequence_fps, &exponent );
568 sequence_fps = MATROSKA_TIMESCALE / ( round( MATROSKA_TIMESCALE / sequence_fps_sig ) / exponent );
569 for( ; i < start && i < sample_count - 1; i++ )
570 timecode_array[i + 1] = timecode_array[i] + 1 / corrected_assume_fps;
571 for( i = start; i <= end && i < sample_count - 1; i++ )
572 timecode_array[i + 1] = timecode_array[i] + 1 / sequence_fps;
574 for( ; i < sample_count - 1; i++ )
575 timecode_array[i + 1] = timecode_array[i] + 1 / corrected_assume_fps;
577 lsmash_free( fps_array );
579 else /* tcfv == 2 */
581 uint32_t num_timecodes = 0;
582 int64_t file_pos = lsmash_ftell( timecode->file );
583 if( file_pos < 0 )
584 return ERROR_MSG( "Failed to tell the postion of input timecode file.\n" );
585 while( fgets( buff, sizeof(buff), timecode->file ) )
587 if( SKIP_LINE_CHARACTER( buff[0] ) )
589 if( !num_timecodes )
591 file_pos = lsmash_ftell( timecode->file );
592 if( file_pos < 0 )
593 return ERROR_MSG( "Failed to tell the postion of input timecode file.\n" );
595 continue;
597 ++num_timecodes;
599 if( !num_timecodes )
600 return ERROR_MSG( "No timecodes!\n" );
601 if( sample_count > num_timecodes )
602 return ERROR_MSG( "Lack number of timecodes.\n" );
603 if( lsmash_fseek( timecode->file, file_pos, SEEK_SET ) != 0 )
604 return ERROR_MSG( "Failed to seek input timecode file.\n" );
605 timecode_array = lsmash_malloc( sample_count * sizeof(uint64_t) );
606 if( !timecode_array )
607 return ERROR_MSG( "Failed to alloc timecodes.\n" );
608 uint32_t i = 0;
609 if( fgets( buff, sizeof(buff), timecode->file ) )
611 ret = sscanf( buff, "%lf", &timecode_array[0] );
612 if( ret != 1 )
614 lsmash_free( timecode_array );
615 return ERROR_MSG( "Invalid timecode number: 0\n" );
617 timecode_array[i++] *= 1e-3; /* Timescale of timecode format v2 is 1000. */
618 while( i < sample_count && fgets( buff, sizeof(buff), timecode->file ) )
620 if( SKIP_LINE_CHARACTER( buff[0] ) )
621 continue;
622 ret = sscanf( buff, "%lf", &timecode_array[i] );
623 timecode_array[i] *= 1e-3; /* Timescale of timecode format v2 is 1000. */
624 if( ret != 1 || timecode_array[i] <= timecode_array[i - 1] )
626 lsmash_free( timecode_array );
627 return ERROR_MSG( "Invalid input timecode.\n" );
629 ++i;
632 if( i < sample_count )
634 lsmash_free( timecode_array );
635 return ERROR_MSG( "Failed to get timecodes.\n" );
637 /* Generate media timescale automatically if needed. */
638 if( sample_count != 1 && timecode->auto_media_timescale )
640 double *fps_array = lsmash_malloc( (sample_count - 1) * sizeof(double) );
641 if( !fps_array )
642 FAILED_PARSE_TIMECODE( "Failed to allocate fps array\n" );
643 for( i = 0; i < sample_count - 1; i++ )
645 fps_array[i] = 1 / (timecode_array[i + 1] - timecode_array[i]);
646 if( timecode->auto_media_timescale )
648 int j = 1;
649 uint64_t fps_num, fps_den;
650 double exponent;
651 double fps_sig = sigexp10( fps_array[i], &exponent );
652 while( 1 )
654 fps_den = j * timecode->media_timebase;
655 fps_num = round( fps_den * fps_sig ) * exponent;
656 if( fps_num > UINT32_MAX
657 || fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
658 break;
659 ++j;
661 timecode->media_timescale = fps_num && timecode->media_timescale
662 ? get_lcm( timecode->media_timescale, fps_num )
663 : fps_num;
664 if( timecode->media_timescale > UINT32_MAX )
666 timecode->auto_media_timescale = 0;
667 continue; /* Don't break because all framerate is needed for try_matroska_timescale. */
671 if( timecode->auto_media_timebase && !timecode->auto_media_timescale
672 && try_matroska_timescale( fps_array, timecode, sample_count - 1 ) < 0 )
673 FAILED_PARSE_TIMECODE( "Failed to try matroska timescale.\n" );
674 lsmash_free( fps_array );
677 if( timecode->auto_media_timescale || timecode->auto_media_timebase )
679 uint64_t reduce = get_gcd( timecode->media_timebase, timecode->media_timescale );
680 timecode->media_timebase /= reduce;
681 timecode->media_timescale /= reduce;
683 else if( timecode->media_timescale > UINT32_MAX || !timecode->media_timescale )
685 lsmash_free( timecode_array );
686 return ERROR_MSG( "Failed to generate media timescale automatically.\n"
687 "Specify an appropriate media timescale manually.\n" );
689 uint32_t timescale = timecode->media_timescale;
690 uint32_t timebase = timecode->media_timebase;
691 double delay_tc = timecode_array[0];
692 timecode->empty_delay = ((uint64_t)(delay_tc * ((double)timescale / timebase) + 0.5)) * timebase;
693 timecode->ts = lsmash_malloc( sample_count * sizeof(uint64_t) );
694 if( !timecode->ts )
696 lsmash_free( timecode_array );
697 return ERROR_MSG( "Failed to allocate timestamps.\n" );
699 timecode->ts[0] = 0;
700 for( uint32_t i = 1; i < sample_count; i++ )
702 timecode->ts[i] = ((uint64_t)((timecode_array[i] - delay_tc) * ((double)timescale / timebase) + 0.5)) * timebase;
703 if( timecode->ts[i] <= timecode->ts[i - 1] )
705 lsmash_free( timecode_array );
706 lsmash_free( timecode->ts );
707 timecode->ts = NULL;
708 return ERROR_MSG( "Invalid timecode.\n" );
711 lsmash_free( timecode_array );
712 return 0;
713 #undef FAILED_PARSE_TIMECODE
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 = lsmash_malloc( sample_delay * sizeof(uint64_t) );
803 if( !prev_reordered_cts )
804 return ERROR_MSG( "Failed to allocate the previous reordered CTS array.\n" );
805 for( uint32_t i = 0; i <= sample_delay; i++ )
807 if( !opt->dts_compression )
808 timestamp[i].dts = timecode->ts[i];
809 else
811 timestamp[i].dts = (i * initial_delta) / (!!opt->media_timescale * sample_delay + 1);
812 if( i && (timestamp[i].dts <= timestamp[i - 1].dts) )
814 lsmash_free( prev_reordered_cts );
815 return ERROR_MSG( "Failed to do DTS compression.\n" );
818 prev_reordered_cts[ i % sample_delay ] = timecode->ts[i] + sample_delay_time;
820 for( uint32_t i = sample_delay + 1; i < sample_count; i++ )
822 timestamp[i].dts = prev_reordered_cts[ (i - sample_delay) % sample_delay ];
823 prev_reordered_cts[ i % sample_delay ] = timecode->ts[i] + sample_delay_time;
825 lsmash_free( prev_reordered_cts );
827 else
828 for( uint32_t i = 0; i < sample_count; i++ )
829 timestamp[i].cts = timestamp[i].dts = timecode->ts[i];
830 if( sample_count > 1 )
832 in_track->last_sample_delta = timecode->ts[sample_count - 1] - timecode->ts[sample_count - 2];
833 timecode->duration = timecode->ts[sample_count - 1] + in_track->last_sample_delta;
835 else /* still image */
836 timecode->duration = in_track->last_sample_delta = UINT32_MAX;
837 in_track->media_param.timescale = timescale;
838 if( lsmash_set_media_timestamps( input->root, track_ID, &ts_list ) )
839 return ERROR_MSG( "Failed to set media timestamps.\n" );
840 lsmash_delete_media_timestamps( &ts_list );
841 return 0;
844 static int check_white_brand( lsmash_brand_type brand )
846 static const lsmash_brand_type brand_white_list[] =
848 ISOM_BRAND_TYPE_3G2A,
849 ISOM_BRAND_TYPE_3GG6,
850 ISOM_BRAND_TYPE_3GG9,
851 ISOM_BRAND_TYPE_3GP4,
852 ISOM_BRAND_TYPE_3GP5,
853 ISOM_BRAND_TYPE_3GP6,
854 ISOM_BRAND_TYPE_3GP7,
855 ISOM_BRAND_TYPE_3GP8,
856 ISOM_BRAND_TYPE_3GP9,
857 ISOM_BRAND_TYPE_3GR6,
858 ISOM_BRAND_TYPE_3GR9,
859 ISOM_BRAND_TYPE_M4A ,
860 ISOM_BRAND_TYPE_M4B ,
861 ISOM_BRAND_TYPE_M4V ,
862 ISOM_BRAND_TYPE_AVC1,
863 ISOM_BRAND_TYPE_DBY1,
864 ISOM_BRAND_TYPE_ISO2,
865 ISOM_BRAND_TYPE_ISO3,
866 ISOM_BRAND_TYPE_ISO4,
867 ISOM_BRAND_TYPE_ISO5,
868 ISOM_BRAND_TYPE_ISO6,
869 ISOM_BRAND_TYPE_ISOM,
870 ISOM_BRAND_TYPE_MP41,
871 ISOM_BRAND_TYPE_MP42,
872 ISOM_BRAND_TYPE_QT ,
875 for( int i = 0; brand_white_list[i]; i++ )
876 if( brand == brand_white_list[i] )
877 return 1;
878 return 0;
881 static int moov_to_front_callback( void *param, uint64_t written_movie_size, uint64_t total_movie_size )
883 eprintf( "Finalizing: [%5.2lf%%]\r", ((double)written_movie_size / total_movie_size) * 100.0 );
884 return 0;
887 static void display_version( void )
889 eprintf( "\n"
890 "L-SMASH isom/mov timeline editor rev%s %s\n"
891 "Built on %s %s\n"
892 "Copyright (C) 2011-2015 L-SMASH project\n",
893 LSMASH_REV, LSMASH_GIT_HASH, __DATE__, __TIME__ );
896 static void display_help( void )
898 display_version();
899 eprintf( "\n"
900 "Usage: timelineeditor [options] input output\n"
901 " options:\n"
902 " --help Display help\n"
903 " --version Display version information\n"
904 " --track <integer> Specify track number to edit [1]\n"
905 " --timecode <string> Specify timecode file to edit timeline\n"
906 " --media-timescale <integer> Specify media timescale to convert\n"
907 " --media-timebase <integer> Specify media timebase to convert\n"
908 " --skip <integer> Skip start of media presentation in milliseconds\n"
909 " --delay <integer> Insert blank clip before actual media presentation in milliseconds\n"
910 " --dts-compression Eliminate composition delay with DTS hack\n"
911 " Multiply media timescale and timebase automatically\n" );
914 int main( int argc, char *argv[] )
916 if ( argc < 2 )
918 display_help();
919 return -1;
921 else if( !strcasecmp( argv[1], "-h" ) || !strcasecmp( argv[1], "--help" ) )
923 display_help();
924 return 0;
926 else if( !strcasecmp( argv[1], "-v" ) || !strcasecmp( argv[1], "--version" ) )
928 display_version();
929 return 0;
931 else if( argc < 3 )
933 display_help();
934 return -1;
936 root_t output = { 0 };
937 root_t input = { 0 };
938 timecode_t timecode = { 0 };
939 movie_io_t io = { &output, &input, &timecode };
940 opt_t opt = { 1, 0, 0, 0, 0, 0 };
941 /* Parse options. */
942 lsmash_get_mainargs( &argc, &argv );
943 int argn = 1;
944 while( argn < argc - 2 )
946 if( !strcasecmp( argv[argn], "--track" ) )
948 opt.track_number = atoi( argv[++argn] );
949 if( !opt.track_number )
950 return TIMELINEEDITOR_ERR( "Invalid track number.\n" );
951 ++argn;
953 else if( !strcasecmp( argv[argn], "--timecode" ) )
955 timecode.file = lsmash_fopen( argv[++argn], "rb" );
956 if( !timecode.file )
957 return TIMELINEEDITOR_ERR( "Failed to open timecode file.\n" );
958 ++argn;
960 else if( !strcasecmp( argv[argn], "--media-timescale" ) )
962 opt.media_timescale = atoi( argv[++argn] );
963 if( !opt.media_timescale )
964 return TIMELINEEDITOR_ERR( "Invalid media timescale.\n" );
965 ++argn;
967 else if( !strcasecmp( argv[argn], "--media-timebase" ) )
969 opt.media_timebase = atoi( argv[++argn] );
970 if( !opt.media_timebase )
971 return TIMELINEEDITOR_ERR( "Invalid media timebase.\n" );
972 ++argn;
974 else if( !strcasecmp( argv[argn], "--skip" ) )
976 opt.skip_duration = atoi( argv[++argn] );
977 if( !opt.skip_duration )
978 return TIMELINEEDITOR_ERR( "Invalid skip duration.\n" );
979 ++argn;
981 else if( !strcasecmp( argv[argn], "--delay" ) )
983 opt.empty_delay = atoi( argv[++argn] );
984 if( !opt.empty_delay )
985 return TIMELINEEDITOR_ERR( "Invalid delay time.\n" );
986 ++argn;
988 else if( !strcasecmp( argv[argn], "--dts-compression" ) )
990 opt.dts_compression = 1;
991 ++argn;
993 else
994 return TIMELINEEDITOR_ERR( "Invalid option.\n" );
996 if( argn > argc - 2 )
997 return TIMELINEEDITOR_ERR( "Invalid arguments.\n" );
998 /* Get input movies. */
999 if( get_movie( &input, argv[argn++] ) )
1000 return TIMELINEEDITOR_ERR( "Failed to get input movie.\n" );
1001 movie_t *in_movie = &input.file.movie;
1002 if( opt.track_number && (opt.track_number > in_movie->num_tracks) )
1003 return TIMELINEEDITOR_ERR( "Invalid track number.\n" );
1004 /* Create output movie. */
1005 file_t *out_file = &output.file;
1006 output.root = lsmash_create_root();
1007 if( !output.root )
1008 return TIMELINEEDITOR_ERR( "failed to create a ROOT for an output file.\n" );
1009 if( lsmash_open_file( argv[argn], 0, &out_file->param ) < 0 )
1010 return TIMELINEEDITOR_ERR( "failed to open an output file.\n" );
1011 file_t *in_file = &input.file;
1012 out_file->param.major_brand = in_file->param.major_brand;
1013 out_file->param.minor_version = in_file->param.minor_version;
1014 out_file->param.brands = in_file->param.brands;
1015 out_file->param.brand_count = in_file->param.brand_count;
1016 out_file->param.max_chunk_duration = 0.5;
1017 out_file->param.max_async_tolerance = 2.0;
1018 out_file->param.max_chunk_size = 4*1024*1024;
1019 if( !check_white_brand( out_file->param.major_brand ) )
1021 /* Replace with whitelisted brand 'mp42'. */
1022 out_file->param.major_brand = ISOM_BRAND_TYPE_MP42;
1023 out_file->param.minor_version = 0;
1024 uint32_t i;
1025 for( i = 0; i < out_file->param.brand_count; i++ )
1026 if( out_file->param.brands[i] == ISOM_BRAND_TYPE_MP42 )
1027 break;
1028 if( i == out_file->param.brand_count )
1030 /* Add 'mp42' into the list of compatible brands. */
1031 out_file->param.brands = lsmash_malloc( (i + 1) * sizeof(lsmash_brand_type) );
1032 if( out_file->param.brands )
1034 memcpy( out_file->param.brands, in_file->param.brands, i * sizeof(lsmash_brand_type) );
1035 out_file->param.brands[i] = ISOM_BRAND_TYPE_MP42;
1039 out_file->fh = lsmash_set_file( output.root, &out_file->param );
1040 if( !out_file->fh )
1041 return TIMELINEEDITOR_ERR( "failed to add an output file into a ROOT.\n" );
1042 if( out_file->param.brands != in_file->param.brands )
1043 lsmash_freep( &out_file->param.brands );
1044 /* Set movie parameters. */
1045 movie_t *out_movie = &out_file->movie;
1046 out_movie->param = in_movie->param; /* Copy movie parameters. */
1047 if( in_movie->num_tracks == 1 )
1048 out_movie->param.timescale = in_movie->track[0].media_param.timescale;
1049 if( lsmash_set_movie_parameters( output.root, &out_movie->param ) )
1050 return TIMELINEEDITOR_ERR( "Failed to set output movie parameters.\n" );
1051 /* Set iTunes metadata. */
1052 for( uint32_t i = 0; i < in_movie->num_itunes_metadata; i++ )
1053 if( lsmash_set_itunes_metadata( output.root, in_movie->itunes_metadata[i] ) )
1055 WARNING_MSG( "failed to set an iTunes metadata.\n" );
1056 continue;
1058 /* Create tracks of the output movie. */
1059 out_movie->track = lsmash_malloc( in_movie->num_tracks * sizeof(track_t) );
1060 if( !out_movie->track )
1061 return TIMELINEEDITOR_ERR( "Failed to alloc output tracks.\n" );
1062 /* Edit timeline. */
1063 if( edit_media_timeline( &input, &timecode, &opt ) )
1064 return TIMELINEEDITOR_ERR( "Failed to edit timeline.\n" );
1065 out_movie->num_tracks = in_movie->num_tracks;
1066 out_movie->current_track_number = 1;
1067 for( uint32_t i = 0; i < in_movie->num_tracks; i++ )
1069 track_t *in_track = &in_movie->track[i];
1070 if( !in_track->active )
1072 -- out_movie->num_tracks;
1073 continue;
1075 track_t *out_track = &out_movie->track[i];
1076 out_track->summary_remap = lsmash_malloc( in_track->num_summaries * sizeof(uint32_t) );
1077 if( !out_track->summary_remap )
1078 return TIMELINEEDITOR_ERR( "failed to create summary mapping for a track.\n" );
1079 memset( out_track->summary_remap, 0, in_track->num_summaries * sizeof(uint32_t) );
1080 out_track->track_ID = lsmash_create_track( output.root, in_track->media_param.handler_type );
1081 if( !out_track->track_ID )
1082 return TIMELINEEDITOR_ERR( "Failed to create a track.\n" );
1083 /* Copy track and media parameters except for track_ID. */
1084 out_track->track_param = in_track->track_param;
1085 out_track->media_param = in_track->media_param;
1086 out_track->track_param.track_ID = out_track->track_ID;
1087 if( lsmash_set_track_parameters( output.root, out_track->track_ID, &out_track->track_param ) )
1088 return TIMELINEEDITOR_ERR( "Failed to set track parameters.\n" );
1089 if( lsmash_set_media_parameters( output.root, out_track->track_ID, &out_track->media_param ) )
1090 return TIMELINEEDITOR_ERR( "Failed to set media parameters.\n" );
1091 uint32_t valid_summary_count = 0;
1092 for( uint32_t k = 0; k < in_track->num_summaries; k++ )
1094 if( !in_track->summaries[k].active )
1096 out_track->summary_remap[k] = 0;
1097 continue;
1099 lsmash_summary_t *summary = in_track->summaries[k].summary;
1100 if( lsmash_add_sample_entry( output.root, out_track->track_ID, summary ) == 0 )
1102 WARNING_MSG( "failed to append a summary.\n" );
1103 lsmash_cleanup_summary( summary );
1104 in_track->summaries[k].summary = NULL;
1105 in_track->summaries[k].active = 0;
1106 out_track->summary_remap[k] = 0;
1107 continue;
1109 out_track->summary_remap[k] = ++valid_summary_count;
1111 if( valid_summary_count == 0 )
1112 return TIMELINEEDITOR_ERR( "failed to append all summaries.\n" );
1113 out_track->last_sample_delta = in_track->last_sample_delta;
1114 out_track->current_sample_number = 1;
1115 out_track->reach_end_of_media_timeline = 0;
1117 /* Start muxing. */
1118 double largest_dts = 0;
1119 uint32_t num_consecutive_sample_skip = 0;
1120 uint32_t num_active_input_tracks = out_movie->num_tracks;
1121 uint64_t total_media_size = 0;
1122 uint8_t sample_count = 0;
1123 while( 1 )
1125 track_t *in_track = &in_movie->track[ in_movie->current_track_number - 1 ];
1126 /* Try append a sample in an input track where we didn't reach the end of media timeline. */
1127 if( !in_track->reach_end_of_media_timeline )
1129 track_t *out_track = &out_movie->track[ out_movie->current_track_number - 1 ];
1130 uint32_t in_track_ID = in_track->track_ID;
1131 uint32_t out_track_ID = out_track->track_ID;
1132 uint32_t input_media_timescale = in_track->media_param.timescale;
1133 /* Get a DTS from a track in an input movie. */
1134 uint64_t dts;
1135 if( lsmash_get_dts_from_media_timeline( input.root, in_track_ID, in_track->current_sample_number, &dts ) )
1137 if( lsmash_check_sample_existence_in_media_timeline( input.root, in_track_ID, in_track->current_sample_number ) )
1138 return TIMELINEEDITOR_ERR( "Failed to get the DTS.\n" );
1139 else
1141 in_track->reach_end_of_media_timeline = 1;
1142 if( --num_active_input_tracks == 0 )
1143 break; /* end of muxing */
1146 /* Get and append a sample if it's good time. */
1147 else if( ((double)dts / input_media_timescale) <= largest_dts
1148 || num_consecutive_sample_skip == num_active_input_tracks )
1150 /* Get an actual sample data from a track in an input movie. */
1151 lsmash_sample_t *sample = lsmash_get_sample_from_media_timeline( input.root, in_track_ID, in_track->current_sample_number );
1152 if( !sample )
1153 return TIMELINEEDITOR_ERR( "Failed to get sample.\n" );
1154 sample->index = sample->index > in_track->num_summaries ? in_track->num_summaries
1155 : sample->index == 0 ? 1
1156 : sample->index;
1157 sample->index = out_track->summary_remap[ sample->index - 1 ];
1158 if( sample->index )
1160 /* Append sample into output movie. */
1161 uint64_t sample_size = sample->length; /* sample will be deleted internally after appending. */
1162 if( lsmash_append_sample( output.root, out_track_ID, sample ) )
1164 lsmash_delete_sample( sample );
1165 return TIMELINEEDITOR_ERR( "Failed to append a sample.\n" );
1167 largest_dts = LSMASH_MAX( largest_dts, (double)dts / input_media_timescale );
1168 total_media_size += sample_size;
1169 ++ in_track->current_sample_number;
1170 num_consecutive_sample_skip = 0;
1171 /* Print, per 256 samples, total size of imported media. */
1172 if( ++sample_count == 0 )
1173 eprintf( "Importing: %"PRIu64" bytes\r", total_media_size );
1176 else
1177 ++num_consecutive_sample_skip; /* Skip appendig sample. */
1179 /* Move the next track. */
1180 if( ++ in_movie->current_track_number > in_movie->num_tracks )
1181 in_movie->current_track_number = 1; /* Back the first track. */
1182 if( ++ out_movie->current_track_number > out_movie->num_tracks )
1183 out_movie->current_track_number = 1; /* Back the first track in the output movie. */
1185 for( uint32_t i = 0; i < out_movie->num_tracks; i++ )
1186 if( lsmash_flush_pooled_samples( output.root, out_movie->track[i].track_ID, out_movie->track[i].last_sample_delta ) )
1187 return TIMELINEEDITOR_ERR( "Failed to flush samples.\n" );
1188 /* Copy timeline maps. */
1189 for( uint32_t i = 0; i < out_movie->num_tracks; i++ )
1190 if( lsmash_copy_timeline_map( output.root, out_movie->track[i].track_ID, input.root, in_movie->track[i].track_ID ) )
1191 return TIMELINEEDITOR_ERR( "Failed to copy a timeline map.\n" );
1192 /* Edit timeline map. */
1193 if( argc > 3 )
1195 track_t *out_track = &out_movie->track[ opt.track_number - 1 ];
1196 uint32_t track_ID = out_track->track_ID;
1197 uint32_t movie_timescale = lsmash_get_movie_timescale( output.root );
1198 uint32_t media_timescale = lsmash_get_media_timescale( output.root, track_ID );
1199 uint64_t empty_delay = timecode.empty_delay + (uint64_t)(opt.empty_delay * (1e-3 * media_timescale) + 0.5);
1200 uint64_t duration = timecode.duration + empty_delay;
1201 if( lsmash_delete_explicit_timeline_map( output.root, track_ID ) )
1202 return TIMELINEEDITOR_ERR( "Failed to delete explicit timeline maps.\n" );
1203 if( timecode.empty_delay )
1205 lsmash_edit_t empty_edit;
1206 empty_edit.duration = ((double)timecode.empty_delay / media_timescale) * movie_timescale;
1207 empty_edit.start_time = ISOM_EDIT_MODE_EMPTY;
1208 empty_edit.rate = ISOM_EDIT_MODE_NORMAL;
1209 if( lsmash_create_explicit_timeline_map( output.root, track_ID, empty_edit ) )
1210 return TIMELINEEDITOR_ERR( "Failed to create a empty duration.\n" );
1211 duration = ((double)duration / media_timescale) * movie_timescale;
1212 duration -= empty_edit.duration;
1214 else
1215 duration = ((double)duration / media_timescale) * movie_timescale;
1216 lsmash_edit_t edit;
1217 edit.duration = duration;
1218 edit.start_time = timecode.composition_delay + (uint64_t)(opt.skip_duration * (1e-3 * media_timescale) + 0.5);
1219 edit.rate = ISOM_EDIT_MODE_NORMAL;
1220 if( lsmash_create_explicit_timeline_map( output.root, track_ID, edit ) )
1221 return TIMELINEEDITOR_ERR( "Failed to create a explicit timeline map.\n" );
1223 /* Finish muxing. */
1224 lsmash_adhoc_remux_t moov_to_front;
1225 moov_to_front.func = moov_to_front_callback;
1226 moov_to_front.buffer_size = 4*1024*1024;
1227 moov_to_front.param = NULL;
1228 eprintf( " \r" );
1229 if( lsmash_finish_movie( output.root, &moov_to_front )
1230 || lsmash_write_lsmash_indicator( output.root ) )
1231 return TIMELINEEDITOR_ERR( "Failed to finish output movie.\n" );
1232 cleanup_root( io.input );
1233 cleanup_root( io.output );
1234 cleanup_timecode( io.timecode );
1235 eprintf( "Timeline editing completed! \n" );
1236 return 0;