Skip to main content

less_avc/
ycbcr_image.rs

1// Copyright 2022-2023 Andrew D. Straw.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT
5// or http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! Data representations for YCbCr image data
9
10use super::*;
11
12/// An image in YCbCr format
13///
14/// This references data stored elsewhere and provides only minimal metadata to
15/// describe the actual image data.
16///
17/// The luma stride must be evenly divisible by 16 and the luma data size must
18/// have an integer multiple of 16 rows. For chroma, this number is 8.
19pub struct YCbCrImage<'a> {
20    /// The data planes for the image
21    pub planes: Planes<'a>,
22    /// The width of the image, in pixels
23    pub width: u32,
24    /// The height of the image, in pixels
25    pub height: u32,
26}
27
28impl<'a> YCbCrImage<'a> {
29    pub(crate) fn luma_bit_depth(&self) -> BitDepth {
30        match &self.planes {
31            Planes::Mono(y) => y.bit_depth,
32            Planes::YCbCr((y, _, _)) => y.bit_depth,
33        }
34    }
35}
36
37/// The data plane(s) within an [YCbCrImage].
38pub enum Planes<'a> {
39    //// Luminance only (monochrome) data.
40    Mono(DataPlane<'a>),
41    //// Luminance and chrominance data.
42    YCbCr((DataPlane<'a>, DataPlane<'a>, DataPlane<'a>)),
43}
44
45/// Data for a single plane (luminance or chrominance) of an image.
46///
47/// The actual data are stored elsewhere and this provides metadata.
48pub struct DataPlane<'a> {
49    /// The image data
50    pub data: &'a [u8],
51    /// The row stride of the image data
52    pub stride: usize,
53    /// The bit depth of the image data
54    pub bit_depth: BitDepth,
55}
56
57impl<'a> YCbCrImage<'a> {
58    pub(crate) fn check_sizes(&self) -> Result<()> {
59        match &self.planes {
60            Planes::Mono(y_plane) | Planes::YCbCr((y_plane, _, _)) => {
61                y_plane.check_sizes(self.width, self.height, 16)?;
62            }
63        }
64
65        match &self.planes {
66            Planes::Mono(_) => {}
67            Planes::YCbCr((_, cb_plane, cr_plane)) => {
68                for chroma_plane in [cb_plane, cr_plane] {
69                    chroma_plane.check_sizes(self.width / 2, self.height / 2, 8)?;
70                }
71            }
72        }
73        Ok(())
74    }
75}
76
77impl<'a> DataPlane<'a> {
78    pub(crate) fn check_sizes(&self, width: u32, height: u32, mb_sz: u32) -> Result<()> {
79        let (width_factor_num, width_factor_denom) = match self.bit_depth {
80            BitDepth::Depth8 => (1, 1),
81            BitDepth::Depth12 => (3, 2),
82        };
83        // Check width
84        if self.stride
85            < next_multiple(width, mb_sz) as usize * width_factor_num / width_factor_denom
86        {
87            return Err(Error::DataShapeProblem {
88                msg: "stride too small",
89                #[cfg(feature = "backtrace")]
90                backtrace: Backtrace::capture(),
91            });
92        }
93        // check height
94        let num_rows = div_ceil(
95            self.data.len().try_into().unwrap(),
96            self.stride.try_into().unwrap(),
97        );
98        if num_rows < next_multiple(height, mb_sz) {
99            return Err(Error::DataShapeProblem {
100                msg: "number of rows too small",
101                #[cfg(feature = "backtrace")]
102                backtrace: Backtrace::capture(),
103            });
104        }
105
106        Ok(())
107    }
108}