Files
momentry_core/src/core/probe/ffprobe.rs
Warren e75c4d6f07 cleanup: remove dead code and duplicate docs
- Remove session-ses_2f27.md (161KB raw session log)
- Remove 49 ROOT_* duplicate files across REFERENCE/
- Remove 14 duplicate files between REFERENCE/ root and history/
- Remove asr_legacy.rs (dead code, replaced by asr.rs)
- Remove src/core/worker/ (duplicate JobWorker)
- Remove src/core/layers/ (empty directory)
- Remove 4 .bak files in src/
- Remove 7 dead private methods in worker/processor.rs
- Remove backup directory from git tracking
2026-05-04 01:31:21 +08:00

90 lines
3.0 KiB
Rust

use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::process::Command;
#[derive(Debug, Serialize, Deserialize)]
pub struct ProbeResult {
pub streams: Vec<StreamInfo>,
pub format: FormatInfo,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct StreamInfo {
pub index: u32,
pub codec_name: Option<String>,
pub codec_type: Option<String>,
pub width: Option<u32>,
pub height: Option<u32>,
pub r_frame_rate: Option<String>,
pub nb_frames: Option<String>,
pub duration: Option<String>,
pub sample_rate: Option<String>,
pub channels: Option<u32>,
#[serde(default)]
pub tags: Option<serde_json::Value>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct FormatInfo {
pub filename: Option<String>,
pub format_name: Option<String>,
pub duration: Option<String>,
pub size: Option<String>,
pub bit_rate: Option<String>,
}
pub fn probe_video(video_path: &str) -> Result<ProbeResult> {
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<StreamInfo> = 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),
nb_frames: s["nb_frames"].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),
tags: s.get("tags").cloned(),
})
.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 })
}