diff --git a/src/player/ffmpeg.rs b/src/player/ffmpeg.rs index 15ef7f4..6521ee1 100644 --- a/src/player/ffmpeg.rs +++ b/src/player/ffmpeg.rs @@ -1,10 +1,9 @@ -//! FFmpeg 封裝 +//! FFmpeg wrapper use anyhow::{Context, Result}; +use std::io::{BufReader, Read}; use std::path::Path; -use std::process::{Command, Stdio, Child, ChildStdout}; -use std::io::{Read, BufReader}; -use std::sync::{Arc, Mutex}; +use std::process::{Child, ChildStdout, Command, Stdio}; #[derive(Debug, Clone)] pub struct VideoInfo { @@ -27,7 +26,7 @@ impl FFmpegDecoder { pub fn new(path: &Path) -> Result { let path_str = path.to_string_lossy().to_string(); let info = Self::probe(path)?; - + Ok(Self { path: path_str, process: None, @@ -39,8 +38,10 @@ impl FFmpegDecoder { fn probe(path: &Path) -> Result { let output = Command::new("ffprobe") .args([ - "-v", "quiet", - "-print_format", "json", + "-v", + "quiet", + "-print_format", + "json", "-show_format", "-show_streams", path.to_str().unwrap_or(""), @@ -48,24 +49,25 @@ impl FFmpegDecoder { .output() .context("Failed to run ffprobe")?; - let json: serde_json::Value = serde_json::from_slice(&output.stdout) - .context("Failed to parse ffprobe output")?; + let json: serde_json::Value = + serde_json::from_slice(&output.stdout).context("Failed to parse ffprobe output")?; let video_stream = json["streams"] .as_array() - .and_then(|streams| { - streams.iter().find(|s| s["codec_type"] == "video") - }) + .and_then(|streams| streams.iter().find(|s| s["codec_type"] == "video")) .context("No video stream found")?; let width = video_stream["width"].as_u64().unwrap_or(0) as u32; let height = video_stream["height"].as_u64().unwrap_or(0) as u32; - + let fps_str = video_stream["r_frame_rate"].as_str().unwrap_or("30/1"); let (num, den) = { let parts: Vec<&str> = fps_str.split('/').collect(); if parts.len() == 2 { - (parts[0].parse::().unwrap_or(30.0), parts[1].parse::().unwrap_or(1.0)) + ( + parts[0].parse::().unwrap_or(30.0), + parts[1].parse::().unwrap_or(1.0), + ) } else { (fps_str.parse::().unwrap_or(30.0), 1.0) } @@ -75,9 +77,12 @@ impl FFmpegDecoder { let duration_str = json["format"]["duration"].as_str().unwrap_or("0"); let duration_sec: f64 = duration_str.parse().unwrap_or(0.0); let duration_ms = (duration_sec * 1000.0) as u64; - + let frame_count = (duration_sec * fps) as u64; - let codec = video_stream["codec_name"].as_str().unwrap_or("unknown").to_string(); + let codec = video_stream["codec_name"] + .as_str() + .unwrap_or("unknown") + .to_string(); Ok(VideoInfo { width, @@ -94,16 +99,20 @@ impl FFmpegDecoder { } pub fn start_decoding(&mut self, start_ms: u64) -> Result<()> { - self.stop()?; - + self.stop(); + let start_sec = start_ms as f64 / 1000.0; - + let mut child = Command::new("ffmpeg") .args([ - "-ss", &format!("{}", start_sec), - "-i", &self.path, - "-f", "rawvideo", - "-pix_fmt", "rgb24", + "-ss", + &format!("{}", start_sec), + "-i", + &self.path, + "-f", + "rawvideo", + "-pix_fmt", + "rgb24", "-", ]) .stdout(Stdio::piped()) @@ -111,12 +120,11 @@ impl FFmpegDecoder { .spawn() .context("Failed to start ffmpeg")?; - let stdout = child.stdout.take() - .context("Failed to capture stdout")?; - + let stdout = child.stdout.take().context("Failed to capture stdout")?; + self.process = Some(child); self.stdout = Some(BufReader::new(stdout)); - + Ok(()) } @@ -135,7 +143,7 @@ impl FFmpegDecoder { pub fn read_frame(&mut self) -> Result>> { let frame_size = (self.info.width * self.info.height * 3) as usize; let mut buffer = vec![0u8; frame_size]; - + if let Some(ref mut reader) = self.stdout { match reader.read_exact(&mut buffer) { Ok(_) => Ok(Some(buffer)),