use crate::AudioTimelineFrames;
use crate::AudioTimelineUnit;
use crate::audio_map::AudioMap;
use std::ops::Add;
use std::ops::Sub;
use std::rc::Rc;
#[derive(Debug)]
pub enum Duration<'a> {
FromAudio(&'a str),
FromVideo(&'a str),
Seconds(f32),
Frames(usize),
Auto,
__Add(Rc<(Duration<'a>, Duration<'a>)>),
__Subtract(Rc<(Duration<'a>, Duration<'a>)>),
}
impl<'a> Add for Duration<'a> {
type Output = Duration<'a>;
fn add(self, rhs: Self) -> Self::Output {
Self::__Add(Rc::new((self, rhs)))
}
}
impl<'a> Sub for Duration<'a> {
type Output = Duration<'a>;
fn sub(self, rhs: Self) -> Self::Output {
Self::__Subtract(Rc::new((self, rhs)))
}
}
impl<'a> Duration<'a> {
pub fn used_audio_files(&self) -> Option<Vec<&'a str>> {
self.used_files(|duration| match duration {
Duration::FromAudio(audio) => Some(audio),
_ => None,
})
}
pub fn used_video_files(&self) -> Option<Vec<&'a str>> {
self.used_files(|duration| match duration {
Duration::FromVideo(video) => Some(video),
_ => None,
})
}
fn used_files(
&self,
pick: impl Fn(&Duration<'a>) -> Option<&'a str> + Copy,
) -> Option<Vec<&'a str>> {
match self {
Duration::__Subtract(alt) | Duration::__Add(alt) => {
let (left, right) = alt.as_ref();
match (left.used_files(pick), right.used_files(pick)) {
(Some(mut left), Some(mut right)) => {
left.append(&mut right);
Some(left)
}
(Some(start), None) => Some(start),
(None, Some(end)) => Some(end),
(None, None) => None,
}
}
duration => pick(duration).map(|file| vec![file]),
}
}
pub(super) fn to_frames_async<TFun: Fn(&str) -> super::error::Result<f64>>(
&'a self,
fps: usize,
related_audio_map: &AudioMap,
resolve_audio_duration: &'a TFun,
) -> crate::error::Result<usize> {
match self {
Duration::FromAudio(audio) | Duration::FromVideo(audio) => Ok(
crate::audio_map::seconds_to_frames_floor(resolve_audio_duration(audio)?, fps),
),
Duration::Seconds(seconds) => Ok((seconds * fps as f32) as usize),
Duration::Frames(frames) => Ok(*frames),
Duration::Auto => {
let resolved_audio_map = related_audio_map
.resolve::<AudioTimelineFrames>(
AudioTimelineFrames::from_usize(0),
&crate::TimeBase {
fps,
sample_rate: 44100,
},
resolve_audio_duration,
)?
.ok_or(crate::error::FFramesError::MissingDurationOrScenes)?;
let max_frame = resolved_audio_map
.into_iter()
.map(|track| track.range.end.as_usize())
.max()
.ok_or(crate::error::FFramesError::MissingDurationOrScenes)?;
Ok(max_frame)
}
Duration::__Add(sum) => {
let (left, right) = sum.as_ref();
let left = left.to_frames_async(fps, related_audio_map, resolve_audio_duration)?;
let right =
right.to_frames_async(fps, related_audio_map, resolve_audio_duration)?;
Ok(left + right)
}
Duration::__Subtract(sub) => {
let (left, right) = sub.as_ref();
let left = left.to_frames_async(fps, related_audio_map, resolve_audio_duration)?;
let right =
right.to_frames_async(fps, related_audio_map, resolve_audio_duration)?;
Ok(left.saturating_sub(right))
}
}
}
}