1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::decoder::tile::TileInfo;
16 use crate::decoder::Category;
17 use crate::decoder::ProgressiveState;
18 use crate::internal_utils::pixels::*;
19 use crate::internal_utils::*;
20 use crate::parser::mp4box::*;
21 use crate::utils::clap::CleanAperture;
22 use crate::*;
23 
24 #[derive(Clone, Copy, Debug, PartialEq)]
25 pub enum Plane {
26     Y = 0,
27     U = 1,
28     V = 2,
29     A = 3,
30 }
31 
32 impl From<usize> for Plane {
from(plane: usize) -> Self33     fn from(plane: usize) -> Self {
34         match plane {
35             1 => Plane::U,
36             2 => Plane::V,
37             3 => Plane::A,
38             _ => Plane::Y,
39         }
40     }
41 }
42 
43 impl Plane {
to_usize(&self) -> usize44     pub fn to_usize(&self) -> usize {
45         match self {
46             Plane::Y => 0,
47             Plane::U => 1,
48             Plane::V => 2,
49             Plane::A => 3,
50         }
51     }
52 }
53 
54 /// cbindgen:ignore
55 pub const MAX_PLANE_COUNT: usize = 4;
56 pub const YUV_PLANES: [Plane; 3] = [Plane::Y, Plane::U, Plane::V];
57 pub const A_PLANE: [Plane; 1] = [Plane::A];
58 pub const ALL_PLANES: [Plane; MAX_PLANE_COUNT] = [Plane::Y, Plane::U, Plane::V, Plane::A];
59 
60 #[repr(C)]
61 #[derive(Clone, Copy, Debug, Default, PartialEq)]
62 // VideoFullRangeFlag as specified in ISO/IEC 23091-2/ITU-T H.273.
63 pub enum YuvRange {
64     Limited = 0,
65     #[default]
66     Full = 1,
67 }
68 
69 #[derive(Default)]
70 pub struct Image {
71     pub width: u32,
72     pub height: u32,
73     pub depth: u8,
74 
75     pub yuv_format: PixelFormat,
76     pub yuv_range: YuvRange,
77     pub chroma_sample_position: ChromaSamplePosition,
78 
79     pub alpha_present: bool,
80     pub alpha_premultiplied: bool,
81 
82     pub row_bytes: [u32; MAX_PLANE_COUNT],
83     pub image_owns_planes: [bool; MAX_PLANE_COUNT],
84 
85     pub planes: [Option<Pixels>; MAX_PLANE_COUNT],
86 
87     pub color_primaries: ColorPrimaries,
88     pub transfer_characteristics: TransferCharacteristics,
89     pub matrix_coefficients: MatrixCoefficients,
90 
91     pub clli: Option<ContentLightLevelInformation>,
92     pub pasp: Option<PixelAspectRatio>,
93     pub clap: Option<CleanAperture>,
94     pub irot_angle: Option<u8>,
95     pub imir_axis: Option<u8>,
96 
97     pub exif: Vec<u8>,
98     pub icc: Vec<u8>,
99     pub xmp: Vec<u8>,
100 
101     pub image_sequence_track_present: bool,
102     pub progressive_state: ProgressiveState,
103 }
104 
105 pub struct PlaneData {
106     pub width: u32,
107     pub height: u32,
108     pub row_bytes: u32,
109     pub pixel_size: u32,
110 }
111 
112 #[derive(Clone, Copy)]
113 pub enum PlaneRow<'a> {
114     Depth8(&'a [u8]),
115     Depth16(&'a [u16]),
116 }
117 
118 impl Image {
depth_valid(&self) -> bool119     pub fn depth_valid(&self) -> bool {
120         matches!(self.depth, 8 | 10 | 12 | 16)
121     }
122 
max_channel(&self) -> u16123     pub fn max_channel(&self) -> u16 {
124         if !self.depth_valid() {
125             0
126         } else {
127             ((1i32 << self.depth) - 1) as u16
128         }
129     }
130 
max_channel_f(&self) -> f32131     pub fn max_channel_f(&self) -> f32 {
132         self.max_channel() as f32
133     }
134 
has_plane(&self, plane: Plane) -> bool135     pub fn has_plane(&self, plane: Plane) -> bool {
136         let plane_index = plane.to_usize();
137         if self.planes[plane_index].is_none() || self.row_bytes[plane_index] == 0 {
138             return false;
139         }
140         self.planes[plane_index].unwrap_ref().has_data()
141     }
142 
has_alpha(&self) -> bool143     pub fn has_alpha(&self) -> bool {
144         self.has_plane(Plane::A)
145     }
146 
has_same_properties(&self, other: &Image) -> bool147     pub fn has_same_properties(&self, other: &Image) -> bool {
148         self.width == other.width && self.height == other.height && self.depth == other.depth
149     }
150 
width(&self, plane: Plane) -> usize151     pub fn width(&self, plane: Plane) -> usize {
152         match plane {
153             Plane::Y | Plane::A => self.width as usize,
154             Plane::U => match self.yuv_format {
155                 PixelFormat::Yuv444
156                 | PixelFormat::AndroidP010
157                 | PixelFormat::AndroidNv12
158                 | PixelFormat::AndroidNv21 => self.width as usize,
159                 PixelFormat::Yuv420 | PixelFormat::Yuv422 => (self.width as usize + 1) / 2,
160                 PixelFormat::None | PixelFormat::Yuv400 => 0,
161             },
162             Plane::V => match self.yuv_format {
163                 PixelFormat::Yuv444 => self.width as usize,
164                 PixelFormat::Yuv420 | PixelFormat::Yuv422 => (self.width as usize + 1) / 2,
165                 PixelFormat::None
166                 | PixelFormat::Yuv400
167                 | PixelFormat::AndroidP010
168                 | PixelFormat::AndroidNv12
169                 | PixelFormat::AndroidNv21 => 0,
170             },
171         }
172     }
173 
height(&self, plane: Plane) -> usize174     pub fn height(&self, plane: Plane) -> usize {
175         match plane {
176             Plane::Y | Plane::A => self.height as usize,
177             Plane::U => match self.yuv_format {
178                 PixelFormat::Yuv444 | PixelFormat::Yuv422 => self.height as usize,
179                 PixelFormat::Yuv420
180                 | PixelFormat::AndroidP010
181                 | PixelFormat::AndroidNv12
182                 | PixelFormat::AndroidNv21 => (self.height as usize + 1) / 2,
183                 PixelFormat::None | PixelFormat::Yuv400 => 0,
184             },
185             Plane::V => match self.yuv_format {
186                 PixelFormat::Yuv444 | PixelFormat::Yuv422 => self.height as usize,
187                 PixelFormat::Yuv420 => (self.height as usize + 1) / 2,
188                 PixelFormat::None
189                 | PixelFormat::Yuv400
190                 | PixelFormat::AndroidP010
191                 | PixelFormat::AndroidNv12
192                 | PixelFormat::AndroidNv21 => 0,
193             },
194         }
195     }
196 
plane_data(&self, plane: Plane) -> Option<PlaneData>197     pub fn plane_data(&self, plane: Plane) -> Option<PlaneData> {
198         if !self.has_plane(plane) {
199             return None;
200         }
201         Some(PlaneData {
202             width: self.width(plane) as u32,
203             height: self.height(plane) as u32,
204             row_bytes: self.row_bytes[plane.to_usize()],
205             pixel_size: if self.depth == 8 { 1 } else { 2 },
206         })
207     }
208 
row(&self, plane: Plane, row: u32) -> AvifResult<&[u8]>209     pub fn row(&self, plane: Plane, row: u32) -> AvifResult<&[u8]> {
210         let plane_data = self.plane_data(plane).ok_or(AvifError::NoContent)?;
211         let start = checked_mul!(row, plane_data.row_bytes)?;
212         self.planes[plane.to_usize()]
213             .unwrap_ref()
214             .slice(start, plane_data.row_bytes)
215     }
216 
row_mut(&mut self, plane: Plane, row: u32) -> AvifResult<&mut [u8]>217     pub fn row_mut(&mut self, plane: Plane, row: u32) -> AvifResult<&mut [u8]> {
218         let plane_data = self.plane_data(plane).ok_or(AvifError::NoContent)?;
219         let row_bytes = plane_data.row_bytes;
220         let start = checked_mul!(row, row_bytes)?;
221         self.planes[plane.to_usize()]
222             .unwrap_mut()
223             .slice_mut(start, row_bytes)
224     }
225 
row16(&self, plane: Plane, row: u32) -> AvifResult<&[u16]>226     pub fn row16(&self, plane: Plane, row: u32) -> AvifResult<&[u16]> {
227         let plane_data = self.plane_data(plane).ok_or(AvifError::NoContent)?;
228         let row_bytes = plane_data.row_bytes / 2;
229         let start = checked_mul!(row, row_bytes)?;
230         self.planes[plane.to_usize()]
231             .unwrap_ref()
232             .slice16(start, row_bytes)
233     }
234 
row16_mut(&mut self, plane: Plane, row: u32) -> AvifResult<&mut [u16]>235     pub fn row16_mut(&mut self, plane: Plane, row: u32) -> AvifResult<&mut [u16]> {
236         let plane_data = self.plane_data(plane).ok_or(AvifError::NoContent)?;
237         let row_bytes = plane_data.row_bytes / 2;
238         let start = checked_mul!(row, row_bytes)?;
239         self.planes[plane.to_usize()]
240             .unwrap_mut()
241             .slice16_mut(start, row_bytes)
242     }
243 
row_generic(&self, plane: Plane, row: u32) -> AvifResult<PlaneRow>244     pub fn row_generic(&self, plane: Plane, row: u32) -> AvifResult<PlaneRow> {
245         Ok(if self.depth == 8 {
246             PlaneRow::Depth8(self.row(plane, row)?)
247         } else {
248             PlaneRow::Depth16(self.row16(plane, row)?)
249         })
250     }
251 
clear_chroma_planes(&mut self)252     pub fn clear_chroma_planes(&mut self) {
253         for plane in [Plane::U, Plane::V] {
254             let plane = plane.to_usize();
255             self.planes[plane] = None;
256             self.row_bytes[plane] = 0;
257             self.image_owns_planes[plane] = false;
258         }
259     }
260 
allocate_planes(&mut self, category: Category) -> AvifResult<()>261     pub fn allocate_planes(&mut self, category: Category) -> AvifResult<()> {
262         let pixel_size: usize = if self.depth == 8 { 1 } else { 2 };
263         for plane in category.planes() {
264             let plane = *plane;
265             let plane_index = plane.to_usize();
266             let width = self.width(plane);
267             let plane_size = checked_mul!(width, self.height(plane))?;
268             let default_value = if plane == Plane::A { self.max_channel() } else { 0 };
269             if self.planes[plane_index].is_some()
270                 && self.planes[plane_index].unwrap_ref().size() == plane_size
271                 && (self.planes[plane_index].unwrap_ref().pixel_bit_size() == 0
272                     || self.planes[plane_index].unwrap_ref().pixel_bit_size() == pixel_size * 8)
273             {
274                 continue;
275             }
276             self.planes[plane_index] = Some(if self.depth == 8 {
277                 Pixels::Buffer(Vec::new())
278             } else {
279                 Pixels::Buffer16(Vec::new())
280             });
281             let pixels = self.planes[plane_index].unwrap_mut();
282             pixels.resize(plane_size, default_value)?;
283             self.row_bytes[plane_index] = u32_from_usize(checked_mul!(width, pixel_size)?)?;
284             self.image_owns_planes[plane_index] = true;
285         }
286         Ok(())
287     }
288 
289     // If src contains pointers, this function will simply make a copy of the pointer without
290     // copying the actual pixels (stealing). If src contains buffer, this function will clone the
291     // buffers (copying).
steal_or_copy_from(&mut self, src: &Image, category: Category) -> AvifResult<()>292     pub fn steal_or_copy_from(&mut self, src: &Image, category: Category) -> AvifResult<()> {
293         for plane in category.planes() {
294             let plane = plane.to_usize();
295             (self.planes[plane], self.row_bytes[plane]) = match &src.planes[plane] {
296                 Some(src_plane) => (Some(src_plane.clone()), src.row_bytes[plane]),
297                 None => (None, 0),
298             }
299         }
300         Ok(())
301     }
302 
copy_from_tile( &mut self, tile: &Image, tile_info: &TileInfo, tile_index: u32, category: Category, ) -> AvifResult<()>303     pub fn copy_from_tile(
304         &mut self,
305         tile: &Image,
306         tile_info: &TileInfo,
307         tile_index: u32,
308         category: Category,
309     ) -> AvifResult<()> {
310         // This function is used only when |tile| contains pointers and self contains buffers.
311         let row_index = tile_index / tile_info.grid.columns;
312         let column_index = tile_index % tile_info.grid.columns;
313         for plane in category.planes() {
314             let plane = *plane;
315             let src_plane = tile.plane_data(plane);
316             if src_plane.is_none() {
317                 continue;
318             }
319             let src_plane = src_plane.unwrap();
320             // If this is the last tile column, clamp to left over width.
321             let src_width_to_copy = if column_index == tile_info.grid.columns - 1 {
322                 let width_so_far = checked_mul!(src_plane.width, column_index)?;
323                 checked_sub!(self.width(plane), usize_from_u32(width_so_far)?)?
324             } else {
325                 usize_from_u32(src_plane.width)?
326             };
327 
328             // If this is the last tile row, clamp to left over height.
329             let src_height_to_copy = if row_index == tile_info.grid.rows - 1 {
330                 let height_so_far = checked_mul!(src_plane.height, row_index)?;
331                 checked_sub!(u32_from_usize(self.height(plane))?, height_so_far)?
332             } else {
333                 src_plane.height
334             };
335 
336             let dst_y_start = checked_mul!(row_index, src_plane.height)?;
337             let dst_x_offset = usize_from_u32(checked_mul!(column_index, src_plane.width)?)?;
338             let dst_x_offset_end = checked_add!(dst_x_offset, src_width_to_copy)?;
339             if self.depth == 8 {
340                 for y in 0..src_height_to_copy {
341                     let src_row = tile.row(plane, y)?;
342                     let src_slice = &src_row[0..src_width_to_copy];
343                     let dst_row = self.row_mut(plane, checked_add!(dst_y_start, y)?)?;
344                     let dst_slice = &mut dst_row[dst_x_offset..dst_x_offset_end];
345                     dst_slice.copy_from_slice(src_slice);
346                 }
347             } else {
348                 for y in 0..src_height_to_copy {
349                     let src_row = tile.row16(plane, y)?;
350                     let src_slice = &src_row[0..src_width_to_copy];
351                     let dst_row = self.row16_mut(plane, checked_add!(dst_y_start, y)?)?;
352                     let dst_slice = &mut dst_row[dst_x_offset..dst_x_offset_end];
353                     dst_slice.copy_from_slice(src_slice);
354                 }
355             }
356         }
357         Ok(())
358     }
359 }
360