oxideav-avif
Pure-Rust AVIF (AV1 Image File Format): the AV1 profile of HEIF /
MIAF. The ISOBMFF / HEIF container — box reader, meta item model,
item payload resolution, derived-image graph, grid / overlay /
identity composition, alpha attachment, clap / irot / imir,
image-sequence tables and the still-image writer — is
oxideav-heif; this crate
owns everything AV1-specific on top of it: av1C and the AV1 item /
sample handling, the av1-avif §2–§8 audits and profile brands, the
AVIF item layout of the muxer, a1op / a1lx / lsel layered items,
the HEIF-extension properties it types beyond the container's set,
avis sequences, HDR metadata authoring and the pixel encoder's tile
election. AV1 pixels come from
oxideav-av1. Zero C
dependencies.
Part of the oxideav framework but usable standalone.
Standalone use
oxideav-avif follows the workspace image-crate API: the same small
root vocabulary as oxideav-png, oxideav-heif, … returning raw
Vec<u8> pixels.
#
Pixels need the registry feature. AVIF is a container whose
pixels come from the AV1 codec crate, and codec crates in this
workspace are framework-only. So:
| Build | Available |
|---|---|
default-features = false (no oxideav-core, no oxideav-av1) |
probe, info, every type (AvifImage, ImageInfo, ColorInfo, Metadata, RgbImage / RgbaImage, Frame, DecodeOptions, EncodeOptions, PixelFormat, Plane, Error), AvifImage::to_rgb8 / to_rgba8 / from_rgb8 / from_rgba8, the container model (parse → AvifFile, parse_header, inspect → AvifInfo, parse_avis), composition over caller-supplied planes (grid, alpha, transform, overlay) and the container muxer (AvifMuxer, encode_still_av1) around an already-coded AV1 payload |
default (registry on) |
everything above plus decode, decode_with, decode_rgb8, decode_rgba8, decode_all / decode_all_with, decode_from, encode, encode_rgb8, encode_rgba8, encode_to, the pixel encoder (still), avis sequence encode, and the framework Decoder / Encoder |
A standalone caller that pairs the container model with its own AV1
decoder builds an AvifImage::new(width, height, format, planes)?
(plane geometry validated) from the composed planes and gets
to_rgba8() like everyone else.
[]
= "0.0" # with pixels (registry on)
# oxideav-avif = { version = "0.0", default-features = false } # container + conversions only
Framework use
With registry the crate also plugs into oxideav-core:
#
The framework AvifDecoder / AvifEncoder are thin adapters over the
functions above: send_packet (one complete AVIF file per packet)
runs decode_with / decode_all_with with the decoder's
DecodeOptions (gain_map=apply / reference_white codec options,
set_options), and emits every frame with its ColorSignal; the
encoder maps a VideoFrame onto the still encoder (quality / q /
alpha_q / chroma / premultiplied options — the schemas are
AvifEncoderOptions / AvifDecoderOptions, declared on the registry
entry, parsed strictly). The decoder honours
Decoder::set_execution_context (the AV1 worker budget; the threads
option fixes it) and the encoder declares its 27 accepted input
layouts (ENCODER_PIXEL_FORMATS) as the registry's
accepted_pixel_formats. From<AvifImage> for VideoFrame and
AvifImage::from_video_frame(&frame, ¶ms) (also
TryFrom<(&VideoFrame, &CodecParameters)>) move pictures between the
two worlds.
Codec id "avif", capability avif_heif_av1_decode;
CodecParameters::extradata is the av1C record.
Supported layouts
PixelFormat (= AvifPixelFormat) mirrors oxideav_core::PixelFormat
by name. Decode yields the storage layout; color.matrix == 0
(identity) means the 4:4:4 planes are G, B, R.
Decode (AvifImage::format) |
8-bit | 10 / 12-bit (LE words) |
|---|---|---|
| 4:2:0 / 4:2:2 / 4:4:4 | Yuv420P Yuv422P Yuv444P |
Yuv420P10Le … Yuv444P12Le |
| … with alpha auxiliary | Yuva420P Yuva422P Yuva444P |
Yuva420P10Le … Yuva444P12Le |
| monochrome | Gray8 |
Gray10Le Gray12Le |
| monochrome + alpha (packed) | Ya8 |
Ya16Le (depth on bit_depth) |
| Encode | Layout written |
|---|---|
encode(&AvifImage) |
the image's own layout and depth; alpha as the AV1-coded alpha auxiliary item; Error::Unsupported for sub-sampled chroma at odd extents (never a silent conversion) |
encode_rgb8 / encode_rgba8 |
8-bit 4:2:0 (EncodeOptions::chroma; 4:4:4 at odd extents), MIAF default colour (BT.709 / sRGB / BT.601, full range), alpha as the auxiliary |
encode(&AvifImage::from_rgb8(..)?) |
identity-matrix 4:4:4 — byte-exact RGB at the default lossless quality |
| canvases past 4096 coded pixels per axis | grid tiling (encode_still_auto) |
encode_all(&[Frame], &EncodeOptions) |
the mirror of decode_all: delay-less frames → the primary plus a brst image burst (encode_still_burst; per-member colour / ICC / alpha / clap, Exif / XMP on the primary), timed frames → an avis image sequence (encode_sequence at timescale 1000, each frame's delay in ms; no alpha — Unsupported); all frames share frame 0's geometry, depth and layout; decode_all(encode_all(f)) == f at the lossless default |
decode_all returns every sample of an avis image sequence (with
its delay), the entities of the primary's brst burst group, else
the primary alone. AvifImage::new / from_rgb8 / from_rgba8 are
Results that refuse a zero dimension or a buffer that does not match
the geometry with InvalidData.
Options
EncodeOptions (Default = lossless): base_q_idx (AV1 quantizer,
0 = lossless) or with_quality(0..=100) (base_q_idx = ((100 − q) × 255 + 50) / 100), alpha_q_idx, premultiplied_alpha (prem
signalling), chroma for the RGB one-call paths, embed_exif /
embed_xmp / embed_icc, speed (EncodeSpeed::Fast default /
Balanced / Thorough — the AV1 search effort; Thorough is the
exhaustive search, minutes per 12 MP), threads (AV1 tile-search
workers; the layout follows the picture size — TILE_LAYOUT_THREADS
— so the bytes are the same at any count). StillEncodeOptions is
the deprecated alias.
DecodeOptions (Default = lenient, Some(16384) × Some(16384),
Some(1 << 28) pixels, Some(1 << 30) input bytes; None =
unlimited): max_width, max_height, max_pixels (also caps every
grid / overlay canvas on the way), max_bytes, strict (an AVIF
brand is required, a claimed mif1 must carry its mandatory boxes),
tone_mapped (apply a tmap gain map — default off: the base
image), reference_white_nits (203), layer (render this spatial
layer of a layered primary instead of its lsel), threads (the AV1
worker budget for every coded item / sample — byte-identical at any
budget; None = serial, or the execution context's budget on the
registry decoder).
Registry encoder options (AvifEncoderOptions): quality 0..=100
(100 = lossless, the default; base_q_idx = ((100 − quality) × 255 + 50) / 100 when q is absent, the alpha auxiliary likewise when
alpha_q is absent), q / alpha_q (explicit base_q_idx, win over
quality), chroma (420 default / 422 / 444: the Y′CbCr layout
a packed RGB(A) frame is coded in at a lossy quality; odd extents
4:4:4; lossless RGB keeps the byte-exact identity coding),
premultiplied, speed (fast default / balanced / thorough:
the AV1 search effort), threads (AV1 tile-search workers; 0 = the
execution context's budget; the tile layout follows the picture size,
so the bytes never depend on it). Measured on a 16 × 16 textured
picture: Yuv420P 592 B exact → quality 50 324 B 37.4 dB → quality 10
294 B 25.0 dB; Rgb24 795 B exact (identity) → 50 329 B 31.0 dB (4:2:0)
→ 10 309 B 24.7 dB. A 12 MP 4:2:0 picture at quality 50 codes in 6.1 s
serial / 1.3 s on 8 workers (examples/decode_threads).
Metadata and colour
AvifImage::color is the item's colr nclx as ColorInfo { range: ColorRange, primaries, transfer, matrix } (H.273 code
points; ColorRange::{Unspecified, Limited, Full}); with
no CICP the MIAF §7.3.6.4 default applies — BT.709 / sRGB / BT.601,
full range. to_rgb8 / to_rgba8 invert the signalled matrix at
the signalled range exactly (round-to-nearest, chroma replicated to
its co-sited luma samples), bring 10 / 12-bit samples to 8 bits as
round(v × 255 / (2^d − 1)), and read a matrix without a kernel
(reserved / unspecified / constant-luminance / ICtCp / YCgCo) as
BT.601 — try_to_rgb8 reports Unsupported instead.
AvifImage::metadata: icc (an ICC colr), exif (from the TIFF
header on — the HEIF A.2.1 offset word is stripped on decode and
re-written on encode), xmp; gamma is always None. encode
writes them back as an ICC colr next to the nclx, an Exif item
and an XMP mime item. HDR descriptive properties (mdcv / clli /
cclv / amve) stay on inspect's AvifInfo and the still
encoder's StillProperties.
Limits
Enforced before any pixel allocation, as Error::LimitExceeded: the
DecodeOptions bounds above, plus the crate's own caps — a 32 MiB
per-item AV1 payload, MAX_GRID_CANVAS_PIXELS / MAX_OVERLAY_CANVAS_PIXELS
(1 << 28), MAX_ITEM_DECODES (4096 item decodes per file),
MAX_DERIVATION_DEPTH. Hostile input returns Error, never panics
(fuzzed: contract_api, derived_graph_decode, and the
cross-decoder harnesses under fuzz/).
Layering
| Layer | Crate | What lives there |
|---|---|---|
ISOBMFF boxes, meta tree, iloc (all construction methods), iref, ipco / ipma, idat, grpl |
oxideav-heif (HeifFile, Meta, boxes) |
parse_header / parse build this crate's Meta from the container's (Meta::from_container); AvifHeader::heif / item_data resolve item bytes |
| Typed properties | oxideav-heif (props) + this crate |
ispe pixi colr pasp clap irot imir iscl auxC clli amve rloc lsel a1op a1lx rref crtt mdft udes altt converted from the container; av1C raw for the AV1 layer; mdcv / cclv read here; the HEIF-extension family (aebr … cmin, transitions, prdi, sstr, txlo, elng, fnch, mskC) parsed here from the raw property bytes |
| Composition | oxideav-heif (compose) |
grid stitch, iovl painting (fill converted with the output's H.273 matrix), alpha attachment, clap → irot → imir in ipma order, MIAF §7.3.6.7 4:4:4 promotion; the decoder walks the graph on the container frame and re-lays the result out as this crate's AvifFrame |
| AVIF rules on top | this crate | av1-avif §4.1 same-depth alpha, nearest-neighbour alpha resize, ispe trim and grid trim with AV1's ceiling chroma (odd 4:2:0 stays 4:2:0), monochrome overlays stay monochrome, degenerate clap passes through, a 4:2:2 quarter turn is refused, lsel / a1op layer selection, the AV1 decode itself |
| Image sequences | oxideav-heif (sequence::parse_movie) + this crate |
first-track sample table, stsd / av1C, tkhd / mdhd / hdlr / elst from the container; sample groups (sbgp / csgp / sgpd), prft / ssix and the §3 / §8 audits here |
| Writer | oxideav-heif (HeifWriter / SequenceWriter) + this crate |
this crate decides brands, item order, property sets, auxC URNs, descriptors, item names and entity groups; the container serialises meta / idat / mdat, raw Exif / XMP bodies, and the avis track (moov with the mandatory ccst, cover still aliasing sample 0) |
Status
Parsing, derived-image composition, image sequences and the writer ride the container crate; the AVIF-side surface below is complete and heavily tested.
Pixel decode is live at every AV1 bit depth. The primary item's
AV1 OBU stream (and every AVIS sample) is handed to
oxideav-av1's
conformance-grade spec-driver decoder; the composition layer then
stitches grid tiles, composites the alpha auxiliary (4:2:0 / 4:2:2 /
4:4:4 / monochrome masters), and applies clap / irot / imir —
at 8, 10 and 12 bits end to end. 10/12-bit output rides little-endian
16-bit word planes (Yuv*P10Le / *P12Le, Gray10Le / Gray12Le,
alpha-composited Yuva*P1xLe, and packed Ya16Le for HBD
monochrome + alpha with the effective depth on the core
significant-bits side channel). Every committed fixture decodes end
to end — including the 3840×2160 alpha composite and the multi-sample
AVIS sequence — and the encode→decode HBD matrix round-trips
sample-exact where lossless.
Derived images decode to pixels. The decoder resolves the
primary's output image per HEIF §6.3 for any item type —
recursively over dimg inputs, cycle- and depth-guarded: grid
tile stitch, iovl overlay composition (§6.6.2.2 canvas + offsets +
layering with the §6.9.1 straight / pre-multiplied alpha rendering,
8/10/12-bit, translucent fills yielding a Yuva* canvas), iden
identity derivations carrying their own clap / irot / imir, and
every item's transformative properties in ipma order. A grid
primary's alpha may be a coded item or a grid of monochrome tiles.
Layered (progressive) items honour lsel / a1op (av1-avif §2.3).
Pixel encode is live (still module). StillImage +
encode_still / encode_still_grid drive oxideav-av1's KEY-frame
encoder across the full (bit depth × chroma format) matrix — 8/10/12
bit × 4:2:0 / 4:2:2 / 4:4:4 / monochrome — plus RGB(A) via the H.273
identity matrix in 4:4:4 (byte-exact lossless round-trips), alpha as
a same-depth monochrome auxiliary (av1-avif §4.1, full-range
signalled in-stream), arbitrary extents (edge-replicated pad to the
coded 8-grid + top-left clap, ispe = coded extents per §2.2.2),
grid tiling with right/bottom trim (64-pixel tile floor + tiling
election, alpha as a hidden alpha grid, pass-through properties on
the grid item), iovl overlays (encode_still_overlay), iden
identity derivations (StillProperties::identity_derivation),
layered / progressive items (encode_still_layered: AV1 spatial
layers + a1lx + lsel), depth-map auxiliaries, and avis image
sequences (sequence::encode_sequence: all-intra or KEY + P groups,
full moov / trak / stbl). The ftyp profile brand
follows the elected AV1 profile (§8: Main → MA1B, High → MA1A,
Professional → general brands only). Lossless encodes decode back
sample-exact through this crate's own decoder; lossy encodes are
PSNR-gated in the test suite; black-box acceptance decodes the
emitted files through an external AVIF decoder binary where one is
installed. The registry Encoder (make_encoder / AvifEncoder)
rides the same pipeline: one video frame in, one complete AVIF file
packet out (quality / q / alpha_q / chroma / premultiplied
codec options; 27 declared input layouts).
The container muxer (mux module) remains available standalone:
given an already-coded AV1 Image Item Data payload plus its av1C
record, AvifMuxer / AvifGridMuxer / AvifOverlayMuxer /
encode_still_av1 emit a conformant AVIF file — ftyp
(avif/mif1/miaf + MA1B/MA1A/no profile brand), the meta
tree serialised by oxideav-heif's HeifWriter (derived-item bodies
in idat, MIAF mdat order, de-duplicated ipco) — with ispe /
pixi / colr / pasp / clap / irot / imir item properties, an
optional AV1-coded alpha auxiliary (auxC + auxl, plus prem from
the master when premultiplied, HEIF 3rd ed. §6.9.1), and optional
grid tiling (dimg). The output round-trips through this crate's
own parse path byte-for-byte (coded payload and every property) and
passes audit_mif1. At this layer the AV1 bitstream is taken
black-box.
Container coverage
| Stage | Coverage |
|---|---|
ftyp brand check |
accepts avif / avis / mif1 / msf1 / miaf (this crate's rule, run before the container parse) |
meta sub-boxes |
by oxideav-heif: hdlr, pitm (v0/v1), iinf (v0/v1) + infe (v2/v3), iloc (v0/v1/v2, construction methods 0/1/2), iref, iprp / ipco / ipma (v0/v1, small + large property indices), idat, grpl — converted into this crate's Meta |
| Item properties | av1C, ispe, colr (nclx + ICC), pixi, pasp, irot, imir, clap, auxC, mdcv, clli, cclv, rloc, lsel, a1op, a1lx (the container-typed ones converted, mdcv / cclv read here), plus the HEIF §6.5 descriptive family parsed here (iscl, rref, crtt, mdft, udes, altt, aebr, wbbr, fobr, afbr, dobr, pano, subs, tols, prdi, the slideshow transition-effect set wipe/zoom/fade/splt/stpe/ssld, cmex camera-extrinsics (quaternion + position + rotation matrix; v1 ISO/IEC 23090-7 rotation struct out of scope), cmin camera-intrinsics, sstr single-stream (§6.5.38 bare marker on a derived item), plus the HEIF §6.10 text/font item-property family txlo text-layout (§6.10.2.1, (flags&1) 16/32-bit geometry + 8.8 font-size percent + TTML2 direction/writing-mode), elng extended-language (§6.10.2.2), fnch font-characteristics (§6.10.4.1, family/style/weight)), and the §11.2.2.2 mask-configuration property mskC (bits-per-pixel + §11.2.2 pixels-per-byte packing). Unknown boxes are retained as Property::Other so indices stay valid |
Region items (rgan) |
region::RegionItem::parse decodes a 'rgan' region item's data into typed RegionGeometry variants — point / rectangle / ellipse / polygon / polyline / referenced-mask / inline-mask (HEIF §11.2.1, (flags&1) 16/32-bit fields, sign-extended coords); inspect::region_items / region_items_for enumerate the region items attached to the primary (or any image item) via the 'cdsc' iref, resolving each one's data through the construction-method-aware iloc path into a ResolvedRegionItem. Derived region items (drgn §11.3.3) resolved by region::resolve_derived_region_items — every 'iden' item carrying a 'drgn' reference to its input region item, audited against the §11.3.3.2.1 shalls (single 'drgn' input + 'drgn'-iref-count ≤ 1 + no item body) as a DerivedRegionItem |
| Essential-property enforcement | Meta::{unsupported_essential_properties, has_unsupported_essential_property} flag any ipma-essential property that lands in Property::Other (av1-avif §2.3.2.1.2 + MIAF §7.3.5) |
Sample Transform (sato) |
descriptor parser + per-sample evaluator (av1-avif §4.2.3); image composition deferred until a real AV1 decoder lands |
Tone Map (tmap) |
four-CC detection + §4.2.2 compliance audit + GainMapMetadata::parse_tone_map_image (HEIF Amd 1 §6.6.2.4.2 ToneMapImage version byte + ISO 21496-1:2025 Annex C.2) + the decoder's applied reconstruction (see Derived images) + the standalone §6 application helpers: unnormalize_log2_gain (Formula 1), weight_factor (Formula 3), apply_component / apply_rgb / apply_plane_rgb reconstruct the linear alternate (HDR) rendition (Baseline + k_base)·2^(W·G) − k_alt (Formula 2) from a linear baseline + the decoded gain plane, with §5.2.5.1 per-component-metadata broadcast and §6.3 NOTE 2 achromatic handling; apply_plane_rgb_coded + normalize_full_range_plane accept the gain plane in its coded integer form at 8/10/12/16 bits (full-range scaling at the coded depth) |
| AV1 layered properties | a1op operating-point selector + a1lx layered-image index (av1-avif §2.3.2) |
| Auxiliary classification | auxC URN routed to Alpha / DepthMap / HdrGainMap / Other |
Container encoder / muxer (mux) |
AvifMuxer / AvifGridMuxer / AvifOverlayMuxer / encode_still_av1 decide the AVIF layout — brands (profile tri-state MA1B default / MA1A / general-brands-only per av1-avif §8.1), item order (primary = item 1, a grid / iovl before its inputs), per-item property sets with their essential flags (av1C / clap / irot / imir / lsel / a1op essential), auxC URNs, the grid / overlay descriptors — and oxideav-heif's HeifWriter serialises meta (iloc v1, derived bodies in idat, de-duplicated ipco, prem master → alpha) + mdat. Round-trips through parse byte-for-byte; passes audit_mif1; opens in heif-info / ImageMagick / ffmpeg (and avifdec for coded / grid primaries) |
Pixel → AVIF still encoder (still) |
StillImage + encode_still / encode_still_grid drive oxideav-av1's still encoder (still_picture = 1, reduced header; Fast effort by default, EncodeSpeed; tile layout from the picture size, searched on EncodeOptions::threads): 8/10/12-bit × 4:2:0/4:2:2/4:4:4/monochrome; RGB(A) via the H.273 identity matrix in 4:4:4 (byte-exact lossless); alpha as a same-depth monochrome auxiliary with in-stream full-range signalling (the §5.5.2 color_range bit — av1-avif §4.1 readers ignore colr on alpha); arbitrary extents via edge-replicated pad + top-left clap (§2.2.3) with ispe = coded extents (§2.2.2 shall); grid tiling (HEIF §6.6.2) with right/bottom trim; ftyp profile brand elected from seq_profile (§8). Lossless round-trips sample-exact through the crate's own decoder; lossy PSNR-gated; black-box-accepted by an external AVIF decoder binary |
Registry Encoder |
one video frame → one complete AVIF file packet; 27 declared input layouts (ENCODER_PIXEL_FORMATS, the registry's accepted_pixel_formats): planar YUV 8-bit (+ YuvJ* full-range), 10/12-bit LE planar, Gray8/10/12, packed Rgb24/Rgba/Bgr24/Bgra (identity 4:4:4 when lossless, Y′CbCr in the chroma layout when lossy; alpha auxiliary), planar Gbrp(a) 8/10/12, Yuva420P, Ya8; codec options quality (0..=100 → base_q_idx, 100 = lossless) / q / alpha_q / chroma / premultiplied, declared as a schema; lossy + lossless capability flags |
Registry Decoder threads |
set_execution_context / the threads option hand the worker budget to the AV1 decoder of every coded item and sequence sample (tile / band / wave / stripe parallel, byte-identical at any budget); the distinct tiles of a grid primary decode round-robin on the same workers; 12 MP tiled still 0.34 s serial → 0.07 s on 8 workers (4.8×), the same picture as a 4 × 3 grid 0.31 s → 0.07 s (4.7×) (examples/decode_threads) |
| Derived images | iovl overlay + iden identity + tmap tone-map derivations resolved end-to-end (HEIF §6.3 / §6.6.2, av1-avif §4.2.2) via a box-graph geometry resolver — no AV1 decode: transform_chain / output_dims_from_reconstructed apply irot/imir/clap/iscl in ipma order (§6.3); reconstructed_dims resolves grid/iovl descriptor dims + recursive iden inputs + tmap base-input extents + sato own/ispe-or-input extents + coded ispe (cycle-guarded, depth 16; descriptor bytes resolve through iloc construction methods 0/1/2); resolve_overlays clips each OverlayPlacement against the canvas (§6.6.2.2.3); resolve_iden_derivations folds the iden's own transforms over its source; resolve_tone_maps resolves each tmap's base/gain-map input ids + rendered (base) extents + per-gain-map coded extents, flagging gain-map up-sampling. Surfaced on AvifInfo::{overlay_resolutions, iden_resolutions, tone_map_resolutions}; inspect() accepts iovl/iden/tmap/sato derived primaries. Pixel composition (oxideav-heif's compose, through overlay::composite_overlay and the decoder's recursive output-image path): iovl canvases painted in dimg order with the §6.9.1 alpha rendering (straight / prem), canvas opacity seeded from the RGBA fill (converted with the output's H.273 matrix at every colr), inputs clipped at the canvas edge, an input at an odd offset on a subsampled axis or carrying alpha promotes the canvas to 4:4:4, monochrome inputs stay monochrome, MAX_OVERLAY_CANVAS_PIXELS bound; iden = its input's output image (alpha inherited) plus the iden's own transforms; both writable via AvifOverlayMuxer / encode_still_overlay and AvifMuxer::with_identity_derivation. tmap pixel reconstruction (HEIF Amd 1:2025 §6.6.2.4 + ISO 21496-1, av1-avif §4.2.2): base by default, opt-in applied decode (AvifDecoder::set_tone_mapped / gain_map=apply) through the container's normative reconstruction in the tmap item's colr at its pixi depth, matching avifgainmaputil tonemap within 1 code both ways; authored via StillProperties::gain_map / AvifMuxer::with_tone_map. sato remains geometry-only (no container counterpart) |
Unified derivation graph (build_derivation_graph / inspect::derivation_graph) |
one decode-free traversal (HEIF §6.6) that walks any derived primary into a DerivationGraph — every reachable node (DerivationNode { DerivationKind ∈ Coded/Grid/Overlay/Identity/ToneMap/SampleTransform/Unknown, reconstructed + output dims, depth }) plus the de-duplicated coded-av01 leaf decode set in first-visit order. Handles nested derivations (iden-of-grid, tmap-over-grid) and diamond graphs (shared leaf listed once); iterative pre-order with a MAX_DERIVATION_DEPTH cycle guard (truncated flag). Accessors: output_dims / root_is_coded / coded_leaf_dims (decode-buffer sizing) / nodes_at_depth / derived_node_count. No pixel composition — the dependency planner a renderer feeds its AV1 decoder |
Entity grouping (grpl) |
typed EntityGroup per EntityToGroupBox (retaining the 24-bit flags); altr / ster / eqiv / pano / prgr progressive-rendering (§6.8.10) / brst burst (§6.8.9) / msrc multi-source (HEIF §9.4) / tsyn time-synchronized capture (§6.8.3) / iaug audio-to-image (§6.8.4, audio_repeats() = flags-LSB) / slid slideshow (§6.8.9) / albc album + favc favorites user-collections (§6.8.7) / the five §6.8.6 bracketed capture-time sets aebr/wbbr/fobr/afbr/dobr (BracketingKind / is_bracketed_set). inspect::entity_groups enumerates the file's grpl decode-free for the typed projections |
Text / font items (text / font) |
inspect::text_items / text_items_for enumerate the §6.10.1 text items ('mime' items linked to an image via the 'text' iref) annotating the primary (or any image item), surfacing each one's content_type and the 'font'-iref-linked font item ids as a ResolvedTextItem; is_font_item recognises a §6.10.3 font item ('mime' + content_type starting font/, RFC 8081) |
| Coded-item dependency roles | inspect::coded_item_dependencies classifies an image item from its outgoing item references into CodedItemDependencies { pred predictively-coded decoding-order list (§6.4.9), base pre-derived-coded inputs (§6.4.7), exbl scalable base-layer (§6.4.8), tbas tile-base relation } with is_predictively_coded / is_pre_derived / has_dependencies projections; backed by the new Meta::iref_targets_of outgoing-reference walker |
| Brand compliance audit | audit_mif1 (HEIF §10.2.1.1); MIAF Baseline (MA1B) / Advanced (MA1A) profile dispatch + av1-avif §8.2/§8.3 profile audit; audit_pred_brand (HEIF §10.2.4.2 — 'pred' brand: per-predictive-item 'pred'-dependency closure + the mif1 primary-independence shall, surfaced on PredBrandCompliance) |
| Metadata items | cdsc iref resolves Exif + XMP attached to the primary; raw bytes on demand via item_payload_bytes |
| Thumbnails | thmb iref enumeration via AvifInfo::thumbnail_item_ids |
| Premultiplied alpha | HEIF prem iref detected and surfaced |
| CICP colour signalling | colr nclx → CicpTriple with H.273 defaults; ICC + Unknown fall back to Unspecified |
| HDR metadata | mdcv (ST 2086), clli (MaxCLL/MaxFALL), cclv, amve ambient viewing environment (AVIF §6.5.36 / ISO/IEC 14496-12; 0.0001-lux illuminance + CIE 1931 ambient-light chromaticity, surfaced on AvifInfo::amve) |
av1C introspection |
bit depth (8/10/12), monochrome flag, chroma subsampling decoded into AvifInfo |
| Sequence Header OBU audit | av1-avif §2.1 "exactly one Sequence Header OBU" container-layer audit |
| Primary item data | resolved by the container (HeifFile::item_data, every iloc construction method: 0 file-offset, 1 idat-offset, 2 item-offset via the 'iloc' reference, ISO/IEC 14496-12 §8.11.3) through AvifHeader::item_data; parse keeps a zero-copy slice for a single-span cm=0 primary. The bare-ItemLocation helpers item_bytes / item_bytes_with_idat / item_bytes_owned* remain for callers holding a plain Meta. Grid tiles, the alpha auxiliary, and metadata items (item_payload_bytes: Exif / XMP / mime / tmap) are all construction-method-aware |
| Grid primary items | grid descriptor parse + dimg tile composition by the container (8/10/12-bit tiles; MAX_GRID_CANVAS_PIXELS bound; the right / bottom trim applied here with AV1's ceiling chroma so an odd 4:2:0 output stays 4:2:0) + alpha auxiliary as a coded item or a grid of monochrome tiles (HEIF §6.4.1) + av1-avif §7 derivation-chain audit + decode-free tile-geometry resolution (resolve_grids → GridResolution: common tile dims + per-tile row-major canvas placement, GridTilePlacement::visible right/bottom trim §6.6.2.3.1, covers_canvas / trimmed_tile_count); surfaced on AvifInfo::{grid_resolutions, has_grid, grid_resolution_for} |
| Alpha auxiliary | auxl + auxC detection + attachment at every depth (Gray8→Ya8, Gray10/12→Ya16Le, Yuv→YuvA incl. *10Le/*12Le) + av1-avif §4.1 same-bit-depth shall enforced before attachment and audited at the container layer |
| Post-transforms | clap → irot → imir in ipma order (HEIF §6.3), at 8/10/12-bit and on the packed Ya8/Ya16Le layouts; an odd clean aperture on subsampled chroma promotes to 4:4:4 (MIAF §7.3.6.7); the standalone apply_* entry points refuse a layout change their (frame, width, height) result cannot carry |
| Layered image items | a1lx / lsel / a1op written by AvifMuxer::{with_layered_index, with_layer_selector, with_operating_point} and encode_still_layered (2..=4 AV1 spatial layers in one temporal unit, per-layer byte sizes from an OBU walk, ispe/clap of the selected layer — av1-avif §2.2.2 / §2.3); the decoder drains every shown frame, renders the lsel layer (or the top one) and decodes non-default a1op operating points |
| AVIS image sequences | encode (encode_sequence over the container's SequenceWriter: ftyp avis/msf1/av01 (+avio), cover still whose primary aliases sample 0, moov/trak with pict handler, av01 sample entry + av1C/colr/clap + ccst, stts/stss/stsc/stsz/stco; all-intra or KEY + P groups; lossless sequences decode exact through this crate, the external AVIF decoder and ffmpeg) + sample-table walk by the container (parse_avis over oxideav_heif::sequence::parse_movie; ISO/IEC 14496-12's mandatory mvhd / tkhd / mdhd / hdlr / stts enforced) + inspect_avis aggregator + §3 / §8.2 / §8.3 audits + edts/elst edit list (ISO/IEC 14496-12 §8.6.6) + mdhd media-timescale plumb + prft ProducerReferenceTimeBox (§8.16.5, v0/v1 NTP→Unix, top-level walk) on AvisMeta::producer_reference_times + ssix SubsegmentIndexBox (§8.16.4, v0; per-subsegment (level: u8, range_size: u24) leva-level byte-range partitions for partial-subsegment access, top-level walk) on AvisMeta::subsegment_indexes |
| Sample grouping | sbgp (SampleToGroupBox, ISO/IEC 14496-12:2015 §8.9.2, v0/v1) + csgp (CompactSampleToGroupBox, :2020 §8.9.5 — 4/8/16/32-bit packed field widths, pattern expansion, traf fragment-local msb) + sgpd (§8.9.3, v0/v1/v2 default index) which now also retains + slices per-entry VisualSampleGroupEntry payloads (v1 default_length fixed-size or self-describing description_length) into SampleGroupDescription::entries; typed decoders for the HEIF §6.8.6 bracketing entries (BracketingEntry: aebr auto-exposure / wbbr white-balance / fobr focus incl. infinity / afbr flash-exposure / dobr depth-of-field via bracketing_entries()) and the §6.8.1.2.2 eqiv VisualEquivalenceEntry (time_offset + 8.8 timescale_multiplier, equivalence_entries()); per-sample group-index lookup via SampleToGroup::group_index_for_sample, surfaced on AvisMeta::{sample_to_groups, sample_group_descriptions} |
Constructing the crate's types
The records a user builds or reads through the documented API — the
picture (AvifImage) and the contract records around it, the
container results (AvifFile, AvifInfo, AvisMeta, …), the typed
metadata (Ispe, Clap, Colr, Mdcv, Clli, …), StillImage /
StillProperties / EncodeOptions / DecodeOptions and the muxer
specs — are
#[non_exhaustive]: build them with Type::new(<every field, in declaration order>) (or Default where one exists) and read /
assign their pub fields; the option records take with_<field>
setters (StillProperties::default().with_irot(Some(1))). The enums
that grow with the standard (Property, Colr, AvifError,
AuxKind, DerivationKind, …) are #[non_exhaustive] too: match
them with a _ arm. The parser's and composer's own records (table
entries, descriptors, placements, the HEIF-extension property family)
are #[doc(hidden)] — reachable, outside the semver contract.
AvifFrame / AvifPlane / AvifPixelFormat and StillChroma stay
plain (the sample model AV1 closes).
Low-overhead files
AVIF (av1-avif, 2025-10) defines no low-overhead profile: mif3 /
mini (HEIF Amd 2:2026 Annex O) are not AVIF brands or boxes, so this
crate's brand rule refuses them. oxideav-heif reads and writes
mini files (an AV1-coded one expands to an avif-equivalent
meta), which is where a .hmg / image/hif2 file opens.
Container-level use
use ;
let bytes = read?;
let info = inspect?; // AvifInfo: everything the container says
println!;
let file = parse?; // AvifFile: brands, meta, the primary av01 item
for item in &file.meta.items
// `file.primary_item_data` is the primary image's AV1 OBU stream and
// `file.av1c` its record — pair them with your own AV1 decoder, then
// `AvifImage::new(w, h, format, planes).to_rgba8()`.
# Ok::
Test fixtures
tests/fixtures/monochrome.avif is Monochrome.avif from
AOMediaCodec/av1-avif
(1280×720, monochrome). tests/fixtures/{gray32,midgray,white16,red,black420}.avif
are tiny reference-encoder-produced AVIFs covering each colour-plane
layout. Integration tests walk the full HEIF hierarchy, extract the
primary item, and decode every fixture to pixels end to end (the flat
lossless fixtures assert exact constant planes).
License
MIT — see LICENSE.