1use std::io::Cursor;
2
3use jpeg_decoder::{Decoder, PixelFormat};
4use styx_core::prelude::*;
5
6#[cfg(feature = "image")]
7use crate::decoder::{ImageDecode, process_to_dynamic};
8use crate::{Codec, CodecDescriptor, CodecError, CodecKind};
9
10pub struct MjpegDecoder {
12 descriptor: CodecDescriptor,
13 pool: BufferPool,
14}
15
16impl MjpegDecoder {
17 pub fn new(output: FourCc) -> Self {
19 Self::with_pool(output, BufferPool::with_limits(2, 1 << 20, 4))
20 }
21
22 pub fn new_for_input(input: FourCc, output: FourCc) -> Self {
24 Self::with_pool_for_input(input, output, BufferPool::with_limits(2, 1 << 20, 4))
25 }
26
27 pub fn with_pool(output: FourCc, pool: BufferPool) -> Self {
29 Self::with_pool_for_input(FourCc::new(*b"MJPG"), output, pool)
30 }
31
32 pub fn with_pool_for_input(input: FourCc, output: FourCc, pool: BufferPool) -> Self {
34 Self {
35 descriptor: CodecDescriptor {
36 kind: CodecKind::Decoder,
37 input,
38 output,
39 name: "mjpeg",
40 impl_name: "jpeg-decoder",
41 },
42 pool,
43 }
44 }
45}
46
47impl Codec for MjpegDecoder {
48 fn descriptor(&self) -> &CodecDescriptor {
49 &self.descriptor
50 }
51
52 fn process(&self, input: FrameLease) -> Result<FrameLease, CodecError> {
53 if input.meta().format.code != self.descriptor.input {
54 return Err(CodecError::FormatMismatch {
55 expected: self.descriptor.input,
56 actual: input.meta().format.code,
57 });
58 }
59
60 let plane = input
61 .planes()
62 .into_iter()
63 .next()
64 .ok_or_else(|| CodecError::Codec("mjpeg frame missing plane".into()))?;
65
66 let mut decoder = Decoder::new(Cursor::new(plane.data()));
67 let pixels = decoder
68 .decode()
69 .map_err(|e| CodecError::Codec(e.to_string()))?;
70 let info = decoder
71 .info()
72 .ok_or_else(|| CodecError::Codec("mjpeg missing info".into()))?;
73
74 if info.pixel_format != PixelFormat::RGB24 {
75 return Err(CodecError::Codec(format!(
76 "unsupported MJPEG pixel format {:?}",
77 info.pixel_format
78 )));
79 }
80
81 let resolution = Resolution::new(info.width as u32, info.height as u32)
82 .ok_or_else(|| CodecError::Codec("invalid jpeg resolution".into()))?;
83 let format = MediaFormat::new(
84 self.descriptor.output,
85 resolution,
86 input.meta().format.color,
87 );
88 let layout = plane_layout_from_dims(resolution.width, resolution.height, 3);
89
90 let mut buf = self.pool.lease();
91 buf.resize(layout.len);
92 let copy_len = pixels.len().min(layout.len);
93 buf.as_mut_slice()[..copy_len].copy_from_slice(&pixels[..copy_len]);
94
95 Ok(FrameLease::single_plane(
96 FrameMeta::new(format, input.meta().timestamp),
97 buf,
98 layout.len,
99 layout.stride,
100 ))
101 }
102}
103
104#[cfg(feature = "image")]
105impl ImageDecode for MjpegDecoder {
106 fn decode_image(&self, frame: FrameLease) -> Result<image::DynamicImage, CodecError> {
107 process_to_dynamic(self, frame)
108 }
109}