in vireo/tools/remux/main.cpp [169:292]
int main(int argc, const char* argv[]) {
__try {
// Parse arguments
if (argc < 3) {
print_usage(common::Path::Filename(argv[0]));
return 1;
}
Config config;
if (parse_arguments(argc, argv, config)) {
return 1;
}
// Read input file
demux::Movie movie(config.infile);
// Check input / output file format combinations to do remux
auto infile_type = movie.file_type();
if (infile_type != config.outfile_type && (infile_type == WebM || config.outfile_type == WebM)) {
cerr << "Cannot remux from " << kFileTypeToString[infile_type] << " to " << kFileTypeToString[config.outfile_type] << endl;
return 1;
}
// Process arguments
if (config.video_only && config.audio_only) {
cerr << "Cannot use video and audio only flags at the same time" << endl;
} else if (config.video_only && movie.video_track.count() == 0) {
cerr << "File does not contain a valid video track" << endl;
return 1;
} else if (config.audio_only && movie.audio_track.count() == 0) {
cerr << "File does not contain a valid audio track" << endl;
return 1;
} else if (movie.video_track.count() == 0 && movie.audio_track.count() == 0) {
cerr << "File does not contain any audio / video tracks" << endl;
return 1;
}
bool remux_audio = (config.video_only || (movie.audio_track.count() == 0)) ? false : true;
bool remux_video = (config.audio_only || (movie.video_track.count() == 0)) ? false : true;
// Process GOP boundaries / arguments
struct dts_pair {
int64_t video;
int64_t audio;
};
vector<dts_pair> dts_at_gop_boundaries;
if (movie.video_track.count()) {
for (const auto& sample: movie.video_track) {
if (sample.keyframe) {
int64_t video_dts = sample.dts;
int64_t audio_dts = remux_audio ? common::round_divide((uint64_t)video_dts, (uint64_t)movie.audio_track.settings().timescale, (uint64_t)movie.video_track.settings().timescale) : 0;
dts_at_gop_boundaries.push_back({ video_dts, audio_dts });
}
}
} else {
dts_at_gop_boundaries.push_back({ 0, movie.audio_track(0).dts });
}
int total_gops = (int)dts_at_gop_boundaries.size();
dts_at_gop_boundaries.push_back({ numeric_limits<int64_t>::max(), numeric_limits<int64_t>::max() });
if (config.start_gop >= total_gops) {
cerr << "start gop has to be between 0 and " << total_gops << endl;
return 1;
}
config.num_gops = min(config.num_gops, (int)total_gops - config.start_gop);
// Main
uint32_t i = 0;
cout << Profile::Function("Remuxing", [&]{
// Get start / end dts for video track
auto start_dts_pair = dts_at_gop_boundaries[config.start_gop];
auto end_dts_pair = dts_at_gop_boundaries[config.start_gop + config.num_gops];
// Get output video track
auto output_video_track = functional::Video<encode::Sample>();
if (remux_video) {
output_video_track = remux<SampleType::Video>(movie.video_track, config, start_dts_pair.video, end_dts_pair.video, i == 0);
}
// Get output audio track
auto output_audio_track = functional::Audio<encode::Sample>();
if (remux_audio) {
output_audio_track = remux<SampleType::Audio>(movie.audio_track, config, start_dts_pair.audio, end_dts_pair.audio, i == 0);
}
// Get output caption track
auto output_caption_track = functional::Caption<encode::Sample>();
if (remux_video) {
output_caption_track = remux<SampleType::Caption>(movie.caption_track, config, start_dts_pair.video, end_dts_pair.video, i == 0);
}
// Add edit boxes only if remuxing input file without any modifications
vector<common::EditBox> edit_boxes;
if (config.file_format == FileFormat::Regular && config.num_gops == total_gops) {
if (remux_audio) {
edit_boxes = movie.audio_track.edit_boxes();
}
if (remux_video) {
edit_boxes.insert(edit_boxes.begin(), movie.video_track.edit_boxes().begin(), movie.video_track.edit_boxes().end());
}
}
// Create muxer
functional::Function<common::Data32> muxer;
if (config.outfile_type == MP4) {
muxer = mux::MP4(output_audio_track, output_video_track, output_caption_track, edit_boxes, config.file_format);
} else if (config.outfile_type == MP2TS) {
muxer = mux::MP2TS(output_audio_track, output_video_track, output_caption_track);
} else {
muxer = mux::WebM(output_audio_track, output_video_track);
}
// Save the output file once
if (i == 0) {
util::save(common::Path::MakeAbsolute(config.outfile), muxer());
} else {
muxer();
}
++i;
}, config.iterations) << endl;
} __catch (std::exception& e) {
cerr << "Error remuxing movie: " << e.what() << endl;
return 1;
}
return 0;
}