1mod ffprobe;
2mod manifest;
3mod processing;
4use dashmap::DashMap;
5use processing::{Subtitles, Video};
6use serde::Serialize;
7use std::path::PathBuf;
8use std::process::Child;
9use std::sync::Arc;
10use std::thread;
11
12use crate::ffprobe::{get_media_info, MediaInfo};
13use crate::manifest::{create_manifest_file, create_manifest_file_subs, create_master_file};
14use crate::processing::{process_video, Audio, Profile};
15
16#[derive(Clone, Debug, Serialize)]
17pub enum ProcessingState {
18 InProgress,
19 Done,
20 NotStarted,
21}
22
23pub struct Parachute {
24 id_to_process: Arc<DashMap<String, ProcessingState>>,
25 ffprobe_path: String,
26 ffmpeg_path: String,
27 cdn_dir_path: String,
28}
29
30impl Parachute {
31 pub fn new(ffprobe_path: &str, ffmpeg_path: &str, cdn_dir_path: &str) -> Self {
32 Self {
33 id_to_process: Arc::new(DashMap::new()),
34 ffprobe_path: ffprobe_path.to_string(),
35 ffmpeg_path: ffmpeg_path.to_string(),
36 cdn_dir_path: cdn_dir_path.to_string(),
37 }
38 }
39
40 pub fn play_video_seq(&self, id: &str, path: &PathBuf) -> ProcessingState {
41 self.id_to_process
42 .entry(id.to_string())
43 .or_insert_with(|| {
44 let id = id.to_string();
45 let mut process = self.start_process(&id, &path);
46 let id_to_process = self.id_to_process.clone();
47 thread::spawn(move || {
48 process
49 .wait()
50 .expect("Something wen't wrong while processing media");
51 id_to_process.insert(id, ProcessingState::Done);
52 println!("Done processing media");
53 });
54 ProcessingState::InProgress
55 })
56 .clone()
57 }
58
59 fn start_process(&self, id: &str, path: &PathBuf) -> Child {
60 let media_info = get_media_info(&self.ffprobe_path, path).unwrap();
61 let video_args = Video::get_args(&media_info);
62 let audio_args = Audio::get_args(&media_info);
63 let subtitle_args = Subtitles::get_args(&media_info);
64 self.create_files(id, &media_info);
65 process_video(
66 path,
67 id,
68 &self.cdn_dir_path,
69 &self.ffmpeg_path,
70 &video_args,
71 &audio_args,
72 &subtitle_args,
73 )
74 }
75
76 fn create_files(&self, id: &str, media_info: &MediaInfo) {
77 let manifest_path = PathBuf::from(format!("{}/{}_manifest.m3u8", self.cdn_dir_path, id));
78 let manifest_subs_path =
79 PathBuf::from(format!("{}/{}_manifest_subs.m3u8", self.cdn_dir_path, id));
80 let playlist_path = PathBuf::from(format!("{}/{}_playlist.m3u8", self.cdn_dir_path, id));
81 let init_seg = format!("{}_init.mp4", id);
82 let duration: f32 = media_info.format.duration.parse().unwrap();
83
84 create_manifest_file(id, &manifest_path, duration, &init_seg).unwrap();
85 create_manifest_file_subs(id, &manifest_subs_path, duration).unwrap();
86 create_master_file(
87 &manifest_path,
88 &manifest_subs_path,
89 &playlist_path,
90 media_info.subtitle.len() == 0,
91 )
92 .unwrap();
93 }
94}