Skip to main content

ff_encode/
error.rs

1//! Error types for encoding operations.
2
3use std::path::PathBuf;
4use thiserror::Error;
5
6/// Encoding error type.
7#[derive(Error, Debug)]
8pub enum EncodeError {
9    /// Cannot create output file
10    #[error("Cannot create output file: {path}")]
11    CannotCreateFile {
12        /// File path that failed
13        path: PathBuf,
14    },
15
16    /// Unsupported codec
17    #[error("Unsupported codec: {codec}")]
18    UnsupportedCodec {
19        /// Codec name
20        codec: String,
21    },
22
23    /// No suitable encoder found
24    #[error("No suitable encoder found for {codec} (tried: {tried:?})")]
25    NoSuitableEncoder {
26        /// Requested codec
27        codec: String,
28        /// Attempted encoders
29        tried: Vec<String>,
30    },
31
32    /// Encoding failed at specific frame
33    #[error("Encoding failed at frame {frame}: {reason}")]
34    EncodingFailed {
35        /// Frame number where encoding failed
36        frame: u64,
37        /// Failure reason
38        reason: String,
39    },
40
41    /// Invalid configuration
42    #[error("Invalid configuration: {reason}")]
43    InvalidConfig {
44        /// Configuration issue description
45        reason: String,
46    },
47
48    /// Hardware encoder unavailable
49    #[error("Hardware encoder unavailable: {encoder}")]
50    HwEncoderUnavailable {
51        /// Hardware encoder name
52        encoder: String,
53    },
54
55    /// Muxing failed
56    #[error("Muxing failed: {reason}")]
57    MuxingFailed {
58        /// Failure reason
59        reason: String,
60    },
61
62    /// `FFmpeg` error
63    #[error("FFmpeg error: {0}")]
64    Ffmpeg(String),
65
66    /// IO error
67    #[error("IO error: {0}")]
68    Io(#[from] std::io::Error),
69
70    /// Encoding cancelled by user
71    #[error("Encoding cancelled by user")]
72    Cancelled,
73}
74
75impl EncodeError {
76    /// Create an error from an FFmpeg error code.
77    ///
78    /// This is more type-safe than implementing `From<i32>` globally,
79    /// as it makes the conversion explicit and prevents accidental
80    /// conversion of arbitrary i32 values.
81    pub(crate) fn from_ffmpeg_error(errnum: i32) -> Self {
82        let error_msg = ff_sys::av_error_string(errnum);
83        EncodeError::Ffmpeg(format!("{} (code: {})", error_msg, errnum))
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::EncodeError;
90
91    #[test]
92    fn from_ffmpeg_error_returns_ffmpeg_variant() {
93        let err = EncodeError::from_ffmpeg_error(ff_sys::error_codes::EINVAL);
94        assert!(matches!(err, EncodeError::Ffmpeg(_)));
95    }
96
97    #[test]
98    fn from_ffmpeg_error_message_contains_code() {
99        let err = EncodeError::from_ffmpeg_error(ff_sys::error_codes::EINVAL);
100        let msg = err.to_string();
101        assert!(msg.contains("code: -22"), "expected 'code: -22' in '{msg}'");
102    }
103
104    #[test]
105    fn from_ffmpeg_error_message_nonempty() {
106        let err = EncodeError::from_ffmpeg_error(ff_sys::error_codes::ENOMEM);
107        let msg = err.to_string();
108        assert!(!msg.is_empty());
109    }
110
111    #[test]
112    fn from_ffmpeg_error_eof() {
113        let err = EncodeError::from_ffmpeg_error(ff_sys::error_codes::EOF);
114        assert!(matches!(err, EncodeError::Ffmpeg(_)));
115        assert!(!err.to_string().is_empty());
116    }
117}