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