mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-12 08:52:32 +00:00
* craft-video: H.264 decoder from FilmCraft (`h264-decode` feature) FilmCraft's crates/h264 at 4c0d2ad7 becomes craft_video::h264::decode. The encoder moves to h264/encode and is still exported from craft_video::h264. Feature h264 now turns on h264-decode and h264-encode, so either half can be built without the other. Without the threads feature a reference row that was never published read through expect(); it now reads as a gray row. 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: H.264 decoder hardening from DeckCraft's copy - The picture store (DPB, current picture, pictures in flight or queued for output) is checked against a memory budget before a picture is allocated; Decoder::set_memory_budget. - configure_avcc checks every entry before handling any: SPS NAL units in the first list, PPS in the second. A picture slice in the record starts no picture. - The inverse transforms clamp coefficients to the spec's r range instead of overflowing. - Temporal direct motion vectors are scaled in i32 and clipped to the spec range. - slice_qp_delta is added with a checked add. - A picture job sets up its picture state inside the panic guard.
35 lines
1.3 KiB
Rust
35 lines
1.3 KiB
Rust
//! Decode speed on a 1080p High-profile stream (ignored by default; run with
|
|
//! `cargo test --release -p craft-video --features h264-decode,threads --test h264_decode perf:: -- --ignored --nocapture`).
|
|
|
|
use crate::common;
|
|
|
|
use craft_video::h264::decode::Decoder;
|
|
use std::time::Instant;
|
|
|
|
fn bench(data: &[u8], threads: usize, iters: usize) -> (usize, f64) {
|
|
let mut best = f64::MAX;
|
|
let mut frames = 0;
|
|
for _ in 0..iters {
|
|
let mut dec = Decoder::with_threads(threads);
|
|
let t0 = Instant::now();
|
|
frames = dec.decode(data, 0).expect("decode").len() + dec.flush().len();
|
|
best = best.min(t0.elapsed().as_secs_f64());
|
|
}
|
|
(frames, best)
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn perf_1080p() {
|
|
let f = common::fixture("bench_1080p");
|
|
let Some((h264, _)) = common::ensure(f) else { return };
|
|
// correctness first
|
|
common::check_fixture("bench_1080p").unwrap();
|
|
let data = std::fs::read(h264).unwrap();
|
|
let cores = std::thread::available_parallelism().map(|n| n.get()).unwrap_or(1);
|
|
for threads in [1, cores.min(16)] {
|
|
let (frames, secs) = bench(&data, threads, 5);
|
|
println!("1080p High CRF20 ({} KB): {threads} thread(s): {frames} frames in {secs:.3}s = {:.1} fps", data.len() / 1024, frames as f64 / secs);
|
|
}
|
|
}
|