yuvutils_rs/
images.rs

1/*
2 * Copyright (c) Radzivon Bartoshyk, 11/2024. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1.  Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * 2.  Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * 3.  Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29use crate::yuv_error::{
30    check_chroma_channel, check_interleaved_chroma_channel, check_rgba_destination,
31    check_y8_channel, check_yuv_packed422,
32};
33use crate::yuv_support::YuvChromaSubsampling;
34use crate::YuvError;
35use std::fmt::Debug;
36
37#[derive(Debug)]
38/// Shared storage type
39pub enum BufferStoreMut<'a, T: Copy + Debug> {
40    Borrowed(&'a mut [T]),
41    Owned(Vec<T>),
42}
43
44impl<T: Copy + Debug> BufferStoreMut<'_, T> {
45    #[allow(clippy::should_implement_trait)]
46    pub fn borrow(&self) -> &[T] {
47        match self {
48            Self::Borrowed(p_ref) => p_ref,
49            Self::Owned(vec) => vec,
50        }
51    }
52
53    #[allow(clippy::should_implement_trait)]
54    pub fn borrow_mut(&mut self) -> &mut [T] {
55        match self {
56            Self::Borrowed(p_ref) => p_ref,
57            Self::Owned(vec) => vec,
58        }
59    }
60}
61
62#[derive(Debug, Clone)]
63/// Non-mutable representation of Bi-Planar YUV image
64pub struct YuvBiPlanarImage<'a, T>
65where
66    T: Copy + Debug,
67{
68    pub y_plane: &'a [T],
69    /// Stride here always means components per row.
70    pub y_stride: u32,
71    pub uv_plane: &'a [T],
72    /// Stride here always means components per row.
73    pub uv_stride: u32,
74    pub width: u32,
75    pub height: u32,
76}
77
78impl<T> YuvBiPlanarImage<'_, T>
79where
80    T: Copy + Debug,
81{
82    pub fn check_constraints(&self, subsampling: YuvChromaSubsampling) -> Result<(), YuvError> {
83        check_y8_channel(self.y_plane, self.y_stride, self.width, self.height)?;
84        check_interleaved_chroma_channel(
85            self.uv_plane,
86            self.uv_stride,
87            self.width,
88            self.height,
89            subsampling,
90        )?;
91        Ok(())
92    }
93}
94
95#[derive(Debug)]
96/// Mutable representation of Bi-Planar YUV image
97pub struct YuvBiPlanarImageMut<'a, T>
98where
99    T: Copy + Debug,
100{
101    pub y_plane: BufferStoreMut<'a, T>,
102    /// Stride here always means components per row.
103    pub y_stride: u32,
104    pub uv_plane: BufferStoreMut<'a, T>,
105    /// Stride here always means components per row.
106    pub uv_stride: u32,
107    pub width: u32,
108    pub height: u32,
109}
110
111impl<T> YuvBiPlanarImageMut<'_, T>
112where
113    T: Copy + Debug,
114{
115    pub fn check_constraints(&self, subsampling: YuvChromaSubsampling) -> Result<(), YuvError> {
116        check_y8_channel(
117            self.y_plane.borrow(),
118            self.y_stride,
119            self.width,
120            self.height,
121        )?;
122        check_interleaved_chroma_channel(
123            self.uv_plane.borrow(),
124            self.uv_stride,
125            self.width,
126            self.height,
127            subsampling,
128        )?;
129        Ok(())
130    }
131}
132
133impl<'a, T> YuvBiPlanarImageMut<'a, T>
134where
135    T: Default + Clone + Copy + Debug,
136{
137    /// Allocates mutable target Bi-Planar image with required chroma subsampling
138    pub fn alloc(width: u32, height: u32, subsampling: YuvChromaSubsampling) -> Self {
139        let chroma_width = match subsampling {
140            YuvChromaSubsampling::Yuv420 | YuvChromaSubsampling::Yuv422 => {
141                (width as usize).div_ceil(2) * 2
142            }
143            YuvChromaSubsampling::Yuv444 => width as usize * 2,
144        };
145        let chroma_height = match subsampling {
146            YuvChromaSubsampling::Yuv420 => (height as usize).div_ceil(2),
147            YuvChromaSubsampling::Yuv422 | YuvChromaSubsampling::Yuv444 => height as usize,
148        };
149        let y_target = vec![T::default(); width as usize * height as usize];
150        let chroma_target = vec![T::default(); chroma_width * chroma_height];
151        YuvBiPlanarImageMut {
152            y_plane: BufferStoreMut::Owned(y_target),
153            y_stride: width,
154            uv_plane: BufferStoreMut::Owned(chroma_target),
155            uv_stride: chroma_width as u32,
156            width,
157            height,
158        }
159    }
160
161    pub fn to_fixed(&'a self) -> YuvBiPlanarImage<'a, T> {
162        YuvBiPlanarImage {
163            y_plane: self.y_plane.borrow(),
164            y_stride: self.y_stride,
165            uv_plane: self.uv_plane.borrow(),
166            uv_stride: self.uv_stride,
167            width: self.width,
168            height: self.height,
169        }
170    }
171}
172
173impl<'a, T> YuvBiPlanarImage<'a, T>
174where
175    T: Default + Clone + Copy + Debug,
176{
177    pub fn from_mut(bi_planar_mut: &'a YuvBiPlanarImageMut<T>) -> Self {
178        YuvBiPlanarImage::<'a, T> {
179            y_plane: bi_planar_mut.y_plane.borrow(),
180            y_stride: bi_planar_mut.y_stride,
181            uv_plane: bi_planar_mut.uv_plane.borrow(),
182            uv_stride: bi_planar_mut.uv_stride,
183            width: bi_planar_mut.width,
184            height: bi_planar_mut.height,
185        }
186    }
187}
188
189#[derive(Debug)]
190/// Represents YUV gray non-mutable image
191pub struct YuvGrayImage<'a, T>
192where
193    T: Copy + Debug,
194{
195    pub y_plane: &'a [T],
196    /// Stride here always means components per row.
197    pub y_stride: u32,
198    pub width: u32,
199    pub height: u32,
200}
201
202impl<T> YuvGrayImage<'_, T>
203where
204    T: Copy + Debug,
205{
206    pub fn check_constraints(&self) -> Result<(), YuvError> {
207        check_y8_channel(self.y_plane, self.y_stride, self.width, self.height)?;
208        Ok(())
209    }
210}
211
212#[derive(Debug)]
213/// Represents YUV gray mutable image
214pub struct YuvGrayImageMut<'a, T>
215where
216    T: Copy + Debug,
217{
218    pub y_plane: BufferStoreMut<'a, T>,
219    /// Stride here always means components per row.
220    pub y_stride: u32,
221    pub width: u32,
222    pub height: u32,
223}
224
225impl<'a, T> YuvGrayImageMut<'a, T>
226where
227    T: Copy + Debug,
228{
229    pub fn check_constraints(&self) -> Result<(), YuvError> {
230        check_y8_channel(
231            self.y_plane.borrow(),
232            self.y_stride,
233            self.width,
234            self.height,
235        )?;
236        Ok(())
237    }
238
239    pub fn to_fixed(&'a self) -> YuvGrayImage<'a, T> {
240        YuvGrayImage {
241            y_plane: self.y_plane.borrow(),
242            y_stride: self.y_stride,
243            width: self.width,
244            height: self.height,
245        }
246    }
247}
248
249impl<T> YuvGrayImageMut<'_, T>
250where
251    T: Copy + Debug + Clone + Default,
252{
253    /// Allocates mutable target gray image
254    pub fn alloc(width: u32, height: u32) -> Self {
255        let y_target = vec![T::default(); width as usize * height as usize];
256        Self {
257            y_plane: BufferStoreMut::Owned(y_target),
258            y_stride: width,
259            width,
260            height,
261        }
262    }
263}
264
265#[derive(Debug)]
266/// Represents YUV gray with alpha non-mutable image
267pub struct YuvGrayAlphaImage<'a, T>
268where
269    T: Copy + Debug,
270{
271    pub y_plane: &'a [T],
272    /// Stride here always means components per row.
273    pub y_stride: u32,
274    pub a_plane: &'a [T],
275    /// Stride here always means components per row.
276    pub a_stride: u32,
277    pub width: u32,
278    pub height: u32,
279}
280
281impl<T> YuvGrayAlphaImage<'_, T>
282where
283    T: Copy + Debug,
284{
285    pub fn check_constraints(&self) -> Result<(), YuvError> {
286        check_y8_channel(self.y_plane, self.y_stride, self.width, self.height)?;
287        check_y8_channel(self.a_plane, self.a_stride, self.width, self.height)?;
288        Ok(())
289    }
290}
291
292#[derive(Debug, Clone)]
293/// Non-mutable representation of Bi-Planar YUV image
294pub struct YuvPlanarImage<'a, T>
295where
296    T: Copy + Debug,
297{
298    pub y_plane: &'a [T],
299    /// Stride here always means components per row.
300    pub y_stride: u32,
301    pub u_plane: &'a [T],
302    /// Stride here always means components per row.
303    pub u_stride: u32,
304    pub v_plane: &'a [T],
305    /// Stride here always means components per row.
306    pub v_stride: u32,
307    pub width: u32,
308    pub height: u32,
309}
310
311impl<T> YuvPlanarImage<'_, T>
312where
313    T: Copy + Debug,
314{
315    pub fn check_constraints(&self, subsampling: YuvChromaSubsampling) -> Result<(), YuvError> {
316        check_y8_channel(self.y_plane, self.y_stride, self.width, self.height)?;
317        check_chroma_channel(
318            self.u_plane,
319            self.u_stride,
320            self.width,
321            self.height,
322            subsampling,
323        )?;
324        check_chroma_channel(
325            self.v_plane,
326            self.v_stride,
327            self.width,
328            self.height,
329            subsampling,
330        )?;
331        Ok(())
332    }
333}
334
335#[derive(Debug)]
336/// Mutable representation of Planar YUV image
337pub struct YuvPlanarImageMut<'a, T>
338where
339    T: Copy + Debug,
340{
341    pub y_plane: BufferStoreMut<'a, T>,
342    /// Stride here always means components per row.
343    pub y_stride: u32,
344    pub u_plane: BufferStoreMut<'a, T>,
345    /// Stride here always means components per row.
346    pub u_stride: u32,
347    pub v_plane: BufferStoreMut<'a, T>,
348    /// Stride here always means components per row.
349    pub v_stride: u32,
350    pub width: u32,
351    pub height: u32,
352}
353
354impl<T> YuvPlanarImageMut<'_, T>
355where
356    T: Copy + Debug,
357{
358    pub fn check_constraints(&self, subsampling: YuvChromaSubsampling) -> Result<(), YuvError> {
359        check_y8_channel(
360            self.y_plane.borrow(),
361            self.y_stride,
362            self.width,
363            self.height,
364        )?;
365        check_chroma_channel(
366            self.u_plane.borrow(),
367            self.u_stride,
368            self.width,
369            self.height,
370            subsampling,
371        )?;
372        check_chroma_channel(
373            self.v_plane.borrow(),
374            self.v_stride,
375            self.width,
376            self.height,
377            subsampling,
378        )?;
379        Ok(())
380    }
381}
382
383impl<'a, T> YuvPlanarImageMut<'a, T>
384where
385    T: Default + Clone + Copy + Debug,
386{
387    /// Allocates mutable target planar image with required chroma subsampling
388    pub fn alloc(width: u32, height: u32, subsampling: YuvChromaSubsampling) -> Self {
389        let chroma_width = match subsampling {
390            YuvChromaSubsampling::Yuv420 | YuvChromaSubsampling::Yuv422 => {
391                (width as usize).div_ceil(2)
392            }
393            YuvChromaSubsampling::Yuv444 => width as usize,
394        };
395        let chroma_height = match subsampling {
396            YuvChromaSubsampling::Yuv420 => (height as usize).div_ceil(2),
397            YuvChromaSubsampling::Yuv422 | YuvChromaSubsampling::Yuv444 => height as usize,
398        };
399        let y_target = vec![T::default(); width as usize * height as usize];
400        let u_target = vec![T::default(); chroma_width * chroma_height];
401        let v_target = vec![T::default(); chroma_width * chroma_height];
402        Self {
403            y_plane: BufferStoreMut::Owned(y_target),
404            y_stride: width,
405            u_plane: BufferStoreMut::Owned(u_target),
406            u_stride: chroma_width as u32,
407            v_plane: BufferStoreMut::Owned(v_target),
408            v_stride: chroma_width as u32,
409            width,
410            height,
411        }
412    }
413
414    pub fn to_fixed(&'a self) -> YuvPlanarImage<'a, T> {
415        YuvPlanarImage {
416            y_plane: self.y_plane.borrow(),
417            y_stride: self.y_stride,
418            u_plane: self.u_plane.borrow(),
419            u_stride: self.u_stride,
420            v_plane: self.v_plane.borrow(),
421            v_stride: self.v_stride,
422            width: self.width,
423            height: self.height,
424        }
425    }
426}
427
428#[derive(Debug)]
429/// Non-mutable representation of Bi-Planar YUV image
430pub struct YuvPlanarImageWithAlpha<'a, T>
431where
432    T: Copy + Debug,
433{
434    pub y_plane: &'a [T],
435    /// Stride here always means components per row.
436    pub y_stride: u32,
437    pub u_plane: &'a [T],
438    /// Stride here always means components per row.
439    pub u_stride: u32,
440    pub v_plane: &'a [T],
441    /// Stride here always means components per row.
442    pub v_stride: u32,
443    pub a_plane: &'a [T],
444    /// Stride here always means components per row.
445    pub a_stride: u32,
446    pub width: u32,
447    pub height: u32,
448}
449
450impl<T> YuvPlanarImageWithAlpha<'_, T>
451where
452    T: Copy + Debug,
453{
454    pub fn check_constraints(&self, subsampling: YuvChromaSubsampling) -> Result<(), YuvError> {
455        check_y8_channel(self.y_plane, self.y_stride, self.width, self.height)?;
456        check_y8_channel(self.a_plane, self.a_stride, self.width, self.height)?;
457        check_chroma_channel(
458            self.u_plane,
459            self.u_stride,
460            self.width,
461            self.height,
462            subsampling,
463        )?;
464        check_chroma_channel(
465            self.v_plane,
466            self.v_stride,
467            self.width,
468            self.height,
469            subsampling,
470        )?;
471        Ok(())
472    }
473}
474
475#[derive(Debug)]
476/// Non-mutable representation of Packed YUV image
477pub struct YuvPackedImage<'a, T>
478where
479    T: Copy + Debug,
480{
481    pub yuy: &'a [T],
482    /// Stride here always means components per row.
483    pub yuy_stride: u32,
484    pub width: u32,
485    pub height: u32,
486}
487
488impl<T> YuvPackedImage<'_, T>
489where
490    T: Copy + Debug,
491{
492    pub fn check_constraints(&self) -> Result<(), YuvError> {
493        check_yuv_packed422(self.yuy, self.yuy_stride, self.width, self.height)?;
494        Ok(())
495    }
496
497    pub fn check_constraints444(&self) -> Result<(), YuvError> {
498        check_rgba_destination(self.yuy, self.yuy_stride, self.width, self.height, 4)?;
499        Ok(())
500    }
501}
502
503#[derive(Debug)]
504/// Mutable representation of Packed YUV image
505pub struct YuvPackedImageMut<'a, T>
506where
507    T: Copy + Debug,
508{
509    pub yuy: BufferStoreMut<'a, T>,
510    /// Stride here always means components per row.
511    pub yuy_stride: u32,
512    pub width: u32,
513    pub height: u32,
514}
515
516impl<T> YuvPackedImageMut<'_, T>
517where
518    T: Copy + Debug,
519{
520    pub fn check_constraints(&self) -> Result<(), YuvError> {
521        check_yuv_packed422(self.yuy.borrow(), self.yuy_stride, self.width, self.height)?;
522        Ok(())
523    }
524
525    pub fn to_fixed(&self) -> YuvPackedImage<T> {
526        YuvPackedImage {
527            yuy: self.yuy.borrow(),
528            yuy_stride: self.yuy_stride,
529            width: self.width,
530            height: self.height,
531        }
532    }
533}