use std::io::Result; use std::path::Path; use std::process::{Child, Command, ExitStatus, Stdio}; use actix::prelude::*; use log::{debug, trace}; // ffmpeg -i test.mp4 -c:v h264 -flags +cgop -g 30 -hls_time 3 out.m3u8 // ffmpeg -i "filename.mp4" -preset veryfast -c:v libx264 -f hls -hls_list_size 100 -hls_time 2 -crf 24 -vf scale=1080:-2,setsar=1:1 attempt/vid_out.m3u8 pub struct StreamActor; impl Actor for StreamActor { type Context = Context; } pub struct ProcessMessage(pub String, pub Child); impl Message for ProcessMessage { type Result = Result; } impl Handler for StreamActor { type Result = Result; fn handle(&mut self, msg: ProcessMessage, _ctx: &mut Self::Context) -> Self::Result { trace!("Message received"); let mut process = msg.1; let result = process.wait(); debug!( "Finished waiting for: {:?}. Code: {:?}", msg.0, result .as_ref() .map_or(-1, |status| status.code().unwrap_or(-1)) ); result } } pub async fn create_playlist(video_path: &str, playlist_file: &str) -> Result { if Path::new(playlist_file).exists() { debug!("Playlist already exists: {}", playlist_file); return Err(std::io::Error::from(std::io::ErrorKind::AlreadyExists)); } let result = Command::new("ffmpeg") .arg("-i") .arg(video_path) .arg("-c:v") .arg("h264") .arg("-crf") .arg("21") .arg("-preset") .arg("veryfast") .arg("-hls_time") .arg("3") .arg("-hls_list_size") .arg("100") .arg("-vf") .arg("scale=1080:-2,setsar=1:1") .arg(playlist_file) .stdout(Stdio::null()) .stderr(Stdio::null()) .spawn(); let start_time = std::time::Instant::now(); loop { actix::clock::delay_for(std::time::Duration::from_secs(1)).await; if Path::new(playlist_file).exists() || std::time::Instant::now() - start_time > std::time::Duration::from_secs(5) { break; } } result } pub fn generate_video_thumbnail(path: &Path, destination: &Path) { Command::new("ffmpeg") .arg("-ss") .arg("3") .arg("-i") .arg(path.to_str().unwrap()) .arg("-vframes") .arg("1") .arg("-f") .arg("image2") .arg(destination) .output() .expect("Failure to create video frame"); }