use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; use std::process::Command; #[derive(Debug, Serialize, Deserialize)] pub struct ProbeResult { pub streams: Vec, pub format: FormatInfo, } #[derive(Debug, Serialize, Deserialize)] pub struct StreamInfo { pub index: u32, pub codec_name: Option, pub codec_type: Option, pub width: Option, pub height: Option, pub r_frame_rate: Option, pub duration: Option, pub sample_rate: Option, pub channels: Option, } #[derive(Debug, Serialize, Deserialize)] pub struct FormatInfo { pub filename: Option, pub format_name: Option, pub duration: Option, pub size: Option, pub bit_rate: Option, } pub fn probe_video(video_path: &str) -> Result { let output = Command::new("ffprobe") .args([ "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", video_path, ]) .output() .context("Failed to run ffprobe")?; if !output.status.success() { let stderr = String::from_utf8_lossy(&output.stderr); anyhow::bail!("ffprobe failed: {}", stderr); } let json_str = String::from_utf8_lossy(&output.stdout); let json: serde_json::Value = serde_json::from_str(&json_str).context("Failed to parse ffprobe output")?; let streams: Vec = json["streams"] .as_array() .map(|arr| { arr.iter() .map(|s| StreamInfo { index: s["index"].as_u64().unwrap_or(0) as u32, codec_name: s["codec_name"].as_str().map(String::from), codec_type: s["codec_type"].as_str().map(String::from), width: s["width"].as_u64().map(|v| v as u32), height: s["height"].as_u64().map(|v| v as u32), r_frame_rate: s["r_frame_rate"].as_str().map(String::from), duration: s["duration"].as_str().map(String::from), sample_rate: s["sample_rate"].as_str().map(String::from), channels: s["channels"].as_u64().map(|v| v as u32), }) .collect() }) .unwrap_or_default(); let format = FormatInfo { filename: json["format"]["filename"].as_str().map(String::from), format_name: json["format"]["format_name"].as_str().map(String::from), duration: json["format"]["duration"].as_str().map(String::from), size: json["format"]["size"].as_str().map(String::from), bit_rate: json["format"]["bit_rate"].as_str().map(String::from), }; Ok(ProbeResult { streams, format }) }