use std::io::Read;
use std::path::{Path, PathBuf};
use std::time::Duration;
use crate::{Error, Result};
pub fn format_time(t: Duration) -> String {
let minutes = t.as_secs() / 60;
let seconds = t.as_secs() % 60;
format!("{:02}:{:02}s", minutes, seconds)
}
pub fn is_valid_video_file(path: impl AsRef<Path>, full: bool, audio: bool) -> bool {
if !full {
let mut buf = [0u8; 8192];
let mut f = std::fs::File::open(path.as_ref()).unwrap();
f.read(&mut buf).unwrap();
return infer::is_video(&buf);
}
if let Ok(input) = ffmpeg_next::format::input(&path.as_ref()) {
let num_video_streams = input
.streams()
.filter(|s| s.parameters().medium() == ffmpeg_next::util::media::Type::Video)
.count();
let num_audio_streams = input
.streams()
.filter(|s| s.parameters().medium() == ffmpeg_next::util::media::Type::Audio)
.count();
num_video_streams > 0 && (!audio || num_audio_streams > 0)
} else {
false
}
}
pub fn find_video_files<P: AsRef<Path>>(
paths: &[P],
full: bool,
audio: bool,
) -> Result<Vec<PathBuf>> {
for path in paths {
let path = path.as_ref();
if !path.exists() {
return Err(Error::PathNotFound(path.to_owned()));
}
}
let mut valid_video_files = Vec::new();
for path in paths {
let path = path.as_ref();
if path.is_dir() {
valid_video_files.extend(
std::fs::read_dir(path)
.unwrap()
.map(|p| {
let entry = p.unwrap();
entry.path()
})
.filter(|p| is_valid_video_file(p, full, audio))
.collect::<Vec<_>>(),
);
} else {
if is_valid_video_file(path, full, audio) {
valid_video_files.push(path.to_owned());
}
}
}
Ok(valid_video_files)
}
pub(crate) fn compute_header_md5sum(video: impl AsRef<Path>) -> crate::Result<String> {
let mut buf = [0u8; 8192];
let mut f = std::fs::File::open(video.as_ref())?;
f.read_exact(&mut buf)?;
let hash = format!("{:x}", md5::compute(&buf));
Ok(hash)
}
pub fn ffmpeg_version() -> u32 {
ffmpeg_next::util::version()
}
pub fn ffmpeg_version_string() -> String {
let version_int = ffmpeg_version();
format!(
"{}.{}.{}",
version_int >> 16, (version_int & 0x00FF00) >> 8, version_int & 0xFF )
}