Skip to content

Commit c545d2f

Browse files
committed
Split of benchmark and permutation engines
1 parent 9492290 commit c545d2f

45 files changed

Lines changed: 2171 additions & 695 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Generated by Cargo
22
# will have compiled files and executables
3-
/target/
3+
target/
44

55
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
66
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
@@ -21,3 +21,7 @@ Cargo.lock
2121
*.pdb
2222
*.log
2323
/results.txt
24+
/old/
25+
26+
# ignore the on-the-fly font file embedded in the executable
27+
tmp.flf

Cargo.toml

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
1-
[package]
2-
name = "encoder_benchmark_tool"
3-
version = "0.1.0"
4-
edition = "2021"
1+
[workspace]
52

6-
[dependencies]
7-
clap = { version = "4.0.32", features = ["derive"] }
8-
compound_duration = "1.2.0"
9-
crossbeam-channel = "0.5.6"
10-
ctrlc = "3.2.4"
11-
filetime = "0.2.19"
12-
indicatif = "0.17.2"
13-
itertools = "0.10.5"
14-
num_cpus = "1.15.0"
15-
regex = "1.7.0"
16-
rev_buf_reader = "0.3.0"
17-
stoppable_thread = "0.2.1"
3+
members = [
4+
"benchmark",
5+
"engine",
6+
"environment",
7+
"ffmpeg",
8+
"permutation",
9+
"permutor",
10+
"cli"
11+
]

benchmark/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "benchmark"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
clap = { version = "4.0.32", features = ["derive"] }
8+
figlet-rs = "0.1.5"
9+
text_io = "0.1.12"
10+
dont_disappear = "3.0.1"
11+
environment = { path = "../environment" }
12+
permutation = { path = "../permutation" }
13+
engine = { path = "../engine" }
14+
ffmpeg = { path = "../ffmpeg" }
15+
cli = { path = "../cli" }

benchmark/src/benchmark_cli.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use clap::Parser;
2+
3+
use cli::cli_util::{are_all_source_files_present, error_with_ack, standard_cli_check};
4+
use cli::supported::{get_download_url, get_supported_inputs};
5+
6+
#[derive(Parser)]
7+
pub struct BenchmarkCli {
8+
/// lists the supported/implemented supported that this tool supports
9+
#[arg(short, long)]
10+
pub list_supported_encoders: bool,
11+
/// the encoder you wish to benchmark: [h264_nvenc, hevc_nvenc, etc]
12+
#[arg(short, long, value_name = "encoder_name", default_value = "encoder")]
13+
pub encoder: String,
14+
/// the source file you wish to benchmark; if not provided, will run standard benchmark on all supported resolutions
15+
#[arg(short, long, value_name = "source.y4m", default_value = "")]
16+
pub source_file: String,
17+
/// logs useful information to help troubleshooting
18+
#[arg(short, long)]
19+
pub verbose: bool,
20+
was_ui_opened: bool,
21+
}
22+
23+
impl BenchmarkCli {
24+
pub fn set_ui_opened(&mut self) {
25+
self.was_ui_opened = true;
26+
}
27+
28+
// used when taking user input for the benchmark
29+
pub fn new() -> Self {
30+
return Self {
31+
list_supported_encoders: false,
32+
encoder: String::from(""),
33+
source_file: String::from(""),
34+
verbose: false,
35+
was_ui_opened: false,
36+
};
37+
}
38+
39+
pub fn validate(&mut self) {
40+
standard_cli_check(self.list_supported_encoders, &self.encoder, &self.source_file, self.was_ui_opened);
41+
42+
// if you did not provide a source file, we'll be running on all expected files
43+
if self.source_file.is_empty() && !are_all_source_files_present() {
44+
println!("You're missing some video source files to run the standard benchmark; you should have the following: \n{:?}", get_supported_inputs());
45+
println!("Please download the ones you are missing from: {}", get_download_url());
46+
println!("If you want to run the tool against a specific resolution/fps, download just that source file and specify it with '-s'");
47+
error_with_ack(self.was_ui_opened);
48+
}
49+
}
50+
}

