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