ez_ffmpeg/core/frame_export/
iter.rs1use super::error::FrameExportError;
5use super::frame::VideoFrame;
6use crate::core::scheduler::ffmpeg_scheduler::{FfmpegScheduler, Running};
7use crate::core::scheduler::owned_run_iter::OwnedRunIter;
8use crate::error::Error;
9use crossbeam_channel::Receiver;
10
11fn map_terminal_error(e: Error) -> Error {
18 match e {
19 Error::FrameFilterProcess(boxed) => match boxed.downcast::<FrameExportError>() {
20 Ok(typed) => Error::FrameExport(*typed),
21 Err(other) => Error::FrameFilterProcess(other),
22 },
23 other => other,
24 }
25}
26
27pub struct FrameIter {
39 inner: OwnedRunIter<VideoFrame>,
40}
41
42impl FrameIter {
43 pub(crate) fn new(rx: Receiver<VideoFrame>, scheduler: FfmpegScheduler<Running>) -> Self {
44 Self {
45 inner: OwnedRunIter::new(rx, scheduler, map_terminal_error),
46 }
47 }
48}
49
50impl Iterator for FrameIter {
51 type Item = Result<VideoFrame, Error>;
52
53 fn next(&mut self) -> Option<Self::Item> {
54 self.inner.next()
55 }
56}
57
58impl std::iter::FusedIterator for FrameIter {}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[test]
65 fn typed_export_error_is_unwrapped_from_filter_process() {
66 let boxed: Box<dyn std::error::Error + Send + Sync> =
67 Box::new(FrameExportError::HdrRequiresToneMapping);
68 let mapped = map_terminal_error(Error::FrameFilterProcess(boxed));
69 assert!(matches!(
70 mapped,
71 Error::FrameExport(FrameExportError::HdrRequiresToneMapping)
72 ));
73 }
74
75 #[test]
76 fn foreign_filter_process_error_passes_through() {
77 let boxed: Box<dyn std::error::Error + Send + Sync> = "some other failure".into();
78 let mapped = map_terminal_error(Error::FrameFilterProcess(boxed));
79 assert!(matches!(mapped, Error::FrameFilterProcess(_)));
80 }
81
82 #[test]
83 fn non_filter_errors_pass_through() {
84 let mapped = map_terminal_error(Error::EOF);
85 assert!(matches!(mapped, Error::EOF));
86 }
87}