1 | use std::error; |
2 | use std::ffi::CStr; |
3 | use std::fmt; |
4 | use std::io; |
5 | use std::str::from_utf8_unchecked; |
6 | |
7 | use ffi::*; |
8 | use libc::{c_char, c_int}; |
9 | |
10 | // Export POSIX error codes so that users can do something like |
11 | // |
12 | // if error == (Error::Other { errno: EAGAIN }) { |
13 | // ... |
14 | // } |
15 | pub use libc::{ |
16 | E2BIG, EACCES, EADDRINUSE, EADDRNOTAVAIL, EAFNOSUPPORT, EAGAIN, EALREADY, EBADF, EBADMSG, |
17 | EBUSY, ECANCELED, ECHILD, ECONNABORTED, ECONNREFUSED, ECONNRESET, EDEADLK, EDESTADDRREQ, EDOM, |
18 | EEXIST, EFAULT, EFBIG, EHOSTUNREACH, EIDRM, EILSEQ, EINPROGRESS, EINTR, EINVAL, EIO, EISCONN, |
19 | EISDIR, ELOOP, EMFILE, EMLINK, EMSGSIZE, ENAMETOOLONG, ENETDOWN, ENETRESET, ENETUNREACH, |
20 | ENFILE, ENOBUFS, ENODATA, ENODEV, ENOENT, ENOEXEC, ENOLCK, ENOLINK, ENOMEM, ENOMSG, |
21 | ENOPROTOOPT, ENOSPC, ENOSR, ENOSTR, ENOSYS, ENOTCONN, ENOTDIR, ENOTEMPTY, ENOTRECOVERABLE, |
22 | ENOTSOCK, ENOTSUP, ENOTTY, ENXIO, EOPNOTSUPP, EOVERFLOW, EOWNERDEAD, EPERM, EPIPE, EPROTO, |
23 | EPROTONOSUPPORT, EPROTOTYPE, ERANGE, EROFS, ESPIPE, ESRCH, ETIME, ETIMEDOUT, ETXTBSY, |
24 | EWOULDBLOCK, EXDEV, |
25 | }; |
26 | |
27 | #[derive (Copy, Clone, PartialEq, Eq)] |
28 | pub enum Error { |
29 | Bug, |
30 | Bug2, |
31 | Unknown, |
32 | Experimental, |
33 | BufferTooSmall, |
34 | Eof, |
35 | Exit, |
36 | External, |
37 | InvalidData, |
38 | PatchWelcome, |
39 | |
40 | InputChanged, |
41 | OutputChanged, |
42 | |
43 | BsfNotFound, |
44 | DecoderNotFound, |
45 | DemuxerNotFound, |
46 | EncoderNotFound, |
47 | OptionNotFound, |
48 | MuxerNotFound, |
49 | FilterNotFound, |
50 | ProtocolNotFound, |
51 | StreamNotFound, |
52 | |
53 | HttpBadRequest, |
54 | HttpUnauthorized, |
55 | HttpForbidden, |
56 | HttpNotFound, |
57 | HttpOther4xx, |
58 | HttpServerError, |
59 | |
60 | /// For AVERROR(e) wrapping POSIX error codes, e.g. AVERROR(EAGAIN). |
61 | Other { |
62 | errno: c_int, |
63 | }, |
64 | } |
65 | |
66 | impl From<c_int> for Error { |
67 | fn from(value: c_int) -> Error { |
68 | match value { |
69 | AVERROR_BSF_NOT_FOUND => Error::BsfNotFound, |
70 | AVERROR_BUG => Error::Bug, |
71 | AVERROR_BUFFER_TOO_SMALL => Error::BufferTooSmall, |
72 | AVERROR_DECODER_NOT_FOUND => Error::DecoderNotFound, |
73 | AVERROR_DEMUXER_NOT_FOUND => Error::DemuxerNotFound, |
74 | AVERROR_ENCODER_NOT_FOUND => Error::EncoderNotFound, |
75 | AVERROR_EOF => Error::Eof, |
76 | AVERROR_EXIT => Error::Exit, |
77 | AVERROR_EXTERNAL => Error::External, |
78 | AVERROR_FILTER_NOT_FOUND => Error::FilterNotFound, |
79 | AVERROR_INVALIDDATA => Error::InvalidData, |
80 | AVERROR_MUXER_NOT_FOUND => Error::MuxerNotFound, |
81 | AVERROR_OPTION_NOT_FOUND => Error::OptionNotFound, |
82 | AVERROR_PATCHWELCOME => Error::PatchWelcome, |
83 | AVERROR_PROTOCOL_NOT_FOUND => Error::ProtocolNotFound, |
84 | AVERROR_STREAM_NOT_FOUND => Error::StreamNotFound, |
85 | AVERROR_BUG2 => Error::Bug2, |
86 | AVERROR_UNKNOWN => Error::Unknown, |
87 | AVERROR_EXPERIMENTAL => Error::Experimental, |
88 | AVERROR_INPUT_CHANGED => Error::InputChanged, |
89 | AVERROR_OUTPUT_CHANGED => Error::OutputChanged, |
90 | AVERROR_HTTP_BAD_REQUEST => Error::HttpBadRequest, |
91 | AVERROR_HTTP_UNAUTHORIZED => Error::HttpUnauthorized, |
92 | AVERROR_HTTP_FORBIDDEN => Error::HttpForbidden, |
93 | AVERROR_HTTP_NOT_FOUND => Error::HttpNotFound, |
94 | AVERROR_HTTP_OTHER_4XX => Error::HttpOther4xx, |
95 | AVERROR_HTTP_SERVER_ERROR => Error::HttpServerError, |
96 | e => Error::Other { |
97 | errno: AVUNERROR(e), |
98 | }, |
99 | } |
100 | } |
101 | } |
102 | |
103 | impl From<Error> for c_int { |
104 | fn from(value: Error) -> c_int { |
105 | match value { |
106 | Error::BsfNotFound => AVERROR_BSF_NOT_FOUND, |
107 | Error::Bug => AVERROR_BUG, |
108 | Error::BufferTooSmall => AVERROR_BUFFER_TOO_SMALL, |
109 | Error::DecoderNotFound => AVERROR_DECODER_NOT_FOUND, |
110 | Error::DemuxerNotFound => AVERROR_DEMUXER_NOT_FOUND, |
111 | Error::EncoderNotFound => AVERROR_ENCODER_NOT_FOUND, |
112 | Error::Eof => AVERROR_EOF, |
113 | Error::Exit => AVERROR_EXIT, |
114 | Error::External => AVERROR_EXTERNAL, |
115 | Error::FilterNotFound => AVERROR_FILTER_NOT_FOUND, |
116 | Error::InvalidData => AVERROR_INVALIDDATA, |
117 | Error::MuxerNotFound => AVERROR_MUXER_NOT_FOUND, |
118 | Error::OptionNotFound => AVERROR_OPTION_NOT_FOUND, |
119 | Error::PatchWelcome => AVERROR_PATCHWELCOME, |
120 | Error::ProtocolNotFound => AVERROR_PROTOCOL_NOT_FOUND, |
121 | Error::StreamNotFound => AVERROR_STREAM_NOT_FOUND, |
122 | Error::Bug2 => AVERROR_BUG2, |
123 | Error::Unknown => AVERROR_UNKNOWN, |
124 | Error::Experimental => AVERROR_EXPERIMENTAL, |
125 | Error::InputChanged => AVERROR_INPUT_CHANGED, |
126 | Error::OutputChanged => AVERROR_OUTPUT_CHANGED, |
127 | Error::HttpBadRequest => AVERROR_HTTP_BAD_REQUEST, |
128 | Error::HttpUnauthorized => AVERROR_HTTP_UNAUTHORIZED, |
129 | Error::HttpForbidden => AVERROR_HTTP_FORBIDDEN, |
130 | Error::HttpNotFound => AVERROR_HTTP_NOT_FOUND, |
131 | Error::HttpOther4xx => AVERROR_HTTP_OTHER_4XX, |
132 | Error::HttpServerError => AVERROR_HTTP_SERVER_ERROR, |
133 | Error::Other { errno } => AVERROR(errno), |
134 | } |
135 | } |
136 | } |
137 | |
138 | impl error::Error for Error {} |
139 | |
140 | impl From<Error> for io::Error { |
141 | fn from(value: Error) -> io::Error { |
142 | io::Error::new(kind:io::ErrorKind::Other, error:value) |
143 | } |
144 | } |
145 | |
146 | impl fmt::Display for Error { |
147 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
148 | f.write_str(data:unsafe { |
149 | from_utf8_unchecked( |
150 | CStr&CStr::from_ptr(match *self { |
151 | Error::Other { errno: i32 } => libc::strerror(errno), |
152 | _ => STRINGS[index(self)].as_ptr(), |
153 | }) |
154 | .to_bytes(), |
155 | ) |
156 | }) |
157 | } |
158 | } |
159 | |
160 | impl fmt::Debug for Error { |
161 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
162 | f.write_str(data:"ffmpeg::Error(" )?; |
163 | f.write_str(&format!(" {}: " , AVUNERROR((*self).into())))?; |
164 | fmt::Display::fmt(self, f)?; |
165 | f.write_str(data:")" ) |
166 | } |
167 | } |
168 | |
169 | #[inline (always)] |
170 | fn index(error: &Error) -> usize { |
171 | match *error { |
172 | Error::BsfNotFound => 0, |
173 | Error::Bug => 1, |
174 | Error::BufferTooSmall => 2, |
175 | Error::DecoderNotFound => 3, |
176 | Error::DemuxerNotFound => 4, |
177 | Error::EncoderNotFound => 5, |
178 | Error::Eof => 6, |
179 | Error::Exit => 7, |
180 | Error::External => 8, |
181 | Error::FilterNotFound => 9, |
182 | Error::InvalidData => 10, |
183 | Error::MuxerNotFound => 11, |
184 | Error::OptionNotFound => 12, |
185 | Error::PatchWelcome => 13, |
186 | Error::ProtocolNotFound => 14, |
187 | Error::StreamNotFound => 15, |
188 | Error::Bug2 => 16, |
189 | Error::Unknown => 17, |
190 | Error::Experimental => 18, |
191 | Error::InputChanged => 19, |
192 | Error::OutputChanged => 20, |
193 | Error::HttpBadRequest => 21, |
194 | Error::HttpUnauthorized => 22, |
195 | Error::HttpForbidden => 23, |
196 | Error::HttpNotFound => 24, |
197 | Error::HttpOther4xx => 25, |
198 | Error::HttpServerError => 26, |
199 | Error::Other { errno: _ } => (-1isize) as usize, |
200 | } |
201 | } |
202 | |
203 | // XXX: the length has to be synced with the number of errors |
204 | static mut STRINGS: [[c_char; AV_ERROR_MAX_STRING_SIZE]; 27] = [[0; AV_ERROR_MAX_STRING_SIZE]; 27]; |
205 | |
206 | pub fn register_all() { |
207 | unsafe { |
208 | av_strerror( |
209 | Error::Bug.into(), |
210 | STRINGS[index(&Error::Bug)].as_mut_ptr(), |
211 | AV_ERROR_MAX_STRING_SIZE, |
212 | ); |
213 | av_strerror( |
214 | Error::Bug2.into(), |
215 | STRINGS[index(&Error::Bug2)].as_mut_ptr(), |
216 | AV_ERROR_MAX_STRING_SIZE, |
217 | ); |
218 | av_strerror( |
219 | Error::Unknown.into(), |
220 | STRINGS[index(&Error::Unknown)].as_mut_ptr(), |
221 | AV_ERROR_MAX_STRING_SIZE, |
222 | ); |
223 | av_strerror( |
224 | Error::Experimental.into(), |
225 | STRINGS[index(&Error::Experimental)].as_mut_ptr(), |
226 | AV_ERROR_MAX_STRING_SIZE, |
227 | ); |
228 | av_strerror( |
229 | Error::BufferTooSmall.into(), |
230 | STRINGS[index(&Error::BufferTooSmall)].as_mut_ptr(), |
231 | AV_ERROR_MAX_STRING_SIZE, |
232 | ); |
233 | av_strerror( |
234 | Error::Eof.into(), |
235 | STRINGS[index(&Error::Eof)].as_mut_ptr(), |
236 | AV_ERROR_MAX_STRING_SIZE, |
237 | ); |
238 | av_strerror( |
239 | Error::Exit.into(), |
240 | STRINGS[index(&Error::Exit)].as_mut_ptr(), |
241 | AV_ERROR_MAX_STRING_SIZE, |
242 | ); |
243 | av_strerror( |
244 | Error::External.into(), |
245 | STRINGS[index(&Error::External)].as_mut_ptr(), |
246 | AV_ERROR_MAX_STRING_SIZE, |
247 | ); |
248 | av_strerror( |
249 | Error::InvalidData.into(), |
250 | STRINGS[index(&Error::InvalidData)].as_mut_ptr(), |
251 | AV_ERROR_MAX_STRING_SIZE, |
252 | ); |
253 | av_strerror( |
254 | Error::PatchWelcome.into(), |
255 | STRINGS[index(&Error::PatchWelcome)].as_mut_ptr(), |
256 | AV_ERROR_MAX_STRING_SIZE, |
257 | ); |
258 | |
259 | av_strerror( |
260 | Error::InputChanged.into(), |
261 | STRINGS[index(&Error::InputChanged)].as_mut_ptr(), |
262 | AV_ERROR_MAX_STRING_SIZE, |
263 | ); |
264 | av_strerror( |
265 | Error::OutputChanged.into(), |
266 | STRINGS[index(&Error::OutputChanged)].as_mut_ptr(), |
267 | AV_ERROR_MAX_STRING_SIZE, |
268 | ); |
269 | |
270 | av_strerror( |
271 | Error::BsfNotFound.into(), |
272 | STRINGS[index(&Error::BsfNotFound)].as_mut_ptr(), |
273 | AV_ERROR_MAX_STRING_SIZE, |
274 | ); |
275 | av_strerror( |
276 | Error::DecoderNotFound.into(), |
277 | STRINGS[index(&Error::DecoderNotFound)].as_mut_ptr(), |
278 | AV_ERROR_MAX_STRING_SIZE, |
279 | ); |
280 | av_strerror( |
281 | Error::DemuxerNotFound.into(), |
282 | STRINGS[index(&Error::DemuxerNotFound)].as_mut_ptr(), |
283 | AV_ERROR_MAX_STRING_SIZE, |
284 | ); |
285 | av_strerror( |
286 | Error::EncoderNotFound.into(), |
287 | STRINGS[index(&Error::EncoderNotFound)].as_mut_ptr(), |
288 | AV_ERROR_MAX_STRING_SIZE, |
289 | ); |
290 | av_strerror( |
291 | Error::OptionNotFound.into(), |
292 | STRINGS[index(&Error::OptionNotFound)].as_mut_ptr(), |
293 | AV_ERROR_MAX_STRING_SIZE, |
294 | ); |
295 | av_strerror( |
296 | Error::MuxerNotFound.into(), |
297 | STRINGS[index(&Error::MuxerNotFound)].as_mut_ptr(), |
298 | AV_ERROR_MAX_STRING_SIZE, |
299 | ); |
300 | av_strerror( |
301 | Error::FilterNotFound.into(), |
302 | STRINGS[index(&Error::FilterNotFound)].as_mut_ptr(), |
303 | AV_ERROR_MAX_STRING_SIZE, |
304 | ); |
305 | av_strerror( |
306 | Error::ProtocolNotFound.into(), |
307 | STRINGS[index(&Error::ProtocolNotFound)].as_mut_ptr(), |
308 | AV_ERROR_MAX_STRING_SIZE, |
309 | ); |
310 | av_strerror( |
311 | Error::StreamNotFound.into(), |
312 | STRINGS[index(&Error::StreamNotFound)].as_mut_ptr(), |
313 | AV_ERROR_MAX_STRING_SIZE, |
314 | ); |
315 | |
316 | av_strerror( |
317 | Error::HttpBadRequest.into(), |
318 | STRINGS[index(&Error::HttpBadRequest)].as_mut_ptr(), |
319 | AV_ERROR_MAX_STRING_SIZE, |
320 | ); |
321 | av_strerror( |
322 | Error::HttpUnauthorized.into(), |
323 | STRINGS[index(&Error::HttpUnauthorized)].as_mut_ptr(), |
324 | AV_ERROR_MAX_STRING_SIZE, |
325 | ); |
326 | av_strerror( |
327 | Error::HttpForbidden.into(), |
328 | STRINGS[index(&Error::HttpForbidden)].as_mut_ptr(), |
329 | AV_ERROR_MAX_STRING_SIZE, |
330 | ); |
331 | av_strerror( |
332 | Error::HttpNotFound.into(), |
333 | STRINGS[index(&Error::HttpNotFound)].as_mut_ptr(), |
334 | AV_ERROR_MAX_STRING_SIZE, |
335 | ); |
336 | av_strerror( |
337 | Error::HttpOther4xx.into(), |
338 | STRINGS[index(&Error::HttpOther4xx)].as_mut_ptr(), |
339 | AV_ERROR_MAX_STRING_SIZE, |
340 | ); |
341 | av_strerror( |
342 | Error::HttpServerError.into(), |
343 | STRINGS[index(&Error::HttpServerError)].as_mut_ptr(), |
344 | AV_ERROR_MAX_STRING_SIZE, |
345 | ); |
346 | } |
347 | } |
348 | |
349 | #[cfg (test)] |
350 | mod tests { |
351 | use super::*; |
352 | |
353 | #[test ] |
354 | fn test_error_roundtrip() { |
355 | assert_eq!(Into::<c_int>::into(Error::from(AVERROR_EOF)), AVERROR_EOF); |
356 | assert_eq!( |
357 | Into::<c_int>::into(Error::from(AVERROR(EAGAIN))), |
358 | AVERROR(EAGAIN) |
359 | ); |
360 | assert_eq!(Error::from(AVERROR(EAGAIN)), Error::Other { errno: EAGAIN }); |
361 | } |
362 | |
363 | #[cfg (any(target_os = "linux" , target_os = "macos" ))] |
364 | #[test ] |
365 | fn test_posix_error_string() { |
366 | assert_eq!( |
367 | Error::from(AVERROR(EAGAIN)).to_string(), |
368 | "Resource temporarily unavailable" |
369 | ) |
370 | } |
371 | } |
372 | |