]> git.nihav.org Git - nihav-encoder.git/commitdiff
add profiles for lazier encoding
authorKostya Shishkov <kostya.shishkov@gmail.com>
Fri, 21 Mar 2025 11:36:58 +0000 (12:36 +0100)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Fri, 21 Mar 2025 11:36:58 +0000 (12:36 +0100)
src/main.rs
src/transcoder.rs

index 551fee1065a8d969c25c5ea585bbe807e43ae115..5b49d41c6b6b3b2850f8a5b53887594adb5e6211 100644 (file)
@@ -187,6 +187,8 @@ fn main() {
     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" => {
@@ -338,6 +340,21 @@ fn main() {
             "--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,
@@ -356,6 +373,7 @@ fn main() {
                         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);
@@ -493,6 +511,22 @@ fn main() {
     }
     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;
@@ -709,3 +743,41 @@ fn main() {
         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:   &[],
+            }
+        },
+    ]),
+];
index 786aedfd2dd75cc245660cfca045dc433596e367..3e78e1d72530f53abeb54ffea840fcf372afe109 100644 (file)
@@ -14,6 +14,18 @@ use crate::acvt::*;
 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]
@@ -396,6 +408,8 @@ pub struct Transcoder {
 
     pub queue:          OutputQueue,
     pub fixed_rate:     bool,
+
+    pub profile:        Option<EncodingProfile>,
 }
 
 impl Transcoder {
@@ -721,9 +735,20 @@ 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 {
@@ -865,13 +890,31 @@ println!("can't generate default channel map for {} channels", dainfo.channels);
 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;
@@ -897,6 +940,9 @@ println!("encoder {} is not supported by output (expected {})", istr.id, istr.ge
                 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();