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 ! ( "\n Run 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 ! ( "\n Choose 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