use super::renderer_error::FFramesRendererResult;
use crate::{
DynamicMediaProvider, RawFontData,
media::{RawMediaFile, Subtitles, VideoMedia},
};
use rayon::prelude::*;
use std::{
collections::HashMap,
ffi::OsStr,
fs,
io::{self},
path::{Path, PathBuf},
sync::{Arc, Mutex},
};
pub struct MediaDirectory(Vec<(PathBuf, RawMediaFile)>);
#[cfg(not(target_arch = "wasm32"))]
impl MediaDirectory {
pub fn read_folder(folder_path: impl AsRef<Path>) -> FFramesRendererResult<MediaDirectory> {
let mut folder_content = vec![];
if !folder_path.as_ref().is_dir() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput, "resources_dir must be a folder",
)
.into());
}
for file in fs::read_dir(folder_path)? {
let path = file?.path();
if !path.is_file() {
continue;
}
match path.extension().and_then(OsStr::to_str) {
Some(
"jpg" | "jpeg" | "png" | "gif" | "vtt" | "mp3" | "wav" | "flac" | "aac" | "pcm"
| "ogg" | "mp2",
) => {
let bytes = fs::read(&path)?;
folder_content.push((path, RawMediaFile::Data(bytes)));
}
Some(
"mp4" | "webm" | "mkv" | "avi" | "mov" | "flv" | "wmv" | "m4v" | "ttf" | "ttc"
| "otf" | "otc",
) => {
folder_content.push((path.clone(), RawMediaFile::Stream(path)));
}
_ => {}
}
}
Ok(MediaDirectory(folder_content))
}
pub fn process_media_source(&self) -> FFramesRendererResult<DynamicMediaProvider<'_>> {
let audio_hash = Mutex::new(HashMap::new());
let subtitles_hash = Mutex::new(HashMap::new());
let image_hash = Mutex::new(HashMap::new());
let fontdata = Mutex::new(Vec::new());
let video_paths = Mutex::new(HashMap::new());
self.0
.par_iter()
.try_for_each(|(path, raw_file)| -> FFramesRendererResult<()> {
if let Some((extension, filename)) = path
.extension()
.and_then(OsStr::to_str)
.zip(path.file_name().and_then(OsStr::to_str))
{
match (extension, raw_file) {
("mp3" | "wav" | "flac" | "aac" | "pcm" | "ogg" | "mp2", _) => {
let audio_data =
crate::media::PreloadedAudioData::decode_raw_file_stereo(
None, path,
)?;
audio_hash.lock()?.insert(
filename.to_owned(),
crate::AudioData::Preloaded(audio_data),
);
}
("vtt", RawMediaFile::Data(bytes)) => {
let str_bytes = std::str::from_utf8(bytes)?;
subtitles_hash.lock()?.insert(
filename.to_owned(),
Subtitles::parse(str_bytes)
.map_err(crate::media::FFramesMediaError::from)?,
);
}
("ttf" | "ttc" | "otf" | "otc", RawMediaFile::Stream(path)) => {
let bytes = fs::read(path)?;
fontdata.lock()?.push(RawFontData {
file_name: filename.to_owned(),
data: Arc::new(bytes),
});
}
("jpg" | "jpeg" | "png", RawMediaFile::Data(bytes)) => {
image_hash.lock()?.insert(
filename.to_owned(),
crate::media::ImageData::new_from_bytes(filename, bytes)?,
);
}
("mp4" | "webm" | "mkv" | "avi" | "mov" | "flv" | "wmv" | "m4v", _) => {
video_paths.lock()?.insert(
filename.to_owned(),
VideoMedia {
path: path.to_owned(),
metadata: None,
},
);
if let Ok(audio_data) =
crate::media::PreloadedAudioData::decode_raw_file_stereo(None, path)
{
audio_hash.lock()?.insert(
filename.to_owned(),
crate::AudioData::Preloaded(audio_data),
);
}
}
_ => {}
};
};
Ok(())
})?;
let provider = DynamicMediaProvider::new(
audio_hash.into_inner()?,
image_hash.into_inner()?,
subtitles_hash.into_inner()?,
video_paths.into_inner()?,
fontdata.into_inner()?,
);
Ok(provider)
}
}