timelineeditor: Dynamic-arrayfy prev_reordered_cts.
[L-SMASH.git] / timelineeditor.c
blobcdabc072a233b01445c29cf9d4c857c4cfa9f8ce
1 /*****************************************************************************
2 * timelineeditor.c:
3 *****************************************************************************
4 * Copyright (C) 2011 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 "lsmash.h"
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <inttypes.h>
30 #define LSMASH_MAX( a, b ) ((a) > (b) ? (a) : (b))
32 #define eprintf( ... ) fprintf( stderr, __VA_ARGS__ )
34 typedef struct
36 uint32_t track_ID;
37 uint32_t last_sample_delta;
38 uint32_t current_sample_number;
39 int reach_end_of_media_timeline;
40 lsmash_track_parameters_t track_param;
41 lsmash_media_parameters_t media_param;
42 } track_t;
44 typedef struct
46 lsmash_root_t *root;
47 lsmash_itunes_metadata_list_t *itunes_meta_list;
48 track_t *track;
49 lsmash_movie_parameters_t movie_param;
50 } movie_t;
52 typedef struct
54 FILE *file;
55 uint64_t *ts;
56 uint32_t sample_count;
57 uint64_t duration;
58 uint64_t composition_delay;
59 uint64_t empty_delay;
60 } timecode_t;
62 typedef struct
64 movie_t *output;
65 movie_t *input;
66 timecode_t *timecode;
67 } movie_io_t;
69 typedef struct
71 uint32_t track_number;
72 uint32_t media_timescale;
73 uint32_t media_timebase;
74 uint32_t skip_duration;
75 uint32_t empty_delay;
76 int dts_compression;
77 } opt_t;
79 static void cleanup_movie( movie_t *movie )
81 if( !movie )
82 return;
83 if( movie->itunes_meta_list )
84 lsmash_destroy_itunes_metadata( movie->itunes_meta_list );
85 if( movie->track )
86 free( movie->track );
87 lsmash_destroy_root( movie->root );
88 movie->root = NULL;
89 movie->itunes_meta_list = NULL;
90 movie->track = NULL;
93 static void cleanup_timecode( timecode_t *timecode )
95 if( !timecode )
96 return;
97 if( timecode->file )
98 fclose( timecode->file );
99 if( timecode->ts )
100 free( timecode->ts );
101 timecode->file = NULL;
102 timecode->ts = NULL;
105 static int timelineeditor_error( movie_io_t *io, char *message )
107 cleanup_movie( io->input );
108 cleanup_movie( io->output );
109 cleanup_timecode( io->timecode );
110 eprintf( message );
111 return -1;
114 static int error_message( char *message )
116 eprintf( message );
117 return -1;
120 #define TIMELINEEDITOR_ERR( message ) timelineeditor_error( &io, message )
121 #define ERROR_MSG( message ) error_message( message )
123 static int get_movie( movie_t *input, char *input_name, uint32_t *num_tracks )
125 if( !strcmp( input_name, "-" ) )
126 return ERROR_MSG( "Standard input not supported.\n" );
127 input->root = lsmash_open_movie( input_name, LSMASH_FILE_MODE_READ );
128 if( !input->root )
129 return ERROR_MSG( "Failed to open input file.\n" );
130 lsmash_movie_parameters_t *movie_param = &input->movie_param;
131 lsmash_initialize_movie_parameters( movie_param );
132 lsmash_get_movie_parameters( input->root, movie_param );
133 *num_tracks = movie_param->number_of_tracks;
134 /* Create tracks. */
135 track_t *track = input->track = malloc( *num_tracks * sizeof(track_t) );
136 if( !track )
137 return ERROR_MSG( "Failed to alloc input tracks.\n" );
138 memset( track, 0, *num_tracks * sizeof(track_t) );
139 for( uint32_t i = 0; i < *num_tracks; i++ )
141 track[i].track_ID = lsmash_get_track_ID( input->root, i + 1 );
142 if( !track[i].track_ID )
143 return ERROR_MSG( "Failed to get track_ID.\n" );
145 for( uint32_t i = 0; i < *num_tracks; i++ )
147 input->itunes_meta_list = lsmash_export_itunes_metadata( input->root );
148 if( !input->itunes_meta_list )
149 return ERROR_MSG( "Failed to get iTunes metadata.\n" );
150 lsmash_initialize_track_parameters( &track[i].track_param );
151 if( lsmash_get_track_parameters( input->root, track[i].track_ID, &track[i].track_param ) )
152 return ERROR_MSG( "Failed to get track parameters.\n" );
153 lsmash_initialize_media_parameters( &track[i].media_param );
154 if( lsmash_get_media_parameters( input->root, track[i].track_ID, &track[i].media_param ) )
155 return ERROR_MSG( "Failed to get media parameters.\n" );
156 if( lsmash_construct_timeline( input->root, track[i].track_ID ) )
157 return ERROR_MSG( "Failed to construct timeline.\n" );
158 if( lsmash_get_last_sample_delta_from_media_timeline( input->root, track[i].track_ID, &track[i].last_sample_delta ) )
159 return ERROR_MSG( "Failed to get the last sample delta.\n" );
160 track[i].current_sample_number = 1;
162 lsmash_discard_boxes( input->root );
163 return 0;
166 static uint64_t get_gcd( uint64_t a, uint64_t b )
168 if( !b )
169 return a;
170 while( 1 )
172 uint64_t c = a % b;
173 if( !c )
174 return b;
175 a = b;
176 b = c;
180 static uint64_t get_media_timebase( lsmash_media_ts_list_t *ts_list )
182 uint64_t timebase = ts_list->timestamp[0].cts;
183 for( uint32_t i = 1; i < ts_list->sample_count; i++ )
184 timebase = get_gcd( timebase, ts_list->timestamp[i].cts );
185 for( uint32_t i = 0; i < ts_list->sample_count; i++ )
186 timebase = get_gcd( timebase, ts_list->timestamp[i].dts );
187 return timebase;
190 static int parse_timecode( movie_io_t *io, lsmash_media_ts_list_t *ts_list, uint32_t timescale, uint32_t timebase )
192 int tcfv;
193 timecode_t *timecode = io->timecode;
194 int ret = fscanf( timecode->file, "# timecode format v%d", &tcfv );
195 if( ret != 1 || tcfv != 2 )
196 return ERROR_MSG( "Unsupported timecode format\n" );
197 char buff[256];
198 uint32_t num_timecodes = 0;
199 uint64_t file_pos = ftell( timecode->file );
200 while( fgets( buff, sizeof(buff), timecode->file ) )
202 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
204 if( !num_timecodes )
205 file_pos = ftell( timecode->file );
206 continue;
208 ++num_timecodes;
210 if( !num_timecodes )
211 return ERROR_MSG( "No timecodes!\n" );
212 if( ts_list->sample_count > num_timecodes )
213 return ERROR_MSG( "Lack number of timecodes!\n" );
214 fseek( timecode->file, file_pos, SEEK_SET );
215 timecode->ts = malloc( ts_list->sample_count * sizeof(uint64_t) );
216 if( !timecode->ts )
217 return ERROR_MSG( "Failed to alloc timestamps.\n" );
218 fgets( buff, sizeof(buff), timecode->file );
219 double tc;
220 ret = sscanf( buff, "%lf", &tc );
221 if( ret != 1 )
222 return ERROR_MSG( "Invalid timecode number: 0\n" );
223 double delay_tc = tc * 1e-3; /* Timecode format v2 is expressed in milliseconds. */
224 timecode->empty_delay = ((uint64_t)(delay_tc * ((double)timescale / timebase) + 0.5)) * timebase;
225 timecode->ts[0] = 0;
226 for( uint32_t i = 1; i < ts_list->sample_count; )
228 fgets( buff, sizeof(buff), timecode->file );
229 if( buff[0] == '#' || buff[0] == '\n' || buff[0] == '\r' )
230 continue;
231 ret = sscanf( buff, "%lf", &tc );
232 if( ret != 1 )
233 return ERROR_MSG( "Invalid timecode\n" );
234 tc *= 1e-3; /* Timecode format v2 is expressed in milliseconds. */
235 timecode->ts[i] = ((uint64_t)((tc - delay_tc) * ((double)timescale / timebase) + 0.5)) * timebase;
236 if( timecode->ts[i] <= timecode->ts[i - 1] )
237 return ERROR_MSG( "Invalid timecode.\n" );
238 ++i;
240 return 0;
243 static uint32_t get_max_sample_delay( lsmash_media_ts_list_t *ts_list )
245 uint32_t sample_delay = 0;
246 uint32_t max_sample_delay = 0;
247 lsmash_media_ts_t *ts = ts_list->timestamp;
248 for( uint32_t i = 1; i < ts_list->sample_count; i++ )
250 if( ts[i].cts < ts[i - 1].cts )
252 ++sample_delay;
253 max_sample_delay = LSMASH_MAX( max_sample_delay, sample_delay );
255 else
256 sample_delay = 0;
258 return max_sample_delay;
261 static int compare_cts( const lsmash_media_ts_t *a, const lsmash_media_ts_t *b )
263 int64_t diff = (int64_t)(a->cts - b->cts);
264 return diff > 0 ? 1 : (diff == 0 ? 0 : -1);
267 static int compare_dts( const lsmash_media_ts_t *a, const lsmash_media_ts_t *b )
269 int64_t diff = (int64_t)(a->dts - b->dts);
270 return diff > 0 ? 1 : (diff == 0 ? 0 : -1);
273 static int edit_media_timeline( movie_io_t *io, opt_t *opt )
275 timecode_t *timecode = io->timecode;
276 if( !timecode->file && !opt->media_timescale && !opt->media_timebase && !opt->dts_compression )
277 return 0;
278 movie_t *input = io->input;
279 track_t *in_track = &input->track[opt->track_number - 1];
280 uint32_t track_ID = in_track->track_ID;
281 lsmash_media_ts_list_t ts_list;
282 if( lsmash_get_media_timestamps( input->root, track_ID, &ts_list ) )
283 return ERROR_MSG( "Failed to get media timestamps.\n" );
284 uint64_t timebase = get_media_timebase( &ts_list );
285 if( !timebase )
286 return ERROR_MSG( "Failed to get media timebase.\n" );
287 lsmash_media_ts_t *timestamp = ts_list.timestamp;
288 uint32_t sample_count = ts_list.sample_count;
289 uint32_t orig_timebase = timebase;
290 uint32_t timescale;
291 double timebase_convert_multiplier;
292 if( opt->media_timescale || opt->media_timebase )
294 uint32_t orig_timescale = in_track->media_param.timescale;
295 timescale = opt->media_timescale ? opt->media_timescale : orig_timescale;
296 timebase = opt->media_timebase ? opt->media_timebase : orig_timebase;
297 if( !opt->media_timescale && opt->media_timebase && (timebase > orig_timebase) )
298 timescale = timescale * ((double)timebase / orig_timebase) + 0.5;
299 timebase_convert_multiplier = ((double)timescale / orig_timescale) * ((double)orig_timebase / timebase);
301 else
303 /* Reduce timescale and timebase. */
304 timescale = in_track->media_param.timescale;
305 uint64_t reduce = get_gcd( timescale, timebase );
306 timescale /= reduce;
307 timebase /= reduce;
308 timebase_convert_multiplier = 1;
310 in_track->media_param.timescale = timescale;
311 /* Parse timecode file. */
312 if( timecode->file && parse_timecode( io, &ts_list, timescale, timebase ) )
313 return ERROR_MSG( "Failed to parse timecode file.\n" );
314 /* Get maximum composition sample delay for DTS generation. */
315 uint32_t sample_delay = get_max_sample_delay( &ts_list );
316 if( sample_delay ) /* Reorder composition order. */
317 qsort( timestamp, sample_count, sizeof(lsmash_media_ts_t), (int(*)( const void *, const void * ))compare_cts );
318 if( !timecode->file )
320 /* Genarate timestamps timescale converted. */
321 timecode->ts = malloc( sample_count * sizeof(uint64_t) );
322 if( !timecode->ts )
323 return ERROR_MSG( "Failed to alloc timestamps\n" );
324 for( uint32_t i = 0; i < sample_count; i++ )
326 timecode->ts[i] = (timestamp[i].cts - timestamp[0].cts) / orig_timebase;
327 timecode->ts[i] = ((uint64_t)(timecode->ts[i] * timebase_convert_multiplier + 0.5)) * timebase;
328 if( i && (timecode->ts[i] <= timecode->ts[i - 1]) )
329 return ERROR_MSG( "Invalid timescale conversion.\n" );
332 if( sample_delay )
334 /* If media timescale is specified, disable DTS compression multiplier. */
335 uint32_t dts_compression_multiplier = opt->dts_compression * !opt->media_timescale * sample_delay + 1;
336 uint64_t initial_delta = timecode->ts[1];
337 in_track->media_param.timescale *= dts_compression_multiplier;
338 if( dts_compression_multiplier > 1 )
339 for( uint32_t i = 0; i < sample_count; i++ )
340 timecode->ts[i] *= dts_compression_multiplier;
341 /* Generate CTS. */
342 uint64_t sample_delay_time = timecode->composition_delay = opt->dts_compression ? 0 : timecode->ts[sample_delay];
343 for( uint32_t i = 0; i < sample_count; i++ )
344 timestamp[i].cts = timecode->ts[i] + sample_delay_time;
345 /* Reorder decode order and generate new DTS from CTS. */
346 qsort( timestamp, sample_count, sizeof(lsmash_media_ts_t), (int(*)( const void *, const void * ))compare_dts );
347 uint64_t prev_reordered_cts[sample_delay];
348 for( uint32_t i = 0; i <= sample_delay; i++ )
350 if( !opt->dts_compression )
351 timestamp[i].dts = timecode->ts[i];
352 else
354 timestamp[i].dts = (i * initial_delta) / (!!opt->media_timescale * sample_delay + 1);
355 if( i && (timestamp[i].dts <= timestamp[i - 1].dts) )
356 return ERROR_MSG( "Failed to do DTS compression.\n" );
358 prev_reordered_cts[ i % sample_delay ] = timecode->ts[i] + sample_delay_time;
360 for( uint32_t i = sample_delay + 1; i < sample_count; i++ )
362 timestamp[i].dts = prev_reordered_cts[ (i - sample_delay) % sample_delay ];
363 prev_reordered_cts[ i % sample_delay ] = timecode->ts[i] + sample_delay_time;
366 else
367 for( uint32_t i = 0; i < sample_count; i++ )
368 timestamp[i].cts = timestamp[i].dts = timecode->ts[i];
369 if( sample_count > 1 )
371 in_track->last_sample_delta = timecode->ts[sample_count - 1] - timecode->ts[sample_count - 2];
372 timecode->duration = timecode->ts[sample_count - 1] + in_track->last_sample_delta;
374 else /* still image */
375 timecode->duration = in_track->last_sample_delta = UINT32_MAX;
376 return lsmash_set_media_timestamps( input->root, track_ID, &ts_list );
379 static int moov_to_front_callback( void *param, uint64_t written_movie_size, uint64_t total_movie_size )
381 eprintf( "Finalizing: [%5.2lf%%]\r", ((double)written_movie_size / total_movie_size) * 100.0 );
382 return 0;
385 int main( int argc, char *argv[] )
387 if( argc < 3 || !strcasecmp( argv[1], "-h" ) || !strcasecmp( argv[1], "--help" ) )
389 fprintf( stderr, "Usage: timelineeditor [options] input output\n"
390 " options:\n"
391 " --track <integer> Specify track number to edit [1]\n"
392 " --timecode <string> Specify timecode file to edit timeline\n"
393 " --media-timescale <integer> Specify media timescale to convert\n"
394 " --media-timebase <integer> Specify media timebase to convert\n"
395 " --skip <integer> Skip start of media presentation in milliseconds\n"
396 " --delay <integer> Insert blank clip before actual media presentation in milliseconds\n"
397 " --dts-compression Eliminate composition delay with DTS hack\n"
398 " Multiply media timescale and timebase automatically\n" );
399 return -1;
401 movie_t output = { 0 };
402 movie_t input = { 0 };
403 timecode_t timecode = { 0 };
404 movie_io_t io = { &output, &input, &timecode };
405 opt_t opt = { 1, 0, 0, 0, 0, 0 };
406 /* Parse options. */
407 int argn = 1;
408 while( argn < argc - 2 )
410 if( !strcasecmp( argv[argn], "--track" ) )
412 opt.track_number = atoi( argv[++argn] );
413 if( !opt.track_number )
414 return TIMELINEEDITOR_ERR( "Invalid track number.\n" );
415 ++argn;
417 else if( !strcasecmp( argv[argn], "--timecode" ) )
419 timecode.file = fopen( argv[++argn], "rb" );
420 if( !timecode.file )
421 return TIMELINEEDITOR_ERR( "Failed to open timecode file.\n" );
422 ++argn;
424 else if( !strcasecmp( argv[argn], "--media-timescale" ) )
426 opt.media_timescale = atoi( argv[++argn] );
427 if( !opt.media_timescale )
428 return TIMELINEEDITOR_ERR( "Invalid media timescale.\n" );
429 ++argn;
431 else if( !strcasecmp( argv[argn], "--media-timebase" ) )
433 opt.media_timebase = atoi( argv[++argn] );
434 if( !opt.media_timebase )
435 return TIMELINEEDITOR_ERR( "Invalid media timebase.\n" );
436 ++argn;
438 else if( !strcasecmp( argv[argn], "--skip" ) )
440 opt.skip_duration = atoi( argv[++argn] );
441 if( !opt.skip_duration )
442 return TIMELINEEDITOR_ERR( "Invalid skip duration.\n" );
443 ++argn;
445 else if( !strcasecmp( argv[argn], "--delay" ) )
447 opt.empty_delay = atoi( argv[++argn] );
448 if( !opt.empty_delay )
449 return TIMELINEEDITOR_ERR( "Invalid delay time.\n" );
450 ++argn;
452 else if( !strcasecmp( argv[argn], "--dts-compression" ) )
454 opt.dts_compression = 1;
455 ++argn;
457 else
458 return TIMELINEEDITOR_ERR( "Invalid option.\n" );
460 if( argn > argc - 2 )
461 return TIMELINEEDITOR_ERR( "Invalid arguments.\n" );
462 uint32_t num_tracks;
463 /* Get input movies. */
464 if( get_movie( &input, argv[argn++], &num_tracks ) )
465 return TIMELINEEDITOR_ERR( "Failed to get input movie.\n" );
466 if( opt.track_number && (opt.track_number > num_tracks) )
467 return TIMELINEEDITOR_ERR( "Invalid track number.\n" );
468 /* Create output movie. */
469 output.root = lsmash_open_movie( argv[argn], LSMASH_FILE_MODE_WRITE );
470 if( !output.root )
471 return TIMELINEEDITOR_ERR( "Failed to open output movie.\n" );
472 output.movie_param = input.movie_param;
473 output.movie_param.max_chunk_duration = 0.5;
474 output.movie_param.max_async_tolerance = 2.0;
475 output.movie_param.max_chunk_size = 4*1024*1024;
476 output.movie_param.max_read_size = 4*1024*1024;
477 if( lsmash_set_movie_parameters( output.root, &output.movie_param ) )
478 return TIMELINEEDITOR_ERR( "Failed to set output movie parameters.\n" );
479 /* Set iTunes metadata. */
480 if( lsmash_import_itunes_metadata( output.root, input.itunes_meta_list ) )
481 return TIMELINEEDITOR_ERR( "Failed to set iTunes metadata.\n" );
482 /* Create tracks of the output movie. */
483 output.track = malloc( num_tracks * sizeof(track_t) );
484 if( !output.track )
485 return TIMELINEEDITOR_ERR( "Failed to alloc output tracks.\n" );
486 /* Edit timeline. */
487 if( edit_media_timeline( &io, &opt ) )
488 return TIMELINEEDITOR_ERR( "Failed to edit timeline.\n" );
489 for( uint32_t i = 0; i < num_tracks; i++ )
491 track_t *in_track = &input.track[i];
492 track_t *out_track = &output.track[i];
493 uint32_t handler_type = in_track->media_param.handler_type;
494 out_track->track_ID = lsmash_create_track( output.root, handler_type );
495 if( !out_track->track_ID )
496 return TIMELINEEDITOR_ERR( "Failed to create a track.\n" );
497 /* Copy track and media parameters except for track_ID. */
498 out_track->track_param = in_track->track_param;
499 out_track->media_param = in_track->media_param;
500 out_track->track_param.track_ID = out_track->track_ID;
501 if( lsmash_set_track_parameters( output.root, out_track->track_ID, &out_track->track_param ) )
502 return TIMELINEEDITOR_ERR( "Failed to set track parameters.\n" );
503 if( lsmash_set_media_parameters( output.root, out_track->track_ID, &out_track->media_param ) )
504 return TIMELINEEDITOR_ERR( "Failed to set media parameters.\n" );
505 if( lsmash_copy_decoder_specific_info( output.root, out_track->track_ID, input.root, in_track->track_ID ) )
506 return TIMELINEEDITOR_ERR( "Failed to copy a Decoder Specific Info.\n" );
507 out_track->last_sample_delta = in_track->last_sample_delta;
508 out_track->current_sample_number = 1;
509 out_track->reach_end_of_media_timeline = 0;
511 /* Start muxing. */
512 double largest_dts = 0;
513 uint32_t current_track_number = 1;
514 uint32_t num_consecutive_sample_skip = 0;
515 uint32_t num_active_input_tracks = num_tracks;
516 uint64_t total_media_size = 0;
517 uint8_t sample_count = 0;
518 while( 1 )
520 track_t *in_track = &input.track[current_track_number - 1];
521 /* Try append a sample in an input track where we didn't reach the end of media timeline. */
522 if( !in_track->reach_end_of_media_timeline )
524 track_t *out_track = &output.track[current_track_number - 1];
525 uint32_t in_track_ID = in_track->track_ID;
526 uint32_t out_track_ID = out_track->track_ID;
527 uint32_t input_media_timescale = in_track->media_param.timescale;
528 /* Get a DTS from a track in an input movie. */
529 uint64_t dts;
530 if( lsmash_get_dts_from_media_timeline( input.root, in_track_ID, in_track->current_sample_number, &dts ) )
532 if( lsmash_check_sample_existence_in_media_timeline( input.root, in_track_ID, in_track->current_sample_number ) )
533 return TIMELINEEDITOR_ERR( "Failed to get the DTS.\n" );
534 else
536 in_track->reach_end_of_media_timeline = 1;
537 if( --num_active_input_tracks == 0 )
538 break; /* end of muxing */
541 /* Get and append a sample if it's good time. */
542 else if( ((double)dts / input_media_timescale) <= largest_dts
543 || num_consecutive_sample_skip == num_active_input_tracks )
545 /* Get an actual sample data from a track in an input movie. */
546 lsmash_sample_t *sample = lsmash_get_sample_from_media_timeline( input.root, in_track_ID, in_track->current_sample_number );
547 if( !sample )
548 return TIMELINEEDITOR_ERR( "Failed to get sample.\n" );
549 /* Append sample into output movie. */
550 uint64_t sample_size = sample->length; /* sample will be deleted internally after appending. */
551 if( lsmash_append_sample( output.root, out_track_ID, sample ) )
553 lsmash_delete_sample( sample );
554 return TIMELINEEDITOR_ERR( "Failed to append a sample.\n" );
556 largest_dts = LSMASH_MAX( largest_dts, (double)dts / input_media_timescale );
557 total_media_size += sample_size;
558 ++ in_track->current_sample_number;
559 num_consecutive_sample_skip = 0;
560 /* Print, per 256 samples, total size of imported media. */
561 if( ++sample_count == 0 )
562 eprintf( "Importing: %"PRIu64" bytes\r", total_media_size );
564 else
565 ++num_consecutive_sample_skip; /* Skip appendig sample. */
567 /* Move the next track. */
568 ++current_track_number;
569 if( current_track_number > num_tracks )
570 current_track_number = 1; /* Back the first track. */
572 for( uint32_t i = 0; i < num_tracks; i++ )
573 if( lsmash_flush_pooled_samples( output.root, output.track[i].track_ID, output.track[i].last_sample_delta ) )
574 return TIMELINEEDITOR_ERR( "Failed to flush samples.\n" );
575 /* Copy timeline maps. */
576 for( uint32_t i = 0; i < num_tracks; i++ )
577 if( lsmash_copy_timeline_map( output.root, output.track[i].track_ID, input.root, input.track[i].track_ID ) )
578 return TIMELINEEDITOR_ERR( "Failed to copy a timeline map.\n" );
579 /* Edit timeline map. */
580 if( argc > 3 )
582 track_t *out_track = &output.track[opt.track_number - 1];
583 uint32_t track_ID = out_track->track_ID;
584 uint32_t movie_timescale = lsmash_get_movie_timescale( output.root );
585 uint32_t media_timescale = lsmash_get_media_timescale( output.root, track_ID );
586 uint32_t empty_delay = timecode.empty_delay + (uint64_t)(opt.empty_delay * (1e-3 * media_timescale) + 0.5);
587 uint32_t duration = timecode.duration + empty_delay;
588 if( lsmash_delete_explicit_timeline_map( output.root, track_ID ) )
589 return TIMELINEEDITOR_ERR( "Failed to delete explicit timeline maps.\n" );
590 if( timecode.empty_delay )
592 uint32_t empty_duration = ((double)timecode.empty_delay / media_timescale) * movie_timescale;
593 if( lsmash_create_explicit_timeline_map( output.root, track_ID, empty_duration, ISOM_EDIT_MODE_EMPTY, ISOM_EDIT_MODE_NORMAL ) )
594 return TIMELINEEDITOR_ERR( "Failed to create a empty duration.\n" );
595 duration = ((double)duration / media_timescale) * movie_timescale;
596 duration -= empty_duration;
598 else
599 duration = ((double)duration / media_timescale) * movie_timescale;
600 uint64_t start_time = timecode.composition_delay + (uint64_t)(opt.skip_duration * (1e-3 * media_timescale) + 0.5);
601 if( lsmash_create_explicit_timeline_map( output.root, track_ID, duration, start_time, ISOM_EDIT_MODE_NORMAL ) )
602 return TIMELINEEDITOR_ERR( "Failed to create a explicit timeline map.\n" );
604 /* Finish muxing. */
605 lsmash_adhoc_remux_t moov_to_front;
606 moov_to_front.func = moov_to_front_callback;
607 moov_to_front.buffer_size = 4*1024*1024;
608 moov_to_front.param = NULL;
609 eprintf( " \r" );
610 if( lsmash_finish_movie( output.root, &moov_to_front ) )
611 return TIMELINEEDITOR_ERR( "Failed to finish output movie.\n" );
612 cleanup_movie( io.input );
613 cleanup_movie( io.output );
614 eprintf( "Timeline editing completed! \n" );
615 return 0;