Skip to main content

ffcli/
args.rs

1use super::*;
2use log::Level;
3
4pub enum FFmpegDefaultArgs {
5    None,
6    Quiet,
7    General,
8}
9
10pub struct FFmpegArgs {
11    default_args: Option<FFmpegDefaultArgs>,
12    filters: Vec<VideoFilter>,
13    log_level: Level,
14    params: Vec<String>,
15}
16
17impl FFmpegArgs {
18    pub fn new(log_level: Level) -> Self {
19        FFmpegArgs {
20            default_args: Some(FFmpegDefaultArgs::General),
21            log_level,
22            filters: Vec::new(),
23            params: Vec::new(),
24        }
25    }
26
27    fn append_params<T>(mut self, param: T) -> Self
28    where
29        T: ToString,
30    {
31        self.params.push(param.to_string());
32        self
33    }
34
35    pub fn default_args(mut self, default_args: Option<FFmpegDefaultArgs>) -> Self {
36        self.default_args = default_args;
37        self
38    }
39
40    pub fn attach<T>(self, format: T) -> Self
41    where
42        T: ToString,
43    {
44        self.append_params("-attach").append_params(format)
45    }
46
47    pub fn c<F, P>(self, format: F, prefix: P) -> Self
48    where
49        F: ToString,
50        P: ToString,
51    {
52        let prefix = prefix.to_string();
53        if !prefix.is_empty() {
54            self.append_params(format!("-c:{}", prefix))
55        } else {
56            self.append_params("-c")
57        }
58        .append_params(format)
59    }
60
61    pub fn dump_attachment<P, O>(self, prefix: P, output: O) -> Self
62    where
63        P: ToString,
64        O: ToString,
65    {
66        self.append_params(format!("-dump_attachment:{}", prefix.to_string()))
67            .append_params(output)
68    }
69
70    pub fn f<T>(self, format: T) -> Self
71    where
72        T: ToString,
73    {
74        self.append_params("-f").append_params(format)
75    }
76
77    pub fn fflags<T>(self, param: T) -> Self
78    where
79        T: ToString,
80    {
81        self.append_params("-fflags").append_params(param)
82    }
83
84    pub fn flags<P1, P2>(self, prefix: P1, param: P2) -> Self
85    where
86        P1: ToString,
87        P2: ToString,
88    {
89        self.append_params(format!("-flags:{}", prefix.to_string()))
90            .append_params(param)
91    }
92
93    pub fn framerate<T>(self, fps: T) -> Self
94    where
95        T: ToString,
96    {
97        self.append_params("-framerate").append_params(fps)
98    }
99
100    pub fn i<T>(self, input: T) -> Self
101    where
102        T: ToString,
103    {
104        self.append_params("-i").append_params(input)
105    }
106
107    pub fn map<T>(self, map: T) -> Self
108    where
109        T: ToString,
110    {
111        self.append_params("-map").append_params(map)
112    }
113
114    pub fn map_metadata<T>(self, map_metadata: T) -> Self
115    where
116        T: ToString,
117    {
118        self.append_params("-map_metadata")
119            .append_params(map_metadata)
120    }
121
122    pub fn metadata<P1, P2>(self, prefix: Option<P1>, param: P2) -> Self
123    where
124        P1: ToString,
125        P2: ToString,
126    {
127        self.append_params(if let Some(prefix) = prefix {
128            format!("-metadata:{}", prefix.to_string())
129        } else {
130            "-metadata".to_string()
131        })
132        .append_params(param)
133    }
134
135    pub fn profile<T>(self, profile: T) -> Self
136    where
137        T: ToString,
138    {
139        self.append_params("-profile").append_params(profile)
140    }
141
142    pub fn q<T>(self, q: T) -> Self
143    where
144        T: ToString,
145    {
146        self.append_params("-q").append_params(q)
147    }
148
149    pub fn raw<T>(self, raw_param: T) -> Self
150    where
151        T: ToString,
152    {
153        self.append_params(raw_param)
154    }
155
156    pub fn vcodec<T>(self, vcodec: T) -> Self
157    where
158        T: ToString,
159    {
160        self.append_params("-vcodec").append_params(vcodec)
161    }
162
163    pub fn vsync<T>(self, param: T) -> Self
164    where
165        T: ToString,
166    {
167        self.append_params("-vsync").append_params(param)
168    }
169
170    pub fn preset(self, preset: VideoPreset) -> Self {
171        self.append_params("-preset").append_params(preset)
172    }
173
174    pub fn vf(mut self, vf: VideoFilter) -> Self {
175        self.filters.push(vf);
176        self
177    }
178
179    fn clear_filter(mut self) -> Self {
180        self.filters.clear();
181        self
182    }
183
184    pub fn build_filter(self) -> Self {
185        if !self.filters.is_empty() {
186            let filters = &self.filters.clone();
187            match self.filters.len() {
188                1 => if self.filters[0].get_inputs().len() > 1
189                    || self.filters[0].get_outputs().len() > 1
190                {
191                    self.append_params("-filter_complex")
192                } else {
193                    self.append_params("-vf")
194                }
195                .append_params(filters[0].clone()),
196                _ => self.append_params("-filter_complex").append_params(
197                    filters
198                        .iter()
199                        .map(ToString::to_string)
200                        .collect::<Vec<_>>()
201                        .join(";"),
202                ),
203            }
204            .clear_filter()
205        } else {
206            self
207        }
208    }
209
210    pub fn build(self) -> Vec<String> {
211        let mut args = vec!["-hide_banner", "-y"];
212        args.append(&mut match self.default_args {
213            Some(FFmpegDefaultArgs::None) => vec!["-loglevel", "quiet"],
214            Some(FFmpegDefaultArgs::Quiet) => vec![
215                "-loglevel",
216                if self.log_level > Level::Info {
217                    "warning"
218                } else {
219                    "error"
220                },
221            ],
222            Some(FFmpegDefaultArgs::General) => vec![
223                "-loglevel",
224                if self.log_level > Level::Info {
225                    "warning"
226                } else {
227                    "error"
228                },
229                "-stats",
230            ],
231            None => vec![],
232        });
233        args.append(&mut self.params.iter().map(AsRef::as_ref).collect());
234        args.iter().map(ToString::to_string).collect::<Vec<_>>()
235    }
236}