benchmark/src/main.rs

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
use std::{env, fs};
2+
use std::fs::File;
3+
use std::io::Write;
4+
5+
use clap::Parser;
6+
use figlet_rs::FIGfont;
7+
use text_io::read;
8+
9+
use cli::cli_util::{is_dev, pause};
10+
use cli::supported::{get_supported_encoders, get_supported_inputs};
11+
use engine::benchmark_engine::BenchmarkEngine;
12+
use engine::h264_hevc_nvenc::Nvenc;
13+
use engine::permute::Permute;
14+
use ffmpeg::metadata::MetaData;
15+
use permutation::permutation::Permutation;
16+
17+
use crate::benchmark_cli::BenchmarkCli;
18+
19+
mod benchmark_cli;
20+
21+
fn main() {
22+
let small_font = include_str!("small.flf");
23+
24+
fig_title(String::from("Encoder-Benchmark"), String::from(small_font));
25+
let mut cli = BenchmarkCli::new();
26+
27+
// if no args were provided, they will be prompted from the user
28+
// this works for both cli running as well as just clicking the executable
29+
let args: Vec<String> = env::args().collect();
30+
if args.len() == 1 {
31+
read_user_input(&mut cli);
32+
cli.set_ui_opened();
33+
} else {
34+
cli = BenchmarkCli::parse();
35+
}
36+
37+
cli.validate();
38+
39+
let input_files = get_input_files(cli.source_file);
40+
let mut engine = BenchmarkEngine::new();
41+
let nvenc = Nvenc::new(cli.encoder == "hevc_nvenc");
42+
43+
// prepare permutations for the engine to run over
44+
for input in input_files {
45+
let mut permutation = Permutation::new(input, cli.encoder.clone());
46+
let settings = get_settings_for(&nvenc);
47+
let bitrate = get_bitrate_for(&permutation.get_metadata());
48+
49+
permutation.bitrate = bitrate;
50+
permutation.encoder_settings = settings;
51+
engine.add(permutation);
52+
}
53+
54+
engine.run();
55+
pause();
56+
}
57+
58+
fn read_user_input(cli: &mut BenchmarkCli) {
59+
loop {
60+
print_options(get_supported_encoders().to_vec());
61+
print!("Choose encoder [0-{}]: ", get_supported_encoders().len() - 1);
62+
let input: String = read!("{}");
63+
64+
if !is_numeric(&input) {
65+
println!("Invalid input, try again...")
66+
} else {
67+
let value: usize = input.parse().unwrap();
68+
69+
if value >= get_supported_encoders().len() {
70+
println!("Invalid input, try again...");
71+
} else {
72+
cli.encoder = String::from(get_supported_encoders()[value]);
73+
break;
74+
}
75+
}
76+
}
77+
78+
let mut full_bench = false;
79+
loop {
80+
print!("\nRun full benchmark? [y/n]: ");
81+
let full: String = read!("{}");
82+
if full != "n" && full != "y" {
83+
println!("Invalid input, try again...");
84+
} else {
85+
if full == "y" {
86+
full_bench = true;
87+
}
88+
89+
break;
90+
}
91+
}
92+
93+
if !full_bench {
94+
loop {
95+
print_options(get_supported_inputs().to_vec());
96+
print!("\nChoose video file to encode [0-{}]: ", get_supported_inputs().len() - 1);
97+
let input: String = read!("{}");
98+
if !is_numeric(&input) {
99+
println!("Invalid input, try again...");
100+
} else {
101+
let value: usize = input.parse().unwrap();
102+
if value >= get_supported_inputs().len() {
103+
println!("Invalid input, try again...");
104+
} else {
105+
cli.source_file = String::from(get_supported_inputs()[value]);
106+
break;
107+
}
108+
}
109+
}
110+
}
111+
112+
println!();
113+
}
114+
115+
fn is_numeric(input: &String) -> bool {
116+
return input.chars().all(char::is_numeric);
117+
}
118+
119+
fn print_options(input_vec: Vec<&str>) {
120+
for i in 0..input_vec.len() {
121+
println!("[{}] - {}", i, input_vec[i]);
122+
}
123+
}
124+
125+
fn get_settings_for(nvenc: &Nvenc) -> String {
126+
// need to support other encoders here
127+
return nvenc.get_benchmark_settings();
128+
}
129+
130+
fn get_bitrate_for(metadata: &MetaData) -> u32 {
131+
// need to support other encoders here
132+
return *Nvenc::get_resolution_to_bitrate_map(metadata.fps).get(&metadata.get_res()).unwrap();
133+
}
134+
135+
fn get_input_files(source_file: String) -> Vec<String> {
136+
if source_file.is_empty() {
137+
return get_supported_inputs()
138+
.iter()
139+
.map(|s| map_file(is_dev(), s))
140+
.collect::<Vec<String>>();
141+
}
142+
143+
return vec![source_file];
144+
}
145+
146+
fn map_file(is_dev: bool, s: &&str) -> String {
147+
let mut file = String::new();
148+
if is_dev {
149+
file.push_str("../");
150+
file.push_str(*s);
151+
} else {
152+
file.push_str(*s);
153+
}
154+
155+
return file;
156+
}
157+
158+
fn fig_title(msg: String, small_font_content: String) {
159+
let small_font_file_name = "tmp.flf";
160+
161+
// create the font file to use, then delete it
162+
let mut tmp_font_file = File::create(small_font_file_name).unwrap();
163+
write!(&mut tmp_font_file, "{}", small_font_content).unwrap();
164+
165+
let small_font = FIGfont::from_file(small_font_file_name).unwrap();
166+
let figure = small_font.convert(msg.as_str());
167+
assert!(figure.is_some());
168+
println!("{}\n", figure.unwrap());
169+
println!("Version v0.0.1-alpha");
170+
println!("Source code: https://github.com/Proryanator/encoder-benchmark\n");
171+
172+
fs::remove_file(small_font_file_name).expect("Not able to delete tmp file");
173+
}

0 commit comments

Comments
 (0)