let mut arg_idx = 1;
let mut printed_info = false;
let mut force_sync = false;
+ let mut profile_name = "".to_string();
+ let mut custom_profile = false;
while arg_idx < args.len() {
match args[arg_idx].as_str() {
"--list-decoders" => {
"--calc-len" => {
transcoder.calc_len = true;
},
+ "--print-profiles" => {
+ println!("Supported profiles:");
+ for (name, profiles) in PROFILES.iter() {
+ print!(" profiles for format '{name}': ");
+ for profile in profiles.iter() {
+ print!(" {}", profile.name);
+ }
+ println!();
+ }
+ printed_info = true;
+ },
+ "--profile" => {
+ next_arg!(args, arg_idx);
+ profile_name = args[arg_idx].to_string();
+ },
"--verbose" | "-v" => transcoder.verbose = 1,
"-vv" => transcoder.verbose = 2,
"-v-" => transcoder.verbose = 0,
println!("invalid output stream option syntax");
return;
}
+ custom_profile = true;
} else if args[arg_idx].starts_with("--iformat") {
let id = parse_id!(&args[arg_idx][9..], "input format", transcoder.input_fmt.len());
next_arg!(args, arg_idx);
}
let mux_creator = ret.unwrap();
+ if custom_profile && !profile_name.is_empty() {
+ println!("profile setting is incompatible with custom --ostream options");
+ return;
+ }
+ if !profile_name.is_empty() {
+ if let Some(profiles) = PROFILES.iter().find(|(fmt, _)| fmt == &output_fmt) {
+ if let Some(ref_profile) = profiles.1.iter().find(|p| p.name == profile_name) {
+ transcoder.profile = Some(ref_profile.profile);
+ } else {
+ println!("profile '{profile_name}' is not defined for output format '{output_fmt}'");
+ }
+ } else {
+ println!("no profiles for output format '{output_fmt}'");
+ }
+ }
+
let mux_quirks = mux_creator.get_quirks();
if mux_quirks.is_fixed_duration() {
transcoder.calc_len = true;
println!("error at finalising muxing");
}
}
+
+struct ProfileDef {
+ name: &'static str,
+ profile: EncodingProfile,
+}
+
+const PROFILES: &[(&str, &[ProfileDef])] = &[
+ ("avi",
+ &[
+ ProfileDef {
+ name: "cinepak",
+ profile: EncodingProfile {
+ vname: "cinepak",
+ voptions: &[],
+ aname: "pcm",
+ aoptions: &[],
+ }
+ },
+ ProfileDef {
+ name: "lossless",
+ profile: EncodingProfile {
+ vname: "zmbv",
+ voptions: &[("range", Some("4")), ("compr_level", Some("fast"))],
+ aname: "pcm",
+ aoptions: &[],
+ }
+ },
+ ProfileDef {
+ name: "ms-lossy",
+ profile: EncodingProfile {
+ vname: "msvideo1",
+ voptions: &[],
+ aname: "ms-adpcm",
+ aoptions: &[],
+ }
+ },
+ ]),
+];
use crate::demux::*;
use crate::imgseq::*;
+#[derive(Clone,Copy,Debug)]
+pub struct EncodingProfile {
+ /// video codec to be used
+ pub vname: &'static str,
+ /// options for the video encoder
+ pub voptions: &'static [(&'static str, Option<&'static str>)],
+ /// audio codec to be used
+ pub aname: &'static str,
+ /// options for the audio encoder
+ pub aoptions: &'static [(&'static str, Option<&'static str>)],
+}
+
#[derive(Clone,Copy,Default,PartialEq)]
pub enum RegisterResult {
#[default]
pub queue: OutputQueue,
pub fixed_rate: bool,
+
+ pub profile: Option<EncodingProfile>,
}
impl Transcoder {
}
}
+ let mut is_undef_codec = cname == "any" || istr.get_info().get_name() == cname;
+ if let Some(ref profile) = self.profile {
+ if istr.get_media_type() == StreamType::Video && !profile.vname.is_empty() {
+ is_undef_codec = false;
+ }
+ if istr.get_media_type() == StreamType::Audio && !profile.aname.is_empty() {
+ is_undef_codec = false;
+ }
+ }
+
if let Some(str_idx) = self.ostr_opts.iter().position(|el| el.id == out_id) {
let oopts = &mut self.ostr_opts[str_idx];
- if oopts.enc_name.as_str() == "copy" && (cname == "any" || istr.get_info().get_name() == cname) {
+
+ if oopts.enc_name.as_str() == "copy" && is_undef_codec {
out_sm.add_stream((*istr).clone());
self.encoders.push(OutputMode::Copy(out_id));
} else if cname == "any" || oopts.enc_name.as_str() == cname {
println!("encoder {} is not supported by output (expected {})", istr.id, istr.get_info().get_name());
return RegisterResult::Failed;
}
- } else if cname == "any" || istr.get_info().get_name() == cname {
+ } else if is_undef_codec {
out_sm.add_stream((*istr).clone());
self.encoders.push(OutputMode::Copy(out_id));
} else {
let mut oopts = OutputStreamOptions {id: out_id, enc_name: cname.to_owned(), enc_params: EncodeParameters::default(), enc_opts: Vec::new() };
- let enc_create = enc_reg.find_encoder(cname);
+ if let Some(ref profile) = self.profile {
+ match istr.get_media_type() {
+ StreamType::Audio if !profile.aname.is_empty() => {
+ oopts.enc_name = profile.aname.to_owned();
+ for (name, argument) in profile.aoptions.iter() {
+ oopts.enc_opts.push(OptionArgs { name: name.to_string(), value: argument.map(|val| val.to_string()) });
+ }
+ },
+ StreamType::Video if !profile.vname.is_empty() => {
+ oopts.enc_name = profile.vname.to_owned();
+ for (name, argument) in profile.voptions.iter() {
+ oopts.enc_opts.push(OptionArgs { name: name.to_string(), value: argument.map(|val| val.to_string()) });
+ }
+ },
+ _ => {},
+ }
+ }
+
+ let enc_create = enc_reg.find_encoder(&oopts.enc_name);
if enc_create.is_none() {
println!("encoder '{}' not found", oopts.enc_name.as_str());
return RegisterResult::Failed;
println!("error initialising encoder");
return RegisterResult::Failed;
}
+
+ parse_and_apply_options!(encoder, &oopts.enc_opts, oopts.enc_name);
+
let enc_stream = ret.unwrap();
//todo check for params mismatch
let real_fmt = enc_stream.get_info().get_properties();