blob: 74202a014b69ca57f9fa288713e4200bfc3df46f [file] [log] [blame]
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![deny(unsafe_op_in_unsafe_fn)]
#![cfg_attr(feature = "disable_cfi", feature(no_sanitize))]
#[macro_use]
mod internal_utils;
pub mod decoder;
pub mod image;
pub mod reformat;
pub mod utils;
#[cfg(feature = "capi")]
pub mod capi;
/// cbindgen:ignore
mod codecs;
mod parser;
use image::*;
// Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1516634.
#[derive(Default)]
pub struct NonRandomHasherState;
impl std::hash::BuildHasher for NonRandomHasherState {
type Hasher = std::collections::hash_map::DefaultHasher;
fn build_hasher(&self) -> std::collections::hash_map::DefaultHasher {
std::collections::hash_map::DefaultHasher::new()
}
}
pub type HashMap<K, V> = std::collections::HashMap<K, V, NonRandomHasherState>;
pub type HashSet<K> = std::collections::HashSet<K, NonRandomHasherState>;
/// cbindgen:enum-trailing-values=[Count]
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
// See https://aomediacodec.github.io/av1-spec/#color-config-semantics.
pub enum PixelFormat {
#[default]
None = 0,
Yuv444 = 1,
Yuv422 = 2,
Yuv420 = 3, // Also used for alpha items when 4:0:0 is not supported by the codec.
Yuv400 = 4,
// The following formats are not found in the AV1 spec. They are formats that are supported by
// Android platform. They are intended to be pass-through formats that are used only by the
// Android MediaCodec wrapper. All internal functions will treat them as opaque.
AndroidP010 = 5,
AndroidNv12 = 6,
AndroidNv21 = 7,
}
impl PixelFormat {
pub fn is_monochrome(&self) -> bool {
*self == Self::Yuv400
}
pub fn plane_count(&self) -> usize {
match self {
PixelFormat::None
| PixelFormat::AndroidP010
| PixelFormat::AndroidNv12
| PixelFormat::AndroidNv21 => 0,
PixelFormat::Yuv400 => 1,
PixelFormat::Yuv420 | PixelFormat::Yuv422 | PixelFormat::Yuv444 => 3,
}
}
pub fn chroma_shift_x(&self) -> (u32, u32) {
match self {
Self::Yuv422 | Self::Yuv420 => (1, 0),
Self::AndroidP010 => (1, 1),
_ => (0, 0),
}
}
pub fn apply_chroma_shift_x(&self, value: u32) -> u32 {
let chroma_shift = self.chroma_shift_x();
(value >> chroma_shift.0) << chroma_shift.1
}
pub fn chroma_shift_y(&self) -> u32 {
match self {
Self::Yuv420 | Self::AndroidP010 | Self::AndroidNv12 | Self::AndroidNv21 => 1,
_ => 0,
}
}
pub fn apply_chroma_shift_y(&self, value: u32) -> u32 {
value >> self.chroma_shift_y()
}
}
// See https://aomediacodec.github.io/av1-spec/#color-config-semantics
// and https://en.wikipedia.org/wiki/Chroma_subsampling#Sampling_positions.
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub enum ChromaSamplePosition {
#[default]
Unknown = 0, // Corresponds to AV1's CSP_UNKNOWN.
Vertical = 1, // Corresponds to AV1's CSP_VERTICAL (MPEG-2, also called "left").
Colocated = 2, // Corresponds to AV1's CSP_COLOCATED (BT.2020, also called "top-left").
Reserved = 3, // Corresponds to AV1's CSP_RESERVED.
}
impl ChromaSamplePosition {
// The AV1 Specification (Version 1.0.0 with Errata 1) does not have a CSP_CENTER value
// for chroma_sample_position, so we are forced to signal CSP_UNKNOWN in the AV1 bitstream
// when the chroma sample position is CENTER.
const CENTER: ChromaSamplePosition = ChromaSamplePosition::Unknown; // JPEG/"center"
}
impl From<u32> for ChromaSamplePosition {
fn from(value: u32) -> Self {
match value {
0 => Self::Unknown,
1 => Self::Vertical,
2 => Self::Colocated,
3 => Self::Reserved,
_ => Self::Unknown,
}
}
}
// See https://aomediacodec.github.io/av1-spec/#color-config-semantics.
#[repr(u16)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub enum ColorPrimaries {
Unknown = 0,
Srgb = 1,
#[default]
Unspecified = 2,
Bt470m = 4,
Bt470bg = 5,
Bt601 = 6,
Smpte240 = 7,
GenericFilm = 8,
Bt2020 = 9,
Xyz = 10,
Smpte431 = 11,
Smpte432 = 12,
Ebu3213 = 22,
}
impl From<u16> for ColorPrimaries {
fn from(value: u16) -> Self {
match value {
0 => Self::Unknown,
1 => Self::Srgb,
2 => Self::Unspecified,
4 => Self::Bt470m,
5 => Self::Bt470bg,
6 => Self::Bt601,
7 => Self::Smpte240,
8 => Self::GenericFilm,
9 => Self::Bt2020,
10 => Self::Xyz,
11 => Self::Smpte431,
12 => Self::Smpte432,
22 => Self::Ebu3213,
_ => Self::default(),
}
}
}
#[allow(non_camel_case_types, non_upper_case_globals)]
impl ColorPrimaries {
pub const Bt709: Self = Self::Srgb;
pub const Iec61966_2_4: Self = Self::Srgb;
pub const Bt2100: Self = Self::Bt2020;
pub const Dci_p3: Self = Self::Smpte432;
}
// See https://aomediacodec.github.io/av1-spec/#color-config-semantics.
#[repr(u16)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub enum TransferCharacteristics {
Unknown = 0,
Bt709 = 1,
#[default]
Unspecified = 2,
Reserved = 3,
Bt470m = 4, // 2.2 gamma
Bt470bg = 5, // 2.8 gamma
Bt601 = 6,
Smpte240 = 7,
Linear = 8,
Log100 = 9,
Log100Sqrt10 = 10,
Iec61966 = 11,
Bt1361 = 12,
Srgb = 13,
Bt2020_10bit = 14,
Bt2020_12bit = 15,
Pq = 16, // Perceptual Quantizer (HDR); BT.2100 PQ
Smpte428 = 17,
Hlg = 18, // Hybrid Log-Gamma (HDR); ARIB STD-B67; BT.2100 HLG
}
impl From<u16> for TransferCharacteristics {
fn from(value: u16) -> Self {
match value {
0 => Self::Unknown,
1 => Self::Bt709,
2 => Self::Unspecified,
3 => Self::Reserved,
4 => Self::Bt470m,
5 => Self::Bt470bg,
6 => Self::Bt601,
7 => Self::Smpte240,
8 => Self::Linear,
9 => Self::Log100,
10 => Self::Log100Sqrt10,
11 => Self::Iec61966,
12 => Self::Bt1361,
13 => Self::Srgb,
14 => Self::Bt2020_10bit,
15 => Self::Bt2020_12bit,
16 => Self::Pq,
17 => Self::Smpte428,
18 => Self::Hlg,
_ => Self::default(),
}
}
}
#[allow(non_upper_case_globals)]
impl TransferCharacteristics {
pub const Smpte2084: Self = Self::Pq;
}
// See https://aomediacodec.github.io/av1-spec/#color-config-semantics.
#[repr(u16)]
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub enum MatrixCoefficients {
Identity = 0,
Bt709 = 1,
#[default]
Unspecified = 2,
Reserved = 3,
Fcc = 4,
Bt470bg = 5,
Bt601 = 6,
Smpte240 = 7,
Ycgco = 8,
Bt2020Ncl = 9,
Bt2020Cl = 10,
Smpte2085 = 11,
ChromaDerivedNcl = 12,
ChromaDerivedCl = 13,
Ictcp = 14,
YcgcoRe = 16,
YcgcoRo = 17,
}
impl From<u16> for MatrixCoefficients {
fn from(value: u16) -> Self {
match value {
0 => Self::Identity,
1 => Self::Bt709,
2 => Self::Unspecified,
3 => Self::Reserved,
4 => Self::Fcc,
5 => Self::Bt470bg,
6 => Self::Bt601,
7 => Self::Smpte240,
8 => Self::Ycgco,
9 => Self::Bt2020Ncl,
10 => Self::Bt2020Cl,
11 => Self::Smpte2085,
12 => Self::ChromaDerivedNcl,
13 => Self::ChromaDerivedCl,
14 => Self::Ictcp,
16 => Self::YcgcoRe,
17 => Self::YcgcoRo,
_ => Self::default(),
}
}
}
#[derive(Debug, Default, PartialEq)]
pub enum AvifError {
#[default]
Ok,
UnknownError(String),
InvalidFtyp,
NoContent,
NoYuvFormatSelected,
ReformatFailed,
UnsupportedDepth,
EncodeColorFailed,
EncodeAlphaFailed,
BmffParseFailed(String),
MissingImageItem,
DecodeColorFailed,
DecodeAlphaFailed,
ColorAlphaSizeMismatch,
IspeSizeMismatch,
NoCodecAvailable,
NoImagesRemaining,
InvalidExifPayload,
InvalidImageGrid(String),
InvalidCodecSpecificOption,
TruncatedData,
IoNotSet,
IoError,
WaitingOnIo,
InvalidArgument,
NotImplemented,
OutOfMemory,
CannotChangeSetting,
IncompatibleImage,
EncodeGainMapFailed,
DecodeGainMapFailed,
InvalidToneMappedImage(String),
}
pub type AvifResult<T> = Result<T, AvifError>;
#[repr(i32)]
#[derive(Clone, Copy, Debug, Default)]
pub enum AndroidMediaCodecOutputColorFormat {
// Flexible YUV 420 format used for 8-bit images:
// https://developer.android.com/reference/android/media/MediaCodecInfo.CodecCapabilities#COLOR_FormatYUV420Flexible
#[default]
Yuv420Flexible = 2135033992,
// YUV P010 format used for 10-bit images:
// https://developer.android.com/reference/android/media/MediaCodecInfo.CodecCapabilities#COLOR_FormatYUVP010
P010 = 54,
}
impl From<i32> for AndroidMediaCodecOutputColorFormat {
fn from(value: i32) -> Self {
match value {
2135033992 => Self::Yuv420Flexible,
54 => Self::P010,
_ => Self::default(),
}
}
}
trait OptionExtension {
type Value;
fn unwrap_ref(&self) -> &Self::Value;
fn unwrap_mut(&mut self) -> &mut Self::Value;
}
impl<T> OptionExtension for Option<T> {
type Value = T;
fn unwrap_ref(&self) -> &T {
self.as_ref().unwrap()
}
fn unwrap_mut(&mut self) -> &mut T {
self.as_mut().unwrap()
}
}
macro_rules! checked_add {
($a:expr, $b:expr) => {
$a.checked_add($b)
.ok_or(AvifError::BmffParseFailed("".into()))
};
}
macro_rules! checked_sub {
($a:expr, $b:expr) => {
$a.checked_sub($b)
.ok_or(AvifError::BmffParseFailed("".into()))
};
}
macro_rules! checked_mul {
($a:expr, $b:expr) => {
$a.checked_mul($b)
.ok_or(AvifError::BmffParseFailed("".into()))
};
}
macro_rules! checked_decr {
($a:expr, $b:expr) => {
$a = checked_sub!($a, $b)?
};
}
macro_rules! checked_incr {
($a:expr, $b:expr) => {
$a = checked_add!($a, $b)?
};
}
pub(crate) use checked_add;
pub(crate) use checked_decr;
pub(crate) use checked_incr;
pub(crate) use checked_mul;
pub(crate) use checked_sub;
#[derive(Clone, Copy, Debug, Default)]
pub struct Grid {
pub rows: u32,
pub columns: u32,
pub width: u32,
pub height: u32,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub enum Category {
#[default]
Color,
Alpha,
Gainmap,
}
impl Category {
const COUNT: usize = 3;
const ALL: [Category; Category::COUNT] = [Self::Color, Self::Alpha, Self::Gainmap];
const ALL_USIZE: [usize; Category::COUNT] = [0, 1, 2];
pub(crate) fn usize(self) -> usize {
match self {
Category::Color => 0,
Category::Alpha => 1,
Category::Gainmap => 2,
}
}
pub fn planes(&self) -> &[Plane] {
match self {
Category::Alpha => &A_PLANE,
_ => &YUV_PLANES,
}
}
}
/// cbindgen:rename-all=CamelCase
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[repr(C)]
pub struct PixelAspectRatio {
pub h_spacing: u32,
pub v_spacing: u32,
}
/// cbindgen:field-names=[maxCLL, maxPALL]
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct ContentLightLevelInformation {
pub max_cll: u16,
pub max_pall: u16,
}
#[derive(Clone, Debug, Default)]
pub struct Nclx {
pub color_primaries: ColorPrimaries,
pub transfer_characteristics: TransferCharacteristics,
pub matrix_coefficients: MatrixCoefficients,
pub yuv_range: YuvRange,
}
pub const MAX_AV1_LAYER_COUNT: usize = 4;