vtx_sdk/modules/media/
ffmpeg.rs1use crate::bindings::vtx::api::vtx_ffmpeg::{self, FfmpegOption, TranscodeProfile};
4use crate::bindings::vtx::api::vtx_types::HttpResponse;
5use crate::bindings::vtx::api::vtx_vfs::Buffer;
6use crate::error::{VtxError, VtxResult};
7
8pub struct TranscodeProfileBuilder {
12 profile: String,
13 input_id: String,
14 options: Vec<FfmpegOption>,
15}
16
17impl TranscodeProfileBuilder {
18 pub fn new(profile: impl Into<String>, input_id: impl Into<String>) -> Self {
23 Self {
24 profile: profile.into(),
25 input_id: input_id.into(),
26 options: Vec::new(),
27 }
28 }
29
30 pub fn new_pipe(profile: impl Into<String>) -> Self {
32 Self::new(profile, "pipe:0")
33 }
34
35 pub fn option(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
37 self.options.push(FfmpegOption {
38 key: key.into(),
39 value: Some(value.into()),
40 });
41 self
42 }
43
44 pub fn flag(mut self, key: impl Into<String>) -> Self {
46 self.options.push(FfmpegOption {
47 key: key.into(),
48 value: None,
49 });
50 self
51 }
52
53 pub fn options<I, K, V>(mut self, options: I) -> Self
55 where
56 I: IntoIterator<Item = (K, V)>,
57 K: Into<String>,
58 V: Into<String>,
59 {
60 for (key, value) in options {
61 self.options.push(FfmpegOption {
62 key: key.into(),
63 value: Some(value.into()),
64 });
65 }
66 self
67 }
68
69 pub fn format(self, format: &str) -> Self {
71 self.option("f", format)
72 }
73
74 pub fn seek(self, start: &str, duration: Option<&str>) -> Self {
76 let mut s = self.option("ss", start);
77 if let Some(d) = duration {
78 s = s.option("t", d);
79 }
80 s
81 }
82
83 pub fn build(self) -> TranscodeProfile {
85 TranscodeProfile {
86 profile: self.profile,
87 input_id: self.input_id,
88 options: self.options,
89 }
90 }
91}
92
93pub struct FfmpegExecutor;
95
96impl FfmpegExecutor {
97 pub fn execute_buffer(profile: &TranscodeProfile) -> VtxResult<Buffer> {
99 vtx_ffmpeg::execute(profile).map_err(VtxError::from_host_message)
100 }
101
102 pub fn execute(profile: &TranscodeProfile) -> VtxResult<HttpResponse> {
104 let buffer = Self::execute_buffer(profile)?;
105 Ok(HttpResponse {
106 status: 200,
107 body: Some(buffer),
108 })
109 }
110}
111
112pub struct FfmpegTask {
127 builder: TranscodeProfileBuilder,
128}
129
130impl FfmpegTask {
131 pub fn new(profile: impl Into<String>, input_id: impl Into<String>) -> Self {
136 Self {
137 builder: TranscodeProfileBuilder::new(profile, input_id),
138 }
139 }
140
141 pub fn new_pipe(profile: impl Into<String>) -> Self {
143 Self {
144 builder: TranscodeProfileBuilder::new_pipe(profile),
145 }
146 }
147
148 pub fn option(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
150 self.builder = self.builder.option(key, value);
151 self
152 }
153
154 pub fn flag(mut self, key: impl Into<String>) -> Self {
156 self.builder = self.builder.flag(key);
157 self
158 }
159
160 pub fn options<I, K, V>(mut self, options: I) -> Self
162 where
163 I: IntoIterator<Item = (K, V)>,
164 K: Into<String>,
165 V: Into<String>,
166 {
167 self.builder = self.builder.options(options);
168 self
169 }
170
171 pub fn format(self, format: &str) -> Self {
173 self.option("f", format)
174 }
175
176 pub fn seek(self, start: &str, duration: Option<&str>) -> Self {
178 let mut s = self.option("ss", start);
179 if let Some(d) = duration {
180 s = s.option("t", d);
181 }
182 s
183 }
184
185 pub fn build(self) -> TranscodeProfile {
187 self.builder.build()
188 }
189
190 pub fn execute_buffer(self) -> VtxResult<Buffer> {
194 let profile = self.build();
195 FfmpegExecutor::execute_buffer(&profile)
196 }
197
198 pub fn execute(self) -> VtxResult<HttpResponse> {
202 let profile = self.build();
203 FfmpegExecutor::execute(&profile)
204 }
205}