Files
momentry_core/src/core/probe/probe.rs
accusys 75edf0aa71 Initial commit: Momentry Core v0.1
- Rust-based digital asset management system
- Video analysis: ASR, OCR, YOLO, Face, Pose
- RAG capabilities with Qdrant vector database
- Multi-database support: PostgreSQL, Redis, MongoDB
- Monitoring system with launchd plists
- n8n workflow automation integration
2026-03-25 14:53:41 +08:00

85 lines
2.8 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 duration: Option<String>,
pub sample_rate: Option<String>,
pub channels: Option<u32>,
}
#[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),
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 })
}