Rust · WebAssembly · No FFmpeg

Frame-exact video and audio,
native and in the browser.

zvidlib decodes, encodes and muxes HEVC, AV1, VP8 and VP9 video and AAC, Opus and Vorbis audio in MP4 and WebM, from one API on desktop and the web. Ask for frame n and get exactly frame n; ask for a sample range and get exactly those samples. Write frame n and the audio stays in sync.

scrub.js
import init, { MediaInput } from "zvidlib";
await init();

const input = await MediaInput.open(blob);
const video = input.video(0);

// Exactly frame 4812, not the keyframe before it.
const frame = await video.get(4812n);
draw(frame.pixels, frame.width, frame.height);

Indexed get and put

Every read returns the exact frame in presentation order, even in streams full of B-frames and long groups of pictures. Decoded frames and decoder state carry over between calls, so sequential reads stay fast.

Instant scrubbing

A built-in seek-preview tier answers any position in constant time while the exact frame decodes behind it. That's what makes a timeline drag feel immediate.

Sample-exact audio

AAC, Opus and Vorbis decode and encode alongside the video. Read any exact sample range with getRange, or exactly the samples a video frame covers. Priming, padding and edit lists are handled, so gapless round trips come back sample for sample, and audio is muxed in sync with the video into MP4 and WebM.

One API, two targets

The same model works in Rust on Windows, macOS and Linux, and in JavaScript through WebAssembly, with BigInt frame indices, Blob and stream I/O, and stable error codes.

Hardware first, Rust always

NVDEC, Media Foundation (NVENC, Quick Sync, AMF), VideoToolbox and WebCodecs when the host has them, and pure-Rust codecs checked against libvpx and libdav1d when it doesn't.

No FFmpeg

No C toolchain, no system packages, no GPL. Every codec and direction is a Cargo feature, so an app builds only what it uses.

Live demo

Everything below runs on zvidlib's WebAssembly build in this tab. Nothing is uploaded.

Loading…

Waiting to load…

Drag the timeline: the nearest seek preview draws at once, then the exact frame replaces it. The clip is a single 768-frame group of pictures, so every exact frame depends on every frame before it. Play reads the clip's AAC soundtrack in exact sample ranges with audio.getRange() and keeps the picture in step with it. Sample: Big Buck Bunny © Blender Foundation, CC BY 3.0.

Codecs and containers

Hardware where the host has it, pure Rust everywhere, WebCodecs in the browser.

Video

CodecDecodeEncodeBrowser
HEVC / H.265 Rust Main, Main 10
HW NVDEC · Media Foundation · VideoToolbox
Rust Main, intra-only (lossless, QP or bitrate)
HW NVENC · Quick Sync · AMF · VideoToolbox
WebCodecs decode with Rust fallback · WebCodecs encode
AV1 Rust Main, 8-bit 4:2:0 and monochrome Rust Main, 8-bit monochrome WebCodecs decode with Rust fallback · WebCodecs encode (color)
VP8 Rust every bitstream version
HW NVDEC · Media Foundation
Rust key and inter frames WebCodecs decode with Rust fallback · WebCodecs encode
VP9 Rust profile 0
HW NVDEC · Media Foundation · VideoToolbox
Rust profile 0, key and inter frames
HW Media Foundation · VideoToolbox
WebCodecs decode with Rust fallback · WebCodecs encode

Audio

CodecNative decodeNative encodeBrowser
AAC-LC OS Media Foundation · AudioToolbox
Rust Symphonia elsewhere
OS Media Foundation · AudioToolbox WebCodecs decode and encode
Opus Rust opus-pure (libopus port) Rust opus-pure WebCodecs with Rust fallback, both directions
Vorbis Rust up to 8 channels Rust libvorbis 1.3.7 port, bit-identical WebCodecs decode with Rust fallback · Rust encode

Containers

ContainerReadWriteCarries
MP4 Ordinary and fragmented, edit lists, cover art Seekable, gapless audio trims, generated cover art HEVC · AV1 · VP9 · AAC · Opus
WebM Seekable files and live MediaRecorder captures Seekable, with Cues AV1 · VP8 · VP9 · Opus · Vorbis

Backend order per platform, Cargo features and the full browser API are in the README and the API docs.

Quick start

One crate for Rust, one package for the browser.

cargo add zvidlib
let source = MemorySource::new(std::fs::read("clip.mp4")?);
let movie = block_on(Mp4Demuxer::open(&source, Mp4DemuxerOptions::default()))?;
let track = movie.tracks.iter().find(|t| t.kind == TrackKind::Video).unwrap();
let samples = block_on(track.to_encoded_video_samples(&source, &limits))?;

let mut reader = ExactFrameReader::new(&native_av1_video_decoder_factory(), config, samples, limits)?;
// Exactly presentation frame 400, never the nearest keyframe.
let frame = reader.get(FrameIndex(400), &CancellationToken::new())?;

Trim the build with Cargo features, for example default-features = false, features = ["vp9-decoder"]. The README has complete read and write programs.

Built with zvidlib

zvid

A collaborative, canvas-based video editor for the browser and desktop. The editor draws each frame onto a canvas, and zvidlib encodes HEVC or AV1 with AAC audio and writes the MP4, in the browser and in the native app. Its DAW capture plugin, ZVID Capture, records cameras from inside Ableton Live through zvidlib's encoders and muxer.

Building something with zvidlib? Add it to the README.