in vireo/tools/transcode/main.cpp [566:683]
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);
// Process arguments
if (config.video_only && config.audio_only) {
cerr << "Only allow one of the --aonly --vonly parameters" << endl;
return 1;
} else if (config.video_only && movie.video_track.settings().timescale == 0) {
cerr << "File does not contain a valid video track" << endl;
return 1;
} else if (config.audio_only && (movie.audio_track.settings().timescale == 0 || movie.audio_track.settings().sample_rate == 0)) {
cerr << "File does not contain a valid audio track" << endl;
return 1;
} else if (config.dash_data && config.dash_init) {
cerr << "Only allow one of the --dashdata --dashinit parameters" << endl;
return 1;
} else if (movie.video_track.settings().timescale == 0 && (movie.audio_track.settings().timescale == 0 || movie.audio_track.settings().sample_rate == 0)) {
cerr << "File does not contain any audio / video tracks" << endl;
return 1;
}
bool transcode_video = (config.audio_only || (movie.video_track.duration() == 0)) ? false : true;
bool transcode_audio = (config.video_only || (movie.audio_track.duration() == 0)) ? false : true;
THROW_IF(!transcode_video && !transcode_audio, Invalid);
auto input_duration = transcode_video ? movie.video_track.duration() : movie.audio_track.duration();
auto timescale = transcode_video ? movie.video_track.settings().timescale : movie.audio_track.settings().timescale;
int input_duration_in_ms = 1000.0f * input_duration / timescale;
int input_start_in_ms = 0;
if (input_duration_in_ms) {
auto input_start = transcode_video ? movie.video_track(0).pts : movie.audio_track(0).pts;
input_start_in_ms = 1000.0f * input_start / timescale;
THROW_IF(input_start_in_ms < 0, Unsupported);
}
int input_end_in_ms = input_start_in_ms + input_duration_in_ms;
int end = (int)min(config.start + (uint64_t)config.duration, (uint64_t)numeric_limits<int>::max());
config.start = max(config.start, input_start_in_ms);
config.duration = max(min(end, input_end_in_ms) - config.start, 0);
if (config.duration == 0) {
cout << "No video content in the given time range" << endl;
return 1;
}
// Main
cout << "Transcoding " << (transcode_video ? (transcode_audio ? "video with audio" : "video") : "audio");
cout << " of duration " << config.duration << " ms, starting from " << config.start << " ms" << endl;
uint32_t i = 0;
cout << Profile::Function("Transcoding", [&]{
// Keep track of the first pts of the encoded tracks (could be either audio or video)
FirstPtsAndTimescale first_pts_and_timescale;
// Get output video track
auto output_video_track = functional::Video<encode::Sample>();
auto fps = (config.fps == -1) ? movie.video_track.fps() : config.fps;
if (transcode_video) {
output_video_track = transcode(movie.video_track, fps, movie.video_track.edit_boxes(), config, first_pts_and_timescale, i == 0);
}
// Get output audio track
auto output_audio_track = functional::Audio<encode::Sample>();
if (transcode_audio) {
output_audio_track = transcode(movie.audio_track, movie.audio_track.edit_boxes(), config, first_pts_and_timescale, i == 0);
}
// Get output caption track
auto output_caption_track = functional::Caption<encode::Sample>();
if (transcode_video) {
auto trimmed_caption = transform::Trim<SampleType::Caption>(movie.caption_track, movie.caption_track.edit_boxes(), config.start, config.duration);
output_caption_track = functional::Caption<encode::Sample>(trimmed_caption.track, encode::Sample::Convert);
}
// Create necessary encoder
functional::Function<common::Data32> encoder;
if (config.outfile_type == MP4) {
FileFormat format = FileFormat::Regular;
if (config.dash_data) {
format = FileFormat::DashData;
} else if (config.dash_init) {
format = FileFormat::DashInitializer;
} else if (config.samples_only) {
format = FileFormat::SamplesOnly;
}
encoder = mux::MP4(output_audio_track, output_video_track, output_caption_track, format);
} else if (config.outfile_type == MP2TS) {
encoder = mux::MP2TS(output_audio_track, output_video_track, output_caption_track);
} else {
encoder = mux::WebM(output_audio_track, output_video_track);
}
// Start encoding and save the output file once
const string abs_dst = common::Path::MakeAbsolute(config.outfile);
if (i == 0) {
util::save(abs_dst, encoder());
} else {
encoder();
}
++i;
}, config.iterations) << endl;
} __catch (std::exception& e) {
cerr << "Error transcoding movie: " << e.what() << endl;
return 1;
}
return 0;
}