upend/src/previews/video.rs

50 lines
1.5 KiB
Rust
Raw Normal View History

2021-12-26 18:16:37 +01:00
use anyhow::anyhow;
use std::io::Read;
use std::path::Path;
use std::process::Command;
use anyhow::Result;
2021-12-27 12:40:02 +01:00
use super::Previewable;
2021-12-26 18:16:37 +01:00
pub struct VideoPath<'a>(pub &'a Path);
2021-12-27 12:40:02 +01:00
impl<'a> Previewable for VideoPath<'a> {
fn get_thumbnail(&self) -> Result<Option<Vec<u8>>> {
2021-12-26 18:16:37 +01:00
let duration_cmd = Command::new("ffprobe")
.args(["-v", "error"])
.args(["-show_entries", "format=duration"])
.args(["-of", "default=noprint_wrappers=1:nokey=1"])
.arg(self.0)
.output()?;
if !duration_cmd.status.success() {
return Err(anyhow!(
"Failed to retrieve file duration: {:?}",
String::from_utf8_lossy(&duration_cmd.stderr)
));
}
let duration = String::from_utf8_lossy(&duration_cmd.stdout)
.trim()
.parse::<f64>()?;
2021-12-26 18:16:37 +01:00
let outfile = tempfile::Builder::new().suffix(".png").tempfile()?;
let thumbnail_cmd = Command::new("ffmpeg")
.args(["-i", &self.0.to_string_lossy()])
.args(["-vframes", "1"])
.args(["-ss", &(duration / 2.0).to_string()])
.arg(&*outfile.path().to_string_lossy())
.arg("-y")
.output()?;
if !thumbnail_cmd.status.success() {
return Err(anyhow!(
"Failed to render thumbnail: {:?}",
String::from_utf8_lossy(&thumbnail_cmd.stderr)
));
}
let mut buffer = Vec::new();
outfile.as_file().read_to_end(&mut buffer)?;
Ok(Some(buffer))
2021-12-26 18:16:37 +01:00
}
}