av2codec — AV2 Video Codec Written in Rust
av2codec is a from-scratch implementation of the AV2 video codec encoder in pure, safe Rust — zero unsafe code, zero C dependencies. This demo showcases the encoder running in the browser via WebAssembly.
To prove spec compliance, the encoded bitstream is decoded by the official AVM reference decoder (also compiled to WASM). Both encoding and decoding happen entirely in the browser — select a sample image or upload your own, adjust the quantization settings, and see the results instantly.
Architecture
Browser
|
|-- av2codec encoder (Rust -> WASM, ~154 KB)
| RGB image -> YUV 4:2:0 -> AV2 bitstream
|
|-- AVM reference decoder (C -> WASM, ~1.7 MB)
| AV2 bitstream -> YUV 4:2:0 -> RGB -> Canvas
|
|-- index.html
UI controls, sample images, canvas rendering
Features
- Select from 9 sample images or upload your own (max 2 MB, max 1024px)
- Choose 8-bit or 10-bit quantization
- Adjustable quantization index (QIndex 1-255)
- Side-by-side original vs. encoded/decoded comparison
- Encode/decode timing and compression statistics
Prerequisites
- Rust (with
wasm32-unknown-unknowntarget):rustup target add wasm32-unknown-unknown - wasm-pack:
cargo install wasm-pack(or see https://rustwasm.github.io/wasm-pack/installer/) - Emscripten SDK (
emcc,emcmake,emmake): https://emscripten.org/docs/getting_started/downloads.html - CMake (3.16+)
- AV2 reference source code (the
av2/AVM repository): https://gitlab.com/AOMediaCodec/avm
Directory Layout
av2codec_demo/
Cargo.toml # Rust crate (encoder WASM bindings)
src/lib.rs # Encoder: RGB->YUV + av2codec encode, exposed via wasm-bindgen
decoder_wasm/
avmdec_wasm.c # Thin C wrapper around AVM reference decoder API
build.sh # Emscripten build script for the reference decoder
web/
index.html # Demo page (single-file HTML + JS)
samples/ # Sample PNG images
pkg/ # [generated] Rust encoder WASM output (wasm-pack)
avmdec.js # [generated] Emscripten JS glue for reference decoder
avmdec.wasm # [generated] Reference decoder WASM binary
Building
1. Clone dependencies
Ensure the following sibling directories exist relative to this project:
parent/
av2/ # AVM reference codec source (git clone from gitlab.com/AOMediaCodec/avm)
wav2c/ # av2codec encoder (Rust library)
av2codec_demo/ # This project
2. Build the encoder (Rust -> WASM)
cd av2codec_demo
wasm-pack build --target web --out-dir web/pkg --release
This compiles the av2codec encoder to WebAssembly and outputs the JS bindings + .wasm file into web/pkg/.
3. Build the reference decoder (C -> WASM)
cd decoder_wasm
bash build.sh
This does two things:
- Cross-compiles the AVM reference decoder library (
libavm.a) using Emscripten with decoder-only configuration (no encoder, no threads, no SIMD, no tests) - Compiles
avmdec_wasm.c(our thin wrapper) and links it withlibavm.ato produceweb/avmdec.js+web/avmdec.wasm
The AV2 source location defaults to ../av2/ relative to this project. Override it with the AV2_SRC environment variable:
AV2_SRC=/path/to/av2 bash build.sh
The libavm.a build is cached in decoder_wasm/build/. Delete that directory to force a full rebuild.
4. Add sample images
Copy sample PNG images into web/samples/. The demo expects these files:
flowers.png city.png dog.png sunset.png waves.png
bulb.png house.png night.png guitar.png
The sample images are from the GB82 Image Set by Gianni Rosato.
5. Serve and open
Any static HTTP server works. For example:
cd web
python3 -m http.server 8080
Then open http://localhost:8080 in a browser.
How It Works
- The user selects or uploads an image
- The image is drawn to a canvas and its RGBA pixel data is extracted
- Encoding (Rust WASM): RGBA pixels are converted to YUV 4:2:0 and encoded into an AV2 bitstream using
av2codec::Encoder - Decoding (C WASM): The bitstream is passed to the AVM reference decoder (
avmdec), which decodes it back to YUV and converts to RGBA - The decoded RGBA data is rendered on a second canvas for side-by-side comparison
- Statistics (encode/decode time, bitstream size, compression ratio) are displayed
Rebuilding After Changes
| What changed | Rebuild command |
|---|---|
Rust encoder code (src/lib.rs) |
wasm-pack build --target web --out-dir web/pkg --release |
C decoder wrapper (decoder_wasm/avmdec_wasm.c) |
cd decoder_wasm && bash build.sh |
AVM reference source (../av2/) |
rm -rf decoder_wasm/build && cd decoder_wasm && bash build.sh |
HTML/JS (web/index.html) |
Just reload the browser |