use crate::bindings::vtx::api::vtx_ffmpeg::{self, FfmpegOption, TranscodeProfile};
use crate::bindings::vtx::api::vtx_types::HttpResponse;
use crate::bindings::vtx::api::vtx_vfs::Buffer;
use crate::error::{VtxError, VtxResult};
pub struct TranscodeProfileBuilder {
profile: String,
input_id: String,
options: Vec<FfmpegOption>,
}
impl TranscodeProfileBuilder {
pub fn new(profile: impl Into<String>, input_id: impl Into<String>) -> Self {
Self {
profile: profile.into(),
input_id: input_id.into(),
options: Vec::new(),
}
}
pub fn new_pipe(profile: impl Into<String>) -> Self {
Self::new(profile, "pipe:0")
}
pub fn option(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.options.push(FfmpegOption {
key: key.into(),
value: Some(value.into()),
});
self
}
pub fn flag(mut self, key: impl Into<String>) -> Self {
self.options.push(FfmpegOption {
key: key.into(),
value: None,
});
self
}
pub fn options<I, K, V>(mut self, options: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
K: Into<String>,
V: Into<String>,
{
for (key, value) in options {
self.options.push(FfmpegOption {
key: key.into(),
value: Some(value.into()),
});
}
self
}
pub fn format(self, format: &str) -> Self {
self.option("f", format)
}
pub fn seek(self, start: &str, duration: Option<&str>) -> Self {
let mut s = self.option("ss", start);
if let Some(d) = duration {
s = s.option("t", d);
}
s
}
pub fn build(self) -> TranscodeProfile {
TranscodeProfile {
profile: self.profile,
input_id: self.input_id,
options: self.options,
}
}
}
pub struct FfmpegExecutor;
impl FfmpegExecutor {
pub fn execute_buffer(profile: &TranscodeProfile) -> VtxResult<Buffer> {
vtx_ffmpeg::execute(profile).map_err(VtxError::from_host_message)
}
pub fn execute(profile: &TranscodeProfile) -> VtxResult<HttpResponse> {
let buffer = Self::execute_buffer(profile)?;
Ok(HttpResponse {
status: 200,
body: Some(buffer),
})
}
}
pub struct FfmpegTask {
builder: TranscodeProfileBuilder,
}
impl FfmpegTask {
pub fn new(profile: impl Into<String>, input_id: impl Into<String>) -> Self {
Self {
builder: TranscodeProfileBuilder::new(profile, input_id),
}
}
pub fn new_pipe(profile: impl Into<String>) -> Self {
Self {
builder: TranscodeProfileBuilder::new_pipe(profile),
}
}
pub fn option(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.builder = self.builder.option(key, value);
self
}
pub fn flag(mut self, key: impl Into<String>) -> Self {
self.builder = self.builder.flag(key);
self
}
pub fn options<I, K, V>(mut self, options: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
K: Into<String>,
V: Into<String>,
{
self.builder = self.builder.options(options);
self
}
pub fn format(self, format: &str) -> Self {
self.option("f", format)
}
pub fn seek(self, start: &str, duration: Option<&str>) -> Self {
let mut s = self.option("ss", start);
if let Some(d) = duration {
s = s.option("t", d);
}
s
}
pub fn build(self) -> TranscodeProfile {
self.builder.build()
}
pub fn execute_buffer(self) -> VtxResult<Buffer> {
let profile = self.build();
FfmpegExecutor::execute_buffer(&profile)
}
pub fn execute(self) -> VtxResult<HttpResponse> {
let profile = self.build();
FfmpegExecutor::execute(&profile)
}
}