ffmpeg_the_third/util/
error.rs

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