mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-29 20:47:00 -06:00
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>
41 lines
1.5 KiB
Rust
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(())
|
|
}
|