1use std::path::PathBuf;
4use thiserror::Error;
5
6#[derive(Error, Debug)]
8pub enum EncodeError {
9 #[error("Cannot create output file: {path}")]
11 CannotCreateFile {
12 path: PathBuf,
14 },
15
16 #[error("Unsupported codec: {codec}")]
18 UnsupportedCodec {
19 codec: String,
21 },
22
23 #[error("No suitable encoder found for {codec} (tried: {tried:?})")]
25 NoSuitableEncoder {
26 codec: String,
28 tried: Vec<String>,
30 },
31
32 #[error("Encoding failed at frame {frame}: {reason}")]
34 EncodingFailed {
35 frame: u64,
37 reason: String,
39 },
40
41 #[error("Invalid configuration: {reason}")]
43 InvalidConfig {
44 reason: String,
46 },
47
48 #[error("Hardware encoder unavailable: {encoder}")]
50 HwEncoderUnavailable {
51 encoder: String,
53 },
54
55 #[error("encoder unavailable: codec={codec} hint={hint}")]
57 EncoderUnavailable {
58 codec: String,
60 hint: String,
62 },
63
64 #[error("Muxing failed: {reason}")]
66 MuxingFailed {
67 reason: String,
69 },
70
71 #[error("ffmpeg error: {message} (code={code})")]
73 Ffmpeg {
74 code: i32,
76 message: String,
78 },
79
80 #[error("IO error: {0}")]
82 Io(#[from] std::io::Error),
83
84 #[error("Invalid option: {name} — {reason}")]
86 InvalidOption {
87 name: String,
89 reason: String,
91 },
92
93 #[error("codec {codec} is not supported by container {container} — {hint}")]
95 UnsupportedContainerCodecCombination {
96 container: String,
98 codec: String,
100 hint: String,
102 },
103
104 #[error("Encoding cancelled by user")]
106 Cancelled,
107
108 #[error("Async encoder worker panicked or disconnected")]
110 WorkerPanicked,
111}
112
113impl EncodeError {
114 pub(crate) fn from_ffmpeg_error(errnum: i32) -> Self {
120 EncodeError::Ffmpeg {
121 code: errnum,
122 message: ff_sys::av_error_string(errnum),
123 }
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::EncodeError;
130
131 #[test]
132 fn from_ffmpeg_error_should_return_ffmpeg_variant() {
133 let err = EncodeError::from_ffmpeg_error(ff_sys::error_codes::EINVAL);
134 assert!(matches!(err, EncodeError::Ffmpeg { .. }));
135 }
136
137 #[test]
138 fn from_ffmpeg_error_should_carry_numeric_code() {
139 let err = EncodeError::from_ffmpeg_error(ff_sys::error_codes::EINVAL);
140 match err {
141 EncodeError::Ffmpeg { code, .. } => assert_eq!(code, ff_sys::error_codes::EINVAL),
142 _ => panic!("expected Ffmpeg variant"),
143 }
144 }
145
146 #[test]
147 fn from_ffmpeg_error_should_format_with_code_in_display() {
148 let err = EncodeError::from_ffmpeg_error(ff_sys::error_codes::EINVAL);
149 let msg = err.to_string();
150 assert!(msg.contains("code=-22"), "expected 'code=-22' in '{msg}'");
151 }
152
153 #[test]
154 fn from_ffmpeg_error_message_should_be_nonempty() {
155 let err = EncodeError::from_ffmpeg_error(ff_sys::error_codes::ENOMEM);
156 assert!(!err.to_string().is_empty());
157 }
158
159 #[test]
160 fn from_ffmpeg_error_eof_should_be_constructible() {
161 let err = EncodeError::from_ffmpeg_error(ff_sys::error_codes::EOF);
162 assert!(matches!(err, EncodeError::Ffmpeg { .. }));
163 assert!(!err.to_string().is_empty());
164 }
165}