use anyhow::Result;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use super::common::EncodedMediaData;
use super::rdma::DecodedMediaData;
pub mod image;
#[cfg(feature = "media-ffmpeg")]
pub mod video;
pub use image::{ImageDecoder, ImageMetadata};
#[cfg(feature = "media-ffmpeg")]
pub use video::{VideoDecoder, VideoMetadata};
#[async_trait::async_trait]
pub trait Decoder: Clone + Send + 'static {
fn decode(&self, data: EncodedMediaData) -> Result<DecodedMediaData>;
fn with_runtime(&self, runtime: Option<&Self>) -> Self;
async fn decode_async(&self, data: EncodedMediaData) -> Result<DecodedMediaData> {
self.decode_async_with_video_hash(data, false).await
}
async fn decode_async_with_video_hash(
&self,
data: EncodedMediaData,
hash_video: bool,
) -> Result<DecodedMediaData> {
let decoder = self.clone();
let result = tokio_rayon::spawn(move || {
let mut decoded = decoder.decode(data)?;
decoded.compute_content_hash(hash_video);
Ok::<_, anyhow::Error>(decoded)
})
.await?;
Ok(result)
}
}
#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct MediaDecoder {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub image: Option<ImageDecoder>,
#[cfg(feature = "media-ffmpeg")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub video: Option<VideoDecoder>,
}
impl MediaDecoder {
pub(crate) fn warn_if_unavailable_backends(&self) {
if let Some(image) = &self.image {
image.warn_if_libjpeg_unavailable();
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum DecodedMediaMetadata {
Image(ImageMetadata),
#[cfg(feature = "media-ffmpeg")]
Video(VideoMetadata),
}