use crate::{
Declined, DecodeError, DecodeOptions, DecodedFrame, Decoder, Frame, FramePixels, FrameReader,
ImageInfo, OpenError, OpenRequest,
};
use std::sync::Arc;
use std::time::Duration;
use valo::{Image, ImageContext};
pub(crate) struct Decoded {
pixels: FramePixels,
expected: [u32; 2],
duration: Duration,
}
pub(crate) struct DecodeService {
images: ImageContext,
decoders: Vec<Box<dyn Decoder>>,
}
impl DecodeService {
pub(crate) fn new(images: ImageContext, decoders: Vec<Box<dyn Decoder>>) -> Self {
Self { images, decoders }
}
pub(crate) async fn open(
&self,
encoded: Arc<[u8]>,
options: DecodeOptions,
) -> Result<Box<dyn FrameReader>, DecodeError> {
self.check_input(&encoded, options)?;
let request = OpenRequest {
encoded,
options,
device: self.images.device().clone(),
};
let reader = self.first_accepting_decoder(&request).await?;
self.check_info(reader.info(), options)?;
Ok(reader)
}
pub(crate) async fn decode_still(
&self,
encoded: Arc<[u8]>,
options: DecodeOptions,
) -> Result<Image, DecodeError> {
let decoded = self.decode_still_frame(encoded, options).await?;
Ok(self.finish(decoded, options.mipmaps)?.image)
}
pub(crate) async fn decode_still_frame(
&self,
encoded: Arc<[u8]>,
options: DecodeOptions,
) -> Result<Decoded, DecodeError> {
let mut reader = self.open(encoded, options).await?;
self.read_frame(reader.as_mut()).await
}
pub(crate) async fn next_frame(
&self,
reader: &mut dyn FrameReader,
mipmaps: bool,
) -> Result<Frame, DecodeError> {
let decoded = self.read_frame(reader).await?;
self.finish(decoded, mipmaps)
}
pub(crate) async fn read_frame(
&self,
reader: &mut dyn FrameReader,
) -> Result<Decoded, DecodeError> {
let expected = reader.info().size;
let DecodedFrame { pixels, duration } = reader.next_frame().await?;
Ok(Decoded {
pixels,
expected,
duration,
})
}
pub(crate) fn finish(&self, decoded: Decoded, mipmaps: bool) -> Result<Frame, DecodeError> {
let Decoded {
pixels,
expected,
duration,
} = decoded;
let image = self.make_image(pixels, mipmaps)?;
if image.size() != expected {
return Err(DecodeError::InvalidData(
"frame size differs from the image header".into(),
));
}
Ok(Frame { image, duration })
}
fn make_image(&self, pixels: FramePixels, mipmaps: bool) -> Result<Image, DecodeError> {
let image = match pixels {
FramePixels::Cpu(buffer) => self.images.upload_pixels(buffer, mipmaps)?,
FramePixels::Gpu(texture) => self.images.import_texture(texture, mipmaps)?,
};
Ok(image)
}
fn check_input(&self, encoded: &[u8], options: DecodeOptions) -> Result<(), DecodeError> {
if self.decoders.is_empty() {
return Err(DecodeError::NoDecoder);
}
if encoded.is_empty() {
return Err(DecodeError::InvalidData("empty encoded image".into()));
}
if encoded.len() > options.limits.max_encoded_bytes {
return Err(DecodeError::LimitExceeded("encoded bytes"));
}
Ok(())
}
fn check_info(&self, info: ImageInfo, options: DecodeOptions) -> Result<(), DecodeError> {
options.limits.check_frame_count(info.frame_count)?;
options.limits.check_source_size(info.size)?;
self.images.check_size(info.size)?;
Ok(())
}
async fn first_accepting_decoder(
&self,
request: &OpenRequest,
) -> Result<Box<dyn FrameReader>, DecodeError> {
let mut declined = Vec::new();
for decoder in &self.decoders {
match decoder.open(request).await {
Ok(reader) => return Ok(reader),
Err(OpenError::Unsupported(reason)) => declined.push(Declined {
decoder: decoder.name(),
reason,
}),
Err(OpenError::Failed(error)) => return Err(error),
}
}
Err(DecodeError::Unsupported(declined))
}
}