• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #![cfg_attr(feature = "disable_cfi", feature(no_sanitize))]
17 
18 #[macro_use]
19 mod internal_utils;
20 
21 pub mod decoder;
22 pub mod image;
23 pub mod reformat;
24 pub mod utils;
25 
26 #[cfg(feature = "capi")]
27 pub mod capi;
28 
29 /// cbindgen:ignore
30 mod codecs;
31 
32 mod parser;
33 
34 use image::*;
35 
36 // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1516634.
37 #[derive(Default)]
38 pub struct NonRandomHasherState;
39 
40 impl std::hash::BuildHasher for NonRandomHasherState {
41     type Hasher = std::collections::hash_map::DefaultHasher;
build_hasher(&self) -> std::collections::hash_map::DefaultHasher42     fn build_hasher(&self) -> std::collections::hash_map::DefaultHasher {
43         std::collections::hash_map::DefaultHasher::new()
44     }
45 }
46 
47 pub type HashMap<K, V> = std::collections::HashMap<K, V, NonRandomHasherState>;
48 pub type HashSet<K> = std::collections::HashSet<K, NonRandomHasherState>;
49 
50 /// cbindgen:enum-trailing-values=[Count]
51 #[repr(C)]
52 #[derive(Clone, Copy, Debug, Default, PartialEq)]
53 // See https://aomediacodec.github.io/av1-spec/#color-config-semantics.
54 pub enum PixelFormat {
55     #[default]
56     None = 0,
57     Yuv444 = 1,
58     Yuv422 = 2,
59     Yuv420 = 3, // Also used for alpha items when 4:0:0 is not supported by the codec.
60     Yuv400 = 4,
61     // The following formats are not found in the AV1 spec. They are formats that are supported by
62     // Android platform. They are intended to be pass-through formats that are used only by the
63     // Android MediaCodec wrapper. All internal functions will treat them as opaque.
64     AndroidP010 = 5,
65     AndroidNv12 = 6,
66     AndroidNv21 = 7,
67 }
68 
69 impl PixelFormat {
is_monochrome(&self) -> bool70     pub fn is_monochrome(&self) -> bool {
71         *self == Self::Yuv400
72     }
73 
plane_count(&self) -> usize74     pub fn plane_count(&self) -> usize {
75         match self {
76             PixelFormat::None
77             | PixelFormat::AndroidP010
78             | PixelFormat::AndroidNv12
79             | PixelFormat::AndroidNv21 => 0,
80             PixelFormat::Yuv400 => 1,
81             PixelFormat::Yuv420 | PixelFormat::Yuv422 | PixelFormat::Yuv444 => 3,
82         }
83     }
84 
chroma_shift_x(&self) -> (u32, u32)85     pub fn chroma_shift_x(&self) -> (u32, u32) {
86         match self {
87             Self::Yuv422 | Self::Yuv420 => (1, 0),
88             Self::AndroidP010 | Self::AndroidNv12 => (1, 1),
89             _ => (0, 0),
90         }
91     }
92 
apply_chroma_shift_x(&self, value: u32) -> u3293     pub fn apply_chroma_shift_x(&self, value: u32) -> u32 {
94         let chroma_shift = self.chroma_shift_x();
95         (value >> chroma_shift.0) << chroma_shift.1
96     }
97 
chroma_shift_y(&self) -> u3298     pub fn chroma_shift_y(&self) -> u32 {
99         match self {
100             Self::Yuv420 | Self::AndroidP010 | Self::AndroidNv12 | Self::AndroidNv21 => 1,
101             _ => 0,
102         }
103     }
104 
apply_chroma_shift_y(&self, value: u32) -> u32105     pub fn apply_chroma_shift_y(&self, value: u32) -> u32 {
106         value >> self.chroma_shift_y()
107     }
108 }
109 
110 // See https://aomediacodec.github.io/av1-spec/#color-config-semantics
111 // and https://en.wikipedia.org/wiki/Chroma_subsampling#Sampling_positions.
112 #[repr(C)]
113 #[derive(Clone, Copy, Debug, Default, PartialEq)]
114 pub enum ChromaSamplePosition {
115     #[default]
116     Unknown = 0, // Corresponds to AV1's CSP_UNKNOWN.
117     Vertical = 1,  // Corresponds to AV1's CSP_VERTICAL (MPEG-2, also called "left").
118     Colocated = 2, // Corresponds to AV1's CSP_COLOCATED (BT.2020, also called "top-left").
119     Reserved = 3,  // Corresponds to AV1's CSP_RESERVED.
120 }
121 
122 impl ChromaSamplePosition {
123     // The AV1 Specification (Version 1.0.0 with Errata 1) does not have a CSP_CENTER value
124     // for chroma_sample_position, so we are forced to signal CSP_UNKNOWN in the AV1 bitstream
125     // when the chroma sample position is CENTER.
126     const CENTER: ChromaSamplePosition = ChromaSamplePosition::Unknown; // JPEG/"center"
127 }
128 
129 impl From<u32> for ChromaSamplePosition {
from(value: u32) -> Self130     fn from(value: u32) -> Self {
131         match value {
132             0 => Self::Unknown,
133             1 => Self::Vertical,
134             2 => Self::Colocated,
135             3 => Self::Reserved,
136             _ => Self::Unknown,
137         }
138     }
139 }
140 
141 // See https://aomediacodec.github.io/av1-spec/#color-config-semantics.
142 #[repr(u16)]
143 #[derive(Clone, Copy, Debug, Default, PartialEq)]
144 pub enum ColorPrimaries {
145     Unknown = 0,
146     Srgb = 1,
147     #[default]
148     Unspecified = 2,
149     Bt470m = 4,
150     Bt470bg = 5,
151     Bt601 = 6,
152     Smpte240 = 7,
153     GenericFilm = 8,
154     Bt2020 = 9,
155     Xyz = 10,
156     Smpte431 = 11,
157     Smpte432 = 12,
158     Ebu3213 = 22,
159 }
160 
161 impl From<u16> for ColorPrimaries {
from(value: u16) -> Self162     fn from(value: u16) -> Self {
163         match value {
164             0 => Self::Unknown,
165             1 => Self::Srgb,
166             2 => Self::Unspecified,
167             4 => Self::Bt470m,
168             5 => Self::Bt470bg,
169             6 => Self::Bt601,
170             7 => Self::Smpte240,
171             8 => Self::GenericFilm,
172             9 => Self::Bt2020,
173             10 => Self::Xyz,
174             11 => Self::Smpte431,
175             12 => Self::Smpte432,
176             22 => Self::Ebu3213,
177             _ => Self::default(),
178         }
179     }
180 }
181 
182 #[allow(non_camel_case_types, non_upper_case_globals)]
183 impl ColorPrimaries {
184     pub const Bt709: Self = Self::Srgb;
185     pub const Iec61966_2_4: Self = Self::Srgb;
186     pub const Bt2100: Self = Self::Bt2020;
187     pub const Dci_p3: Self = Self::Smpte432;
188 }
189 
190 // See https://aomediacodec.github.io/av1-spec/#color-config-semantics.
191 #[repr(u16)]
192 #[derive(Clone, Copy, Debug, Default, PartialEq)]
193 pub enum TransferCharacteristics {
194     Unknown = 0,
195     Bt709 = 1,
196     #[default]
197     Unspecified = 2,
198     Reserved = 3,
199     Bt470m = 4,  // 2.2 gamma
200     Bt470bg = 5, // 2.8 gamma
201     Bt601 = 6,
202     Smpte240 = 7,
203     Linear = 8,
204     Log100 = 9,
205     Log100Sqrt10 = 10,
206     Iec61966 = 11,
207     Bt1361 = 12,
208     Srgb = 13,
209     Bt2020_10bit = 14,
210     Bt2020_12bit = 15,
211     Pq = 16, // Perceptual Quantizer (HDR); BT.2100 PQ
212     Smpte428 = 17,
213     Hlg = 18, // Hybrid Log-Gamma (HDR); ARIB STD-B67; BT.2100 HLG
214 }
215 
216 impl From<u16> for TransferCharacteristics {
from(value: u16) -> Self217     fn from(value: u16) -> Self {
218         match value {
219             0 => Self::Unknown,
220             1 => Self::Bt709,
221             2 => Self::Unspecified,
222             3 => Self::Reserved,
223             4 => Self::Bt470m,
224             5 => Self::Bt470bg,
225             6 => Self::Bt601,
226             7 => Self::Smpte240,
227             8 => Self::Linear,
228             9 => Self::Log100,
229             10 => Self::Log100Sqrt10,
230             11 => Self::Iec61966,
231             12 => Self::Bt1361,
232             13 => Self::Srgb,
233             14 => Self::Bt2020_10bit,
234             15 => Self::Bt2020_12bit,
235             16 => Self::Pq,
236             17 => Self::Smpte428,
237             18 => Self::Hlg,
238             _ => Self::default(),
239         }
240     }
241 }
242 
243 #[allow(non_upper_case_globals)]
244 impl TransferCharacteristics {
245     pub const Smpte2084: Self = Self::Pq;
246 }
247 
248 // See https://aomediacodec.github.io/av1-spec/#color-config-semantics.
249 #[repr(u16)]
250 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
251 pub enum MatrixCoefficients {
252     Identity = 0,
253     Bt709 = 1,
254     #[default]
255     Unspecified = 2,
256     Reserved = 3,
257     Fcc = 4,
258     Bt470bg = 5,
259     Bt601 = 6,
260     Smpte240 = 7,
261     Ycgco = 8,
262     Bt2020Ncl = 9,
263     Bt2020Cl = 10,
264     Smpte2085 = 11,
265     ChromaDerivedNcl = 12,
266     ChromaDerivedCl = 13,
267     Ictcp = 14,
268     YcgcoRe = 16,
269     YcgcoRo = 17,
270 }
271 
272 impl From<u16> for MatrixCoefficients {
from(value: u16) -> Self273     fn from(value: u16) -> Self {
274         match value {
275             0 => Self::Identity,
276             1 => Self::Bt709,
277             2 => Self::Unspecified,
278             3 => Self::Reserved,
279             4 => Self::Fcc,
280             5 => Self::Bt470bg,
281             6 => Self::Bt601,
282             7 => Self::Smpte240,
283             8 => Self::Ycgco,
284             9 => Self::Bt2020Ncl,
285             10 => Self::Bt2020Cl,
286             11 => Self::Smpte2085,
287             12 => Self::ChromaDerivedNcl,
288             13 => Self::ChromaDerivedCl,
289             14 => Self::Ictcp,
290             16 => Self::YcgcoRe,
291             17 => Self::YcgcoRo,
292             _ => Self::default(),
293         }
294     }
295 }
296 
297 #[derive(Debug, Default, PartialEq)]
298 pub enum AvifError {
299     #[default]
300     Ok,
301     UnknownError(String),
302     InvalidFtyp,
303     NoContent,
304     NoYuvFormatSelected,
305     ReformatFailed,
306     UnsupportedDepth,
307     EncodeColorFailed,
308     EncodeAlphaFailed,
309     BmffParseFailed(String),
310     MissingImageItem,
311     DecodeColorFailed,
312     DecodeAlphaFailed,
313     ColorAlphaSizeMismatch,
314     IspeSizeMismatch,
315     NoCodecAvailable,
316     NoImagesRemaining,
317     InvalidExifPayload,
318     InvalidImageGrid(String),
319     InvalidCodecSpecificOption,
320     TruncatedData,
321     IoNotSet,
322     IoError,
323     WaitingOnIo,
324     InvalidArgument,
325     NotImplemented,
326     OutOfMemory,
327     CannotChangeSetting,
328     IncompatibleImage,
329     EncodeGainMapFailed,
330     DecodeGainMapFailed,
331     InvalidToneMappedImage(String),
332 }
333 
334 pub type AvifResult<T> = Result<T, AvifError>;
335 
336 #[repr(i32)]
337 #[derive(Clone, Copy, Debug, Default)]
338 pub enum AndroidMediaCodecOutputColorFormat {
339     // Flexible YUV 420 format used for 8-bit images:
340     // https://developer.android.com/reference/android/media/MediaCodecInfo.CodecCapabilities#COLOR_FormatYUV420Flexible
341     #[default]
342     Yuv420Flexible = 2135033992,
343     // YUV P010 format used for 10-bit images:
344     // https://developer.android.com/reference/android/media/MediaCodecInfo.CodecCapabilities#COLOR_FormatYUVP010
345     P010 = 54,
346 }
347 
348 impl From<i32> for AndroidMediaCodecOutputColorFormat {
from(value: i32) -> Self349     fn from(value: i32) -> Self {
350         match value {
351             2135033992 => Self::Yuv420Flexible,
352             54 => Self::P010,
353             _ => Self::default(),
354         }
355     }
356 }
357 
358 trait OptionExtension {
359     type Value;
360 
unwrap_ref(&self) -> &Self::Value361     fn unwrap_ref(&self) -> &Self::Value;
unwrap_mut(&mut self) -> &mut Self::Value362     fn unwrap_mut(&mut self) -> &mut Self::Value;
363 }
364 
365 impl<T> OptionExtension for Option<T> {
366     type Value = T;
367 
unwrap_ref(&self) -> &T368     fn unwrap_ref(&self) -> &T {
369         self.as_ref().unwrap()
370     }
371 
unwrap_mut(&mut self) -> &mut T372     fn unwrap_mut(&mut self) -> &mut T {
373         self.as_mut().unwrap()
374     }
375 }
376 
377 macro_rules! checked_add {
378     ($a:expr, $b:expr) => {
379         $a.checked_add($b)
380             .ok_or(AvifError::BmffParseFailed("".into()))
381     };
382 }
383 
384 macro_rules! checked_sub {
385     ($a:expr, $b:expr) => {
386         $a.checked_sub($b)
387             .ok_or(AvifError::BmffParseFailed("".into()))
388     };
389 }
390 
391 macro_rules! checked_mul {
392     ($a:expr, $b:expr) => {
393         $a.checked_mul($b)
394             .ok_or(AvifError::BmffParseFailed("".into()))
395     };
396 }
397 
398 macro_rules! checked_decr {
399     ($a:expr, $b:expr) => {
400         $a = checked_sub!($a, $b)?
401     };
402 }
403 
404 macro_rules! checked_incr {
405     ($a:expr, $b:expr) => {
406         $a = checked_add!($a, $b)?
407     };
408 }
409 
410 pub(crate) use checked_add;
411 pub(crate) use checked_decr;
412 pub(crate) use checked_incr;
413 pub(crate) use checked_mul;
414 pub(crate) use checked_sub;
415 
416 #[derive(Clone, Copy, Debug, Default)]
417 pub struct Grid {
418     pub rows: u32,
419     pub columns: u32,
420     pub width: u32,
421     pub height: u32,
422 }
423 
424 #[derive(Clone, Copy, Debug, Default, PartialEq)]
425 pub enum Category {
426     #[default]
427     Color,
428     Alpha,
429     Gainmap,
430 }
431 
432 impl Category {
433     const COUNT: usize = 3;
434     const ALL: [Category; Category::COUNT] = [Self::Color, Self::Alpha, Self::Gainmap];
435     const ALL_USIZE: [usize; Category::COUNT] = [0, 1, 2];
436 
usize(self) -> usize437     pub(crate) fn usize(self) -> usize {
438         match self {
439             Category::Color => 0,
440             Category::Alpha => 1,
441             Category::Gainmap => 2,
442         }
443     }
444 
planes(&self) -> &[Plane]445     pub fn planes(&self) -> &[Plane] {
446         match self {
447             Category::Alpha => &A_PLANE,
448             _ => &YUV_PLANES,
449         }
450     }
451 }
452 
453 /// cbindgen:rename-all=CamelCase
454 #[derive(Clone, Copy, Debug, Default, PartialEq)]
455 #[repr(C)]
456 pub struct PixelAspectRatio {
457     pub h_spacing: u32,
458     pub v_spacing: u32,
459 }
460 
461 /// cbindgen:field-names=[maxCLL, maxPALL]
462 #[repr(C)]
463 #[derive(Clone, Copy, Debug, Default, PartialEq)]
464 pub struct ContentLightLevelInformation {
465     pub max_cll: u16,
466     pub max_pall: u16,
467 }
468 
469 #[derive(Clone, Debug, Default)]
470 pub struct Nclx {
471     pub color_primaries: ColorPrimaries,
472     pub transfer_characteristics: TransferCharacteristics,
473     pub matrix_coefficients: MatrixCoefficients,
474     pub yuv_range: YuvRange,
475 }
476 
477 pub const MAX_AV1_LAYER_COUNT: usize = 4;
478