Skip to main content

ff_filter/
error.rs

1//! Error types for filter graph operations.
2
3use thiserror::Error;
4
5/// Errors that can occur during filter graph construction and processing.
6#[derive(Debug, Error)]
7pub enum FilterError {
8    /// Failed to build the filter graph (invalid filter chain or `FFmpeg` error
9    /// during graph creation).
10    #[error("failed to build filter graph")]
11    BuildFailed,
12
13    /// A frame processing operation (push or pull) failed.
14    #[error("failed to process frame")]
15    ProcessFailed,
16
17    /// An invalid configuration was detected during graph construction.
18    #[error("invalid filter configuration: {reason}")]
19    InvalidConfig {
20        /// Human-readable reason for the failure.
21        reason: String,
22    },
23
24    /// A frame was pushed to an invalid input slot.
25    #[error("invalid input: slot={slot} reason={reason}")]
26    InvalidInput {
27        /// The slot index that was out of range or otherwise invalid.
28        slot: usize,
29        /// Human-readable reason for the failure.
30        reason: String,
31    },
32
33    /// An underlying `FFmpeg` function returned an error code.
34    #[error("ffmpeg error: {message} (code={code})")]
35    Ffmpeg {
36        /// The raw `FFmpeg` error code.
37        code: i32,
38        /// Human-readable description of the error.
39        message: String,
40    },
41
42    /// A multi-track composition or mixing operation failed.
43    ///
44    /// Returned by [`MultiTrackComposer::build`](crate::MultiTrackComposer::build) and
45    /// [`MultiTrackAudioMixer::build`](crate::MultiTrackAudioMixer::build) when the
46    /// `FFmpeg` filter graph cannot be constructed.
47    #[error("composition failed: {reason}")]
48    CompositionFailed {
49        /// Human-readable reason for the failure.
50        reason: String,
51    },
52
53    /// An analysis operation failed for a structural reason.
54    ///
55    /// Returned by [`LoudnessMeter::measure`](crate::analysis::LoudnessMeter::measure)
56    /// when the input file is not found, the format is unsupported, or the
57    /// `FFmpeg` filter graph cannot be constructed.
58    #[error("analysis failed: {reason}")]
59    AnalysisFailed {
60        /// Human-readable reason for the failure.
61        reason: String,
62    },
63}
64
65#[cfg(test)]
66mod tests {
67    use super::FilterError;
68    use std::error::Error;
69
70    #[test]
71    fn build_failed_should_display_correct_message() {
72        let err = FilterError::BuildFailed;
73        assert_eq!(err.to_string(), "failed to build filter graph");
74    }
75
76    #[test]
77    fn process_failed_should_display_correct_message() {
78        let err = FilterError::ProcessFailed;
79        assert_eq!(err.to_string(), "failed to process frame");
80    }
81
82    #[test]
83    fn invalid_input_should_display_slot_and_reason() {
84        let err = FilterError::InvalidInput {
85            slot: 2,
86            reason: "slot out of range".to_string(),
87        };
88        assert_eq!(
89            err.to_string(),
90            "invalid input: slot=2 reason=slot out of range"
91        );
92    }
93
94    #[test]
95    fn ffmpeg_should_display_code_and_message() {
96        let err = FilterError::Ffmpeg {
97            code: -22,
98            message: "Invalid argument".to_string(),
99        };
100        assert_eq!(err.to_string(), "ffmpeg error: Invalid argument (code=-22)");
101    }
102
103    #[test]
104    fn composition_failed_should_display_reason() {
105        let err = FilterError::CompositionFailed {
106            reason: "no layers".to_string(),
107        };
108        assert_eq!(err.to_string(), "composition failed: no layers");
109    }
110
111    #[test]
112    fn analysis_failed_should_display_reason() {
113        let err = FilterError::AnalysisFailed {
114            reason: "file not found".to_string(),
115        };
116        assert_eq!(err.to_string(), "analysis failed: file not found");
117    }
118
119    #[test]
120    fn filter_error_should_implement_std_error() {
121        fn assert_error<E: Error>(_: &E) {}
122        assert_error(&FilterError::BuildFailed);
123        assert_error(&FilterError::ProcessFailed);
124        assert_error(&FilterError::InvalidInput {
125            slot: 0,
126            reason: String::new(),
127        });
128        assert_error(&FilterError::Ffmpeg {
129            code: 0,
130            message: String::new(),
131        });
132    }
133}