static int open_file( char *psz_filename, hnd_t *p_handle, cli_output_opt_t *opt ) { *p_handle = NULL; int b_regular = strcmp( psz_filename, "-" ); b_regular = b_regular && x264_is_regular_file_path( psz_filename ); if( b_regular ) { FILE *fh = x264_fopen( psz_filename, "wb" ); MP4_FAIL_IF_ERR( !fh, "cannot open output file `%s'.\n", psz_filename ); b_regular = x264_is_regular_file( fh ); fclose( fh ); } mp4_hnd_t *p_mp4 = calloc( 1, sizeof(mp4_hnd_t) ); MP4_FAIL_IF_ERR( !p_mp4, "failed to allocate memory for muxer information.\n" ); p_mp4->b_dts_compress = opt->use_dts_compress; p_mp4->b_use_recovery = 0; // we don't really support recovery p_mp4->b_fragments = !b_regular; p_mp4->b_stdout = !strcmp( psz_filename, "-" ); p_mp4->p_root = lsmash_create_root(); MP4_FAIL_IF_ERR_EX( !p_mp4->p_root, "failed to create root.\n" ); MP4_FAIL_IF_ERR_EX( lsmash_open_file( psz_filename, 0, &p_mp4->file_param ) < 0, "failed to open an output file.\n" ); if( p_mp4->b_fragments ) p_mp4->file_param.mode |= LSMASH_FILE_MODE_FRAGMENTED; p_mp4->summary = (lsmash_video_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_VIDEO ); MP4_FAIL_IF_ERR_EX( !p_mp4->summary, "failed to allocate memory for summary information of video.\n" ); p_mp4->summary->sample_type = ISOM_CODEC_TYPE_AVC1_VIDEO; *p_handle = p_mp4; return 0; }
int main( int argc, char *argv[] ) { if ( argc < 2 ) { display_help(); return -1; } else if( !strcasecmp( argv[1], "-h" ) || !strcasecmp( argv[1], "--help" ) ) { display_help(); return 0; } else if( !strcasecmp( argv[1], "-v" ) || !strcasecmp( argv[1], "--version" ) ) { display_version(); return 0; } int dump_box = 1; int chapter = 0; char *filename; lsmash_get_mainargs( &argc, &argv ); if( argc > 2 ) { if( !strcasecmp( argv[1], "--box" ) ) DO_NOTHING; else if( !strcasecmp( argv[1], "--chapter" ) ) chapter = 1; else if( !strcasecmp( argv[1], "--timestamp" ) ) dump_box = 0; else { display_help(); return -1; } filename = argv[2]; } else { filename = argv[1]; } /* Open the input file. */ lsmash_root_t *root = lsmash_create_root(); if( !root ) { fprintf( stderr, "Failed to create a ROOT.\n" ); return -1; } lsmash_file_parameters_t file_param = { 0 }; if( lsmash_open_file( filename, 1, &file_param ) < 0 ) return BOXDUMPER_ERR( "Failed to open an input file.\n" ); if( dump_box ) file_param.mode |= LSMASH_FILE_MODE_DUMP; lsmash_file_t *file = lsmash_set_file( root, &file_param ); if( !file ) return BOXDUMPER_ERR( "Failed to add a file into a ROOT.\n" ); if( lsmash_read_file( file, &file_param ) < 0 ) return BOXDUMPER_ERR( "Failed to read a file\n" ); /* Dump the input file. */ if( chapter ) { if( lsmash_print_chapter_list( root ) ) return BOXDUMPER_ERR( "Failed to extract chapter.\n" ); } else if( dump_box ) { if( lsmash_print_movie( root, "-" ) ) return BOXDUMPER_ERR( "Failed to dump box structure.\n" ); } else { lsmash_movie_parameters_t movie_param; lsmash_initialize_movie_parameters( &movie_param ); lsmash_get_movie_parameters( root, &movie_param ); uint32_t num_tracks = movie_param.number_of_tracks; for( uint32_t track_number = 1; track_number <= num_tracks; track_number++ ) { uint32_t track_ID = lsmash_get_track_ID( root, track_number ); if( !track_ID ) return BOXDUMPER_ERR( "Failed to get track_ID.\n" ); lsmash_media_parameters_t media_param; lsmash_initialize_media_parameters( &media_param ); if( lsmash_get_media_parameters( root, track_ID, &media_param ) ) return BOXDUMPER_ERR( "Failed to get media parameters.\n" ); if( lsmash_construct_timeline( root, track_ID ) ) return BOXDUMPER_ERR( "Failed to construct timeline.\n" ); uint32_t timeline_shift; if( lsmash_get_composition_to_decode_shift_from_media_timeline( root, track_ID, &timeline_shift ) ) return BOXDUMPER_ERR( "Failed to get timestamps.\n" ); lsmash_media_ts_list_t ts_list; if( lsmash_get_media_timestamps( root, track_ID, &ts_list ) ) return BOXDUMPER_ERR( "Failed to get timestamps.\n" ); fprintf( stdout, "track_ID: %"PRIu32"\n", track_ID ); fprintf( stdout, "Media timescale: %"PRIu32"\n", media_param.timescale ); lsmash_media_ts_t *ts_array = ts_list.timestamp; if( !ts_array ) { fprintf( stdout, "\n" ); continue; } for( uint32_t i = 0; i < ts_list.sample_count; i++ ) fprintf( stdout, "DTS = %"PRIu64", CTS = %"PRIu64"\n", ts_array[i].dts, ts_array[i].cts + timeline_shift ); lsmash_free( ts_array ); fprintf( stdout, "\n" ); } } lsmash_destroy_root( root ); return 0; }
bool fcMP4Muxer::mux(const Params ¶ms) { lsmash_root_t *root; lsmash_file_parameters_t mp4_stream; lsmash_file_parameters_t h264_stream; lsmash_brand_type major_brand = ISOM_BRAND_TYPE_MP42; lsmash_brand_type compatible_brands[2] = { ISOM_BRAND_TYPE_MP42, ISOM_BRAND_TYPE_ISOM }; uint32_t fps_num = params.frame_rate; uint32_t fps_den = 1; // 出力 mp4 root = lsmash_create_root(); if (lsmash_open_file(params.out_mp4_path, 0, &mp4_stream) != 0) { return false; } mp4_stream.major_brand = major_brand; mp4_stream.brands = compatible_brands; mp4_stream.brand_count = sizeof(compatible_brands) / sizeof(compatible_brands[0]); mp4_stream.minor_version = 0; lsmash_set_file(root, &mp4_stream); lsmash_movie_parameters_t movie_param; lsmash_initialize_movie_parameters(&movie_param); lsmash_set_movie_parameters(root, &movie_param); int track_number = 1; MP4TrackData track_data[2]; int num_track_data = 0; if (params.in_h264_path) { importer_t *h264_importer = lsmash_importer_open(params.in_h264_path, "H.264"); if (h264_importer == nullptr) { return false; } int h264_track_id = lsmash_create_track(root, ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK); lsmash_track_parameters_t track_param; lsmash_initialize_track_parameters(&track_param); (int&)track_param.mode = ISOM_TRACK_IN_MOVIE | ISOM_TRACK_IN_PREVIEW; int sample_entry = 0; lsmash_summary_t *summary = lsmash_duplicate_summary(h264_importer, track_number); auto video_summary = (lsmash_video_summary_t*)summary; track_param.display_width = video_summary->width << 16; track_param.display_height = video_summary->height << 16; lsmash_set_track_parameters(root, h264_track_id, &track_param); sample_entry = lsmash_add_sample_entry(root, h264_track_id, summary); auto& td = track_data[num_track_data++]; td.importer = h264_importer; td.summary = summary; td.sample_entry = sample_entry; td.track_number = track_number; td.track_id = h264_track_id; td.timescale = video_summary->timescale; td.timebase = video_summary->timebase; lsmash_media_parameters_t media_param; lsmash_initialize_media_parameters(&media_param); media_param.timescale = td.timescale; lsmash_set_media_parameters(root, h264_track_id, &media_param); } if (params.in_aac_path) { importer_t *aac_importer = lsmash_importer_open(params.in_aac_path, "adts"); if (aac_importer == nullptr) { return false; } int aac_track_id = lsmash_create_track(root, ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK); lsmash_track_parameters_t track_param; lsmash_initialize_track_parameters(&track_param); (int&)track_param.mode = ISOM_TRACK_IN_MOVIE | ISOM_TRACK_IN_PREVIEW; int sample_entry = 0; lsmash_summary_t *summary = lsmash_duplicate_summary(aac_importer, track_number); auto audio_summary = (lsmash_audio_summary_t*)summary; lsmash_set_track_parameters(root, aac_track_id, &track_param); sample_entry = lsmash_add_sample_entry(root, aac_track_id, summary); auto& td = track_data[num_track_data++]; td.importer = aac_importer; td.summary = summary; td.sample_entry = sample_entry; td.track_number = track_number; td.track_id = aac_track_id; td.timescale = audio_summary->frequency; td.timebase = 1; lsmash_media_parameters_t media_param; lsmash_initialize_media_parameters(&media_param); media_param.timescale = td.timescale; lsmash_set_media_parameters(root, aac_track_id, &media_param); } double largest_dts = 0.0; uint32_t num_consecutive_sample_skip = 0; for (int ti = 0;;) { auto &td = track_data[ti]; if (!td.sample) { int ret = lsmash_importer_get_access_unit(td.importer, td.track_number, &td.sample); if (ret <= -1) // error { lsmash_delete_sample(td.sample); break; } else if (ret == 1) /* a change of stream's properties */ { lsmash_cleanup_summary(td.summary); td.summary = lsmash_duplicate_summary(td.importer, td.track_number); td.sample_entry = lsmash_add_sample_entry(root, td.track_id, td.summary); if (!td.sample_entry) { break; } } else if (ret == 2) /* EOF */ { lsmash_delete_sample(td.sample); break; } if (td.sample) { td.sample->index = td.sample_entry; td.sample->dts *= td.timebase; td.sample->cts *= td.timebase; td.dts = (double)td.sample->dts / td.timescale; } } if (td.sample) { if (td.dts <= largest_dts || num_consecutive_sample_skip == num_track_data) { uint64_t sample_size = td.sample->length; uint64_t sample_dts = td.sample->dts; uint64_t sample_cts = td.sample->cts; if (lsmash_append_sample(root, td.track_id, td.sample)) { return false; } td.prev_dts = sample_dts; td.sample = nullptr; largest_dts = std::max<double>(largest_dts, td.dts); num_consecutive_sample_skip = 0; } else { // skip ++num_consecutive_sample_skip; } } ti = (ti + 1) % num_track_data; } for (int i = 0; i < num_track_data; ++i) { lsmash_flush_pooled_samples(root, track_data[i].track_id, fps_den); lsmash_cleanup_summary(track_data[i].summary); lsmash_importer_close(track_data[i].importer); } lsmash_finish_movie(root, nullptr); lsmash_close_file(&mp4_stream); lsmash_destroy_root(root); return true; }