use std::{path::Path, process};
use avio::AsyncVideoDecoder;
use futures::StreamExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut args = std::env::args().skip(1);
let mut input = None::<String>;
while let Some(flag) = args.next() {
match flag.as_str() {
"--input" | "-i" => input = Some(args.next().unwrap_or_default()),
other => {
eprintln!("Unknown flag: {other}");
process::exit(1);
}
}
}
let input = input.unwrap_or_else(|| {
eprintln!("Usage: async_decode_video --input <file>");
process::exit(1);
});
let in_name = Path::new(&input)
.file_name()
.and_then(|n| n.to_str())
.unwrap_or(&input);
println!("Input: {in_name}");
println!();
println!("=== Pattern 1: frame-by-frame with decode_frame() ===");
let mut decoder = match AsyncVideoDecoder::open(input.clone()).await {
Ok(d) => d,
Err(e) => {
eprintln!("Skipping (open failed): {e}");
return Ok(());
}
};
let mut frame_count: u64 = 0;
loop {
match decoder.decode_frame().await {
Ok(Some(frame)) => {
if frame_count == 0 {
println!(
"First frame: {}x{} pts={:?}",
frame.width(),
frame.height(),
frame.timestamp(),
);
}
frame_count += 1;
}
Ok(None) => break,
Err(e) => {
eprintln!("Decode error: {e}");
break;
}
}
}
println!("Decoded {frame_count} frames");
println!();
println!("=== Pattern 2: stream API with into_stream() ===");
let decoder = match AsyncVideoDecoder::open(input.clone()).await {
Ok(d) => d,
Err(e) => {
eprintln!("Skipping (open failed): {e}");
return Ok(());
}
};
let total = decoder
.into_stream()
.filter_map(|result| async move { result.ok() })
.count()
.await;
println!("Total frames via stream: {total}");
println!();
println!("=== Pattern 3: stream spawned on a background task ===");
let decoder = match AsyncVideoDecoder::open(input.clone()).await {
Ok(d) => d,
Err(e) => {
eprintln!("Skipping (open failed): {e}");
return Ok(());
}
};
let handle = tokio::spawn(async move {
let mut count: u64 = 0;
let stream = decoder.into_stream();
tokio::pin!(stream);
while let Some(result) = stream.next().await {
match result {
Ok(_frame) => count += 1,
Err(e) => {
eprintln!("Background decode error: {e}");
break;
}
}
}
count
});
let background_count = handle.await?;
println!("Background task decoded {background_count} frames");
Ok(())
}