1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2010-2017 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
7 * Takashi Hirata <silverfilain@gmail.com>
9 * Permission to use, copy, modify, and/or distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *****************************************************************************/
22 /* This file is available under an ISC license. */
32 #include "importer/importer.h"
34 #define MAX_NUM_OF_BRANDS 50
35 #define MAX_NUM_OF_INPUTS 10
36 #define MAX_NUM_OF_TRACKS 1
53 uint32_t beats_per_minute
;
67 int compact_size_table
;
69 uint32_t movie_timescale
;
70 uint32_t num_of_brands
;
71 uint32_t brands
[MAX_NUM_OF_BRANDS
];
73 uint32_t minor_version
;
74 uint32_t num_of_inputs
;
78 char *copyright_notice
;
79 uint16_t copyright_language
;
80 itunes_metadata_t itunes_metadata
;
81 uint16_t default_language
;
92 uint32_t encoder_delay
;
93 int16_t alternate_group
;
94 uint16_t ISO_language
;
95 uint16_t copyright_language
;
96 char *copyright_notice
;
100 } input_track_option_t
;
104 lsmash_summary_t
*summary
;
105 input_track_option_t opt
;
112 char *whole_track_option
;
113 int num_of_track_delimiters
;
121 importer_t
*importer
;
122 input_track_t track
[MAX_NUM_OF_TRACKS
];
123 uint32_t num_of_tracks
;
124 uint32_t num_of_active_tracks
;
125 uint32_t current_track_number
;
130 lsmash_summary_t
*summary
;
131 lsmash_sample_t
*sample
;
136 uint32_t sample_entry
;
137 uint32_t current_sample_number
;
139 uint32_t priming_samples
;
142 int64_t start_offset
;
149 output_track_t
*track
;
150 uint32_t num_of_tracks
;
151 uint32_t current_track_number
;
158 lsmash_file_parameters_t param
;
159 output_movie_t movie
;
172 input_t input
[MAX_NUM_OF_INPUTS
];
173 uint32_t num_of_inputs
;
176 static void cleanup_muxer( muxer_t
*muxer
)
180 output_t
*output
= &muxer
->output
;
181 lsmash_close_file( &output
->file
.param
);
182 lsmash_destroy_root( output
->root
);
183 if( output
->file
.movie
.track
)
185 for( uint32_t i
= 0; i
< output
->file
.movie
.num_of_tracks
; i
++ )
187 output_track_t
*out_track
= &output
->file
.movie
.track
[i
];
188 lsmash_delete_sample( out_track
->sample
);
190 lsmash_free( output
->file
.movie
.track
);
192 for( uint32_t i
= 0; i
< muxer
->num_of_inputs
; i
++ )
194 input_t
*input
= &muxer
->input
[i
];
195 lsmash_importer_close( input
->importer
);
196 for( uint32_t j
= 0; j
< input
->num_of_tracks
; j
++ )
197 lsmash_cleanup_summary( input
->track
[j
].summary
);
198 lsmash_destroy_root( input
->root
);
202 #define eprintf( ... ) fprintf( stderr, __VA_ARGS__ )
203 #define REFRESH_CONSOLE eprintf( " \r" )
205 static int muxer_error( muxer_t
*muxer
, const char *message
, ... )
207 cleanup_muxer( muxer
);
209 eprintf( "Error: " );
211 va_start( args
, message
);
212 vfprintf( stderr
, message
, args
);
217 static int error_message( const char *message
, ... )
220 eprintf( "Error: " );
222 va_start( args
, message
);
223 vfprintf( stderr
, message
, args
);
228 static void display_version( void )
231 "L-SMASH isom/mov multiplexer rev%s %s\n"
233 "Copyright (C) 2010-2017 L-SMASH project\n",
234 LSMASH_REV
, LSMASH_GIT_HASH
, __DATE__
, __TIME__
);
237 static void display_help( void )
241 "Usage: muxer [global_options] -i input1 [-i input2 -i input3 ...] -o output\n"
243 " --help Display help\n"
244 " --version Display version information\n"
245 " --optimize-pd Optimize for progressive download\n"
246 " --interleave <integer> Specify time interval for media interleaving in milliseconds\n"
247 " --file-format <string> Specify output file format\n"
248 " Multiple file format can be specified by comma separators\n"
249 " The first is applied as the best used one\n"
250 " --isom-version <integer> Specify maximum compatible ISO Base Media version\n"
251 " --shift-timeline Enable composition to decode timeline shift\n"
252 " --chapter <string> Set chapters from the file.\n"
253 " --chpl-with-bom Add UTF-8 BOM to the chapter strings\n"
254 " in the chapter list. (experimental)\n"
255 " --chapter-track <integer> Set which track the chapter applies to.\n"
256 " This option takes effect only when reference\n"
257 " chapter is available.\n"
258 " If this option is not used, it defaults to 1.\n"
259 " --copyright-notice <arg> Specify copyright notice with or without language (latter string)\n"
260 " <arg> is <string> or <string>/<string>\n"
261 " --language <string> Specify the default language for all the output tracks.\n"
262 " This option is overridden by the track options.\n"
263 " --compact-size-table Compress sample size tables if possible.\n"
264 " --movie-timescale <integer> Specify movie timescale.\n"
265 "Output file formats:\n"
266 " mp4, mov, 3gp, 3g2, m4a, m4v\n"
269 " disable Disable this track\n"
270 " fps=<arg> Specify video framerate\n"
271 " <arg> is <integer> or <integer>/<integer>\n"
272 " language=<string> Specify media language\n"
273 " alternate-group=<integer> Specify alternate group\n"
274 " encoder-delay=<integer> Represent audio encoder delay (priming samples) explicitly\n"
275 " copyright=<arg> Specify copyright notice with or without language (latter string)\n"
276 " <arg> is <string> or <string>/<string>\n"
277 " handler=<string> Set media handler name\n"
278 " sbr Enable backward-compatible SBR explicit signaling mode\n"
279 " par=<integer>:<integer> Specify pixel aspect ratio of the first sequence\n"
280 " And never change ones in the media stream.\n"
281 "How to use track options:\n"
282 " -i input?[track_option1],[track_option2]...\n"
285 " --album-name <string> Album name\n"
286 " --artist <string> Artist\n"
287 " --comment <string> User comment\n"
288 " --release-date <string> Release date (YYYY-MM-DD)\n"
289 " --encoder <string> Person or company that encoded the recording\n"
290 " --genre <string> Genre\n"
291 " --lyrics <string> Lyrics\n"
292 " --title <string> Title or song name\n"
293 " --composer <string> Composer\n"
294 " --album-artist <string> Artist for the whole album (if different than the individual tracks)\n"
295 " --copyright <string> Copyright\n"
296 " --description <string> Description\n"
297 " --grouping <string> Grouping\n"
298 " --tempo <integer> Beats per minute\n" );
301 static int muxer_usage_error( void )
307 #define MUXER_ERR( ... ) muxer_error( &muxer, __VA_ARGS__ )
308 #define ERROR_MSG( ... ) error_message( __VA_ARGS__ )
309 #define MUXER_USAGE_ERR() muxer_usage_error();
311 static int add_brand( option_t
*opt
, uint32_t brand
)
313 if( opt
->num_of_brands
>= MAX_NUM_OF_BRANDS
)
315 /* Avoid duplication. */
316 for( uint32_t i
= 0; i
< opt
->num_of_brands
; i
++ )
317 if( opt
->brands
[i
] == brand
)
319 opt
->brands
[opt
->num_of_brands
++] = brand
;
323 static int setup_isom_version( option_t
*opt
)
325 add_brand( opt
, ISOM_BRAND_TYPE_ISOM
);
326 if( opt
->isom_version
> 6 )
327 return ERROR_MSG( "unknown ISO Base Media version.\n" );
328 #define SET_ISOM_VERSION( version ) \
329 if( opt->isom_version >= version ) \
330 add_brand( opt, ISOM_BRAND_TYPE_ISO##version )
331 SET_ISOM_VERSION( 2 );
332 SET_ISOM_VERSION( 3 );
333 SET_ISOM_VERSION( 4 );
334 SET_ISOM_VERSION( 5 );
335 SET_ISOM_VERSION( 6 );
336 #undef SET_ISOM_VERSION
340 static int decide_brands( option_t
*opt
)
342 if( opt
->num_of_brands
== 0 )
344 /* default file format */
345 opt
->major_brand
= ISOM_BRAND_TYPE_MP42
;
346 opt
->minor_version
= 0x00000000;
347 add_brand( opt
, ISOM_BRAND_TYPE_MP42
);
348 add_brand( opt
, ISOM_BRAND_TYPE_MP41
);
349 add_brand( opt
, ISOM_BRAND_TYPE_ISOM
);
351 eprintf( "MP4 muxing mode\n" );
352 return setup_isom_version( opt
);
354 opt
->major_brand
= opt
->brands
[0]; /* Pick the first brand as major brand. */
355 for( uint32_t i
= 0; i
< opt
->num_of_brands
; i
++ )
357 switch( opt
->brands
[i
] )
359 case ISOM_BRAND_TYPE_3GP6
:
360 /* When being compatible with 3gp6, also compatible with 3g2a. */
361 add_brand( opt
, ISOM_BRAND_TYPE_3G2A
);
364 case ISOM_BRAND_TYPE_3G2A
:
367 case ISOM_BRAND_TYPE_QT
:
370 case ISOM_BRAND_TYPE_M4A
:
371 case ISOM_BRAND_TYPE_M4V
:
372 opt
->itunes_movie
= 1;
374 case ISOM_BRAND_TYPE_MP42
:
375 add_brand( opt
, ISOM_BRAND_TYPE_MP42
);
376 add_brand( opt
, ISOM_BRAND_TYPE_MP41
);
381 if( opt
->brands
[i
] != ISOM_BRAND_TYPE_QT
)
384 switch( opt
->major_brand
)
386 case ISOM_BRAND_TYPE_MP42
:
387 opt
->minor_version
= 0x00000000;
388 eprintf( "MP4 muxing mode\n" );
390 case ISOM_BRAND_TYPE_M4A
:
391 case ISOM_BRAND_TYPE_M4V
:
392 opt
->minor_version
= 0x00000000;
393 eprintf( "iTunes MP4 muxing mode\n" );
395 case ISOM_BRAND_TYPE_3GP6
:
396 opt
->minor_version
= 0x00000000; /* means, 3gp(3gp6) 6.0.0 : "6" is not included in minor_version. */
397 eprintf( "3GPP muxing mode\n" );
399 case ISOM_BRAND_TYPE_3G2A
:
400 opt
->minor_version
= 0x00010000; /* means, 3g2(3g2a) 1.0.0 : a == 1 */
401 eprintf( "3GPP2 muxing mode\n" );
403 case ISOM_BRAND_TYPE_QT
:
404 opt
->minor_version
= 0x00000000; /* We don't know exact version of the spec to use QTFF features. */
405 eprintf( "QuickTime file format muxing mode\n" );
410 /* Set up ISO Base Media version. */
412 setup_isom_version( opt
);
413 if( opt
->num_of_brands
> MAX_NUM_OF_BRANDS
)
414 return ERROR_MSG( "exceed the maximum number of brands we can deal with.\n" );
418 static int parse_global_options( int argc
, char **argv
, muxer_t
*muxer
)
422 else if( !strcasecmp( argv
[1], "-h" ) || !strcasecmp( argv
[1], "--help" ) )
427 else if( !strcasecmp( argv
[1], "-v" ) || !strcasecmp( argv
[1], "--version" ) )
429 muxer
->opt
.version
= 1;
435 option_t
*opt
= &muxer
->opt
;
437 opt
->add_bom_to_chpl
= 0;
438 while( argc
> i
&& *argv
[i
] == '-' )
440 #define CHECK_NEXT_ARG if( argc == ++i ) return -1
441 if( !strcasecmp( argv
[i
], "-i" ) || !strcasecmp( argv
[i
], "--input" ) )
444 if( opt
->num_of_inputs
+ 1 > MAX_NUM_OF_INPUTS
)
445 return ERROR_MSG( "exceed the maximum number of input files.\n" );
446 input_t
*input
= &muxer
->input
[opt
->num_of_inputs
];
447 input_option_t
*input_movie_opt
= &input
->opt
;
450 input_movie_opt
->num_of_track_delimiters
+= (*p
++ == '?');
451 if( input_movie_opt
->num_of_track_delimiters
> MAX_NUM_OF_TRACKS
)
452 return ERROR_MSG( "you specified options to exceed the maximum number of tracks per input files.\n" );
453 input
->file_name
= strtok( argv
[i
], "?" );
454 input_movie_opt
->whole_track_option
= strtok( NULL
, "" );
455 if( input_movie_opt
->num_of_track_delimiters
)
457 input_track_option_t
*track_opt
= &input
->track
[0].opt
;
458 track_opt
->raws
= strtok( input_movie_opt
->whole_track_option
, "?" );
459 #if (MAX_NUM_OF_TRACKS - 1)
460 for( uint32_t j
= 1; j
< input_movie_opt
->num_of_track_delimiters
; j
++ )
462 track_opt
= &input
->track
[j
].opt
;
463 track_opt
->raws
= strtok( NULL
, "?" );
467 ++ opt
->num_of_inputs
;
469 else if( !strcasecmp( argv
[i
], "-o" ) || !strcasecmp( argv
[i
], "--output" ) )
472 muxer
->output
.file
.name
= argv
[i
];
474 else if( !strcasecmp( argv
[i
], "--optimize-pd" ) )
475 opt
->optimize_pd
= 1;
476 else if( !strcasecmp( argv
[i
], "--interleave" ) )
479 if( opt
->interleave
)
480 return ERROR_MSG( "you specified --interleave twice.\n" );
481 opt
->interleave
= atoi( argv
[i
] );
483 else if( !strcasecmp( argv
[i
], "--file-format" ) )
492 { ISOM_BRAND_TYPE_MP42
, "mp4" },
493 { ISOM_BRAND_TYPE_QT
, "mov" },
494 { ISOM_BRAND_TYPE_3GP6
, "3gp" },
495 { ISOM_BRAND_TYPE_3G2A
, "3g2" },
496 { ISOM_BRAND_TYPE_M4A
, "m4a" },
497 { ISOM_BRAND_TYPE_M4V
, "m4v" },
500 char *file_format
= NULL
;
501 while( (file_format
= strtok( file_format
? NULL
: argv
[i
], "," )) != NULL
)
504 for( j
= 0; file_format_list
[j
].file_format
; j
++ )
505 if( !strcmp( file_format
, file_format_list
[j
].file_format
) )
507 int ret
= add_brand( opt
, file_format_list
[j
].brand_4cc
);
509 return ERROR_MSG( "you specified same output file format twice.\n" );
511 return ERROR_MSG( "exceed the maximum number of brands we can deal with.\n" );
514 if( !file_format_list
[j
].file_format
)
515 return MUXER_USAGE_ERR();
518 else if( !strcasecmp( argv
[i
], "--isom-version" ) )
521 if( opt
->isom_version
)
522 return ERROR_MSG( "you specified --isom-version twice.\n" );
523 opt
->isom_version
= atoi( argv
[i
] );
525 else if( !strcasecmp( argv
[i
], "--shift-timeline" ) )
526 opt
->timeline_shift
= 1;
527 else if( !strcasecmp( argv
[i
], "compact-size-table" ) )
528 opt
->compact_size_table
= 1;
529 else if( !strcasecmp( argv
[i
], "--chapter" ) )
532 opt
->chap_file
= argv
[i
];
534 else if( !strcasecmp( argv
[i
], "--chapter-track" ) )
537 opt
->chap_track
= atoi( argv
[i
] );
538 if( !opt
->chap_track
)
539 return ERROR_MSG( "%s is an invalid track number.\n", argv
[i
] );
541 else if( !strcasecmp( argv
[i
], "--chpl-with-bom" ) )
542 opt
->add_bom_to_chpl
= 1;
543 else if( !strcasecmp( argv
[i
], "--copyright-notice" ) )
546 if( opt
->copyright_notice
)
547 return ERROR_MSG( "you specified --copyright-notice twice.\n" );
548 opt
->copyright_notice
= argv
[i
];
549 char *language
= opt
->copyright_notice
;
552 if( *language
== '/' )
559 opt
->copyright_language
= language
? lsmash_pack_iso_language( language
) : ISOM_LANGUAGE_CODE_UNDEFINED
;
561 else if( !strcasecmp( argv
[i
], "--movie-timescale" ) )
564 if( opt
->movie_timescale
)
565 return ERROR_MSG( "you specified --movie-timescale twice.\n" );
566 opt
->movie_timescale
= atoi( argv
[i
] );
568 /* iTunes metadata */
569 #define CHECK_ITUNES_METADATA_ARG_STRING( argument, value ) \
570 else if( !strcasecmp( argv[i], "--"#argument ) ) \
573 if( opt->itunes_metadata.value ) \
574 return ERROR_MSG( "you specified --"#argument" twice.\n" ); \
575 opt->itunes_metadata.value = argv[i]; \
577 CHECK_ITUNES_METADATA_ARG_STRING( album
-name
, album_name
)
578 CHECK_ITUNES_METADATA_ARG_STRING( artist
, artist
)
579 CHECK_ITUNES_METADATA_ARG_STRING( comment
, comment
)
580 CHECK_ITUNES_METADATA_ARG_STRING( release
-date
, release_date
)
581 CHECK_ITUNES_METADATA_ARG_STRING( encoder
, encoder
)
582 CHECK_ITUNES_METADATA_ARG_STRING( genre
, genre
)
583 CHECK_ITUNES_METADATA_ARG_STRING( lyrics
, lyrics
)
584 CHECK_ITUNES_METADATA_ARG_STRING( title
, title
)
585 CHECK_ITUNES_METADATA_ARG_STRING( composer
, composer
)
586 CHECK_ITUNES_METADATA_ARG_STRING( album
-artist
, album_artist
)
587 CHECK_ITUNES_METADATA_ARG_STRING( copyright
, copyright
)
588 CHECK_ITUNES_METADATA_ARG_STRING( description
, description
)
589 CHECK_ITUNES_METADATA_ARG_STRING( grouping
, grouping
)
590 #undef CHECK_ITUNES_METADATA_ARG_STRING
591 else if( !strcasecmp( argv
[i
], "--tempo" ) )
594 if( opt
->itunes_metadata
.beats_per_minute
)
595 return ERROR_MSG( "you specified --tempo twice.\n" );
596 opt
->itunes_metadata
.beats_per_minute
= atoi( argv
[i
] );
598 else if( !strcasecmp( argv
[i
], "--language" ) )
601 opt
->default_language
= lsmash_pack_iso_language( argv
[i
] );
603 #undef CHECK_NEXT_ARG
605 return ERROR_MSG( "you specified invalid option: %s.\n", argv
[i
] );
608 if( !muxer
->output
.file
.name
)
609 return ERROR_MSG( "output file name is not specified.\n" );
610 if( decide_brands( opt
) )
611 return ERROR_MSG( "failed to set up output file format.\n" );
612 if( opt
->timeline_shift
&& !opt
->qtff
&& opt
->isom_version
< 4 )
613 return ERROR_MSG( "timeline shift requires --file-format mov, or --isom-version 4 or later.\n" );
614 muxer
->num_of_inputs
= opt
->num_of_inputs
;
618 static int parse_track_options( input_t
*input
)
620 for( input
->current_track_number
= 1;
621 input
->current_track_number
<= input
->num_of_tracks
;
622 input
->current_track_number
++ )
624 input_track_t
*in_track
= &input
->track
[input
->current_track_number
- 1];
625 input_track_option_t
*track_opt
= &in_track
->opt
;
626 if( track_opt
->raws
== NULL
)
629 if( !strchr( track_opt
->raws
, ':' )
630 || strchr( track_opt
->raws
, ':' ) == track_opt
->raws
)
631 return ERROR_MSG( "track number is not specified in %s\n", track_opt
->raws
);
632 if( strchr( track_opt
->raws
, ':' ) != strrchr( track_opt
->raws
, ':' ) )
633 return ERROR_MSG( "multiple colons inside one track option in %s.\n", track_opt
->raws
);
634 uint32_t track_number
= atoi( strtok( track_opt
->raws
, ":" ) );
635 if( track_number
== 0 || track_number
> MAX_NUM_OF_TRACKS
)
636 return ERROR_MSG( "%s is an invalid track number %"PRIu32
".\n", strtok( track_opt
->raws
, ":" ), track_number
);
637 in_track
= &input
->track
[track_number
- 1];
638 track_opt
= &in_track
->opt
;
640 while( (track_option
= strtok( NULL
, "," )) != NULL
)
642 char *track_option
= NULL
;
643 while( (track_option
= strtok( track_option
? NULL
: track_opt
->raws
, "," )) != NULL
)
646 if( strchr( track_option
, '=' ) != strrchr( track_option
, '=' ) )
647 return ERROR_MSG( "multiple equal signs inside one track option in %s\n", track_option
);
648 if( strstr( track_option
, "disable" ) )
649 track_opt
->disable
= 1;
650 else if( strstr( track_option
, "alternate-group=" ) )
652 char *track_parameter
= strchr( track_option
, '=' ) + 1;
653 track_opt
->alternate_group
= atoi( track_parameter
);
655 else if( strstr( track_option
, "encoder-delay=" ) )
657 char *track_parameter
= strchr( track_option
, '=' ) + 1;
658 track_opt
->encoder_delay
= atoi( track_parameter
);
660 else if( strstr( track_option
, "language=" ) )
662 char *track_parameter
= strchr( track_option
, '=' ) + 1;
663 track_opt
->ISO_language
= lsmash_pack_iso_language( track_parameter
);
665 else if( strstr( track_option
, "fps=" ) )
667 char *track_parameter
= strchr( track_option
, '=' ) + 1;
668 if( sscanf( track_parameter
, "%"SCNu32
"/%"SCNu32
, &track_opt
->fps_num
, &track_opt
->fps_den
) == 1 )
670 track_opt
->fps_num
= atoi( track_parameter
);
671 track_opt
->fps_den
= 1;
673 track_opt
->user_fps
= 1;
675 else if( strstr( track_option
, "copyright=" ) )
677 char *track_parameter
= strchr( track_option
, '=' ) + 1;
678 track_opt
->copyright_notice
= track_parameter
;
679 while( *track_parameter
)
681 if( *track_parameter
== '/' )
683 *track_parameter
++ = '\0';
688 track_opt
->copyright_language
= lsmash_pack_iso_language( track_parameter
);
690 else if( strstr( track_option
, "handler=" ) )
692 char *track_parameter
= strchr( track_option
, '=' ) + 1;
693 track_opt
->handler_name
= track_parameter
;
695 else if( strstr( track_option
, "sbr" ) )
697 else if( strstr( track_option
, "par=" ) )
699 char *track_parameter
= strchr( track_option
, '=' ) + 1;
700 if( sscanf( track_parameter
, "%"SCNu32
":%"SCNu32
, &track_opt
->par_h
, &track_opt
->par_v
) != 2 )
702 track_opt
->par_h
= 0;
703 track_opt
->par_v
= 0;
707 return ERROR_MSG( "unknown track option %s\n", track_option
);
713 static void display_codec_name( lsmash_codec_type_t codec_type
, uint32_t track_number
)
715 #define DISPLAY_CODEC_NAME( codec, codec_name ) \
716 else if( lsmash_check_codec_type_identical( codec_type, codec ) ) \
717 eprintf( "Track %"PRIu32": "#codec_name"\n", track_number )
719 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_AVC1_VIDEO
, H
.264 Advanced Video Coding
);
720 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_HVC1_VIDEO
, H
.265 High Efficiency Video Coding
);
721 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_VC_1_VIDEO
, SMPTE VC
-1 Advanced Profile
);
722 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_MP4A_AUDIO
, MPEG
-4 Audio
);
723 DISPLAY_CODEC_NAME( QT_CODEC_TYPE_MP4A_AUDIO
, MPEG
-4 Audio
);
724 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_AC_3_AUDIO
, AC
-3 );
725 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_EC_3_AUDIO
, Enhanced AC
-3 );
726 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_DTSC_AUDIO
, DTS
);
727 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_DTSE_AUDIO
, DTS LBR
);
728 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_DTSH_AUDIO
, DTS
-HD
);
729 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_DTSL_AUDIO
, DTS
-HD Lossless
);
730 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_DTSX_AUDIO
, DTS
:X
);
731 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_SAWB_AUDIO
, Wideband AMR voice
);
732 DISPLAY_CODEC_NAME( ISOM_CODEC_TYPE_SAMR_AUDIO
, Narrowband AMR voice
);
733 DISPLAY_CODEC_NAME( QT_CODEC_TYPE_LPCM_AUDIO
, Uncompressed Audio
);
734 #undef DISPLAY_CODEC_NAME
737 static int open_input_files( muxer_t
*muxer
)
739 output_movie_t
*out_movie
= &muxer
->output
.file
.movie
;
740 option_t
*opt
= &muxer
->opt
;
741 for( uint32_t current_input_number
= 1; current_input_number
<= muxer
->num_of_inputs
; current_input_number
++ )
743 input_t
*input
= &muxer
->input
[current_input_number
- 1];
744 /* Initialize importer framework. */
745 lsmash_root_t
*root
= lsmash_create_root();
747 return ERROR_MSG( "failed to create a ROOT for input file.\n" );
749 input
->importer
= lsmash_importer_open( root
, input
->file_name
, "auto" );
750 if( !input
->importer
)
751 return ERROR_MSG( "failed to open input file.\n" );
752 input
->num_of_tracks
= lsmash_importer_get_track_count( input
->importer
);
753 if( input
->num_of_tracks
== 0 )
754 return ERROR_MSG( "there is no valid track in input file.\n" );
755 if( opt
->default_language
)
756 for( int i
= 0; i
< input
->num_of_tracks
; i
++ )
757 input
->track
[i
].opt
.ISO_language
= opt
->default_language
;
758 /* Parse track options */
759 if( parse_track_options( input
) )
760 return ERROR_MSG( "failed to parse track options.\n" );
761 /* Activate tracks by CODEC type. */
762 for( input
->current_track_number
= 1;
763 input
->current_track_number
<= input
->num_of_tracks
;
764 input
->current_track_number
++ )
766 input_track_t
*in_track
= &input
->track
[input
->current_track_number
- 1];
767 int err
= lsmash_importer_construct_timeline( input
->importer
, input
->current_track_number
);
768 if( err
< 0 && err
!= LSMASH_ERR_PATCH_WELCOME
)
770 in_track
->active
= 0;
773 in_track
->summary
= lsmash_duplicate_summary( input
->importer
, input
->current_track_number
);
774 if( !in_track
->summary
)
775 return ERROR_MSG( "failed to get input summary.\n" );
776 /* Check codec type. */
777 lsmash_codec_type_t codec_type
= in_track
->summary
->sample_type
;
778 in_track
->active
= 1;
779 if( lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_AVC1_VIDEO
) )
782 add_brand( opt
, ISOM_BRAND_TYPE_AVC1
);
784 else if( lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_HVC1_VIDEO
) )
786 if( !opt
->isom
&& opt
->qtff
)
787 return ERROR_MSG( "the input seems HEVC, at present available only for ISO Base Media file format.\n" );
789 else if( lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_VC_1_VIDEO
) )
791 if( !opt
->isom
&& opt
->qtff
)
792 return ERROR_MSG( "the input seems VC-1, at present available only for ISO Base Media file format.\n" );
794 else if( lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_MP4A_AUDIO
)
795 || lsmash_check_codec_type_identical( codec_type
, QT_CODEC_TYPE_MP4A_AUDIO
) )
797 else if( lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_AC_3_AUDIO
)
798 || lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_EC_3_AUDIO
) )
800 if( !opt
->isom
&& opt
->qtff
)
801 return ERROR_MSG( "the input seems (Enhanced) AC-3, at present available only for ISO Base Media file format.\n" );
802 add_brand( opt
, ISOM_BRAND_TYPE_DBY1
);
804 else if( lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_DTSC_AUDIO
)
805 || lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_DTSE_AUDIO
)
806 || lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_DTSH_AUDIO
)
807 || lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_DTSL_AUDIO
)
808 || lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_DTSX_AUDIO
) )
810 if( !opt
->isom
&& opt
->qtff
)
811 return ERROR_MSG( "the input seems DTS(-HD) Audio, at present available only for ISO Base Media file format.\n" );
813 else if( lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_SAWB_AUDIO
)
814 || lsmash_check_codec_type_identical( codec_type
, ISOM_CODEC_TYPE_SAMR_AUDIO
) )
816 if( !opt
->brand_3gx
)
817 return ERROR_MSG( "the input seems AMR-NB/WB, available for 3GPP(2) file format.\n" );
819 else if( lsmash_check_codec_type_identical( codec_type
, QT_CODEC_TYPE_LPCM_AUDIO
) )
821 if( opt
->isom
&& !opt
->qtff
)
822 return ERROR_MSG( "the input seems Uncompressed Audio, at present available only for QuickTime file format.\n" );
827 lsmash_cleanup_summary( in_track
->summary
);
828 in_track
->summary
= NULL
;
829 in_track
->active
= 0;
831 if( in_track
->active
)
833 ++ input
->num_of_active_tracks
;
834 display_codec_name( codec_type
, out_movie
->num_of_tracks
+ input
->num_of_active_tracks
);
837 out_movie
->num_of_tracks
+= input
->num_of_active_tracks
;
839 if( out_movie
->num_of_tracks
== 0 )
840 return ERROR_MSG( "there is no media that can be stored in output movie.\n" );
844 static int set_itunes_metadata( output_t
*output
, option_t
*opt
)
846 if( !opt
->itunes_movie
)
848 itunes_metadata_t
*metadata
= &opt
->itunes_metadata
;
849 #define SET_ITUNES_METADATA( item, type, value ) \
851 && lsmash_set_itunes_metadata( output->root, (lsmash_itunes_metadata_t){ item, ITUNES_METADATA_TYPE_NONE, { .type = value }, NULL, NULL } ) ) \
853 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_ENCODING_TOOL
, string
, "L-SMASH" );
854 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_ALBUM_NAME
, string
, metadata
->album_name
);
855 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_ARTIST
, string
, metadata
->artist
);
856 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_USER_COMMENT
, string
, metadata
->comment
);
857 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_RELEASE_DATE
, string
, metadata
->release_date
);
858 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_ENCODED_BY
, string
, metadata
->encoder
);
859 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_USER_GENRE
, string
, metadata
->genre
);
860 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_LYRICS
, string
, metadata
->lyrics
);
861 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_TITLE
, string
, metadata
->title
);
862 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_COMPOSER
, string
, metadata
->composer
);
863 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_ALBUM_ARTIST
, string
, metadata
->album_artist
);
864 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_COPYRIGHT
, string
, metadata
->copyright
);
865 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_DESCRIPTION
, string
, metadata
->description
);
866 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_GROUPING
, string
, metadata
->grouping
);
867 SET_ITUNES_METADATA( ITUNES_METADATA_ITEM_BEATS_PER_MINUTE
, integer
, metadata
->beats_per_minute
);
868 #undef SET_ITUNES_METADATA
872 static int prepare_output( muxer_t
*muxer
)
874 option_t
*opt
= &muxer
->opt
;
875 output_t
*output
= &muxer
->output
;
876 output_file_t
*out_file
= &output
->file
;
877 output_movie_t
*out_movie
= &out_file
->movie
;
878 /* Allocate output tracks. */
879 out_movie
->track
= lsmash_malloc( out_movie
->num_of_tracks
* sizeof(output_track_t
) );
880 if( !out_movie
->track
)
881 return ERROR_MSG( "failed to allocate output tracks.\n" );
882 memset( out_movie
->track
, 0, out_movie
->num_of_tracks
* sizeof(output_track_t
) );
883 /* Initialize L-SMASH muxer */
884 output
->root
= lsmash_create_root();
886 return ERROR_MSG( "failed to create a ROOT for output file.\n" );
887 lsmash_file_parameters_t
*file_param
= &out_file
->param
;
888 if( lsmash_open_file( out_file
->name
, 0, file_param
) < 0 )
889 return ERROR_MSG( "failed to open an output file.\n" );
890 file_param
->major_brand
= opt
->major_brand
;
891 file_param
->brands
= opt
->brands
;
892 file_param
->brand_count
= opt
->num_of_brands
;
893 file_param
->minor_version
= opt
->minor_version
;
894 if( opt
->interleave
)
895 file_param
->max_chunk_duration
= opt
->interleave
* 1e-3;
896 out_file
->fh
= lsmash_set_file( output
->root
, file_param
);
898 return ERROR_MSG( "failed to add an output file into a ROOT.\n" );
899 /* Initialize movie */
900 lsmash_movie_parameters_t movie_param
;
901 lsmash_initialize_movie_parameters( &movie_param
);
902 if( opt
->movie_timescale
)
903 movie_param
.timescale
= opt
->movie_timescale
;
904 if( lsmash_set_movie_parameters( output
->root
, &movie_param
) )
905 return ERROR_MSG( "failed to set movie parameters.\n" );
906 if( opt
->copyright_notice
907 && lsmash_set_copyright( output
->root
, 0, opt
->copyright_language
, opt
->copyright_notice
) )
908 return ERROR_MSG( "failed to set a copyright notice for the entire movie.\n" );
909 if( set_itunes_metadata( output
, opt
) )
910 return ERROR_MSG( "failed to set iTunes metadata.\n" );
911 out_movie
->current_track_number
= 1;
912 for( uint32_t current_input_number
= 1; current_input_number
<= muxer
->num_of_inputs
; current_input_number
++ )
914 input_t
*input
= &muxer
->input
[current_input_number
- 1];
915 for( input
->current_track_number
= 1;
916 input
->current_track_number
<= input
->num_of_tracks
;
917 input
->current_track_number
++ )
919 input_track_t
*in_track
= &input
->track
[ input
->current_track_number
- 1 ];
920 if( !in_track
->active
)
922 input_track_option_t
*track_opt
= &in_track
->opt
;
923 output_track_t
*out_track
= &out_movie
->track
[ out_movie
->current_track_number
- 1 ];
924 /* Set up track parameters. */
925 lsmash_track_parameters_t track_param
;
926 lsmash_initialize_track_parameters( &track_param
);
927 track_param
.mode
= ISOM_TRACK_IN_MOVIE
| ISOM_TRACK_IN_PREVIEW
;
928 if( !track_opt
->disable
)
929 track_param
.mode
|= ISOM_TRACK_ENABLED
;
931 track_param
.mode
|= QT_TRACK_IN_POSTER
;
932 track_param
.alternate_group
= track_opt
->alternate_group
;
933 lsmash_media_parameters_t media_param
;
934 lsmash_initialize_media_parameters( &media_param
);
935 media_param
.ISO_language
= track_opt
->ISO_language
;
936 media_param
.compact_sample_size_table
= opt
->compact_size_table
;
937 switch( in_track
->summary
->summary_type
)
939 case LSMASH_SUMMARY_TYPE_VIDEO
:
941 out_track
->track_ID
= lsmash_create_track( output
->root
, ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
);
942 if( !out_track
->track_ID
)
943 return ERROR_MSG( "failed to create a track.\n" );
944 lsmash_video_summary_t
*summary
= (lsmash_video_summary_t
*)in_track
->summary
;
945 uint64_t display_width
= (uint64_t)summary
->width
<< 16;
946 uint64_t display_height
= (uint64_t)summary
->height
<< 16;
947 if( track_opt
->par_h
&& track_opt
-> par_v
)
949 summary
->par_h
= track_opt
->par_h
;
950 summary
->par_v
= track_opt
->par_v
;
952 if( summary
->par_h
&& summary
->par_v
)
954 double sar
= (double)summary
->par_h
/ summary
->par_v
;
956 display_width
*= sar
;
958 display_height
/= sar
;
960 track_param
.display_width
= display_width
<= UINT32_MAX
? display_width
: UINT32_MAX
;
961 track_param
.display_height
= display_height
<= UINT32_MAX
? display_height
: UINT32_MAX
;
962 /* Initialize media */
963 uint32_t timescale
= 25; /* default value */
964 uint32_t timebase
= 1; /* default value */
965 if( track_opt
->user_fps
)
967 timescale
= track_opt
->fps_num
<< (!!summary
->sample_per_field
);
968 timebase
= track_opt
->fps_den
;
970 else if( !summary
->vfr
)
972 if( lsmash_check_codec_type_identical( summary
->sample_type
, ISOM_CODEC_TYPE_AVC1_VIDEO
)
973 || lsmash_check_codec_type_identical( summary
->sample_type
, ISOM_CODEC_TYPE_HVC1_VIDEO
) )
975 uint32_t compare_timebase
= summary
->timebase
;
976 uint32_t compare_timescale
= summary
->timescale
;
983 { 24000, 1001 }, { 30000, 1001 }, { 60000, 1001 }, { 120000, 1001 }, { 72000, 1001 },
984 { 25, 1 }, { 50, 1 }, { 24, 1 }, { 30, 1 }, { 60, 1 }, { 120, 1 }, { 72, 1 }, { 0, 0 }
986 for( int i
= 0; well_known_fps
[i
].timescale
; i
++ )
987 if( well_known_fps
[i
].timescale
== compare_timescale
988 && well_known_fps
[i
].timebase
== compare_timebase
)
990 timescale
= well_known_fps
[i
].timescale
;
991 timebase
= well_known_fps
[i
].timebase
;
994 lsmash_codec_specific_t
*bitrate
= lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE
,
995 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED
);
997 lsmash_add_codec_specific_data( in_track
->summary
, bitrate
);
998 lsmash_destroy_codec_specific_data( bitrate
);
1002 timescale
= summary
->timescale
;
1003 timebase
= summary
->timebase
;
1006 media_param
.timescale
= timescale
;
1007 media_param
.media_handler_name
= track_opt
->handler_name
? track_opt
->handler_name
: "L-SMASH Video Handler";
1008 media_param
.roll_grouping
= 1;
1009 media_param
.rap_grouping
= opt
->isom_version
>= 6;
1010 out_track
->timescale
= timescale
;
1011 out_track
->timebase
= timebase
;
1014 case LSMASH_SUMMARY_TYPE_AUDIO
:
1016 out_track
->track_ID
= lsmash_create_track( output
->root
, ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
);
1017 if( !out_track
->track_ID
)
1018 return ERROR_MSG( "failed to create a track.\n" );
1019 lsmash_audio_summary_t
*summary
= (lsmash_audio_summary_t
*)in_track
->summary
;
1020 if( track_opt
->sbr
)
1022 /* Check if explicit SBR is valid or not. */
1023 if( lsmash_mp4sys_get_object_type_indication( (lsmash_summary_t
*)summary
) != MP4SYS_OBJECT_TYPE_Audio_ISO_14496_3
)
1024 return ERROR_MSG( "--sbr is only valid with MPEG-4 Audio.\n" );
1025 summary
->sbr_mode
= MP4A_AAC_SBR_BACKWARD_COMPATIBLE
;
1026 if( lsmash_setup_AudioSpecificConfig( summary
) )
1027 return ERROR_MSG( "failed to set SBR mode.\n" );
1029 media_param
.timescale
= summary
->frequency
;
1030 media_param
.media_handler_name
= track_opt
->handler_name
? track_opt
->handler_name
: "L-SMASH Audio Handler";
1031 media_param
.roll_grouping
= (opt
->isom_version
>= 2 || (opt
->qtff
&& !in_track
->lpcm
));
1032 out_track
->priming_samples
= track_opt
->encoder_delay
;
1033 out_track
->timescale
= summary
->frequency
;
1034 out_track
->timebase
= 1;
1035 out_track
->lpcm
= in_track
->lpcm
;
1039 return ERROR_MSG( "not supported stream type.\n" );
1041 /* Reset the movie timescale in order to match the media timescale if only one track is there. */
1042 if( muxer
->num_of_inputs
== 1
1043 && current_input_number
== 1
1044 && input
->current_track_number
== 1 )
1046 movie_param
.timescale
= media_param
.timescale
;
1047 if( lsmash_set_movie_parameters( output
->root
, &movie_param
) )
1048 return ERROR_MSG( "failed to set movie parameters.\n" );
1050 /* Set copyright information. */
1051 if( track_opt
->copyright_notice
1052 && lsmash_set_copyright( output
->root
, out_track
->track_ID
, track_opt
->copyright_language
, track_opt
->copyright_notice
) )
1053 return ERROR_MSG( "failed to set a copyright notice.\n" );
1054 /* Set track parameters. */
1055 if( lsmash_set_track_parameters( output
->root
, out_track
->track_ID
, &track_param
) )
1056 return ERROR_MSG( "failed to set track parameters.\n" );
1057 /* Set media parameters. */
1058 if( lsmash_set_media_parameters( output
->root
, out_track
->track_ID
, &media_param
) )
1059 return ERROR_MSG( "failed to set media parameters.\n" );
1060 out_track
->summary
= in_track
->summary
;
1061 out_track
->sample_entry
= lsmash_add_sample_entry( output
->root
, out_track
->track_ID
, out_track
->summary
);
1062 if( !out_track
->sample_entry
)
1063 return ERROR_MSG( "failed to add sample description entry.\n" );
1064 out_track
->active
= 1;
1065 ++ out_movie
->current_track_number
;
1067 input
->current_track_number
= 1;
1069 out_movie
->current_track_number
= 1;
1073 static void set_reference_chapter_track( output_t
*output
, option_t
*opt
)
1075 if( !opt
->chap_file
|| (!opt
->qtff
&& !opt
->itunes_movie
) || (opt
->brand_3gx
== 1) )
1077 lsmash_create_reference_chapter_track( output
->root
, opt
->chap_track
, opt
->chap_file
);
1080 static int do_mux( muxer_t
*muxer
)
1082 #define LSMASH_MAX( a, b ) ((a) > (b) ? (a) : (b))
1083 option_t
*opt
= &muxer
->opt
;
1084 output_t
*output
= &muxer
->output
;
1085 output_movie_t
*out_movie
= &output
->file
.movie
;
1086 set_reference_chapter_track( output
, opt
);
1087 double largest_dts
= 0;
1088 uint32_t current_input_number
= 1;
1089 uint32_t num_consecutive_sample_skip
= 0;
1090 uint32_t num_active_input_tracks
= out_movie
->num_of_tracks
;
1091 uint64_t total_media_size
= 0;
1092 uint32_t progress_pos
= 0;
1095 input_t
*input
= &muxer
->input
[current_input_number
- 1];
1096 output_track_t
*out_track
= &out_movie
->track
[ out_movie
->current_track_number
- 1 ];
1097 if( out_track
->active
)
1099 lsmash_sample_t
*sample
= out_track
->sample
;
1100 /* Get a new sample data if the track doesn't hold any one. */
1103 /* lsmash_importer_get_access_unit() returns 1 if there're any changes in stream's properties. */
1104 int ret
= lsmash_importer_get_access_unit( input
->importer
, input
->current_track_number
, &sample
);
1105 if( ret
== LSMASH_ERR_MEMORY_ALLOC
)
1106 return ERROR_MSG( "failed to alloc memory for buffer.\n" );
1107 else if( ret
<= -1 )
1109 lsmash_delete_sample( sample
);
1110 ERROR_MSG( "failed to get a frame from input file. Maybe corrupted.\n"
1111 "Aborting muxing operation and trying to let output be valid file.\n" );
1114 else if( ret
== 1 ) /* a change of stream's properties */
1116 input_track_t
*in_track
= &input
->track
[input
->current_track_number
- 1];
1117 lsmash_cleanup_summary( in_track
->summary
);
1118 in_track
->summary
= lsmash_duplicate_summary( input
->importer
, input
->current_track_number
);
1119 out_track
->summary
= in_track
->summary
;
1120 out_track
->sample_entry
= lsmash_add_sample_entry( output
->root
, out_track
->track_ID
, out_track
->summary
);
1121 if( !out_track
->sample_entry
)
1123 ERROR_MSG( "failed to add sample description entry.\n" );
1127 else if( ret
== 2 ) /* EOF */
1129 /* No more appendable samples in this track. */
1130 lsmash_delete_sample( sample
);
1132 out_track
->active
= 0;
1133 out_track
->last_delta
= lsmash_importer_get_last_delta( input
->importer
, input
->current_track_number
);
1134 if( out_track
->last_delta
== 0 )
1135 ERROR_MSG( "failed to get the last sample delta.\n" );
1136 out_track
->last_delta
*= out_track
->timebase
;
1137 if( --num_active_input_tracks
== 0 )
1138 break; /* Reached the end of whole tracks. */
1142 sample
->index
= out_track
->sample_entry
;
1143 sample
->dts
*= out_track
->timebase
;
1144 sample
->cts
*= out_track
->timebase
;
1145 if( opt
->timeline_shift
)
1147 if( out_track
->current_sample_number
== 0 )
1148 out_track
->ctd_shift
= sample
->cts
;
1149 sample
->cts
-= out_track
->ctd_shift
;
1151 out_track
->dts
= (double)sample
->dts
/ out_track
->timescale
;
1152 out_track
->sample
= sample
;
1157 /* Append a sample if meeting a condition. */
1158 if( out_track
->dts
<= largest_dts
|| num_consecutive_sample_skip
== num_active_input_tracks
)
1160 uint64_t sample_size
= sample
->length
; /* sample might be deleted internally after appending. */
1161 uint64_t sample_dts
= sample
->dts
; /* same as above */
1162 uint64_t sample_cts
= sample
->cts
; /* same as above */
1163 if( lsmash_append_sample( output
->root
, out_track
->track_ID
, sample
) )
1164 return ERROR_MSG( "failed to append a sample.\n" );
1165 if( out_track
->current_sample_number
== 0 )
1166 out_track
->start_offset
= sample_cts
;
1168 out_track
->last_delta
= sample_dts
- out_track
->prev_dts
; /* for any changes in stream's properties */
1169 out_track
->prev_dts
= sample_dts
;
1170 out_track
->sample
= NULL
;
1171 largest_dts
= LSMASH_MAX( largest_dts
, out_track
->dts
);
1172 total_media_size
+= sample_size
;
1173 ++ out_track
->current_sample_number
;
1174 num_consecutive_sample_skip
= 0;
1175 /* Print, per 4 megabytes, total size of imported media. */
1176 if( (total_media_size
>> 22) > progress_pos
)
1178 progress_pos
= total_media_size
>> 22;
1179 eprintf( "Importing: %"PRIu64
" bytes\r", total_media_size
);
1183 ++num_consecutive_sample_skip
; /* Skip appendig sample. */
1186 if( ++ out_movie
->current_track_number
> out_movie
->num_of_tracks
)
1187 out_movie
->current_track_number
= 1; /* Back the first output track. */
1188 /* Move the next track. */
1189 if( ++ input
->current_track_number
> input
->num_of_tracks
)
1191 /* Move the next input movie. */
1192 input
->current_track_number
= 1;
1193 if( ++ current_input_number
> muxer
->num_of_inputs
)
1194 current_input_number
= 1; /* Back the first input movie. */
1197 for( out_movie
->current_track_number
= 1;
1198 out_movie
->current_track_number
<= out_movie
->num_of_tracks
;
1199 out_movie
->current_track_number
++ )
1202 output_track_t
*out_track
= &out_movie
->track
[ out_movie
->current_track_number
- 1 ];
1203 uint32_t last_sample_delta
= out_track
->lpcm
? 1 : out_track
->last_delta
;
1204 if( lsmash_flush_pooled_samples( output
->root
, out_track
->track_ID
, last_sample_delta
) )
1205 ERROR_MSG( "failed to flush the rest of samples.\n" );
1206 /* Create edit list.
1207 * Don't trust media duration basically. It's just duration of media, not duration of track presentation. */
1208 uint64_t actual_duration
= out_track
->lpcm
1209 ? lsmash_get_media_duration( output
->root
, out_track
->track_ID
)
1210 : out_track
->prev_dts
+ last_sample_delta
;
1211 actual_duration
-= out_track
->priming_samples
;
1213 edit
.duration
= actual_duration
* ((double)lsmash_get_movie_timescale( output
->root
) / out_track
->timescale
);
1214 edit
.start_time
= out_track
->priming_samples
+ out_track
->start_offset
;
1215 edit
.rate
= ISOM_EDIT_MODE_NORMAL
;
1216 if( lsmash_create_explicit_timeline_map( output
->root
, out_track
->track_ID
, edit
) )
1217 ERROR_MSG( "failed to set timeline map.\n" );
1223 static int moov_to_front_callback( void *param
, uint64_t written_movie_size
, uint64_t total_movie_size
)
1225 static uint32_t progress_pos
= 0;
1226 if ( (written_movie_size
>> 24) <= progress_pos
)
1229 eprintf( "Finalizing: [%5.2lf%%]\r", total_movie_size
? ((double)written_movie_size
/ total_movie_size
) * 100.0 : 0 );
1230 /* Print, per 16 megabytes */
1231 progress_pos
= written_movie_size
>> 24;
1235 static int finish_movie( output_t
*output
, option_t
*opt
)
1237 /* Set chapter list. */
1238 if( opt
->chap_file
)
1239 lsmash_set_tyrant_chapter( output
->root
, opt
->chap_file
, opt
->add_bom_to_chpl
);
1242 if( opt
->optimize_pd
)
1244 lsmash_adhoc_remux_t moov_to_front
;
1245 moov_to_front
.func
= moov_to_front_callback
;
1246 moov_to_front
.buffer_size
= 4*1024*1024; /* 4MiB */
1247 moov_to_front
.param
= NULL
;
1248 return lsmash_finish_movie( output
->root
, &moov_to_front
);
1250 if( lsmash_finish_movie( output
->root
, NULL
) )
1252 return lsmash_write_lsmash_indicator( output
->root
);
1255 int main( int argc
, char *argv
[] )
1257 muxer_t muxer
= { { 0 } };
1258 lsmash_get_mainargs( &argc
, &argv
);
1259 if( parse_global_options( argc
, argv
, &muxer
) )
1260 return MUXER_USAGE_ERR();
1261 if( muxer
.opt
.help
)
1264 cleanup_muxer( &muxer
);
1267 else if( muxer
.opt
.version
)
1270 cleanup_muxer( &muxer
);
1273 if( open_input_files( &muxer
) )
1274 return MUXER_ERR( "failed to open input files.\n" );
1275 if( prepare_output( &muxer
) )
1276 return MUXER_ERR( "failed to set up preparation for output.\n" );
1277 if( do_mux( &muxer
) )
1278 return MUXER_ERR( "failed to do muxing.\n" );
1279 if( finish_movie( &muxer
.output
, &muxer
.opt
) )
1280 return MUXER_ERR( "failed to finish movie.\n" );
1282 eprintf( "Muxing completed!\n" );
1283 cleanup_muxer( &muxer
); /* including lsmash_destroy_root() */