use std::time::Duration;
use ff_format::{AudioFrame, VideoFrame};
use crate::animation::AnimationEntry;
use crate::error::FilterError;
use crate::filter_inner::FilterGraphInner;
use super::builder::FilterGraphBuilder;
pub struct FilterGraph {
pub(crate) inner: FilterGraphInner,
pub(crate) output_resolution: Option<(u32, u32)>,
pub(crate) pending_animations: Vec<AnimationEntry>,
}
impl std::fmt::Debug for FilterGraph {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FilterGraph").finish_non_exhaustive()
}
}
impl FilterGraph {
#[must_use]
pub fn builder() -> FilterGraphBuilder {
FilterGraphBuilder::new()
}
pub(crate) fn from_prebuilt(inner: FilterGraphInner) -> Self {
Self {
inner,
output_resolution: None,
pending_animations: Vec::new(),
}
}
pub(crate) fn from_prebuilt_animated(
inner: FilterGraphInner,
animations: Vec<AnimationEntry>,
) -> Self {
Self {
inner,
output_resolution: None,
pending_animations: animations,
}
}
pub fn tick(&mut self, t: Duration) {
if !self.pending_animations.is_empty() {
self.inner.apply_animations(&self.pending_animations, t);
}
}
#[must_use]
pub fn output_resolution(&self) -> Option<(u32, u32)> {
self.output_resolution
}
pub fn push_video(&mut self, slot: usize, frame: &VideoFrame) -> Result<(), FilterError> {
if !self.pending_animations.is_empty() {
let t = frame.timestamp().as_duration();
self.inner.apply_animations(&self.pending_animations, t);
}
self.inner.push_video(slot, frame)
}
pub fn pull_video(&mut self) -> Result<Option<VideoFrame>, FilterError> {
self.inner.pull_video()
}
pub fn push_audio(&mut self, slot: usize, frame: &AudioFrame) -> Result<(), FilterError> {
if !self.pending_animations.is_empty() {
let t = frame.timestamp().as_duration();
self.inner.apply_animations(&self.pending_animations, t);
}
self.inner.push_audio(slot, frame)
}
pub fn pull_audio(&mut self) -> Result<Option<AudioFrame>, FilterError> {
self.inner.pull_audio()
}
}