Files
filmcraft/crates/vp8/examples/vp8dec.rs
MrCloudy2andClaude Opus 5.5 53a0d959fe #432: VP8 video decodes (clean-room pure-Rust VP8 decoder)
VP8 WebM showed black video: there was no VP8 decoder. New L0 crate
filmcraft-vp8, implemented from RFC 6386 sections 1-19 (tables extracted
from the RFC text, nothing from the attached reference decoder): every
coding tool, versions 0-3, hidden altref frames, size changes. Bit-exact
with libvpx on 62 libvpx VP8 test vectors, real-world FATE samples and
generated fixtures; never panics on corrupted input.

Wired into codecs for Matroska / WebM (V_VP8, including the alpha layer
of transparent WebM) and MP4 (vp08). VP8 colour is BT.601 (RFC 6386 9.2).
A hidden altref frame is a WebM block of its own with the time of the
frame that follows it: the VP8 time lookup now moves on to that shown
frame instead of repeating the previous one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:13:07 +02:00

41 lines
1.5 KiB
Rust

//! Decode an IVF file to raw I420 (`vp8dec in.ivf out.yuv`), for comparison with other decoders.
//! With `VP8DEC_SIZES` set, prints the size of each picture.
use std::io::Write;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = std::env::args().collect();
let [_, input, output] = args.as_slice() else {
return Err("usage: vp8dec in.ivf out.yuv".into());
};
let data = std::fs::read(input)?;
let hdr_len = usize::from(u16::from_le_bytes([data[6], data[7]]));
let mut pos = hdr_len;
let mut out = std::io::BufWriter::new(std::fs::File::create(output)?);
let mut dec = filmcraft_vp8::Decoder::new();
let mut n = 0;
let t = std::time::Instant::now();
while pos + 12 <= data.len() {
let size = u32::from_le_bytes(data[pos..pos + 4].try_into()?) as usize;
let pts = i64::from_le_bytes(data[pos + 4..pos + 12].try_into()?);
pos += 12;
let frame = &data[pos..(pos + size).min(data.len())];
pos += size;
match dec.decode(frame, pts) {
Ok(Some(p)) => {
if std::env::var_os("VP8DEC_SIZES").is_some() {
println!("{} {}", p.width, p.height);
}
out.write_all(&p.y)?;
out.write_all(&p.u)?;
out.write_all(&p.v)?;
n += 1;
}
Ok(None) => {}
Err(e) => eprintln!("frame at pts {pts}: {e}"),
}
}
eprintln!("{n} pictures in {:.2}s; {:?}", t.elapsed().as_secs_f64(), dec.stats());
Ok(())
}