use super::error::FrameExportError;
use super::frame::VideoFrame;
use crate::core::scheduler::ffmpeg_scheduler::{FfmpegScheduler, Running};
use crate::core::scheduler::owned_run_iter::OwnedRunIter;
use crate::error::Error;
use crossbeam_channel::Receiver;
fn map_terminal_error(e: Error) -> Error {
match e {
Error::FrameFilterProcess(boxed) => match boxed.downcast::<FrameExportError>() {
Ok(typed) => Error::FrameExport(*typed),
Err(other) => Error::FrameFilterProcess(other),
},
other => other,
}
}
pub struct FrameIter {
inner: OwnedRunIter<VideoFrame>,
}
impl FrameIter {
pub(crate) fn new(rx: Receiver<VideoFrame>, scheduler: FfmpegScheduler<Running>) -> Self {
Self {
inner: OwnedRunIter::new(rx, scheduler, map_terminal_error),
}
}
}
impl Iterator for FrameIter {
type Item = Result<VideoFrame, Error>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl std::iter::FusedIterator for FrameIter {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn typed_export_error_is_unwrapped_from_filter_process() {
let boxed: Box<dyn std::error::Error + Send + Sync> =
Box::new(FrameExportError::HdrRequiresToneMapping);
let mapped = map_terminal_error(Error::FrameFilterProcess(boxed));
assert!(matches!(
mapped,
Error::FrameExport(FrameExportError::HdrRequiresToneMapping)
));
}
#[test]
fn foreign_filter_process_error_passes_through() {
let boxed: Box<dyn std::error::Error + Send + Sync> = "some other failure".into();
let mapped = map_terminal_error(Error::FrameFilterProcess(boxed));
assert!(matches!(mapped, Error::FrameFilterProcess(_)));
}
#[test]
fn non_filter_errors_pass_through() {
let mapped = map_terminal_error(Error::EOF);
assert!(matches!(mapped, Error::EOF));
}
}