zenavif-parse
AVIF container parser (ISOBMFF/MIAF demuxer) that extracts AV1 payloads, alpha channels, grid tiles, and animation frames from AVIF files. Written entirely in safe Rust with fallible allocations throughout.
This is a fork of kornelski/avif-parse, which itself descends from Mozilla's MP4 parser used in Firefox. The upstream crate is battle-tested against untrusted data; this fork extends it with the features needed for a complete AVIF decoder.
What changed from avif-parse
The upstream avif-parse handles single still images well. This fork adds everything else an AVIF decoder needs:
New zero-copy API — AvifParser parses box structure and records byte offsets without copying mdat content. Data access returns Cow<[u8]> — borrowed for single-extent items (the common case), owned only when extents must be concatenated.
Grid image support — Parses iref dimg references and ImageGrid property boxes to identify grid tiles. Falls back to calculating grid layout from ispe (Image Spatial Extents) properties when no explicit grid box exists.
Animated AVIF — Parses moov/trak boxes, stts timing, stco/co64 chunk offsets, and sample tables. Frames are accessed on-demand via iterator or index.
Resource limits — DecodeConfig caps peak memory, megapixels, animation frame count, and grid tile count during parsing. Limits are checked before allocations, not after.
Cooperative cancellation — All parsing paths accept an enough::Stop token for cancellation.
Parsing fixes — Size-0 box support (ISOBMFF "extends to EOF"), idat construction method support (iloc construction_method=1), correct construction_method handling (upstream guessed based on offset value).
The original read_avif() / AvifData API is preserved for backwards compatibility, but AvifParser is preferred for new code.
Usage
Zero-copy parser (recommended)
use AvifParser;
let bytes = read?;
let parser = from_bytes?;
// Primary item — zero-copy for single-extent items
let primary = parser.primary_data?;
decode_av1?;
// Alpha channel
if let Some = parser.alpha_data
if parser.premultiplied_alpha
Three constructors, each with a _with_config variant for resource limits:
from_bytes(&[u8])— borrows the input; data access is zero-copyfrom_owned(Vec<u8>)— takes ownership; returnsAvifParser<'static>from_reader(impl Read)— reads into an owned buffer; returnsAvifParser<'static>
Grid images
if let Some = parser.grid_config
Animated AVIF
if let Some = parser.animation_info
AV1 metadata without decoding
let meta = parser.primary_metadata?;
println!;
Resource limits
use ;
let config = default
.with_peak_memory_limit // 64MB
.with_total_megapixels_limit
.with_max_animation_frames
.with_max_grid_tiles;
let parser = from_bytes_with_config?;
Defaults: 1GB peak memory, 512MP total, 10k frames, 1k tiles. Use DecodeConfig::unlimited() to disable all limits.
Legacy API (feature = "eager")
The original read_avif() / AvifData API and C FFI are behind the eager feature flag, off by default.
[]
= { = "0.1", = ["eager"] }
use read_avif;
let data = read_avif?;
decode_av1?;
Upstream contributions welcome
All code in this fork is available under the same MPL-2.0 license as the original. The upstream maintainers are welcome to incorporate any or all changes — no attribution to this fork required. If specific features would be useful upstream in a different form, open an issue and we can restructure to fit.
Credits
This crate builds directly on work by:
- Kornel Lesinski — created and maintains avif-parse
- Mozilla — the original
mp4parsecrate that avif-parse forked from, used in Firefox - Ralph Giles, Matthew Gregan, Alfredo Yang, Jon Bauman — original mp4parse authors
License
MPL-2.0 (unchanged from upstream).
This crate doesn't include an AV1 decoder. For full AVIF decoding, see zenavif which pairs this parser with rav1d.