From 7d5e8834531915381a12af4b374f2322bd6853d5 Mon Sep 17 00:00:00 2001 From: Ryan Laseter Date: Fri, 3 Mar 2023 17:49:44 -0600 Subject: [PATCH] AMF support, improved result file for permutations, and option to allow duplicate scoring (#7) --- Cargo.lock | 10 +- Cargo.toml | 3 +- README.md | 5 +- benchmark/Cargo.toml | 3 +- benchmark/src/main.rs | 45 +++-- cli/src/supported.rs | 4 +- codecs/Cargo.toml | 9 + codecs/src/amf.rs | 184 ++++++++++++++++++ codecs/src/lib.rs | 18 ++ .../h264_hevc_nvenc.rs => codecs/src/nvenc.rs | 11 +- {engine => codecs}/src/permute.rs | 0 {engine => codecs}/src/resolutions.rs | 0 codecs/src/vendor.rs | 5 + engine/Cargo.toml | 1 - engine/src/lib.rs | 4 - engine/src/nvenc.rs | 7 - engine/src/permutation_engine.rs | 8 +- engine/src/result.rs | 8 + permutation/src/permutation.rs | 2 + permutor-cli/Cargo.toml | 3 +- permutor-cli/src/main.rs | 52 ++++- permutor-cli/src/permutor_cli.rs | 5 +- 22 files changed, 343 insertions(+), 44 deletions(-) create mode 100644 codecs/Cargo.toml create mode 100644 codecs/src/amf.rs create mode 100644 codecs/src/lib.rs rename engine/src/h264_hevc_nvenc.rs => codecs/src/nvenc.rs (96%) rename {engine => codecs}/src/permute.rs (100%) rename {engine => codecs}/src/resolutions.rs (100%) create mode 100644 codecs/src/vendor.rs delete mode 100644 engine/src/nvenc.rs diff --git a/Cargo.lock b/Cargo.lock index 3356dbc..d6d24c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,7 @@ version = "0.1.0" dependencies = [ "clap", "cli", + "codecs", "dont_disappear", "engine", "environment", @@ -90,6 +91,13 @@ dependencies = [ "environment", ] +[[package]] +name = "codecs" +version = "0.1.0" +dependencies = [ + "itertools", +] + [[package]] name = "compound_duration" version = "1.2.0" @@ -297,7 +305,6 @@ dependencies = [ "ctrlc", "ffmpeg", "indicatif", - "itertools", "permutation", "stoppable_thread", ] @@ -548,6 +555,7 @@ version = "0.1.0" dependencies = [ "clap", "cli", + "codecs", "engine", "environment", "ffmpeg", diff --git a/Cargo.toml b/Cargo.toml index 8df0061..e3c7b44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,5 +8,6 @@ members = [ "permutation", "permutor-cli", "cli", - "gpus" + "gpus", + "codecs" ] \ No newline at end of file diff --git a/README.md b/README.md index 64a955b..e13911b 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,10 @@ PCI bottlenecking for GPU's not in the primary slot. - do make sure your SSD drive in Windows does _not_ have drive compression enabled. This can severely affect your sequential read speeds, which is very important for reading high resolution/fps input files -- the tool does _not_ support multiple Nvidia GPU's in your system, so it's suggested to just have 1 in your system +- the tool supports multiple Nvidia GPU's in your system for both the benchmark & permutor-cli tool, so you can feel + free to have more than 1 for your testing (although the benchmark would only run against one) +- the tool does _not_ support multiple AMD GPU's for the benchmark tool, but you are able to still specify _-gpu_ with + the permutor-cli tool --- diff --git a/benchmark/Cargo.toml b/benchmark/Cargo.toml index 4bc8652..9a66f27 100644 --- a/benchmark/Cargo.toml +++ b/benchmark/Cargo.toml @@ -13,4 +13,5 @@ permutation = { path = "../permutation" } engine = { path = "../engine" } ffmpeg = { path = "../ffmpeg" } cli = { path = "../cli" } -gpus = { path = "../gpus" } \ No newline at end of file +gpus = { path = "../gpus" } +codecs = { path = "../codecs" } \ No newline at end of file diff --git a/benchmark/src/main.rs b/benchmark/src/main.rs index 6e1ace4..9cfd24e 100644 --- a/benchmark/src/main.rs +++ b/benchmark/src/main.rs @@ -8,9 +8,12 @@ use text_io::read; use cli::cli_util::{is_dev, pause}; use cli::supported::{get_supported_encoders, get_supported_inputs}; +use codecs::amf::Amf; +use codecs::get_vendor_for_codec; +use codecs::nvenc::Nvenc; +use codecs::permute::Permute; +use codecs::vendor::Vendor; use engine::benchmark_engine::BenchmarkEngine; -use engine::h264_hevc_nvenc::Nvenc; -use engine::permute::Permute; use ffmpeg::metadata::MetaData; use gpus::get_gpus; use permutation::permutation::Permutation; @@ -41,15 +44,13 @@ fn main() { cli.validate(); - let input_files = get_input_files(cli.source_file); + let input_files = get_input_files(cli.source_file.clone()); let mut engine = BenchmarkEngine::new(); - let nvenc = Nvenc::new(cli.encoder == "hevc_nvenc", cli.gpu); - // prepare permutations for the engine to run over for input in input_files { let mut permutation = Permutation::new(input, cli.encoder.clone()); - let settings = get_settings_for(&nvenc); - let bitrate = get_bitrate_for(&permutation.get_metadata()); + let settings = get_benchmark_settings_for(&cli); + let bitrate = get_bitrate_for(&permutation.get_metadata(), cli.encoder.clone()); permutation.bitrate = bitrate; permutation.encoder_settings = settings; @@ -151,14 +152,32 @@ fn print_options(input_vec: Vec<&str>) { } } -fn get_settings_for(nvenc: &Nvenc) -> String { - // need to support other encoders here - return nvenc.get_benchmark_settings(); +fn get_benchmark_settings_for(cli: &BenchmarkCli) -> String { + let vendor = get_vendor_for_codec(&cli.encoder); + + return match vendor { + Vendor::Nvidia => { + let nvenc = Nvenc::new(cli.encoder == "hevc_nvenc", cli.gpu); + nvenc.get_benchmark_settings() + } + + Vendor::AMD => { + let amf = Amf::new(cli.encoder == "hevc_nvenc", cli.gpu); + amf.get_benchmark_settings() + } + Vendor::Unknown => { + // nothing to do here + String::from("") + } + }; } -fn get_bitrate_for(metadata: &MetaData) -> u32 { - // need to support other encoders here - return *Nvenc::get_resolution_to_bitrate_map(metadata.fps).get(&metadata.get_res()).unwrap(); +fn get_bitrate_for(metadata: &MetaData, string: String) -> u32 { + if string.contains("nvenc") { + return *Nvenc::get_resolution_to_bitrate_map(metadata.fps).get(&metadata.get_res()).unwrap(); + } else { + return *Amf::get_resolution_to_bitrate_map(metadata.fps).get(&metadata.get_res()).unwrap(); + } } fn get_input_files(source_file: String) -> Vec { diff --git a/cli/src/supported.rs b/cli/src/supported.rs index b23cd75..7e74534 100644 --- a/cli/src/supported.rs +++ b/cli/src/supported.rs @@ -1,4 +1,4 @@ -const SUPPORTED_ENCODERS: [&'static str; 2] = ["h264_nvenc", "hevc_nvenc"]; +const SUPPORTED_ENCODERS: [&'static str; 4] = ["h264_nvenc", "hevc_nvenc", "h264_amf", "hevc_amf"]; const DOWNLOAD_URL: &str = "https://www.dropbox.com/sh/x08pkk47lc1v5ex/AADGaoOjOcA0-uPo7I0NaxL-a?dl=0"; const ENCODE_FILES: [&'static str; 8] = ["720-60.y4m", "720-120.y4m", "1080-60.y4m", "1080-120.y4m", "2k-60.y4m", "2k-120.y4m", "4k-60.y4m", "4k-120.y4m"]; @@ -6,7 +6,7 @@ pub fn is_encoder_supported(potential_encoder: &String) -> bool { return SUPPORTED_ENCODERS.contains(&potential_encoder.as_str()); } -pub fn get_supported_encoders() -> [&'static str; 2] { +pub fn get_supported_encoders() -> [&'static str; 4] { return SUPPORTED_ENCODERS; } diff --git a/codecs/Cargo.toml b/codecs/Cargo.toml new file mode 100644 index 0000000..982f985 --- /dev/null +++ b/codecs/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "codecs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +itertools = "0.10.5" \ No newline at end of file diff --git a/codecs/src/amf.rs b/codecs/src/amf.rs new file mode 100644 index 0000000..40609cc --- /dev/null +++ b/codecs/src/amf.rs @@ -0,0 +1,184 @@ +use std::collections::HashMap; + +use itertools::Itertools; + +use crate::permute::Permute; +use crate::resolutions::map_res_to_bitrate; + +pub struct Amf { + usages: Vec<&'static str>, + qualities: Vec<&'static str>, + profiles: Vec<&'static str>, + profile_tiers: Vec<&'static str>, + rate_controls: Vec<&'static str>, + // might be able to make this the size we're expecting + permutations: Vec, + index: i32, + gpu: u8, +} + +impl Amf { + pub fn new(is_hevc: bool, gpu: u8) -> Self { + Self { + usages: get_amf_usages(), + qualities: get_amf_quality(), + // this is the only difference between hevc & h264 + profiles: if is_hevc { vec!["main"] } else { vec!["main", "high", "constrained_baseline", "constrained_high"] }, + // leaving out vbr rate controls as these are not ideal for game streaming + profile_tiers: get_amf_profile_tiers(is_hevc), + rate_controls: vec!["cbr"], + permutations: Vec::new(), + // starts at -1, so that first next() will return the first element + index: -1, + gpu, + } + } + + pub fn get_benchmark_settings(&self) -> String { + // both hevc and h264 perform best at main (kinda, h264 it doesn't matter much) + // hevc and h264 both share the same high fps with the same settings, even without profile_tier for hevc + let profile = "main"; + return format!("-usage ultralowlatency -quality speed -profile:v {} -rc cbr -cbr true -gpu {}", profile, self.gpu); + } + + fn has_next(&self) -> bool { + return self.index != (self.permutations.len() - 1) as i32; + } +} + +fn get_amf_profile_tiers(hevc: bool) -> Vec<&'static str> { + if hevc { + return vec!["main", "high"]; + } + + // there are no amf profile tiers for h264 + return vec![]; +} + +fn get_amf_usages() -> Vec<&'static str> { + return vec!["transcoding", "ultralowlatency", "lowlatency", "webcam"]; +} + +fn get_amf_quality() -> Vec<&'static str> { + return vec!["balanced", "speed", "quality"]; +} + +#[derive(Copy, Clone)] +struct AmfSettings { + usage: &'static str, + quality: &'static str, + profile: &'static str, + profile_tier: &'static str, + rate_control: &'static str, + gpu: u8, +} + +impl AmfSettings { + fn to_string(&self) -> String { + let mut args = String::new(); + args.push_str("-usage "); + args.push_str(self.usage); + args.push_str(" -quality "); + args.push_str(self.quality); + args.push_str(" -profile:v "); + args.push_str(self.profile); + + if !self.profile_tier.is_empty() { + args.push_str(" -profile_tier "); + args.push_str(self.profile_tier); + } + + args.push_str(" -rc "); + args.push_str(self.rate_control); + // always set this to constant bit rate to ensure reliable stream + args.push_str(" -cbr true"); + args.push_str(" -gpu "); + args.push_str(self.gpu.to_string().as_str()); + + return args; + } +} + +impl Iterator for Amf { + type Item = (usize, String); + + // maybe we can pull this code out + fn next(&mut self) -> Option { + if !self.has_next() { + return None; + } + + self.index += 1; + + let usize_index = self.index as usize; + return Option::from((usize_index as usize, self.permutations.get(usize_index).unwrap().to_string())); + } +} + +impl Permute for Amf { + fn init(&mut self) -> &Vec { + // reset index, otherwise we won't be able to iterate at all + self.index = -1; + + // clear the vectors if there were entries before + self.permutations.clear(); + + let mut permutations = if self.profile_tiers.is_empty() { vec![&self.usages, &self.qualities, &self.profiles, &self.rate_controls] } else { + vec![&self.usages, &self.qualities, &self.profiles, &self.profile_tiers, &self.rate_controls] + } + .into_iter().multi_cartesian_product(); + + loop { + let perm = permutations.next(); + if perm.is_none() { + break; + } + + let unwrapped_perm = perm.unwrap(); + let profile_tier = if !self.profile_tiers.is_empty() { unwrapped_perm.get(3).unwrap() } else { "" }; + let rc_index = if !self.profile_tiers.is_empty() { 4 } else { 3 }; + let settings = AmfSettings { + usage: unwrapped_perm.get(0).unwrap(), + quality: unwrapped_perm.get(1).unwrap(), + profile: unwrapped_perm.get(2).unwrap(), + profile_tier, + rate_control: unwrapped_perm.get(rc_index).unwrap(), + gpu: self.gpu, + }; + + self.permutations.push(settings.to_string()); + } + + return &self.permutations; + } + + fn run_standard_only(&mut self) -> &Vec { + // reset index, otherwise we won't be able to iterate at all + self.index = -1; + + // clear the vectors if there were entries before + self.permutations.clear(); + + // note: this only works when hevc/h264 both use just 1 profile, if we add more this will break + self.permutations.push(String::from(self.get_benchmark_settings())); + return &self.permutations; + } + + + fn get_resolution_to_bitrate_map(fps: u32) -> HashMap { + let mut map: HashMap = HashMap::new(); + + // bitrates are within 5Mb/s of each other, using higher one + // note: these are the 60fps bitrate values + let mut bitrates: [u32; 4] = [20, 35, 50, 85]; + + // 120 fps is effectively double the bitrate + if fps == 120 { + bitrates.iter_mut().for_each(|b| *b = *b * 2); + } + + map_res_to_bitrate(&mut map, bitrates); + + return map; + } +} \ No newline at end of file diff --git a/codecs/src/lib.rs b/codecs/src/lib.rs new file mode 100644 index 0000000..3bb5f1a --- /dev/null +++ b/codecs/src/lib.rs @@ -0,0 +1,18 @@ +use crate::vendor::Vendor; + +pub mod nvenc; +pub mod amf; +pub mod permute; +mod resolutions; +pub mod vendor; + + +pub fn get_vendor_for_codec(codec: &String) -> Vendor { + if codec.contains("nvenc") { + return Vendor::Nvidia; + } else if codec.contains("amf") { + return Vendor::AMD; + } + + return Vendor::Unknown; +} \ No newline at end of file diff --git a/engine/src/h264_hevc_nvenc.rs b/codecs/src/nvenc.rs similarity index 96% rename from engine/src/h264_hevc_nvenc.rs rename to codecs/src/nvenc.rs index 646c580..710d5f4 100644 --- a/engine/src/h264_hevc_nvenc.rs +++ b/codecs/src/nvenc.rs @@ -2,7 +2,6 @@ use std::collections::HashMap; use itertools::Itertools; -use crate::nvenc::{get_nvenc_presets, get_nvenc_tunes}; use crate::permute::Permute; use crate::resolutions::map_res_to_bitrate; @@ -42,6 +41,14 @@ impl Nvenc { } } +fn get_nvenc_presets() -> Vec<&'static str> { + return vec!["p1", "p2", "p3", "p4", "p5", "p6", "p7"]; +} + +fn get_nvenc_tunes() -> Vec<&'static str> { + return vec!["hq", "ll", "ull"]; +} + #[derive(Copy, Clone)] struct NvencSettings { preset: &'static str, @@ -150,7 +157,7 @@ impl Permute for Nvenc { #[cfg(test)] mod tests { - use crate::h264_hevc_nvenc::Nvenc; + use crate::nvenc::Nvenc; use crate::permute::Permute; #[test] diff --git a/engine/src/permute.rs b/codecs/src/permute.rs similarity index 100% rename from engine/src/permute.rs rename to codecs/src/permute.rs diff --git a/engine/src/resolutions.rs b/codecs/src/resolutions.rs similarity index 100% rename from engine/src/resolutions.rs rename to codecs/src/resolutions.rs diff --git a/codecs/src/vendor.rs b/codecs/src/vendor.rs new file mode 100644 index 0000000..fccad06 --- /dev/null +++ b/codecs/src/vendor.rs @@ -0,0 +1,5 @@ +pub enum Vendor { + Nvidia, + AMD, + Unknown, +} \ No newline at end of file diff --git a/engine/Cargo.toml b/engine/Cargo.toml index b8a4d6f..c0cae4a 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" [dependencies] compound_duration = "1.2.0" -itertools = "0.10.5" crossbeam-channel = "0.5.6" ctrlc = "3.2.4" indicatif = "0.17.2" diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 4549294..a12e05b 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -1,10 +1,6 @@ mod engine; pub mod result; pub mod fps_stats; -pub mod h264_hevc_nvenc; -pub mod nvenc; -pub mod permute; -pub mod resolutions; pub mod progressbar; pub mod threads; pub mod stat_tcp_listener; diff --git a/engine/src/nvenc.rs b/engine/src/nvenc.rs deleted file mode 100644 index 0cff8f5..0000000 --- a/engine/src/nvenc.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub fn get_nvenc_presets() -> Vec<&'static str> { - return vec!["p1", "p2", "p3", "p4", "p5", "p6", "p7"]; -} - -pub fn get_nvenc_tunes() -> Vec<&'static str> { - return vec!["hq", "ll", "ull"]; -} \ No newline at end of file diff --git a/engine/src/permutation_engine.rs b/engine/src/permutation_engine.rs index f4bcc06..60cd9c2 100644 --- a/engine/src/permutation_engine.rs +++ b/engine/src/permutation_engine.rs @@ -54,7 +54,7 @@ impl PermutationEngine { log_permutation_header(i, &self.permutations, calc_time, ignore_factor); // if this permutation was added to the list of duplicates, skip to save calculation time - if will_be_duplicate(&self.dup_results, &permutation) { + if !permutation.allow_duplicates && permutation.check_quality && will_be_duplicate(&self.dup_results, &permutation) { draw_yellow_bar(permutation.get_metadata().frames); println!("\n!!! Above encoder settings will produce identical vmaf score as other permutations, skipping... \n"); continue; @@ -78,7 +78,7 @@ impl PermutationEngine { } let is_initial_bitrate_permutation_over = i == self.permutations.len() - 1 || self.permutations[i + 1].clone().bitrate != permutation.bitrate; - self.add_result(result, is_initial_bitrate_permutation_over); + self.add_result(result, is_initial_bitrate_permutation_over, permutation.check_quality, permutation.allow_duplicates); // we'll calculate the ignore factor of permutations that will be skipped if is_initial_bitrate_permutation_over { @@ -104,10 +104,10 @@ impl PermutationEngine { self.permutations.push(permutation); } - fn add_result(&mut self, result: PermutationResult, is_bitrate_permutation_over: bool) { + fn add_result(&mut self, result: PermutationResult, is_bitrate_permutation_over: bool, is_checking_quality: bool, allow_duplicates: bool) { // only do this duplicate mapping during the first bitrate permutation // notice how we do not add this for overloaded results - if !result.was_overloaded && !is_bitrate_permutation_over { + if !allow_duplicates && is_checking_quality && !result.was_overloaded && !is_bitrate_permutation_over { let score_str = result.vmaf_score.to_string(); if !self.vmaf_scores.contains(&score_str) { self.results.push(result); diff --git a/engine/src/result.rs b/engine/src/result.rs index 37b1fd2..f361cca 100644 --- a/engine/src/result.rs +++ b/engine/src/result.rs @@ -68,7 +68,15 @@ pub fn log_results_to_file(results: Vec, runtime_str: &String writeln!(&mut w, "Results from entire permutation:").unwrap(); writeln!(&mut w, "==================================================================================================================================================================").unwrap(); writeln!(&mut w, " [Resolution]\t[FPS]\t[Bitrate]\t[Encode Time]\t[VMAF Time]\t[VMAF Score]\t[Average FPS]\t[1%'ile]\t[90%'ile]\t[Encoder Settings]").unwrap(); + let mut current_bitrate = 0; + for result in &results { + // print a line split between bitrate permutations for improved readability + if !is_benchmark && current_bitrate != result.bitrate { + writeln!(&mut w, "##################################################################################################################################################################").unwrap(); + current_bitrate = result.bitrate; + } + writeln!(&mut w, "{}", result.to_string()).unwrap(); } writeln!(&mut w, "==================================================================================================================================================================").unwrap(); diff --git a/permutation/src/permutation.rs b/permutation/src/permutation.rs index a817c41..c709c82 100644 --- a/permutation/src/permutation.rs +++ b/permutation/src/permutation.rs @@ -9,6 +9,7 @@ pub struct Permutation { pub bitrate: u32, pub metadata: MetaData, pub check_quality: bool, + pub allow_duplicates: bool, pub detect_overload: bool, pub verbose: bool, } @@ -22,6 +23,7 @@ impl Permutation { bitrate: 0, metadata: MetaData::new(), check_quality: false, + allow_duplicates: false, detect_overload: false, verbose: false, } diff --git a/permutor-cli/Cargo.toml b/permutor-cli/Cargo.toml index ce74eb6..22c182c 100644 --- a/permutor-cli/Cargo.toml +++ b/permutor-cli/Cargo.toml @@ -11,4 +11,5 @@ environment = { path = "../environment" } engine = { path = "../engine" } cli = { path = "../cli" } permutation = { path = "../permutation" } -ffmpeg = { path = "../ffmpeg" } \ No newline at end of file +ffmpeg = { path = "../ffmpeg" } +codecs = { path = "../codecs" } \ No newline at end of file diff --git a/permutor-cli/src/main.rs b/permutor-cli/src/main.rs index 738b4fc..a711744 100644 --- a/permutor-cli/src/main.rs +++ b/permutor-cli/src/main.rs @@ -1,8 +1,11 @@ use clap::Parser; -use engine::h264_hevc_nvenc::Nvenc; +use codecs::amf::Amf; +use codecs::get_vendor_for_codec; +use codecs::nvenc::Nvenc; +use codecs::permute::Permute; +use codecs::vendor::Vendor; use engine::permutation_engine::PermutationEngine; -use engine::permute::Permute; use permutation::permutation::Permutation; use crate::permutor_cli::PermutorCli; @@ -16,9 +19,17 @@ fn main() { log_special_arguments(&cli); let mut engine = PermutationEngine::new(); - let mut nvenc = Nvenc::new(cli.encoder == "hevc_nvenc", cli.gpu); + let vendor = get_vendor_for_codec(&cli.encoder.clone()); for bitrate in get_bitrate_permutations(cli.bitrate, cli.max_bitrate_permutation.unwrap()) { - build_setting_permutations(&mut engine, &mut nvenc, &cli, bitrate); + match vendor { + Vendor::Nvidia => { + build_nvenc_setting_permutations(&mut engine, &cli, bitrate); + } + Vendor::AMD => { + build_amf_setting_permutations(&mut engine, &cli, bitrate); + } + Vendor::Unknown => {} + } } engine.run(); @@ -35,6 +46,10 @@ fn log_special_arguments(cli: &PermutorCli) { println!(" -calculating vmaf score"); } + if cli.allow_duplicate_scores { + println!(" -ignoring whether expected vmaf score will be duplicated"); + } + if cli.verbose { println!(" -verbose enabled"); } @@ -45,7 +60,9 @@ fn log_special_arguments(cli: &PermutorCli) { } } -fn build_setting_permutations(engine: &mut PermutationEngine, nvenc: &mut Nvenc, cli: &PermutorCli, bitrate: u32) { +fn build_nvenc_setting_permutations(engine: &mut PermutationEngine, cli: &PermutorCli, bitrate: u32) { + let mut nvenc = Nvenc::new(cli.encoder == "hevc_nvenc", cli.gpu); + // initialize the permutations each time nvenc.init(); @@ -57,6 +74,31 @@ fn build_setting_permutations(engine: &mut PermutationEngine, nvenc: &mut Nvenc, permutation.check_quality = cli.check_quality; permutation.verbose = cli.verbose; permutation.detect_overload = cli.detect_overload; + permutation.allow_duplicates = cli.allow_duplicate_scores; + engine.add(permutation); + + // break out early here to just make 1 permutation + if cli.test_run { + break; + } + } +} + +fn build_amf_setting_permutations(engine: &mut PermutationEngine, cli: &PermutorCli, bitrate: u32) { + let mut amf = Amf::new(cli.encoder == "hevc_amf", cli.gpu); + + // initialize the permutations each time + amf.init(); + + while let Some((_encoder_index, settings)) = amf.next() { + let mut permutation = Permutation::new(cli.source_file.clone(), cli.encoder.clone()); + permutation.video_file = cli.source_file.clone(); + permutation.encoder_settings = settings; + permutation.bitrate = bitrate; + permutation.check_quality = cli.check_quality; + permutation.verbose = cli.verbose; + permutation.detect_overload = cli.detect_overload; + permutation.allow_duplicates = cli.allow_duplicate_scores; engine.add(permutation); // break out early here to just make 1 permutation diff --git a/permutor-cli/src/permutor_cli.rs b/permutor-cli/src/permutor_cli.rs index 643ede7..3146044 100644 --- a/permutor-cli/src/permutor_cli.rs +++ b/permutor-cli/src/permutor_cli.rs @@ -13,6 +13,9 @@ pub struct PermutorCli { /// whether to run vmaf score on each permutation or not #[arg(short, long)] pub check_quality: bool, + /// when used with check_quality, encodes that produce the same quality will still be encoded + #[arg(short, long)] + pub(crate) allow_duplicate_scores: bool, // stop an encoding session if the encoder can't keep up with the input file's FPS #[arg(short, long)] pub detect_overload: bool, @@ -51,6 +54,6 @@ impl PermutorCli { } pub fn has_special_options(&self) -> bool { - return self.check_quality || self.detect_overload || self.verbose || self.test_run; + return self.check_quality || self.detect_overload || self.verbose || self.test_run || self.allow_duplicate_scores; } } \ No newline at end of file