mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-12 08:52:32 +00:00
* craft-video: HEVC decoder from FilmCraft (`hevc-decode` feature) FilmCraft's crates/hevc at 4c0d2ad7 becomes craft_video::hevc::decode. The encoder moves to hevc/encode and is still exported from craft_video::hevc. Feature hevc now turns on hevc-decode and hevc-encode, so either half can be built without the other. craft_video::budget (the picture memory budget from DeckCraft's bitstream crate) is added for the next commit. craft-video is built at opt-level 3 in the dev profile, as FilmCraft built its codecs. * craft-video: HEVC decoder hardening from DeckCraft's copy - The picture store (DPB, current picture, pictures in flight) is checked against a memory budget before a picture is allocated; Decoder::set_memory_budget. - configure_hvcc checks every array before handling any NAL: only VPS, SPS, PPS and SEI arrays, each NAL header agreeing with its array type. A picture slice in the record starts no picture. - init_qp_minus26, slice_qp_delta and delta_chroma_log2_weight_denom are range checked before the additions that overflowed on Exp-Golomb values near the i32 limits. - A picture job sets up its picture state inside the panic guard.
37 lines
1.6 KiB
Rust
37 lines
1.6 KiB
Rust
//! Decode an Annex-B H.265 file to raw planar YUV (yuv420p or yuv420p10le):
|
|
//! `cargo run --release -p craft-video --features hevc-decode,threads --example hevc_hevcdec -- in.hevc out.yuv`
|
|
|
|
use craft_video::hevc::decode::Decoder;
|
|
|
|
fn main() {
|
|
let args: Vec<String> = std::env::args().collect();
|
|
if args.len() < 2 {
|
|
eprintln!("usage: hevcdec <in.hevc> [out.yuv]");
|
|
std::process::exit(2);
|
|
}
|
|
let data = std::fs::read(&args[1]).expect("read input");
|
|
let t0 = std::time::Instant::now();
|
|
// HEVC_THREADS=n sets the thread count, HEVC_LOOPS=k decodes the file k times (benchmarking).
|
|
let threads = std::env::var("HEVC_THREADS").ok().and_then(|s| s.parse().ok()).unwrap_or(0usize);
|
|
let loops = std::env::var("HEVC_LOOPS").ok().and_then(|s| s.parse().ok()).unwrap_or(1usize);
|
|
let mut pics = Vec::new();
|
|
for _ in 0..loops {
|
|
let mut dec = if threads > 0 { Decoder::with_threads(threads) } else { Decoder::new() };
|
|
// HEVC_DRAFT=1: draft mode (non-reference pictures skip deblocking and SAO).
|
|
dec.set_draft(std::env::var_os("HEVC_DRAFT").is_some());
|
|
pics = dec.decode(&data, 0).expect("decode");
|
|
pics.extend(dec.flush());
|
|
}
|
|
let secs = t0.elapsed().as_secs_f64();
|
|
eprintln!("{} pictures in {:.3}s ({:.1} fps)", pics.len(), secs, pics.len() as f64 / secs);
|
|
if let Some(out) = args.get(2) {
|
|
let mut buf = Vec::new();
|
|
for p in &pics {
|
|
buf.extend(p.y.to_le_bytes());
|
|
buf.extend(p.u.to_le_bytes());
|
|
buf.extend(p.v.to_le_bytes());
|
|
}
|
|
std::fs::write(out, buf).expect("write output");
|
|
}
|
|
}
|