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 #![deny(unsafe_op_in_unsafe_fn)]
16 
17 pub mod decoder;
18 pub mod image;
19 pub mod reformat;
20 pub mod utils;
21 
22 #[cfg(feature = "capi")]
23 pub mod capi;
24 
25 /// cbindgen:ignore
26 mod codecs;
27 
28 mod internal_utils;
29 mod parser;
30 
31 // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1516634.
32 #[derive(Default)]
33 pub struct NonRandomHasherState;
34 
35 impl std::hash::BuildHasher for NonRandomHasherState {
36     type Hasher = std::collections::hash_map::DefaultHasher;
build_hasher(&self) -> std::collections::hash_map::DefaultHasher37     fn build_hasher(&self) -> std::collections::hash_map::DefaultHasher {
38         std::collections::hash_map::DefaultHasher::new()
39     }
40 }
41 
42 pub type HashMap<K, V> = std::collections::HashMap<K, V, NonRandomHasherState>;
43 pub type HashSet<K> = std::collections::HashSet<K, NonRandomHasherState>;
44 
45 /// cbindgen:enum-trailing-values=[Count]
46 #[repr(C)]
47 #[derive(Clone, Copy, Debug, Default, PartialEq)]
48 // See https://aomediacodec.github.io/av1-spec/#color-config-semantics.
49 pub enum PixelFormat {
50     #[default]
51     None = 0,
52     Yuv444 = 1,
53     Yuv422 = 2,
54     Yuv420 = 3, // Also used for alpha items when 4:0:0 is not supported by the codec.
55     Yuv400 = 4,
56     // The following formats are not found in the AV1 spec. They are formats that are supported by
57     // Android platform. They are intended to be pass-through formats that are used only by the
58     // Android MediaCodec wrapper. All internal functions will treat them as opaque.
59     AndroidP010 = 5,
60     AndroidNv12 = 6,
61     AndroidNv21 = 7,
62 }
63 
64 impl PixelFormat {
is_monochrome(&self) -> bool65     pub fn is_monochrome(&self) -> bool {
66         *self == Self::Yuv400
67     }
68 
plane_count(&self) -> usize69     pub fn plane_count(&self) -> usize {
70         match self {
71             PixelFormat::None
72             | PixelFormat::AndroidP010
73             | PixelFormat::AndroidNv12
74             | PixelFormat::AndroidNv21 => 0,
75             PixelFormat::Yuv400 => 1,
76             PixelFormat::Yuv420 | PixelFormat::Yuv422 | PixelFormat::Yuv444 => 3,
77         }
78     }
79 
chroma_shift_x(&self) -> (u32, u32)80     pub fn chroma_shift_x(&self) -> (u32, u32) {
81         match self {
82             Self::Yuv422 | Self::Yuv420 => (1, 0),
83             Self::AndroidP010 => (1, 1),
84             _ => (0, 0),
85         }
86     }
87 
chroma_shift_y(&self) -> u3288     pub fn chroma_shift_y(&self) -> u32 {
89         match self {
90             Self::Yuv420 | Self::AndroidP010 | Self::AndroidNv12 | Self::AndroidNv21 => 1,
91             _ => 0,
92         }
93     }
94 }
95 
96 // See https://aomediacodec.github.io/av1-spec/#color-config-semantics
97 // and https://en.wikipedia.org/wiki/Chroma_subsampling#Sampling_positions.
98 #[repr(C)]
99 #[derive(Clone, Copy, Debug, Default, PartialEq)]
100 pub enum ChromaSamplePosition {
101     #[default]
102     Unknown = 0, // Corresponds to AV1's CSP_UNKNOWN.
103     Vertical = 1,  // Corresponds to AV1's CSP_VERTICAL (MPEG-2, also called "left").
104     Colocated = 2, // Corresponds to AV1's CSP_COLOCATED (BT.2020, also called "top-left").
105     Reserved = 3,  // Corresponds to AV1's CSP_RESERVED.
106 }
107 
108 impl ChromaSamplePosition {
109     // The AV1 Specification (Version 1.0.0 with Errata 1) does not have a CSP_CENTER value
110     // for chroma_sample_position, so we are forced to signal CSP_UNKNOWN in the AV1 bitstream
111     // when the chroma sample position is CENTER.
112     const CENTER: ChromaSamplePosition = ChromaSamplePosition::Unknown; // JPEG/"center"
113 }
114 
115 impl From<u32> for ChromaSamplePosition {
from(value: u32) -> Self116     fn from(value: u32) -> Self {
117         match value {
118             0 => Self::Unknown,
119             1 => Self::Vertical,
120             2 => Self::Colocated,
121             3 => Self::Reserved,
122             _ => Self::Unknown,
123         }
124     }
125 }
126 
127 // See https://aomediacodec.github.io/av1-spec/#color-config-semantics.
128 #[repr(u16)]
129 #[derive(Clone, Copy, Debug, Default, PartialEq)]
130 pub enum ColorPrimaries {
131     Unknown = 0,
132     Srgb = 1,
133     #[default]
134     Unspecified = 2,
135     Bt470m = 4,
136     Bt470bg = 5,
137     Bt601 = 6,
138     Smpte240 = 7,
139     GenericFilm = 8,
140     Bt2020 = 9,
141     Xyz = 10,
142     Smpte431 = 11,
143     Smpte432 = 12,
144     Ebu3213 = 22,
145 }
146 
147 impl From<u16> for ColorPrimaries {
from(value: u16) -> Self148     fn from(value: u16) -> Self {
149         match value {
150             0 => Self::Unknown,
151             1 => Self::Srgb,
152             2 => Self::Unspecified,
153             4 => Self::Bt470m,
154             5 => Self::Bt470bg,
155             6 => Self::Bt601,
156             7 => Self::Smpte240,
157             8 => Self::GenericFilm,
158             9 => Self::Bt2020,
159             10 => Self::Xyz,
160             11 => Self::Smpte431,
161             12 => Self::Smpte432,
162             22 => Self::Ebu3213,
163             _ => Self::default(),
164         }
165     }
166 }
167 
168 #[allow(non_camel_case_types, non_upper_case_globals)]
169 impl ColorPrimaries {
170     pub const Bt709: Self = Self::Srgb;
171     pub const Iec61966_2_4: Self = Self::Srgb;
172     pub const Bt2100: Self = Self::Bt2020;
173     pub const Dci_p3: Self = Self::Smpte432;
174 }
175 
176 // See https://aomediacodec.github.io/av1-spec/#color-config-semantics.
177 #[repr(u16)]
178 #[derive(Clone, Copy, Debug, Default, PartialEq)]
179 pub enum TransferCharacteristics {
180     Unknown = 0,
181     Bt709 = 1,
182     #[default]
183     Unspecified = 2,
184     Reserved = 3,
185     Bt470m = 4,  // 2.2 gamma
186     Bt470bg = 5, // 2.8 gamma
187     Bt601 = 6,
188     Smpte240 = 7,
189     Linear = 8,
190     Log100 = 9,
191     Log100Sqrt10 = 10,
192     Iec61966 = 11,
193     Bt1361 = 12,
194     Srgb = 13,
195     Bt2020_10bit = 14,
196     Bt2020_12bit = 15,
197     Pq = 16, // Perceptual Quantizer (HDR); BT.2100 PQ
198     Smpte428 = 17,
199     Hlg = 18, // Hybrid Log-Gamma (HDR); ARIB STD-B67; BT.2100 HLG
200 }
201 
202 impl From<u16> for TransferCharacteristics {
from(value: u16) -> Self203     fn from(value: u16) -> Self {
204         match value {
205             0 => Self::Unknown,
206             1 => Self::Bt709,
207             2 => Self::Unspecified,
208             3 => Self::Reserved,
209             4 => Self::Bt470m,
210             5 => Self::Bt470bg,
211             6 => Self::Bt601,
212             7 => Self::Smpte240,
213             8 => Self::Linear,
214             9 => Self::Log100,
215             10 => Self::Log100Sqrt10,
216             11 => Self::Iec61966,
217             12 => Self::Bt1361,
218             13 => Self::Srgb,
219             14 => Self::Bt2020_10bit,
220             15 => Self::Bt2020_12bit,
221             16 => Self::Pq,
222             17 => Self::Smpte428,
223             18 => Self::Hlg,
224             _ => Self::default(),
225         }
226     }
227 }
228 
229 #[allow(non_upper_case_globals)]
230 impl TransferCharacteristics {
231     pub const Smpte2084: Self = Self::Pq;
232 }
233 
234 // See https://aomediacodec.github.io/av1-spec/#color-config-semantics.
235 #[repr(u16)]
236 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
237 pub enum MatrixCoefficients {
238     Identity = 0,
239     Bt709 = 1,
240     #[default]
241     Unspecified = 2,
242     Reserved = 3,
243     Fcc = 4,
244     Bt470bg = 5,
245     Bt601 = 6,
246     Smpte240 = 7,
247     Ycgco = 8,
248     Bt2020Ncl = 9,
249     Bt2020Cl = 10,
250     Smpte2085 = 11,
251     ChromaDerivedNcl = 12,
252     ChromaDerivedCl = 13,
253     Ictcp = 14,
254     YcgcoRe = 16,
255     YcgcoRo = 17,
256 }
257 
258 impl From<u16> for MatrixCoefficients {
from(value: u16) -> Self259     fn from(value: u16) -> Self {
260         match value {
261             0 => Self::Identity,
262             1 => Self::Bt709,
263             2 => Self::Unspecified,
264             3 => Self::Reserved,
265             4 => Self::Fcc,
266             5 => Self::Bt470bg,
267             6 => Self::Bt601,
268             7 => Self::Smpte240,
269             8 => Self::Ycgco,
270             9 => Self::Bt2020Ncl,
271             10 => Self::Bt2020Cl,
272             11 => Self::Smpte2085,
273             12 => Self::ChromaDerivedNcl,
274             13 => Self::ChromaDerivedCl,
275             14 => Self::Ictcp,
276             16 => Self::YcgcoRe,
277             17 => Self::YcgcoRo,
278             _ => Self::default(),
279         }
280     }
281 }
282 
283 #[derive(Debug, Default, PartialEq)]
284 pub enum AvifError {
285     #[default]
286     Ok,
287     UnknownError(String),
288     InvalidFtyp,
289     NoContent,
290     NoYuvFormatSelected,
291     ReformatFailed,
292     UnsupportedDepth,
293     EncodeColorFailed,
294     EncodeAlphaFailed,
295     BmffParseFailed(String),
296     MissingImageItem,
297     DecodeColorFailed,
298     DecodeAlphaFailed,
299     ColorAlphaSizeMismatch,
300     IspeSizeMismatch,
301     NoCodecAvailable,
302     NoImagesRemaining,
303     InvalidExifPayload,
304     InvalidImageGrid(String),
305     InvalidCodecSpecificOption,
306     TruncatedData,
307     IoNotSet,
308     IoError,
309     WaitingOnIo,
310     InvalidArgument,
311     NotImplemented,
312     OutOfMemory,
313     CannotChangeSetting,
314     IncompatibleImage,
315     EncodeGainMapFailed,
316     DecodeGainMapFailed,
317     InvalidToneMappedImage(String),
318 }
319 
320 pub type AvifResult<T> = Result<T, AvifError>;
321 
322 #[repr(i32)]
323 #[derive(Clone, Copy, Debug, Default)]
324 pub enum AndroidMediaCodecOutputColorFormat {
325     // Flexible YUV 420 format used for 8-bit images:
326     // https://developer.android.com/reference/android/media/MediaCodecInfo.CodecCapabilities#COLOR_FormatYUV420Flexible
327     #[default]
328     Yuv420Flexible = 2135033992,
329     // YUV P010 format used for 10-bit images:
330     // https://developer.android.com/reference/android/media/MediaCodecInfo.CodecCapabilities#COLOR_FormatYUVP010
331     P010 = 54,
332 }
333 
334 impl From<i32> for AndroidMediaCodecOutputColorFormat {
from(value: i32) -> Self335     fn from(value: i32) -> Self {
336         match value {
337             2135033992 => Self::Yuv420Flexible,
338             54 => Self::P010,
339             _ => Self::default(),
340         }
341     }
342 }
343 
344 trait OptionExtension {
345     type Value;
346 
unwrap_ref(&self) -> &Self::Value347     fn unwrap_ref(&self) -> &Self::Value;
unwrap_mut(&mut self) -> &mut Self::Value348     fn unwrap_mut(&mut self) -> &mut Self::Value;
349 }
350 
351 impl<T> OptionExtension for Option<T> {
352     type Value = T;
353 
unwrap_ref(&self) -> &T354     fn unwrap_ref(&self) -> &T {
355         self.as_ref().unwrap()
356     }
357 
unwrap_mut(&mut self) -> &mut T358     fn unwrap_mut(&mut self) -> &mut T {
359         self.as_mut().unwrap()
360     }
361 }
362 
363 macro_rules! checked_add {
364     ($a:expr, $b:expr) => {
365         $a.checked_add($b)
366             .ok_or(AvifError::BmffParseFailed("".into()))
367     };
368 }
369 
370 macro_rules! checked_sub {
371     ($a:expr, $b:expr) => {
372         $a.checked_sub($b)
373             .ok_or(AvifError::BmffParseFailed("".into()))
374     };
375 }
376 
377 macro_rules! checked_mul {
378     ($a:expr, $b:expr) => {
379         $a.checked_mul($b)
380             .ok_or(AvifError::BmffParseFailed("".into()))
381     };
382 }
383 
384 macro_rules! checked_decr {
385     ($a:expr, $b:expr) => {
386         $a = checked_sub!($a, $b)?
387     };
388 }
389 
390 macro_rules! checked_incr {
391     ($a:expr, $b:expr) => {
392         $a = checked_add!($a, $b)?
393     };
394 }
395 
396 pub(crate) use checked_add;
397 pub(crate) use checked_decr;
398 pub(crate) use checked_incr;
399 pub(crate) use checked_mul;
400 pub(crate) use checked_sub;
401