From 529be1a519734df08fa279c78f228e85c9908d6f Mon Sep 17 00:00:00 2001 From: Chris Cochrun Date: Sat, 22 Apr 2023 07:18:05 -0500 Subject: [PATCH] adding an ffmpeg.rs and thumbnailing fn This module adds a bg_from_video function that takes uses the ffmpeg binary to create thumbnails and adds them to the apps local data directory. --- src/rust/ffmpeg.rs | 56 +++++++++++++++++++++++++++++++++++++++++ src/rust/lib.rs | 1 + src/rust/slide_model.rs | 40 ++++++++++++++++------------- 3 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 src/rust/ffmpeg.rs diff --git a/src/rust/ffmpeg.rs b/src/rust/ffmpeg.rs new file mode 100644 index 0000000..6f04f36 --- /dev/null +++ b/src/rust/ffmpeg.rs @@ -0,0 +1,56 @@ +use dirs; +use std::fs; +use std::io::{self, Write}; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::str; + +pub fn bg_from_video(video: &Path) -> PathBuf { + let video = PathBuf::from(video); + println!("{:?}", video); + println!("{:?}", video.file_name()); + let mut data_dir = dirs::data_local_dir().unwrap(); + data_dir.push("librepresenter"); + data_dir.push("thumbnails"); + if !data_dir.exists() { + fs::create_dir(&data_dir).expect("Could not create thumbnails dir"); + } + let mut screenshot = data_dir.clone(); + screenshot.push(video.file_name().unwrap()); + screenshot.set_extension("png"); + if !screenshot.exists() { + let output_duration = Command::new("ffprobe") + .args(&["-i", &video.to_string_lossy()]) + .output() + .expect("failed to execute ffprobe"); + let mut duration = String::from(""); + let mut at_second: i32; + at_second = 2; + let mut log = str::from_utf8(&output_duration.stdout) + .expect("Using non UTF-8 characters") + .to_string(); + if let Some(duration_index) = &log.find("Duration") { + duration = log.split_off(*duration_index + 10); + duration.truncate(11); + println!("rust-duration-is: {duration}"); + } + let output = Command::new("ffmpeg") + .args(&[ + "-i", + &video.to_string_lossy(), + "-ss", + &at_second.to_string(), + "-vframes", + "1", + "-y", + &screenshot.to_string_lossy(), + ]) + .output() + .expect("failed to execute ffmpeg"); + io::stdout().write_all(&output.stdout).unwrap(); + io::stderr().write_all(&output.stderr).unwrap(); + } else { + println!("Screenshot already exists"); + } + screenshot +} diff --git a/src/rust/lib.rs b/src/rust/lib.rs index 6bf6e44..9d30632 100644 --- a/src/rust/lib.rs +++ b/src/rust/lib.rs @@ -1,3 +1,4 @@ +pub mod ffmpeg; mod file_helper; pub mod image_model; pub mod models; diff --git a/src/rust/slide_model.rs b/src/rust/slide_model.rs index 5ed1c42..4ffe412 100644 --- a/src/rust/slide_model.rs +++ b/src/rust/slide_model.rs @@ -124,26 +124,15 @@ mod slide_model { // use crate::video_thumbnail; // use image::{ImageBuffer, Rgba}; + use crate::ffmpeg; use std::path::PathBuf; impl qobject::SlideyMod { - #[qinvokable] - pub fn video_thumbnail( - mut self: Pin<&mut Self>, - video: QString, - service_item_id: i32, - index: i32, - ) -> QString { + pub fn video_thumbnail(mut self: Pin<&mut Self>, video: &QString) -> QString { let video = video.to_string(); - let mut path = PathBuf::from(video); - println!("{:?}", path); - // let mut image_iter = video_thumbnail::ImageIter::new(path)?; - // image_iter.seek(2.0); + let path = PathBuf::from(video); + let video = ffmpeg::bg_from_video(&path); - // if let Some(image) = image_iter.next() { - // image.save("image.jpg"); - // } - - QString::default() + QString::from(video.to_str().unwrap()) } #[qinvokable] @@ -218,7 +207,16 @@ mod slide_model { fn add_slide(mut self: Pin<&mut Self>, slide: &Slidey) { let index = self.as_ref().slides().len() as i32; println!("{:?}", slide); - let slide = slide.clone(); + let mut slide = slide.clone(); + if !&slide.video_background.is_empty() { + slide.video_thumbnail = self + .as_mut() + .video_thumbnail(&slide.video_background) + .insert(0, &QString::from("file://")) + .to_owned(); + println!("rust-inserted: {:?}", slide.video_thumbnail); + } + unsafe { self.as_mut() .begin_insert_rows(&QModelIndex::default(), index, index); @@ -230,6 +228,14 @@ mod slide_model { fn insert_slide(mut self: Pin<&mut Self>, slide: &Slidey, id: i32) { let mut slide = slide.clone(); slide.slide_index = id; + if !&slide.video_background.is_empty() { + slide.video_thumbnail = self + .as_mut() + .video_thumbnail(&slide.video_background) + .insert(0, &QString::from("file://")) + .to_owned(); + println!("rust-inserted: {:?}", slide.video_thumbnail); + } unsafe { self.as_mut()