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