rusty_av2d
A pure-Rust AV2 video decoder. No C, no FFI, no unsafe shelling out to a reference library.
rusty_av2d decodes AV2 — the successor to AV1 currently
being developed by the Alliance for Open Media — and produces output that is
byte-identical to the AVM reference decoder across a 45-clip conformance
corpus covering every major tool in the format.
Research preview. AV2 is not a finalized standard. Read Limitations before depending on this — especially if you care about long-term bitstream stability or decode speed.
Why this exists
Every AV2 decoder available today is the C reference (libavm). This is the
first independent implementation, and it is written in a memory-safe language.
The goal was never "fast" — it was provably correct. The project is verified the way a codec should be: not by eyeballing output, but by decoding real streams and comparing every byte against the reference implementation. When our output and AVM's output differ by a single bit in a single pixel, the build is red.
What "byte-identical" means here
45 clips, each decoded and compared byte-for-byte against AOM's avmdec
(and against dav2d where it supports the stream). Any mismatch fails the
gate. Alongside them run 111 unit and integration tests. Both must pass before
any change lands.
The corpus exercises:
| Area | Coverage |
|---|---|
| Intra | All prediction modes, palette / screen content, IntraBC + morph_pred |
| Inter | Compound prediction, B-pyramids, the warp family, wedge compound, motion modes |
| TIP | Temporal interpolated prediction, including TIP-as-output frames |
| Transforms | TX partitioning, secondary transforms, quantization matrices |
| In-loop filters | Deblocking, CDEF, loop restoration, CCSO, GDF |
| Frame types | Key, inter, S-frames, film grain, delta-Q |
| Geometry | 64px and 128px superblocks, arbitrary (non-aligned) frame dimensions |
| Formats | Full {8-bit, 10-bit} × {4:2:0, 4:2:2, 4:4:4} matrix |
| Tiling | Multi-tile streams and their cross-products |
Eleven of the clips are single-tool-disabled controls: each one turns off exactly one sequence-header tool, verifying that the gate for that tool is honored in both directions.
Install
[]
= "0.1"
Requires Rust 1.79+. On x86 targets you'll want nasm
installed for the assembly paths; build with --no-default-features to skip it.
Usage
The decoder exposes a safe Rust API that mirrors
dav1d-rs, so it drops into existing code
with minimal changes:
use ;
let mut dec = new?;
// Feed one temporal unit at a time (e.g. an IVF frame payload).
dec.send_data?;
// Drain everything that unit produced.
loop
A Settings builder controls thread count, frame delay, film-grain
application, operating point, and which in-loop filters run:
use ;
let mut settings = new;
settings.set_n_threads;
settings.set_apply_grain;
let mut dec = with_settings?;
The C ABI
A C ABI is also exported (dav1d_open, dav1d_send_data, dav1d_get_picture,
…) so the crate can be linked as a staticlib by non-Rust callers. It is on by
default via the capi feature.
Those symbol names are inherited from the dav1d lineage, which means they
collide at link time with any other decoder from that lineage — notably
rav1d. The assembly kernels export a handful of shared lookup tables under
the same names, for the same reason. If you link both decoders into one
binary, build with default features off:
= { = "0.1", = false, = ["bitdepth_8", "bitdepth_16"] }
That drops both the C ABI and the assembly paths, leaving no unmangled
symbols. The safe Rust API is unaffected either way — this is exactly how
remade_ffmpeg_rs
links AV1 and AV2 side by side.
Limitations
These are real, and you should read them before building on this.
- AV2 is not a finalized standard. There are no official conformance vectors. "Correct" here means bit-exact against AVM as of this commit — the bitstream itself may still change under us.
- Performance is unoptimized and unmeasured. Correctness was the only
goal. The decode path also carries ~425 bounds/liveness guard calls used for
corrupt-input hardening, which are pure overhead in a trusted-input setting.
Do not benchmark this against
libavmand expect a fair fight. - Research-grade internals. The AV2 path uses thread-local state rather
than the upstream pipeline structure, and retains in-tree diagnostic probes
(silent unless
RUSTY_AV2D_DEBUG=1). - Threading is under-tested. Correctness is gated single-threaded; multi-threaded output has only been spot-checked.
- Decoder only. There is no encoder in this crate.
See STATUS.md for the full scope statement.
Robustness
Corrupt input is fuzz-tested with bit-flips, truncation, and header mutation. The most recent 1000-case campaign produced zero panics and zero hangs; malformed streams return errors rather than crashing.
That is sampling, not proof. Two modules (av2_qm, av2_palette) are
additionally panic-free by construction under
#![deny(clippy::indexing_slicing)]; the rest of the decode path is not yet.
Provenance
rusty_av2d is a fork of rav1d, the
pure-Rust AV1 decoder, which is itself a port of
dav1d. The AV1 scaffold was
retargeted to AV2 by inverting the AVM reference decoder's parse, brick by
brick, against a symbol-level oracle.
Licensed BSD-2-Clause, retained in full from upstream — see
COPYING and NOTICE.md. Copyright is held by the
dav1d authors, VideoLAN, Two Orioles LLC, the Rav1d Developers, and Prossimo,
alongside subsequent AV2 work.
Related
Part of Remade With Rust — a family of
pure-Rust media codecs. rusty_av2d plugs into
remade_ffmpeg_rs as
the rff-codec-av2 backend.