Skip to main content

oxideav_core/
format.rs

1//! Media-type and sample/pixel format enumerations.
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
4pub enum MediaType {
5    Audio,
6    Video,
7    Subtitle,
8    Data,
9    Unknown,
10}
11
12/// Audio sample format.
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub enum SampleFormat {
15    /// Unsigned 8-bit, interleaved.
16    U8,
17    /// Signed 8-bit, interleaved. Native format of Amiga 8SVX and MOD samples.
18    S8,
19    /// Signed 16-bit little-endian, interleaved.
20    S16,
21    /// Signed 24-bit packed (3 bytes/sample) little-endian, interleaved.
22    S24,
23    /// Signed 32-bit little-endian, interleaved.
24    S32,
25    /// 32-bit IEEE float, interleaved.
26    F32,
27    /// 64-bit IEEE float, interleaved.
28    F64,
29    /// Planar variants — one plane per channel.
30    U8P,
31    S16P,
32    S32P,
33    F32P,
34    F64P,
35}
36
37impl SampleFormat {
38    pub fn is_planar(&self) -> bool {
39        matches!(
40            self,
41            Self::U8P | Self::S16P | Self::S32P | Self::F32P | Self::F64P
42        )
43    }
44
45    /// Bytes per sample *per channel*.
46    pub fn bytes_per_sample(&self) -> usize {
47        match self {
48            Self::U8 | Self::U8P | Self::S8 => 1,
49            Self::S16 | Self::S16P => 2,
50            Self::S24 => 3,
51            Self::S32 | Self::S32P | Self::F32 | Self::F32P => 4,
52            Self::F64 | Self::F64P => 8,
53        }
54    }
55
56    pub fn is_float(&self) -> bool {
57        matches!(self, Self::F32 | Self::F64 | Self::F32P | Self::F64P)
58    }
59}
60
61/// Video pixel format.
62///
63/// The first six variants (`Yuv420P` through `Gray8`) are the original
64/// formats produced by the early codec crates. Everything beyond that is
65/// additional surface handled by `oxideav-pixfmt` and the still-image
66/// codecs (PNG, GIF, still-JPEG). The enum is `#[non_exhaustive]` so new
67/// variants can land without breaking downstream crates — consumers that
68/// match must include a wildcard arm.
69#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
70#[non_exhaustive]
71pub enum PixelFormat {
72    /// 8-bit YUV 4:2:0, planar (Y, U, V).
73    Yuv420P,
74    /// 8-bit YUV 4:2:2, planar.
75    Yuv422P,
76    /// 8-bit YUV 4:4:4, planar.
77    Yuv444P,
78    /// Packed 8-bit RGB, 3 bytes/pixel.
79    Rgb24,
80    /// Packed 8-bit RGBA, 4 bytes/pixel.
81    Rgba,
82    /// Packed 8-bit grayscale.
83    Gray8,
84
85    // --- Palette ---
86    /// 8-bit palette indices — companion palette carried out of band.
87    Pal8,
88
89    // --- Packed RGB/BGR swizzles ---
90    /// Packed 8-bit BGR, 3 bytes/pixel.
91    Bgr24,
92    /// Packed 8-bit BGRA, 4 bytes/pixel.
93    Bgra,
94    /// Packed 8-bit ARGB, 4 bytes/pixel (alpha first).
95    Argb,
96    /// Packed 8-bit ABGR, 4 bytes/pixel.
97    Abgr,
98
99    // --- Deeper packed RGB ---
100    /// Packed 16-bit-per-channel RGB, little-endian, 6 bytes/pixel.
101    Rgb48Le,
102    /// Packed 16-bit-per-channel RGBA, little-endian, 8 bytes/pixel.
103    Rgba64Le,
104
105    // --- Grayscale deeper / partial bit depths ---
106    /// 16-bit little-endian grayscale.
107    Gray16Le,
108    /// 10-bit grayscale in a 16-bit little-endian word.
109    Gray10Le,
110    /// 12-bit grayscale in a 16-bit little-endian word.
111    Gray12Le,
112
113    // --- Higher-precision YUV ---
114    /// 10-bit YUV 4:2:0 planar, little-endian 16-bit storage.
115    Yuv420P10Le,
116    /// 10-bit YUV 4:2:2 planar, little-endian 16-bit storage.
117    Yuv422P10Le,
118    /// 10-bit YUV 4:4:4 planar, little-endian 16-bit storage.
119    Yuv444P10Le,
120    /// 12-bit YUV 4:2:0 planar, little-endian 16-bit storage.
121    Yuv420P12Le,
122
123    // --- Full-range ("J") YUV ---
124    /// JPEG/full-range YUV 4:2:0 planar.
125    YuvJ420P,
126    /// JPEG/full-range YUV 4:2:2 planar.
127    YuvJ422P,
128    /// JPEG/full-range YUV 4:4:4 planar.
129    YuvJ444P,
130
131    // --- Semi-planar YUV ---
132    /// YUV 4:2:0, planar Y + interleaved UV (NV12).
133    Nv12,
134    /// YUV 4:2:0, planar Y + interleaved VU (NV21).
135    Nv21,
136
137    // --- Gray + alpha / YUV + alpha ---
138    /// Packed grayscale + alpha, 2 bytes/pixel (Y, A).
139    Ya8,
140    /// Yuv420P with an additional full-resolution alpha plane.
141    Yuva420P,
142
143    // --- Mono (1 bit per pixel) ---
144    /// 1 bit per pixel, packed MSB-first, 0 = black.
145    MonoBlack,
146    /// 1 bit per pixel, packed MSB-first, 0 = white.
147    MonoWhite,
148
149    // --- Interleaved YUV 4:2:2 ---
150    /// Packed 4:2:2, byte order Y0 U0 Y1 V0.
151    Yuyv422,
152    /// Packed 4:2:2, byte order U0 Y0 V0 Y1.
153    Uyvy422,
154
155    // --- Print / prepress ---
156    /// Packed 8-bit CMYK, 4 bytes/pixel in byte order C, M, Y, K.
157    /// "Regular" convention: C=0 means no cyan ink (white), C=255 means
158    /// full cyan. Used by JPEG 4-component scans from non-Adobe encoders
159    /// and by many print-side image toolchains. Adobe Photoshop's
160    /// inverted CMYK (where 0 = full ink) is a separate variant reserved
161    /// for a future `CmykInverted`.
162    Cmyk,
163}
164
165impl PixelFormat {
166    /// True if this format stores its components in separate planes.
167    pub fn is_planar(&self) -> bool {
168        matches!(
169            self,
170            Self::Yuv420P
171                | Self::Yuv422P
172                | Self::Yuv444P
173                | Self::Yuv420P10Le
174                | Self::Yuv422P10Le
175                | Self::Yuv444P10Le
176                | Self::Yuv420P12Le
177                | Self::YuvJ420P
178                | Self::YuvJ422P
179                | Self::YuvJ444P
180                | Self::Nv12
181                | Self::Nv21
182                | Self::Yuva420P
183        )
184    }
185
186    /// True if the format is a palette index format (`Pal8`).
187    pub fn is_palette(&self) -> bool {
188        matches!(self, Self::Pal8)
189    }
190
191    /// True if this format carries an alpha channel.
192    pub fn has_alpha(&self) -> bool {
193        matches!(
194            self,
195            Self::Rgba
196                | Self::Bgra
197                | Self::Argb
198                | Self::Abgr
199                | Self::Rgba64Le
200                | Self::Ya8
201                | Self::Yuva420P
202        )
203    }
204
205    /// Number of planes in the stored layout. Packed and palette formats
206    /// return 1; NV12/NV21 return 2; planar YUV without alpha returns 3;
207    /// YuvA variants return 4.
208    pub fn plane_count(&self) -> usize {
209        match self {
210            Self::Nv12 | Self::Nv21 => 2,
211            Self::Yuv420P
212            | Self::Yuv422P
213            | Self::Yuv444P
214            | Self::Yuv420P10Le
215            | Self::Yuv422P10Le
216            | Self::Yuv444P10Le
217            | Self::Yuv420P12Le
218            | Self::YuvJ420P
219            | Self::YuvJ422P
220            | Self::YuvJ444P => 3,
221            Self::Yuva420P => 4,
222            _ => 1,
223        }
224    }
225
226    /// Rough bits-per-pixel estimate, useful for buffer sizing. Not exact
227    /// for chroma-subsampled YUV — intended for worst-case preallocation
228    /// rather than wire-accurate accounting.
229    pub fn bits_per_pixel_approx(&self) -> u32 {
230        match self {
231            Self::MonoBlack | Self::MonoWhite => 1,
232            Self::Gray8 | Self::Pal8 => 8,
233            Self::Ya8 => 16,
234            Self::Gray16Le | Self::Gray10Le | Self::Gray12Le => 16,
235            Self::Rgb24 | Self::Bgr24 => 24,
236            Self::Rgba | Self::Bgra | Self::Argb | Self::Abgr => 32,
237            Self::Rgb48Le => 48,
238            Self::Rgba64Le => 64,
239            Self::Yuyv422 | Self::Uyvy422 => 16,
240            Self::Cmyk => 32,
241            // Planar YUV: 4:2:0 ≈ 12, 4:2:2 ≈ 16, 4:4:4 ≈ 24
242            // 10/12-bit variants double the byte count but we report the
243            // packed-bits-per-pixel estimate for a uniform heuristic.
244            Self::Yuv420P | Self::YuvJ420P | Self::Nv12 | Self::Nv21 => 12,
245            Self::Yuv422P | Self::YuvJ422P => 16,
246            Self::Yuv444P | Self::YuvJ444P => 24,
247            Self::Yuv420P10Le | Self::Yuv420P12Le => 24,
248            Self::Yuv422P10Le => 32,
249            Self::Yuv444P10Le => 48,
250            Self::Yuva420P => 20,
251        }
252    }
253}