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}