use std::{path::Path, process, time::Duration};
use avio::{HardwareAccel, SeekMode, VideoDecoder};
fn main() {
let mut args = std::env::args().skip(1);
let mut input = None::<String>;
let mut accel_str = "auto".to_string();
while let Some(flag) = args.next() {
match flag.as_str() {
"--input" | "-i" => input = Some(args.next().unwrap_or_default()),
"--accel" => accel_str = args.next().unwrap_or_else(|| "auto".to_string()),
other => {
eprintln!("Unknown flag: {other}");
process::exit(1);
}
}
}
let input = input.unwrap_or_else(|| {
eprintln!(
"Usage: hardware_decode --input <file> \
[--accel nvdec|qsv|amf|videotoolbox|vaapi|auto|none]"
);
process::exit(1);
});
let accel = match accel_str.to_lowercase().as_str() {
"auto" => HardwareAccel::Auto,
"none" => HardwareAccel::None,
"nvdec" => HardwareAccel::Nvdec,
"qsv" => HardwareAccel::Qsv,
"amf" => HardwareAccel::Amf,
"videotoolbox" => HardwareAccel::VideoToolbox,
"vaapi" => HardwareAccel::Vaapi,
other => {
eprintln!(
"Unknown accel '{other}' \
(try auto, none, nvdec, qsv, amf, videotoolbox, vaapi)"
);
process::exit(1);
}
};
println!(
"Requested accel: {} (is_specific={})",
accel.name(),
accel.is_specific()
);
let in_name = Path::new(&input)
.file_name()
.and_then(|n| n.to_str())
.unwrap_or(&input);
let mut decoder = match VideoDecoder::open(&input).hardware_accel(accel).build() {
Ok(d) => d,
Err(e) => {
println!(
"Skipping: hardware backend '{}' unavailable — {e}",
accel.name()
);
return;
}
};
println!(
"Input: {in_name} {}×{} {:.2} fps codec={}",
decoder.width(),
decoder.height(),
decoder.frame_rate(),
decoder.stream_info().codec_name(),
);
let seek_to = Duration::from_secs(1);
println!(
"Seeking to {:.1}s with SeekMode::Backward ...",
seek_to.as_secs_f64()
);
if let Err(e) = decoder.seek(seek_to, SeekMode::Backward) {
println!("Seek not supported or failed: {e}");
if let Err(e2) = VideoDecoder::open(&input)
.hardware_accel(accel)
.build()
.map(|_| ())
{
eprintln!("Could not re-open: {e2}");
process::exit(1);
}
}
let mut count = 0u32;
let limit = 30;
loop {
match decoder.decode_one() {
Ok(Some(frame)) => {
if count == 0 {
println!(
"First frame: {}×{} format={} pts={:.3}s",
frame.width(),
frame.height(),
frame.format(),
frame.timestamp().as_secs_f64(),
);
}
count += 1;
if count >= limit {
break;
}
}
Ok(None) => break,
Err(e) => {
eprintln!("Decode error: {e}");
process::exit(1);
}
}
}
println!("Decoded {count} frames using accel='{}'", accel.name());
}