use super::media::MediaData;
use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VideoData {
pub base64_data: String,
pub format: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_secs: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub width: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub height: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub frame_rate: Option<f32>,
}
impl MediaData for VideoData {
fn base64_data(&self) -> &str {
&self.base64_data
}
fn format_id(&self) -> &str {
&self.format
}
fn mime_type(&self) -> String {
match self.format.as_str() {
"mp4" => "video/mp4",
"webm" => "video/webm",
"mov" => "video/quicktime",
"avi" => "video/x-msvideo",
"mkv" => "video/x-matroska",
"flv" => "video/x-flv",
"wmv" => "video/x-ms-wmv",
"m4v" => "video/x-m4v",
"3gp" => "video/3gpp",
"ogv" => "video/ogg",
_ => "video/mp4",
}
.to_string()
}
fn from_base64(base64_data: impl Into<String>, format: impl Into<String>) -> Self {
Self {
base64_data: base64_data.into(),
format: format.into(),
duration_secs: None,
width: None,
height: None,
frame_rate: None,
}
}
fn guess_format(path: &Path) -> String {
path.extension()
.and_then(|e| e.to_str())
.unwrap_or("mp4")
.to_lowercase()
}
}
impl VideoData {
pub fn from_base64(base64_data: impl Into<String>, format: impl Into<String>) -> Self {
<Self as MediaData>::from_base64(base64_data, format)
}
pub fn from_bytes(bytes: &[u8], format: impl Into<String>) -> Self {
<Self as MediaData>::from_bytes(bytes, format)
}
pub fn from_file(path: impl AsRef<Path>) -> crate::error::Result<Self> {
<Self as MediaData>::from_file(path)
}
pub async fn from_file_async(path: impl AsRef<Path> + Send) -> crate::error::Result<Self> {
<Self as MediaData>::from_file_async(path).await
}
pub fn from_url(url: impl Into<String>) -> Self {
Self {
base64_data: url.into(),
format: "url".to_string(),
duration_secs: None,
width: None,
height: None,
frame_rate: None,
}
}
pub fn with_duration(mut self, duration_secs: f64) -> Self {
self.duration_secs = Some(duration_secs);
self
}
pub fn with_dimensions(mut self, width: u32, height: u32) -> Self {
self.width = Some(width);
self.height = Some(height);
self
}
pub fn with_frame_rate(mut self, frame_rate: f32) -> Self {
self.frame_rate = Some(frame_rate);
self
}
pub fn to_bytes(&self) -> crate::error::Result<Vec<u8>> {
Ok(BASE64.decode(&self.base64_data)?)
}
pub fn mime_type(&self) -> String {
<Self as MediaData>::mime_type(self)
}
pub fn to_data_url(&self) -> String {
if self.format == "url" {
self.base64_data.clone()
} else {
format!("data:{};base64,{}", self.mime_type(), self.base64_data)
}
}
}