timelineeditor: Remove redundant 'if's for freeing.
[L-SMASH.git] / cli / timelineeditor.c
blobaab14724636bbc31c8c7717b1333be54898d22e0
1 /*****************************************************************************
2 * timelineeditor.c
3 *****************************************************************************
4 * Copyright (C) 2011-2017 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_num;
107 uint32_t skip_duration_den;
108 uint32_t empty_delay_num;
109 uint32_t empty_delay_den;
110 int dts_compression;
111 } opt_t;
113 static void cleanup_root( root_t *h )
115 if( !h )
116 return;
117 movie_t *movie = &h->file.movie;
118 if( movie->itunes_metadata )
120 for( uint32_t i = 0; i < movie->num_itunes_metadata; i++ )
122 lsmash_itunes_metadata_t *metadata = &movie->itunes_metadata[i];
123 if( metadata->type == ITUNES_METADATA_TYPE_STRING )
124 lsmash_free( metadata->value.string );
125 else if( metadata->type == ITUNES_METADATA_TYPE_BINARY )
126 lsmash_free( metadata->value.binary.data );
127 lsmash_free( metadata->meaning );
128 lsmash_free( metadata->name );
130 lsmash_freep( &movie->itunes_metadata );
132 lsmash_freep( &movie->track );
133 lsmash_close_file( &h->file.param );
134 lsmash_destroy_root( h->root );
135 h->root = NULL;
138 static void cleanup_timecode( timecode_t *timecode )
140 if( !timecode )
141 return;
142 if( timecode->file )
144 fclose( timecode->file );
145 timecode->file = NULL;
147 lsmash_freep( &timecode->ts );
150 static int error_message( const char* message, ... )
152 REFRESH_CONSOLE;
153 eprintf( "Error: " );
154 va_list args;
155 va_start( args, message );
156 vfprintf( stderr, message, args );
157 va_end( args );
158 return -1;
161 static int warning_message( const char* message, ... )
163 REFRESH_CONSOLE;
164 eprintf( "Warning: " );
165 va_list args;
166 va_start( args, message );
167 vfprintf( stderr, message, args );
168 va_end( args );
169 return -1;
172 static int timelineeditor_error( movie_io_t *io, const char *message, ... )
174 cleanup_root( io->input );
175 cleanup_root( io->output );
176 cleanup_timecode( io->timecode );
177 va_list args;
178 va_start( args, message );
179 error_message( message, args );
180 va_end( args );
181 return -1;
184 #define TIMELINEEDITOR_ERR( ... ) timelineeditor_error( &io, __VA_ARGS__ )
185 #define ERROR_MSG( ... ) error_message( __VA_ARGS__ )
186 #define WARNING_MSG( ... ) warning_message( __VA_ARGS__ )
188 static char *duplicate_string( char *src )
190 if( !src )
191 return NULL;
192 int dst_size = strlen( src ) + 1;
193 char *dst = lsmash_malloc( dst_size );
194 if( !dst )
195 return NULL;
196 memcpy( dst, src, dst_size );
197 return dst;
200 static int get_itunes_metadata( lsmash_root_t *root, uint32_t metadata_number, lsmash_itunes_metadata_t *metadata )
202 memset( metadata, 0, sizeof(lsmash_itunes_metadata_t) );
203 if( lsmash_get_itunes_metadata( root, metadata_number, metadata ) )
204 return -1;
205 lsmash_itunes_metadata_t shadow = *metadata;
206 metadata->meaning = NULL;
207 metadata->name = NULL;
208 memset( &metadata->value, 0, sizeof(lsmash_itunes_metadata_value_t) );
209 if( shadow.meaning )
211 metadata->meaning = duplicate_string( shadow.meaning );
212 if( !metadata->meaning )
213 return -1;
215 if( shadow.name )
217 metadata->name = duplicate_string( shadow.name );
218 if( !metadata->name )
219 goto fail;
221 if( shadow.type == ITUNES_METADATA_TYPE_STRING )
223 metadata->value.string = duplicate_string( shadow.value.string );
224 if( !metadata->value.string )
225 goto fail;
227 else if( shadow.type == ITUNES_METADATA_TYPE_BINARY )
229 metadata->value.binary.data = lsmash_malloc( shadow.value.binary.size );
230 if( !metadata->value.binary.data )
231 goto fail;
232 memcpy( metadata->value.binary.data, shadow.value.binary.data, shadow.value.binary.size );
234 return 0;
235 fail:
236 lsmash_free( metadata->meaning );
237 lsmash_free( metadata->name );
238 return -1;
241 static int get_summaries( root_t *input, track_t *track )
243 track->num_summaries = lsmash_count_summary( input->root, track->track_ID );
244 if( track->num_summaries == 0 )
245 return ERROR_MSG( "Failed to get find valid summaries.\n" );
246 track->summaries = lsmash_malloc( track->num_summaries * sizeof(summary_t) );
247 if( !track->summaries )
248 return ERROR_MSG( "failed to alloc input summaries.\n" );
249 memset( track->summaries, 0, track->num_summaries * sizeof(summary_t) );
250 for( uint32_t j = 0; j < track->num_summaries; j++ )
252 lsmash_summary_t *summary = lsmash_get_summary( input->root, track->track_ID, j + 1 );
253 if( !summary )
255 WARNING_MSG( "failed to get a summary.\n" );
256 continue;
258 track->summaries[j].summary = summary;
259 track->summaries[j].active = 1;
261 return 0;
264 static int get_movie( root_t *input, char *input_name )
266 if( !strcmp( input_name, "-" ) )
267 return ERROR_MSG( "Standard input not supported.\n" );
268 input->root = lsmash_create_root();
269 if( !input->root )
270 return ERROR_MSG( "failed to create a ROOT for an input file.\n" );
271 file_t *in_file = &input->file;
272 if( lsmash_open_file( input_name, 1, &in_file->param ) < 0 )
273 return ERROR_MSG( "failed to open an input file.\n" );
274 in_file->fh = lsmash_set_file( input->root, &in_file->param );
275 if( !in_file->fh )
276 return ERROR_MSG( "failed to add an input file into a ROOT.\n" );
277 if( lsmash_read_file( in_file->fh, &in_file->param ) < 0 )
278 return ERROR_MSG( "failed to read an input file\n" );
279 movie_t *movie = &in_file->movie;
280 movie->num_itunes_metadata = lsmash_count_itunes_metadata( input->root );
281 if( movie->num_itunes_metadata )
283 movie->itunes_metadata = lsmash_malloc( movie->num_itunes_metadata * sizeof(lsmash_itunes_metadata_t) );
284 if( !movie->itunes_metadata )
285 return ERROR_MSG( "failed to alloc iTunes metadata.\n" );
286 uint32_t itunes_metadata_count = 0;
287 for( uint32_t i = 1; i <= movie->num_itunes_metadata; i++ )
289 if( get_itunes_metadata( input->root, i, &movie->itunes_metadata[itunes_metadata_count] ) )
291 WARNING_MSG( "failed to get an iTunes metadata.\n" );
292 continue;
294 ++itunes_metadata_count;
296 movie->num_itunes_metadata = itunes_metadata_count;
298 lsmash_initialize_movie_parameters( &movie->param );
299 lsmash_get_movie_parameters( input->root, &movie->param );
300 movie->num_tracks = movie->param.number_of_tracks;
301 movie->current_track_number = 1;
302 /* Create tracks. */
303 track_t *track = movie->track = lsmash_malloc( movie->num_tracks * sizeof(track_t) );
304 if( !track )
305 return ERROR_MSG( "Failed to alloc input tracks.\n" );
306 memset( track, 0, movie->num_tracks * sizeof(track_t) );
307 for( uint32_t i = 0; i < movie->num_tracks; i++ )
309 track[i].track_ID = lsmash_get_track_ID( input->root, i + 1 );
310 if( !track[i].track_ID )
311 return ERROR_MSG( "Failed to get track_ID.\n" );
313 for( uint32_t i = 0; i < movie->num_tracks; i++ )
315 lsmash_initialize_track_parameters( &track[i].track_param );
316 if( lsmash_get_track_parameters( input->root, track[i].track_ID, &track[i].track_param ) )
318 WARNING_MSG( "failed to get track parameters.\n" );
319 continue;
321 lsmash_initialize_media_parameters( &track[i].media_param );
322 if( lsmash_get_media_parameters( input->root, track[i].track_ID, &track[i].media_param ) )
324 WARNING_MSG( "failed to get media parameters.\n" );
325 continue;
327 if( lsmash_construct_timeline( input->root, track[i].track_ID ) )
329 WARNING_MSG( "failed to construct timeline.\n" );
330 continue;
332 if( lsmash_get_last_sample_delta_from_media_timeline( input->root, track[i].track_ID, &track[i].last_sample_delta ) )
334 WARNING_MSG( "failed to get the last sample delta.\n" );
335 continue;
337 if( get_summaries( input, &track[i] ) )
339 WARNING_MSG( "failed to get valid summaries.\n" );
340 continue;
342 track[i].active = 1;
343 track[i].current_sample_number = 1;
345 lsmash_destroy_children( lsmash_file_as_box( in_file->fh ) );
346 return 0;
349 static inline uint64_t get_gcd( uint64_t a, uint64_t b )
351 if( !b )
352 return a;
353 while( 1 )
355 uint64_t c = a % b;
356 if( !c )
357 return b;
358 a = b;
359 b = c;
363 static inline uint64_t get_lcm( uint64_t a, uint64_t b )
365 if( !a )
366 return 0;
367 return (a / get_gcd( a, b )) * b;
370 static uint64_t get_media_timebase( lsmash_media_ts_list_t *ts_list )
372 uint64_t timebase = ts_list->timestamp[0].cts;
373 for( uint32_t i = 1; i < ts_list->sample_count; i++ )
374 timebase = get_gcd( timebase, ts_list->timestamp[i].cts );
375 for( uint32_t i = 0; i < ts_list->sample_count; i++ )
376 timebase = get_gcd( timebase, ts_list->timestamp[i].dts );
377 return timebase;
380 static inline double sigexp10( double value, double *exponent )
382 /* This function separates significand and exp10 from double floating point. */
383 *exponent = 1;
384 while( value < 1 )
386 value *= 10;
387 *exponent /= 10;
389 while( value >= 10 )
391 value /= 10;
392 *exponent *= 10;
394 return value;
397 #define DOUBLE_EPSILON 5e-6
398 #define MATROSKA_TIMESCALE 1000000000
399 #define SKIP_LINE_CHARACTER( x ) ((x) == '#' || (x) == '\n' || (x) == '\r')
401 static double correct_fps( double fps, timecode_t *timecode )
403 int i = 1;
404 uint64_t fps_num, fps_den;
405 double exponent;
406 double fps_sig = sigexp10( fps, &exponent );
407 while( 1 )
409 fps_den = i * timecode->media_timebase;
410 fps_num = round( fps_den * fps_sig ) * exponent;
411 if( fps_num > UINT32_MAX )
412 return ERROR_MSG( "framerate correction failed.\n"
413 "Specify an appropriate timebase manually or remake timecode file.\n" );
414 if( fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
415 break;
416 ++i;
418 if( timecode->auto_media_timescale )
420 timecode->media_timescale = timecode->media_timescale
421 ? get_lcm( timecode->media_timescale, fps_num )
422 : fps_num;
423 if( timecode->media_timescale > UINT32_MAX )
424 timecode->auto_media_timescale = 0;
426 return (double)fps_num / fps_den;
429 static int try_matroska_timescale( double *fps_array, timecode_t *timecode, uint32_t num_loops )
431 timecode->media_timebase = 0;
432 timecode->media_timescale = MATROSKA_TIMESCALE;
433 for( uint32_t i = 0; i < num_loops; i++ )
435 uint64_t fps_den;
436 double exponent;
437 double fps_sig = sigexp10( fps_array[i], &exponent );
438 fps_den = round( MATROSKA_TIMESCALE / fps_sig ) / exponent;
439 timecode->media_timebase = fps_den && timecode->media_timebase
440 ? get_gcd( timecode->media_timebase, fps_den )
441 : fps_den;
442 if( timecode->media_timebase > UINT32_MAX || !timecode->media_timebase )
443 return ERROR_MSG( "Automatic media timescale generation failed.\n"
444 "Specify media timescale manually.\n" );
446 return 0;
449 static int parse_timecode( timecode_t *timecode, uint32_t sample_count )
451 #define FAILED_PARSE_TIMECODE( ... ) \
452 do \
454 lsmash_free( fps_array ); \
455 lsmash_free( timecode_array ); \
456 return ERROR_MSG( __VA_ARGS__ ); \
458 while( 0 )
459 int tcfv;
460 int ret = fscanf( timecode->file, "# timecode format v%d", &tcfv );
461 if( ret != 1 || (tcfv != 1 && tcfv != 2) )
462 return ERROR_MSG( "Unsupported timecode format\n" );
463 char buff[256];
464 double *timecode_array = NULL;
465 if( tcfv == 1 )
467 double assume_fps = 0;
468 /* Get assumed framerate. */
469 while( fgets( buff, sizeof(buff), timecode->file ) )
471 if( SKIP_LINE_CHARACTER( buff[0] ) )
472 continue;
473 if( sscanf( buff, "assume %lf", &assume_fps ) != 1
474 && sscanf( buff, "Assume %lf", &assume_fps ) != 1 )
475 return ERROR_MSG( "Assumed fps not found\n" );
476 break;
478 if( assume_fps <= 0 )
479 return ERROR_MSG( "Invalid assumed fps\n" );
480 int64_t file_pos = lsmash_ftell( timecode->file );
481 if( file_pos < 0 )
482 return ERROR_MSG( "Failed to tell the postion of input timecode file.\n" );
483 /* Check whether valid or not and count number of sequences. */
484 uint32_t num_sequences = 0;
485 int64_t start, end;
486 int64_t prev_start = -1, prev_end = -1;
487 double sequence_fps;
488 while( fgets( buff, sizeof(buff), timecode->file ) )
490 if( SKIP_LINE_CHARACTER( buff[0] ) )
491 continue;
492 ret = sscanf( buff, "%"SCNd64",%"SCNd64",%lf", &start, &end, &sequence_fps );
493 if( ret != 3 && ret != EOF )
494 return ERROR_MSG( "Invalid input timecode file\n" );
495 if( start > end || start <= prev_start || end <= prev_end || sequence_fps <= 0 )
496 return ERROR_MSG( "Invalid input timecode file\n" );
497 prev_start = start;
498 prev_end = end;
499 if( timecode->auto_media_timescale || timecode->auto_media_timebase )
500 ++num_sequences;
502 if( lsmash_fseek( timecode->file, file_pos, SEEK_SET ) != 0 )
503 return ERROR_MSG( "Failed to seek input timecode file.\n" );
504 /* Preparation storing timecodes. */
505 double *fps_array = lsmash_malloc( ((timecode->auto_media_timescale || timecode->auto_media_timebase) * num_sequences + 1) * sizeof(double) );
506 if( !fps_array )
507 return ERROR_MSG( "Failed to allocate fps array\n" );
508 double corrected_assume_fps = correct_fps( assume_fps, timecode );
509 if( corrected_assume_fps < 0 )
510 FAILED_PARSE_TIMECODE( "Failed to correct the assumed framerate\n" );
511 timecode_array = lsmash_malloc( sample_count * sizeof(double) );
512 if( !timecode_array )
513 FAILED_PARSE_TIMECODE( "Failed to alloc timecodes\n" );
514 timecode_array[0] = 0;
515 num_sequences = 0;
516 uint32_t i = 0;
517 while( i < sample_count - 1 && fgets( buff, sizeof(buff), timecode->file ) )
519 if( SKIP_LINE_CHARACTER( buff[0] ) )
520 continue;
521 ret = sscanf( buff, "%"SCNd64",%"SCNd64",%lf", &start, &end, &sequence_fps );
522 if( ret != 3 )
523 start = end = sample_count - 1;
524 for( ; i < start && i < sample_count - 1; i++ )
525 timecode_array[i + 1] = timecode_array[i] + 1 / corrected_assume_fps;
526 if( i < sample_count - 1 )
528 if( timecode->auto_media_timescale || timecode->auto_media_timebase )
529 fps_array[num_sequences++] = sequence_fps;
530 sequence_fps = correct_fps( sequence_fps, timecode );
531 if( sequence_fps < 0 )
532 FAILED_PARSE_TIMECODE( "Failed to correct the framerate of a sequence.\n" );
533 for( i = start; i <= end && i < sample_count - 1; i++ )
534 timecode_array[i + 1] = timecode_array[i] + 1 / sequence_fps;
537 for( ; i < sample_count - 1; i++ )
538 timecode_array[i + 1] = timecode_array[i] + 1 / corrected_assume_fps;
539 if( timecode->auto_media_timescale || timecode->auto_media_timebase )
540 fps_array[num_sequences] = assume_fps;
541 /* Assume matroska timebase if automatic timescale generation isn't done yet. */
542 if( timecode->auto_media_timebase && !timecode->auto_media_timescale )
544 double exponent;
545 double assume_fps_sig, sequence_fps_sig;
546 if( try_matroska_timescale( fps_array, timecode, num_sequences + 1 ) < 0 )
547 FAILED_PARSE_TIMECODE( "Failed to try matroska timescale.\n" );
548 if( lsmash_fseek( timecode->file, file_pos, SEEK_SET ) != 0 )
549 FAILED_PARSE_TIMECODE( "Failed to seek input timecode file.\n" );
550 assume_fps_sig = sigexp10( assume_fps, &exponent );
551 corrected_assume_fps = MATROSKA_TIMESCALE / ( round( MATROSKA_TIMESCALE / assume_fps_sig ) / exponent );
552 for( i = 0; i < sample_count - 1 && fgets( buff, sizeof(buff), timecode->file ); )
554 if( SKIP_LINE_CHARACTER( buff[0] ) )
555 continue;
556 ret = sscanf( buff, "%"SCNd64",%"SCNd64",%lf", &start, &end, &sequence_fps );
557 if( ret != 3 )
558 start = end = sample_count - 1;
559 sequence_fps_sig = sigexp10( sequence_fps, &exponent );
560 sequence_fps = MATROSKA_TIMESCALE / ( round( MATROSKA_TIMESCALE / sequence_fps_sig ) / exponent );
561 for( ; i < start && i < sample_count - 1; i++ )
562 timecode_array[i + 1] = timecode_array[i] + 1 / corrected_assume_fps;
563 for( i = start; i <= end && i < sample_count - 1; i++ )
564 timecode_array[i + 1] = timecode_array[i] + 1 / sequence_fps;
566 for( ; i < sample_count - 1; i++ )
567 timecode_array[i + 1] = timecode_array[i] + 1 / corrected_assume_fps;
569 lsmash_free( fps_array );
571 else /* tcfv == 2 */
573 uint32_t num_timecodes = 0;
574 int64_t file_pos = lsmash_ftell( timecode->file );
575 if( file_pos < 0 )
576 return ERROR_MSG( "Failed to tell the postion of input timecode file.\n" );
577 while( fgets( buff, sizeof(buff), timecode->file ) )
579 if( SKIP_LINE_CHARACTER( buff[0] ) )
581 if( !num_timecodes )
583 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" );
587 continue;
589 ++num_timecodes;
591 if( !num_timecodes )
592 return ERROR_MSG( "No timecodes!\n" );
593 if( sample_count > num_timecodes )
594 return ERROR_MSG( "Lack number of timecodes.\n" );
595 if( lsmash_fseek( timecode->file, file_pos, SEEK_SET ) != 0 )
596 return ERROR_MSG( "Failed to seek input timecode file.\n" );
597 timecode_array = lsmash_malloc( sample_count * sizeof(uint64_t) );
598 if( !timecode_array )
599 return ERROR_MSG( "Failed to alloc timecodes.\n" );
600 uint32_t i = 0;
601 if( fgets( buff, sizeof(buff), timecode->file ) )
603 ret = sscanf( buff, "%lf", &timecode_array[0] );
604 if( ret != 1 )
606 lsmash_free( timecode_array );
607 return ERROR_MSG( "Invalid timecode number: 0\n" );
609 timecode_array[i++] *= 1e-3; /* Timescale of timecode format v2 is 1000. */
610 while( i < sample_count && fgets( buff, sizeof(buff), timecode->file ) )
612 if( SKIP_LINE_CHARACTER( buff[0] ) )
613 continue;
614 ret = sscanf( buff, "%lf", &timecode_array[i] );
615 timecode_array[i] *= 1e-3; /* Timescale of timecode format v2 is 1000. */
616 if( ret != 1 || timecode_array[i] <= timecode_array[i - 1] )
618 lsmash_free( timecode_array );
619 return ERROR_MSG( "Invalid input timecode.\n" );
621 ++i;
624 if( i < sample_count )
626 lsmash_free( timecode_array );
627 return ERROR_MSG( "Failed to get timecodes.\n" );
629 /* Generate media timescale automatically if needed. */
630 if( sample_count != 1 && timecode->auto_media_timescale )
632 double *fps_array = lsmash_malloc( (sample_count - 1) * sizeof(double) );
633 if( !fps_array )
634 FAILED_PARSE_TIMECODE( "Failed to allocate fps array\n" );
635 for( i = 0; i < sample_count - 1; i++ )
637 fps_array[i] = 1 / (timecode_array[i + 1] - timecode_array[i]);
638 if( timecode->auto_media_timescale )
640 int j = 1;
641 uint64_t fps_num, fps_den;
642 double exponent;
643 double fps_sig = sigexp10( fps_array[i], &exponent );
644 while( 1 )
646 fps_den = j * timecode->media_timebase;
647 fps_num = round( fps_den * fps_sig ) * exponent;
648 if( fps_num > UINT32_MAX
649 || fabs( ((double)fps_num / fps_den) / exponent - fps_sig ) < DOUBLE_EPSILON )
650 break;
651 ++j;
653 timecode->media_timescale = fps_num && timecode->media_timescale
654 ? get_lcm( timecode->media_timescale, fps_num )
655 : fps_num;
656 if( timecode->media_timescale > UINT32_MAX )
658 timecode->auto_media_timescale = 0;
659 continue; /* Don't break because all framerate is needed for try_matroska_timescale. */
663 if( timecode->auto_media_timebase && !timecode->auto_media_timescale
664 && try_matroska_timescale( fps_array, timecode, sample_count - 1 ) < 0 )
665 FAILED_PARSE_TIMECODE( "Failed to try matroska timescale.\n" );
666 lsmash_free( fps_array );
669 if( timecode->auto_media_timescale || timecode->auto_media_timebase )
671 uint64_t reduce = get_gcd( timecode->media_timebase, timecode->media_timescale );
672 timecode->media_timebase /= reduce;
673 timecode->media_timescale /= reduce;
675 else if( timecode->media_timescale > UINT32_MAX || !timecode->media_timescale )
677 lsmash_free( timecode_array );
678 return ERROR_MSG( "Failed to generate media timescale automatically.\n"
679 "Specify an appropriate media timescale manually.\n" );
681 uint32_t timescale = timecode->media_timescale;
682 uint32_t timebase = timecode->media_timebase;
683 double delay_tc = timecode_array[0];
684 timecode->empty_delay = ((uint64_t)(delay_tc * ((double)timescale / timebase) + 0.5)) * timebase;
685 timecode->ts = lsmash_malloc( sample_count * sizeof(uint64_t) );
686 if( !timecode->ts )
688 lsmash_free( timecode_array );
689 return ERROR_MSG( "Failed to allocate timestamps.\n" );
691 timecode->ts[0] = 0;
692 for( uint32_t i = 1; i < sample_count; i++ )
694 timecode->ts[i] = ((uint64_t)((timecode_array[i] - delay_tc) * ((double)timescale / timebase) + 0.5)) * timebase;
695 if( timecode->ts[i] <= timecode->ts[i - 1] )
697 lsmash_free( timecode_array );
698 lsmash_free( timecode->ts );
699 timecode->ts = NULL;
700 return ERROR_MSG( "Invalid timecode.\n" );
703 lsmash_free( timecode_array );
704 return 0;
705 #undef FAILED_PARSE_TIMECODE
708 #undef DOUBLE_EPSILON
709 #undef MATROSKA_TIMESCALE
710 #undef SKIP_LINE_CHARACTER
712 static int edit_media_timeline( root_t *input, timecode_t *timecode, opt_t *opt )
714 track_t *in_track = &input->file.movie.track[opt->track_number - 1];
715 uint32_t track_ID = in_track->track_ID;
716 lsmash_media_ts_list_t ts_list;
717 if( lsmash_get_media_timestamps( input->root, track_ID, &ts_list ) )
718 return ERROR_MSG( "Failed to get media timestamps.\n" );
719 uint64_t timebase = get_media_timebase( &ts_list );
720 if( !timebase )
721 return ERROR_MSG( "Failed to get media timebase.\n" );
722 lsmash_media_ts_t *timestamp = ts_list.timestamp;
723 uint32_t sample_count = ts_list.sample_count;
724 uint32_t orig_timebase = timebase;
725 uint32_t timescale;
726 double timebase_convert_multiplier;
727 if( opt->media_timescale || opt->media_timebase )
729 uint32_t orig_timescale = in_track->media_param.timescale;
730 timescale = opt->media_timescale ? opt->media_timescale : orig_timescale;
731 timebase = opt->media_timebase ? opt->media_timebase : orig_timebase;
732 if( !opt->media_timescale && opt->media_timebase && (timebase > orig_timebase) )
733 timescale = timescale * ((double)timebase / orig_timebase) + 0.5;
734 timebase_convert_multiplier = ((double)timescale / orig_timescale) * ((double)orig_timebase / timebase);
736 else
738 /* Reduce timescale and timebase. */
739 timescale = in_track->media_param.timescale;
740 uint64_t reduce = get_gcd( timescale, timebase );
741 timescale /= reduce;
742 timebase /= reduce;
743 timebase_convert_multiplier = 1;
745 /* Parse timecode file. */
746 if( timecode->file )
748 timecode->auto_media_timescale = !opt->media_timescale;
749 timecode->auto_media_timebase = !opt->media_timebase;
750 timecode->media_timescale = timecode->auto_media_timescale ? 0 : timescale;
751 timecode->media_timebase = timebase;
752 if( parse_timecode( timecode, sample_count ) )
753 return ERROR_MSG( "Failed to parse timecode file.\n" );
754 timescale = timecode->media_timescale;
755 timebase = timecode->media_timebase;
757 /* Get maximum composition sample delay for DTS generation. */
758 uint32_t sample_delay;
759 if( lsmash_get_max_sample_delay( &ts_list, &sample_delay ) )
760 return ERROR_MSG( "Failed to get maximum composition sample delay.\n" );
761 if( sample_delay ) /* Reorder composition order. */
762 lsmash_sort_timestamps_composition_order( &ts_list );
763 if( !timecode->file )
765 /* Genarate timestamps timescale converted. */
766 timecode->ts = lsmash_malloc( sample_count * sizeof(uint64_t) );
767 if( !timecode->ts )
768 return ERROR_MSG( "Failed to alloc timestamps\n" );
769 for( uint32_t i = 0; i < sample_count; i++ )
771 timecode->ts[i] = (timestamp[i].cts - timestamp[0].cts) / orig_timebase;
772 timecode->ts[i] = ((uint64_t)(timecode->ts[i] * timebase_convert_multiplier + 0.5)) * timebase;
773 if( i && (timecode->ts[i] <= timecode->ts[i - 1]) )
774 return ERROR_MSG( "Invalid timescale conversion.\n" );
777 if( sample_delay )
779 /* If media timescale is specified, disable DTS compression multiplier. */
780 uint32_t dts_compression_multiplier = opt->dts_compression * !opt->media_timescale * sample_delay + 1;
781 uint64_t initial_delta = timecode->ts[1];
782 timescale *= dts_compression_multiplier;
783 if( dts_compression_multiplier > 1 )
784 for( uint32_t i = 0; i < sample_count; i++ )
785 timecode->ts[i] *= dts_compression_multiplier;
786 /* Generate CTS. */
787 uint64_t sample_delay_time = timecode->composition_delay = opt->dts_compression ? 0 : timecode->ts[sample_delay];
788 for( uint32_t i = 0; i < sample_count; i++ )
789 timestamp[i].cts = timecode->ts[i] + sample_delay_time;
790 /* Reorder decode order and generate new DTS from CTS. */
791 lsmash_sort_timestamps_decoding_order( &ts_list );
792 uint64_t *prev_reordered_cts = lsmash_malloc( sample_delay * sizeof(uint64_t) );
793 if( !prev_reordered_cts )
794 return ERROR_MSG( "Failed to allocate the previous reordered CTS array.\n" );
795 for( uint32_t i = 0; i <= sample_delay; i++ )
797 if( !opt->dts_compression )
798 timestamp[i].dts = timecode->ts[i];
799 else
801 timestamp[i].dts = (i * initial_delta) / (!!opt->media_timescale * sample_delay + 1);
802 if( i && (timestamp[i].dts <= timestamp[i - 1].dts) )
804 lsmash_free( prev_reordered_cts );
805 return ERROR_MSG( "Failed to do DTS compression.\n" );
808 prev_reordered_cts[ i % sample_delay ] = timecode->ts[i] + sample_delay_time;
810 for( uint32_t i = sample_delay + 1; i < sample_count; i++ )
812 timestamp[i].dts = prev_reordered_cts[ (i - sample_delay) % sample_delay ];
813 prev_reordered_cts[ i % sample_delay ] = timecode->ts[i] + sample_delay_time;
815 lsmash_free( prev_reordered_cts );
817 else
818 for( uint32_t i = 0; i < sample_count; i++ )
819 timestamp[i].cts = timestamp[i].dts = timecode->ts[i];
820 if( sample_count > 1 )
822 in_track->last_sample_delta = timecode->ts[sample_count - 1] - timecode->ts[sample_count - 2];
823 timecode->duration = timecode->ts[sample_count - 1] + in_track->last_sample_delta;
825 else /* still image */
826 timecode->duration = in_track->last_sample_delta = UINT32_MAX;
827 in_track->media_param.timescale = timescale;
828 if( lsmash_set_media_timestamps( input->root, track_ID, &ts_list ) )
829 return ERROR_MSG( "Failed to set media timestamps.\n" );
830 lsmash_delete_media_timestamps( &ts_list );
831 return 0;
834 static int check_white_brand( lsmash_brand_type brand )
836 static const lsmash_brand_type brand_white_list[] =
838 ISOM_BRAND_TYPE_3G2A,
839 ISOM_BRAND_TYPE_3GG6,
840 ISOM_BRAND_TYPE_3GG9,
841 ISOM_BRAND_TYPE_3GP4,
842 ISOM_BRAND_TYPE_3GP5,
843 ISOM_BRAND_TYPE_3GP6,
844 ISOM_BRAND_TYPE_3GP7,
845 ISOM_BRAND_TYPE_3GP8,
846 ISOM_BRAND_TYPE_3GP9,
847 ISOM_BRAND_TYPE_3GR6,
848 ISOM_BRAND_TYPE_3GR9,
849 ISOM_BRAND_TYPE_M4A ,
850 ISOM_BRAND_TYPE_M4B ,
851 ISOM_BRAND_TYPE_M4V ,
852 ISOM_BRAND_TYPE_AVC1,
853 ISOM_BRAND_TYPE_DBY1,
854 ISOM_BRAND_TYPE_ISO2,
855 ISOM_BRAND_TYPE_ISO3,
856 ISOM_BRAND_TYPE_ISO4,
857 ISOM_BRAND_TYPE_ISO5,
858 ISOM_BRAND_TYPE_ISO6,
859 ISOM_BRAND_TYPE_ISOM,
860 ISOM_BRAND_TYPE_MP41,
861 ISOM_BRAND_TYPE_MP42,
862 ISOM_BRAND_TYPE_QT ,
865 for( int i = 0; brand_white_list[i]; i++ )
866 if( brand == brand_white_list[i] )
867 return 1;
868 return 0;
871 static int moov_to_front_callback( void *param, uint64_t written_movie_size, uint64_t total_movie_size )
873 eprintf( "Finalizing: [%5.2lf%%]\r", ((double)written_movie_size / total_movie_size) * 100.0 );
874 return 0;
877 static void display_version( void )
879 eprintf( "\n"
880 "L-SMASH isom/mov timeline editor rev%s %s\n"
881 "Built on %s %s\n"
882 "Copyright (C) 2011-2017 L-SMASH project\n",
883 LSMASH_REV, LSMASH_GIT_HASH, __DATE__, __TIME__ );
886 static void display_help( void )
888 display_version();
889 eprintf( "\n"
890 "Usage: timelineeditor [options] input output\n"
891 " options:\n"
892 " --help Display help\n"
893 " --version Display version information\n"
894 " --track <integer> Specify track number to edit [1]\n"
895 " --timecode <string> Specify timecode file to edit timeline\n"
896 " --media-timescale <integer> Specify media timescale to convert\n"
897 " --media-timebase <integer> Specify media timebase to convert\n"
898 " --skip <rational> Skip start of media presentation in arbitrary units\n"
899 " --delay <rational> Insert blank clip before actual media presentation in arbitrary units\n"
900 " --dts-compression Eliminate composition delay with DTS hack\n"
901 " Multiply media timescale and timebase automatically\n" );
904 int main( int argc, char *argv[] )
906 if ( argc < 2 )
908 display_help();
909 return -1;
911 else if( !strcasecmp( argv[1], "-h" ) || !strcasecmp( argv[1], "--help" ) )
913 display_help();
914 return 0;
916 else if( !strcasecmp( argv[1], "-v" ) || !strcasecmp( argv[1], "--version" ) )
918 display_version();
919 return 0;
921 else if( argc < 3 )
923 display_help();
924 return -1;
926 root_t output = { 0 };
927 root_t input = { 0 };
928 timecode_t timecode = { 0 };
929 movie_io_t io = { &output, &input, &timecode };
930 opt_t opt =
932 .track_number = 1,
933 .media_timescale = 0,
934 .media_timebase = 0,
935 .skip_duration_num = 0,
936 .skip_duration_den = 1,
937 .empty_delay_num = 0,
938 .empty_delay_den = 1,
939 .dts_compression = 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 char *skip_param = argv[++argn];
977 if( sscanf( skip_param, "%"SCNu32"/%"SCNu32, &opt.skip_duration_num, &opt.skip_duration_den ) != 2 )
979 opt.skip_duration_num = atoi( skip_param );
980 opt.skip_duration_den = 1;
982 if( opt.skip_duration_num == 0 )
983 return TIMELINEEDITOR_ERR( "Invalid skip duration.\n" );
984 ++argn;
986 else if( !strcasecmp( argv[argn], "--delay" ) )
988 char *delay_param = argv[++argn];
989 if( sscanf( delay_param, "%"SCNu32"/%"SCNu32, &opt.empty_delay_num, &opt.empty_delay_den ) != 2 )
991 opt.empty_delay_num = atoi( delay_param );
992 opt.empty_delay_den = 1;
994 if( opt.empty_delay_num == 0 )
995 return TIMELINEEDITOR_ERR( "Invalid delay time.\n" );
996 ++argn;
998 else if( !strcasecmp( argv[argn], "--dts-compression" ) )
1000 opt.dts_compression = 1;
1001 ++argn;
1003 else
1004 return TIMELINEEDITOR_ERR( "Invalid option.\n" );
1006 if( argn > argc - 2 )
1007 return TIMELINEEDITOR_ERR( "Invalid arguments.\n" );
1008 /* Get input movies. */
1009 if( get_movie( &input, argv[argn++] ) )
1010 return TIMELINEEDITOR_ERR( "Failed to get input movie.\n" );
1011 movie_t *in_movie = &input.file.movie;
1012 if( opt.track_number && (opt.track_number > in_movie->num_tracks) )
1013 return TIMELINEEDITOR_ERR( "Invalid track number.\n" );
1014 /* Create output movie. */
1015 file_t *out_file = &output.file;
1016 output.root = lsmash_create_root();
1017 if( !output.root )
1018 return TIMELINEEDITOR_ERR( "failed to create a ROOT for an output file.\n" );
1019 if( lsmash_open_file( argv[argn], 0, &out_file->param ) < 0 )
1020 return TIMELINEEDITOR_ERR( "failed to open an output file.\n" );
1021 file_t *in_file = &input.file;
1022 out_file->param.major_brand = in_file->param.major_brand;
1023 out_file->param.minor_version = in_file->param.minor_version;
1024 out_file->param.brands = in_file->param.brands;
1025 out_file->param.brand_count = in_file->param.brand_count;
1026 out_file->param.max_chunk_duration = 0.5;
1027 out_file->param.max_async_tolerance = 2.0;
1028 out_file->param.max_chunk_size = 4*1024*1024;
1029 if( !check_white_brand( out_file->param.major_brand ) )
1031 /* Replace with whitelisted brand 'mp42'. */
1032 out_file->param.major_brand = ISOM_BRAND_TYPE_MP42;
1033 out_file->param.minor_version = 0;
1034 uint32_t i;
1035 for( i = 0; i < out_file->param.brand_count; i++ )
1036 if( out_file->param.brands[i] == ISOM_BRAND_TYPE_MP42 )
1037 break;
1038 if( i == out_file->param.brand_count )
1040 /* Add 'mp42' into the list of compatible brands. */
1041 out_file->param.brands = lsmash_malloc( (i + 1) * sizeof(lsmash_brand_type) );
1042 if( out_file->param.brands )
1044 memcpy( out_file->param.brands, in_file->param.brands, i * sizeof(lsmash_brand_type) );
1045 out_file->param.brands[i] = ISOM_BRAND_TYPE_MP42;
1049 out_file->fh = lsmash_set_file( output.root, &out_file->param );
1050 if( !out_file->fh )
1051 return TIMELINEEDITOR_ERR( "failed to add an output file into a ROOT.\n" );
1052 if( out_file->param.brands != in_file->param.brands )
1053 lsmash_freep( &out_file->param.brands );
1054 /* Set movie parameters. */
1055 movie_t *out_movie = &out_file->movie;
1056 out_movie->param = in_movie->param; /* Copy movie parameters. */
1057 if( in_movie->num_tracks == 1 )
1058 out_movie->param.timescale = in_movie->track[0].media_param.timescale;
1059 if( lsmash_set_movie_parameters( output.root, &out_movie->param ) )
1060 return TIMELINEEDITOR_ERR( "Failed to set output movie parameters.\n" );
1061 /* Set iTunes metadata. */
1062 for( uint32_t i = 0; i < in_movie->num_itunes_metadata; i++ )
1063 if( lsmash_set_itunes_metadata( output.root, in_movie->itunes_metadata[i] ) )
1065 WARNING_MSG( "failed to set an iTunes metadata.\n" );
1066 continue;
1068 /* Create tracks of the output movie. */
1069 out_movie->track = lsmash_malloc( in_movie->num_tracks * sizeof(track_t) );
1070 if( !out_movie->track )
1071 return TIMELINEEDITOR_ERR( "Failed to alloc output tracks.\n" );
1072 /* Edit timeline. */
1073 if( edit_media_timeline( &input, &timecode, &opt ) )
1074 return TIMELINEEDITOR_ERR( "Failed to edit timeline.\n" );
1075 out_movie->num_tracks = in_movie->num_tracks;
1076 out_movie->current_track_number = 1;
1077 for( uint32_t i = 0; i < in_movie->num_tracks; i++ )
1079 track_t *in_track = &in_movie->track[i];
1080 if( !in_track->active )
1082 -- out_movie->num_tracks;
1083 continue;
1085 track_t *out_track = &out_movie->track[i];
1086 out_track->summary_remap = lsmash_malloc( in_track->num_summaries * sizeof(uint32_t) );
1087 if( !out_track->summary_remap )
1088 return TIMELINEEDITOR_ERR( "failed to create summary mapping for a track.\n" );
1089 memset( out_track->summary_remap, 0, in_track->num_summaries * sizeof(uint32_t) );
1090 out_track->track_ID = lsmash_create_track( output.root, in_track->media_param.handler_type );
1091 if( !out_track->track_ID )
1092 return TIMELINEEDITOR_ERR( "Failed to create a track.\n" );
1093 /* Copy track and media parameters except for track_ID. */
1094 out_track->track_param = in_track->track_param;
1095 out_track->media_param = in_track->media_param;
1096 out_track->track_param.track_ID = out_track->track_ID;
1097 if( lsmash_set_track_parameters( output.root, out_track->track_ID, &out_track->track_param ) )
1098 return TIMELINEEDITOR_ERR( "Failed to set track parameters.\n" );
1099 if( lsmash_set_media_parameters( output.root, out_track->track_ID, &out_track->media_param ) )
1100 return TIMELINEEDITOR_ERR( "Failed to set media parameters.\n" );
1101 uint32_t valid_summary_count = 0;
1102 for( uint32_t k = 0; k < in_track->num_summaries; k++ )
1104 if( !in_track->summaries[k].active )
1106 out_track->summary_remap[k] = 0;
1107 continue;
1109 lsmash_summary_t *summary = in_track->summaries[k].summary;
1110 if( lsmash_add_sample_entry( output.root, out_track->track_ID, summary ) == 0 )
1112 WARNING_MSG( "failed to append a summary.\n" );
1113 lsmash_cleanup_summary( summary );
1114 in_track->summaries[k].summary = NULL;
1115 in_track->summaries[k].active = 0;
1116 out_track->summary_remap[k] = 0;
1117 continue;
1119 out_track->summary_remap[k] = ++valid_summary_count;
1121 if( valid_summary_count == 0 )
1122 return TIMELINEEDITOR_ERR( "failed to append all summaries.\n" );
1123 out_track->last_sample_delta = in_track->last_sample_delta;
1124 out_track->current_sample_number = 1;
1125 out_track->reach_end_of_media_timeline = 0;
1127 /* Start muxing. */
1128 double largest_dts = 0;
1129 uint32_t num_consecutive_sample_skip = 0;
1130 uint32_t num_active_input_tracks = out_movie->num_tracks;
1131 uint64_t total_media_size = 0;
1132 uint32_t progress_pos = 0;
1133 while( 1 )
1135 track_t *in_track = &in_movie->track[ in_movie->current_track_number - 1 ];
1136 /* Try append a sample in an input track where we didn't reach the end of media timeline. */
1137 if( !in_track->reach_end_of_media_timeline )
1139 track_t *out_track = &out_movie->track[ out_movie->current_track_number - 1 ];
1140 uint32_t in_track_ID = in_track->track_ID;
1141 uint32_t out_track_ID = out_track->track_ID;
1142 uint32_t input_media_timescale = in_track->media_param.timescale;
1143 /* Get a DTS from a track in an input movie. */
1144 uint64_t dts;
1145 if( lsmash_get_dts_from_media_timeline( input.root, in_track_ID, in_track->current_sample_number, &dts ) )
1147 if( lsmash_check_sample_existence_in_media_timeline( input.root, in_track_ID, in_track->current_sample_number ) )
1148 return TIMELINEEDITOR_ERR( "Failed to get the DTS.\n" );
1149 else
1151 in_track->reach_end_of_media_timeline = 1;
1152 if( --num_active_input_tracks == 0 )
1153 break; /* end of muxing */
1156 /* Get and append a sample if it's good time. */
1157 else if( ((double)dts / input_media_timescale) <= largest_dts
1158 || num_consecutive_sample_skip == num_active_input_tracks )
1160 /* Get an actual sample data from a track in an input movie. */
1161 lsmash_sample_t *sample = lsmash_get_sample_from_media_timeline( input.root, in_track_ID, in_track->current_sample_number );
1162 if( !sample )
1163 return TIMELINEEDITOR_ERR( "Failed to get sample.\n" );
1164 sample->index = sample->index > in_track->num_summaries ? in_track->num_summaries
1165 : sample->index == 0 ? 1
1166 : sample->index;
1167 sample->index = out_track->summary_remap[ sample->index - 1 ];
1168 if( sample->index )
1170 /* Append sample into output movie. */
1171 uint64_t sample_size = sample->length; /* sample will be deleted internally after appending. */
1172 if( lsmash_append_sample( output.root, out_track_ID, sample ) )
1174 lsmash_delete_sample( sample );
1175 return TIMELINEEDITOR_ERR( "Failed to append a sample.\n" );
1177 largest_dts = LSMASH_MAX( largest_dts, (double)dts / input_media_timescale );
1178 total_media_size += sample_size;
1179 ++ in_track->current_sample_number;
1180 num_consecutive_sample_skip = 0;
1181 /* Print, per 4 megabytes, total size of imported media. */
1182 if( (total_media_size >> 22) > progress_pos )
1184 progress_pos = total_media_size >> 22;
1185 eprintf( "Importing: %"PRIu64" bytes\r", total_media_size );
1189 else
1190 ++num_consecutive_sample_skip; /* Skip appendig sample. */
1192 /* Move the next track. */
1193 if( ++ in_movie->current_track_number > in_movie->num_tracks )
1194 in_movie->current_track_number = 1; /* Back the first track. */
1195 if( ++ out_movie->current_track_number > out_movie->num_tracks )
1196 out_movie->current_track_number = 1; /* Back the first track in the output movie. */
1198 for( uint32_t i = 0; i < out_movie->num_tracks; i++ )
1199 if( lsmash_flush_pooled_samples( output.root, out_movie->track[i].track_ID, out_movie->track[i].last_sample_delta ) )
1200 return TIMELINEEDITOR_ERR( "Failed to flush samples.\n" );
1201 /* Copy timeline maps. */
1202 for( uint32_t i = 0; i < out_movie->num_tracks; i++ )
1203 if( lsmash_copy_timeline_map( output.root, out_movie->track[i].track_ID, input.root, in_movie->track[i].track_ID ) )
1204 return TIMELINEEDITOR_ERR( "Failed to copy a timeline map.\n" );
1205 /* Edit timeline map. */
1206 if( argc > 3 )
1208 track_t *out_track = &out_movie->track[ opt.track_number - 1 ];
1209 uint32_t track_ID = out_track->track_ID;
1210 uint32_t movie_timescale = lsmash_get_movie_timescale( output.root );
1211 uint32_t media_timescale = lsmash_get_media_timescale( output.root, track_ID );
1212 uint64_t empty_delay = timecode.empty_delay + (uint64_t)((double)((uint64_t)opt.empty_delay_num * media_timescale) / opt.empty_delay_den + 0.5);
1213 uint64_t duration = timecode.duration + empty_delay;
1214 if( lsmash_delete_explicit_timeline_map( output.root, track_ID ) )
1215 return TIMELINEEDITOR_ERR( "Failed to delete explicit timeline maps.\n" );
1216 if( empty_delay )
1218 lsmash_edit_t empty_edit;
1219 empty_edit.duration = ((double)empty_delay / media_timescale) * movie_timescale;
1220 empty_edit.start_time = ISOM_EDIT_MODE_EMPTY;
1221 empty_edit.rate = ISOM_EDIT_MODE_NORMAL;
1222 if( lsmash_create_explicit_timeline_map( output.root, track_ID, empty_edit ) )
1223 return TIMELINEEDITOR_ERR( "Failed to create a empty duration.\n" );
1224 duration = ((double)duration / media_timescale) * movie_timescale;
1225 duration -= empty_edit.duration;
1227 else
1228 duration = ((double)duration / media_timescale) * movie_timescale;
1229 lsmash_edit_t edit;
1230 edit.duration = duration;
1231 edit.start_time = timecode.composition_delay + (uint64_t)((double)((uint64_t)opt.skip_duration_num * media_timescale) / opt.skip_duration_den + 0.5);
1232 edit.rate = ISOM_EDIT_MODE_NORMAL;
1233 if( lsmash_create_explicit_timeline_map( output.root, track_ID, edit ) )
1234 return TIMELINEEDITOR_ERR( "Failed to create a explicit timeline map.\n" );
1236 /* Finish muxing. */
1237 lsmash_adhoc_remux_t moov_to_front;
1238 moov_to_front.func = moov_to_front_callback;
1239 moov_to_front.buffer_size = 4*1024*1024;
1240 moov_to_front.param = NULL;
1241 eprintf( " \r" );
1242 if( lsmash_finish_movie( output.root, &moov_to_front )
1243 || lsmash_write_lsmash_indicator( output.root ) )
1244 return TIMELINEEDITOR_ERR( "Failed to finish output movie.\n" );
1245 cleanup_root( io.input );
1246 cleanup_root( io.output );
1247 cleanup_timecode( io.timecode );
1248 eprintf( "Timeline editing completed! \n" );
1249 return 0;