#![cfg_attr(feature = "registry", doc = "```no_run")]
#![cfg_attr(not(feature = "registry"), doc = "```ignore")]
pub mod alpha;
pub mod api;
pub mod avis;
pub mod box_parser;
pub mod cicp;
pub mod derived;
pub mod error;
mod frame_bridge;
pub mod grid;
pub mod image;
pub mod inspect;
pub mod meta;
pub mod mux;
pub mod overlay;
pub mod parser;
pub mod region;
pub mod sample_group;
pub mod transform;
#[cfg(feature = "registry")]
mod av1_config;
#[cfg(feature = "registry")]
pub mod api_codec;
#[cfg(feature = "registry")]
pub mod decoder;
#[cfg(feature = "registry")]
pub mod encoder;
#[cfg(feature = "registry")]
pub mod sequence;
#[cfg(feature = "registry")]
pub mod signal;
#[cfg(feature = "registry")]
pub mod still;
pub use alpha::{composite_alpha, find_alpha_item_id, ALPHA_URN_PREFIX};
pub use api::{
info, probe, AvifImage, ColorInfo, ColorRange, DecodeOptions, EncodeOptions, EncodeSpeed,
Frame, ImageInfo, Metadata, PixelFormat, Plane, RgbImage, RgbaImage, StillChroma,
};
pub use avis::{
audit_avis_profile_compliance, audit_avis_sequence, audit_edit_list, inspect_avis, parse_avis,
parse_prft, parse_producer_reference_times, parse_ssix, parse_subsegment_indexes, sample_bytes,
AvisInfo, AvisMeta, AvisProfileCompliance, AvisSequenceCompliance, EditListCompliance,
EditListEntry, ProducerReferenceTime, Sample, SubsegmentIndex, SubsegmentRange, HANDLER_PICT,
NTP_UNIX_EPOCH_OFFSET_SECONDS,
};
pub use cicp::{
effective_cicp, is_matrix_reserved, is_primaries_reserved, is_transfer_reserved, matrix_name,
primaries_name, transfer_name, CicpTriple,
};
pub use derived::{
audit_alpha_bit_depth, audit_avif_profile_compliance, audit_iden_derivations, audit_pred_brand,
audit_sequence_header_obu, audit_tone_map, build_derivation_graph, normalize_full_range_plane,
output_dims_from_reconstructed, parse_grpl, reconstructed_dims, resolve_grids,
resolve_iden_derivations, resolve_overlays, resolve_tone_maps, transform_chain,
AlphaBitDepthAudit, AvifProfile, AvifProfileCompliance, BracketingKind, DerivationGraph,
DerivationKind, DerivationNode, DimTransform, EntityGroup, GainMapChannel, GainMapMetadata,
GainMapRational, GridResolution, GridTilePlacement, IdenCompliance, IdenResolution,
ImageOverlay, Mif1Compliance, OverlayEntry, OverlayPlacement, OverlayResolution,
PredBrandCompliance, SampleTransform, SequenceHeaderObuAudit, Token, ToneMapCompliance,
ToneMapResolution, MAX_DERIVATION_DEPTH,
};
pub use error::{AvifError, Result};
pub type Error = AvifError;
pub use grid::{composite_grid, ImageGrid};
pub use image::{AvifFrame, AvifPixelFormat, AvifPlane};
pub use inspect::{
coded_item_dependencies, derivation_graph, entity_groups, gain_map_metadata, inspect,
is_font_item, item_payload_bytes, region_items, region_items_for, text_items, text_items_for,
transforms_for, AvifInfo, CodedItemDependencies, ResolvedRegionItem, ResolvedTextItem,
};
pub use meta::{
A1lx, A1op, Aebr, Afbr, Altt, AuxC, AuxKind, Cclv, Clap, Clli, Cmex, Cmin, Colr, Crtt, Dobr,
Elng, Fade, Fnch, Fobr, Imir, IrefEntry, Irot, Iscl, Ispe, ItemInfo, ItemLocation, Lsel, MaskC,
Mdcv, Mdft, Meta, Pano, PanoGrid, Pasp, Pixi, Prdi, Property, Rloc, Rref, Splt, Ssld, Sstr,
Stpe, Subs, SubsEntry, Tols, Txlo, Udes, Wbbr, Wipe, Zoom, AUX_URN_ALPHA_HEVC,
AUX_URN_ALPHA_MPEG, AUX_URN_DEPTH_HEVC, AUX_URN_DEPTH_MPEG, AUX_URN_HDR_GAINMAP,
ITEM_TYPE_EXIF, ITEM_TYPE_IDEN, ITEM_TYPE_IOVL, ITEM_TYPE_MIME, ITEM_TYPE_SATO, ITEM_TYPE_TMAP,
ITEM_TYPE_URI,
};
pub use mux::{
encode_still_av1, AvifGridMuxer, AvifMuxer, AvifOverlayMuxer, BurstAlpha, BurstMember,
EntityGroupSpec, GridTile, IdentityDerivation, OverlayLayer, ToneMapItem,
};
pub use overlay::{composite_overlay, OverlayInput, MAX_OVERLAY_CANVAS_PIXELS};
pub use parser::{
audit_mif1, classify_brands, item_bytes, item_bytes_owned, item_bytes_owned_full,
item_bytes_owned_with_idat, item_bytes_with_idat, parse, parse_header, AvifFile, AvifHeader,
BrandClass, BRAND_AVIF, BRAND_AVIO, BRAND_AVIS, BRAND_MA1A, BRAND_MA1B, BRAND_MIAF, BRAND_MIF1,
BRAND_MSF1, ITEM_TYPE_AV01, ITEM_TYPE_GRID,
};
pub use region::{
resolve_derived_region_items, DerivedRegionItem, RegionGeometry, RegionItem, ITEM_TYPE_MSKI,
ITEM_TYPE_RGAN, REF_TYPE_DRGN,
};
pub use sample_group::{
parse_csgp, parse_sample_group_descriptions, parse_sample_to_groups, parse_sbgp, parse_sgpd,
BracketingEntry, SampleGroupDescription, SampleToGroup, SampleToGroupKind, SampleToGroupRun,
VisualEquivalenceEntry,
};
pub use transform::{apply_clap, apply_imir, apply_irot, crop_top_left};
#[cfg(feature = "registry")]
pub use api_codec::{
decode, decode_all, decode_all_with, decode_from, decode_rgb8, decode_rgba8, decode_with,
encode, encode_all, encode_rgb8, encode_rgba8, encode_to,
};
#[cfg(feature = "registry")]
pub use decoder::{
make_decoder, AvifDecoder, AvifDecoderOptions, MAX_GRID_CANVAS_PIXELS, MAX_ITEM_DECODES,
};
#[cfg(feature = "registry")]
pub use encoder::{
make_encoder, quality_to_base_q_idx, AvifEncoder, AvifEncoderOptions, ENCODER_PIXEL_FORMATS,
};
#[cfg(feature = "registry")]
pub use sequence::{encode_sequence, SequenceEncodeOptions};
#[cfg(feature = "registry")]
pub use signal::{color_signal_for, labelled_pixel_format, miaf_default_signal};
#[cfg(feature = "registry")]
#[allow(deprecated)]
pub use still::StillEncodeOptions;
#[cfg(feature = "registry")]
pub use still::{
elect_grid_tiling, encode_still, encode_still_auto, encode_still_burst, encode_still_grid,
encode_still_layered, encode_still_overlay, GainMapSpec, OverlayCanvas, OverlayLayerImage,
StillImage, StillProperties, GRID_MIN_TILE_DIM, STILL_MAX_CODED_DIM, TILE_LAYOUT_THREADS,
};
#[cfg(feature = "registry")]
#[doc(hidden)]
pub use registry_glue::__oxideav_entry;
pub const CODEC_ID_STR: &str = "avif";
#[cfg(feature = "registry")]
mod registry_glue {
use oxideav_core::{
CodecCapabilities, CodecId, CodecInfo, CodecRegistry, ContainerRegistry, Error,
RuntimeContext,
};
use crate::decoder::make_decoder;
use crate::encoder::make_encoder;
use crate::error::AvifError;
use crate::CODEC_ID_STR;
impl From<AvifError> for Error {
fn from(e: AvifError) -> Self {
match e {
AvifError::InvalidData(s) => Error::InvalidData(s),
AvifError::Unsupported(s) => Error::Unsupported(s),
AvifError::LimitExceeded(s) => Error::ResourceExhausted(s),
AvifError::Io(e) => Error::Io(e),
}
}
}
pub fn register_codecs(reg: &mut CodecRegistry) {
let caps = CodecCapabilities::video("avif_heif_av1_decode")
.with_decode()
.with_encode()
.with_lossy(true)
.with_lossless(true)
.with_intra_only(true)
.with_pixel_formats(crate::encoder::ENCODER_PIXEL_FORMATS.to_vec());
reg.register(
CodecInfo::new(CodecId::new(CODEC_ID_STR))
.capabilities(caps)
.decoder(make_decoder)
.encoder(make_encoder)
.encoder_options::<crate::encoder::AvifEncoderOptions>()
.decoder_options::<crate::decoder::AvifDecoderOptions>(),
);
}
pub fn register(ctx: &mut RuntimeContext) {
register_codecs(&mut ctx.codecs);
register_containers(&mut ctx.containers);
}
oxideav_core::register!("avif", register);
pub fn register_with_av1(reg: &mut CodecRegistry) {
register_codecs(reg);
oxideav_av1::registry::register_codecs(reg);
}
pub fn register_containers(reg: &mut ContainerRegistry) {
reg.register_extension("avif", CODEC_ID_STR);
reg.register_extension("avifs", CODEC_ID_STR);
}
}
#[cfg(feature = "registry")]
pub use registry_glue::{register, register_codecs, register_containers, register_with_av1};
#[cfg(all(test, feature = "registry"))]
mod tests {
use super::*;
use oxideav_core::{
CodecId, CodecParameters, CodecRegistry, ContainerRegistry, Error, Frame, RuntimeContext,
};
#[test]
fn register_installs_factories() {
let mut reg = CodecRegistry::new();
register_codecs(&mut reg);
let id = CodecId::new(CODEC_ID_STR);
let mut params = CodecParameters::video(id.clone());
params.width = Some(8);
params.height = Some(8);
params.pixel_format = Some(oxideav_core::PixelFormat::Gray8);
let mut enc = reg.first_encoder(¶ms).expect("encoder factory");
let frame = Frame::Video(oxideav_core::frame::VideoFrame {
pts: Some(0),
planes: vec![oxideav_core::frame::VideoPlane {
stride: 8,
data: (0..64u8).collect(),
}],
});
enc.send_frame(&frame).expect("send_frame");
let pkt = enc.receive_packet().expect("receive_packet");
crate::parser::parse(&pkt.data).expect("emitted packet is a parseable AVIF file");
let bare = reg
.first_encoder(&CodecParameters::video(id))
.expect("encoder factory");
let mut bare = bare;
let empty = Frame::Video(oxideav_core::frame::VideoFrame {
pts: Some(0),
planes: vec![],
});
match bare.send_frame(&empty) {
Err(Error::InvalidData(msg)) => assert!(msg.contains("width"), "{msg}"),
other => panic!("encoder send_frame: expected InvalidData, got {other:?}"),
}
let params = CodecParameters::video(CodecId::new(CODEC_ID_STR));
let _ = reg.first_decoder(¶ms).expect("decoder factory");
}
#[test]
fn avif_extension_resolves_to_avif_container() {
let mut reg = ContainerRegistry::new();
register_containers(&mut reg);
assert_eq!(reg.container_for_extension("avif"), Some(CODEC_ID_STR));
assert_eq!(reg.container_for_extension("AVIF"), Some(CODEC_ID_STR));
assert_eq!(reg.container_for_extension("avifs"), Some(CODEC_ID_STR));
}
#[test]
fn register_via_runtime_context_installs_codec_factory() {
let mut ctx = RuntimeContext::new();
register(&mut ctx);
let id = CodecId::new(CODEC_ID_STR);
let params = CodecParameters::video(id);
let _dec = ctx
.codecs
.first_decoder(¶ms)
.expect("avif decoder factory");
assert_eq!(
ctx.containers.container_for_extension("avif"),
Some(CODEC_ID_STR)
);
assert_eq!(
ctx.containers.container_for_extension("avifs"),
Some(CODEC_ID_STR)
);
}
}