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 pub mod io;
16 pub mod pixels;
17 pub mod stream;
18 
19 use crate::parser::mp4box::*;
20 use crate::*;
21 
22 use std::ops::Range;
23 
24 // Some HEIF fractional fields can be negative, hence Fraction and UFraction.
25 // The denominator is always unsigned.
26 
27 /// cbindgen:field-names=[n,d]
28 #[derive(Clone, Copy, Debug, Default)]
29 #[repr(C)]
30 pub struct Fraction(pub i32, pub u32);
31 
32 /// cbindgen:field-names=[n,d]
33 #[derive(Clone, Copy, Debug, Default, PartialEq)]
34 #[repr(C)]
35 pub struct UFraction(pub u32, pub u32);
36 
37 // 'clap' fractions do not follow this pattern: both numerators and denominators
38 // are used as i32, but they are signalled as u32 according to the specification
39 // as of 2024. This may be fixed in later versions of the specification, see
40 // https://github.com/AOMediaCodec/libavif/pull/1749#discussion_r1391612932.
41 #[derive(Clone, Copy, Debug, Default)]
42 pub struct IFraction(pub i32, pub i32);
43 
44 impl TryFrom<UFraction> for IFraction {
45     type Error = AvifError;
46 
try_from(uf: UFraction) -> AvifResult<IFraction>47     fn try_from(uf: UFraction) -> AvifResult<IFraction> {
48         Ok(IFraction(uf.0 as i32, i32_from_u32(uf.1)?))
49     }
50 }
51 
52 impl IFraction {
gcd(a: i32, b: i32) -> i3253     fn gcd(a: i32, b: i32) -> i32 {
54         let mut a = if a < 0 { -a as i64 } else { a as i64 };
55         let mut b = if b < 0 { -b as i64 } else { b as i64 };
56         while b != 0 {
57             let r = a % b;
58             a = b;
59             b = r;
60         }
61         a as i32
62     }
63 
simplified(n: i32, d: i32) -> Self64     pub fn simplified(n: i32, d: i32) -> Self {
65         let mut fraction = IFraction(n, d);
66         fraction.simplify();
67         fraction
68     }
69 
simplify(&mut self)70     pub fn simplify(&mut self) {
71         let gcd = Self::gcd(self.0, self.1);
72         if gcd > 1 {
73             self.0 /= gcd;
74             self.1 /= gcd;
75         }
76     }
77 
get_i32(&self) -> i3278     pub fn get_i32(&self) -> i32 {
79         assert!(self.1 != 0);
80         self.0 / self.1
81     }
82 
get_u32(&self) -> AvifResult<u32>83     pub fn get_u32(&self) -> AvifResult<u32> {
84         u32_from_i32(self.get_i32())
85     }
86 
is_integer(&self) -> bool87     pub fn is_integer(&self) -> bool {
88         self.0 % self.1 == 0
89     }
90 
common_denominator(&mut self, val: &mut IFraction) -> AvifResult<()>91     fn common_denominator(&mut self, val: &mut IFraction) -> AvifResult<()> {
92         self.simplify();
93         if self.1 == val.1 {
94             return Ok(());
95         }
96         let self_d = self.1;
97         self.0 = self
98             .0
99             .checked_mul(val.1)
100             .ok_or(AvifError::UnknownError("".into()))?;
101         self.1 = self
102             .1
103             .checked_mul(val.1)
104             .ok_or(AvifError::UnknownError("".into()))?;
105         val.0 = val
106             .0
107             .checked_mul(self_d)
108             .ok_or(AvifError::UnknownError("".into()))?;
109         val.1 = val
110             .1
111             .checked_mul(self_d)
112             .ok_or(AvifError::UnknownError("".into()))?;
113         Ok(())
114     }
115 
add(&mut self, val: &IFraction) -> AvifResult<()>116     pub fn add(&mut self, val: &IFraction) -> AvifResult<()> {
117         let mut val = *val;
118         val.simplify();
119         self.common_denominator(&mut val)?;
120         self.0 = self
121             .0
122             .checked_add(val.0)
123             .ok_or(AvifError::UnknownError("".into()))?;
124         self.simplify();
125         Ok(())
126     }
127 
sub(&mut self, val: &IFraction) -> AvifResult<()>128     pub fn sub(&mut self, val: &IFraction) -> AvifResult<()> {
129         let mut val = *val;
130         val.simplify();
131         self.common_denominator(&mut val)?;
132         self.0 = self
133             .0
134             .checked_sub(val.0)
135             .ok_or(AvifError::UnknownError("".into()))?;
136         self.simplify();
137         Ok(())
138     }
139 }
140 
141 macro_rules! conversion_function {
142     ($func:ident, $to: ident, $from:ty) => {
143         pub fn $func(value: $from) -> AvifResult<$to> {
144             $to::try_from(value).or(Err(AvifError::BmffParseFailed("".into())))
145         }
146     };
147 }
148 
149 conversion_function!(usize_from_u64, usize, u64);
150 conversion_function!(usize_from_u32, usize, u32);
151 conversion_function!(usize_from_u16, usize, u16);
152 #[cfg(feature = "android_mediacodec")]
153 conversion_function!(usize_from_isize, usize, isize);
154 conversion_function!(u64_from_usize, u64, usize);
155 conversion_function!(u32_from_usize, u32, usize);
156 conversion_function!(u32_from_u64, u32, u64);
157 conversion_function!(u32_from_i32, u32, i32);
158 conversion_function!(i32_from_u32, i32, u32);
159 #[cfg(feature = "android_mediacodec")]
160 conversion_function!(isize_from_i32, isize, i32);
161 #[cfg(feature = "capi")]
162 conversion_function!(isize_from_u32, isize, u32);
163 conversion_function!(isize_from_usize, isize, usize);
164 #[cfg(feature = "android_mediacodec")]
165 conversion_function!(i32_from_usize, i32, usize);
166 
167 macro_rules! clamp_function {
168     ($func:ident, $type:ty) => {
169         pub fn $func(value: $type, low: $type, high: $type) -> $type {
170             if value < low {
171                 low
172             } else if value > high {
173                 high
174             } else {
175                 value
176             }
177         }
178     };
179 }
180 
181 clamp_function!(clamp_u16, u16);
182 clamp_function!(clamp_f32, f32);
183 clamp_function!(clamp_i32, i32);
184 
185 // Returns the colr nclx property. Returns an error if there are multiple ones.
find_nclx(properties: &[ItemProperty]) -> AvifResult<Option<&Nclx>>186 pub fn find_nclx(properties: &[ItemProperty]) -> AvifResult<Option<&Nclx>> {
187     let mut single_nclx: Option<&Nclx> = None;
188     for property in properties {
189         if let ItemProperty::ColorInformation(ColorInformation::Nclx(nclx)) = property {
190             if single_nclx.is_some() {
191                 return Err(AvifError::BmffParseFailed(
192                     "multiple nclx were found".into(),
193                 ));
194             }
195             single_nclx = Some(nclx);
196         }
197     }
198     Ok(single_nclx)
199 }
200 
201 // Returns the colr icc property. Returns an error if there are multiple ones.
find_icc(properties: &[ItemProperty]) -> AvifResult<Option<&Vec<u8>>>202 pub fn find_icc(properties: &[ItemProperty]) -> AvifResult<Option<&Vec<u8>>> {
203     let mut single_icc: Option<&Vec<u8>> = None;
204     for property in properties {
205         if let ItemProperty::ColorInformation(ColorInformation::Icc(icc)) = property {
206             if single_icc.is_some() {
207                 return Err(AvifError::BmffParseFailed("multiple icc were found".into()));
208             }
209             single_icc = Some(icc);
210         }
211     }
212     Ok(single_icc)
213 }
214 
check_limits(width: u32, height: u32, size_limit: u32, dimension_limit: u32) -> bool215 pub fn check_limits(width: u32, height: u32, size_limit: u32, dimension_limit: u32) -> bool {
216     if height == 0 {
217         return false;
218     }
219     if width > size_limit / height {
220         return false;
221     }
222     if dimension_limit != 0 && (width > dimension_limit || height > dimension_limit) {
223         return false;
224     }
225     true
226 }
227 
limited_to_full(min: i32, max: i32, full: i32, v: u16) -> u16228 fn limited_to_full(min: i32, max: i32, full: i32, v: u16) -> u16 {
229     let v = v as i32;
230     clamp_i32(
231         (((v - min) * full) + ((max - min) / 2)) / (max - min),
232         0,
233         full,
234     ) as u16
235 }
236 
limited_to_full_y(depth: u8, v: u16) -> u16237 pub fn limited_to_full_y(depth: u8, v: u16) -> u16 {
238     match depth {
239         8 => limited_to_full(16, 235, 255, v),
240         10 => limited_to_full(64, 940, 1023, v),
241         12 => limited_to_full(256, 3760, 4095, v),
242         _ => 0,
243     }
244 }
245 
create_vec_exact<T>(size: usize) -> AvifResult<Vec<T>>246 pub fn create_vec_exact<T>(size: usize) -> AvifResult<Vec<T>> {
247     let mut v = Vec::<T>::new();
248     let allocation_size = size
249         .checked_mul(std::mem::size_of::<T>())
250         .ok_or(AvifError::OutOfMemory)?;
251     // TODO: b/342251590 - Do not request allocations of more than what is allowed in Chromium's
252     // partition allocator. This is the allowed limit in the chromium fuzzers. The value comes
253     // from:
254     // https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/src/partition_alloc/partition_alloc_constants.h;l=433-440;drc=c0265133106c7647e90f9aaa4377d28190b1a6a9.
255     // Requesting an allocation larger than this value will cause the fuzzers to crash instead of
256     // returning null. Remove this check once that behavior is fixed.
257     if u64_from_usize(allocation_size)? >= 2_145_386_496 {
258         return Err(AvifError::OutOfMemory);
259     }
260     if v.try_reserve_exact(size).is_err() {
261         return Err(AvifError::OutOfMemory);
262     }
263     Ok(v)
264 }
265 
266 #[cfg(test)]
assert_eq_f32_array(a: &[f32], b: &[f32])267 pub fn assert_eq_f32_array(a: &[f32], b: &[f32]) {
268     assert_eq!(a.len(), b.len());
269     for i in 0..a.len() {
270         assert!((a[i] - b[i]).abs() <= std::f32::EPSILON);
271     }
272 }
273 
check_slice_range(len: usize, range: &Range<usize>) -> AvifResult<()>274 pub fn check_slice_range(len: usize, range: &Range<usize>) -> AvifResult<()> {
275     if range.start >= len || range.end > len {
276         return Err(AvifError::NoContent);
277     }
278     Ok(())
279 }
280