1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
use std::ffi::{CStr, NulError};
use std::fmt;
use crate::sys;
/// Errors that [`codecpod`](crate) may produce.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// The path contains an interior NUL byte and cannot be converted to a C string.
#[error("invalid path: contains interior NUL")]
InvalidPath(#[from] NulError),
/// The caller passed an invalid argument.
#[error("invalid argument: {0}")]
InvalidArg(&'static str),
/// The input file contains no audio stream.
#[error("file has no audio stream")]
NoAudioStream,
/// No decoder matching the given codec id could be found.
#[error("decoder not found for codec id {0}")]
DecoderNotFound(u32),
/// The audio stream reported an invalid channel count or sample rate.
#[error("invalid stream parameters: channels={channels} sample_rate={sample_rate}")]
InvalidStreamParameters {
/// Channel count reported by the stream.
channels: i32,
/// Sample rate reported by the stream.
sample_rate: i32,
},
/// No encoder matching the given name could be found (not enabled at build time).
#[error("encoder not found: {0}")]
EncoderNotFound(&'static str),
/// The encoder does not support the target sample rate.
#[error("encoder does not support sample rate {sample_rate} (supported: {supported:?})")]
UnsupportedSampleRate {
/// Sample rate requested by the caller.
sample_rate: i32,
/// List of sample rates supported by the encoder.
supported: Vec<i32>,
},
/// The input [`SampleData`](crate::SampleData) length does not match `channels * frames`,
/// or `channels` / `sample_rate` is 0.
#[error("invalid input buffer: {0}")]
InvalidInputBuffer(&'static str),
/// An `av_opt_set` / `av_opt_set_int` / `av_opt_set_double` call failed. The common cause
/// is that the encoder does not support the given AVOption (a misspelled key or a mismatched FFmpeg encoder version).
#[error("av_opt_set({key}): {code}")]
AvOptSetFailed {
/// Key of the AVOption that failed to be set.
key: &'static str,
/// FFmpeg error code.
code: FFmpegError,
},
/// Memory allocation failed.
#[error("memory allocation failed")]
OutOfMemory,
/// The `avformat_open_input` call failed.
#[error("avformat_open_input: {0}")]
OpenInput(FFmpegError),
/// The `avformat_find_stream_info` call failed.
#[error("avformat_find_stream_info: {0}")]
FindStreamInfo(FFmpegError),
/// `avcodec_alloc_context3` returned NULL.
#[error("avcodec_alloc_context3 returned NULL")]
AllocCodecContext,
/// The `avcodec_parameters_to_context` call failed.
#[error("avcodec_parameters_to_context: {0}")]
CodecParameters(FFmpegError),
/// The `avcodec_open2` call failed.
#[error("avcodec_open2: {0}")]
OpenCodec(FFmpegError),
/// The `swr_alloc_set_opts2` call failed.
#[error("swr_alloc_set_opts2: {0}")]
SwrAlloc(FFmpegError),
/// The `swr_init` call failed.
#[error("swr_init: {0}")]
SwrInit(FFmpegError),
/// The `swr_convert` call failed.
#[error("swr_convert: {0}")]
SwrConvert(FFmpegError),
/// The `av_seek_frame` call failed.
#[error("av_seek_frame: {0}")]
Seek(FFmpegError),
/// The `av_read_frame` call failed.
#[error("av_read_frame: {0}")]
ReadFrame(FFmpegError),
/// The `avcodec_send_packet` call failed.
#[error("avcodec_send_packet: {0}")]
SendPacket(FFmpegError),
/// The `avcodec_receive_frame` call failed.
#[error("avcodec_receive_frame: {0}")]
ReceiveFrame(FFmpegError),
/// The `avformat_alloc_output_context2` call failed.
#[error("avformat_alloc_output_context2: {0}")]
AllocOutputContext(FFmpegError),
/// `avformat_new_stream` returned NULL.
#[error("avformat_new_stream returned NULL")]
NewStream,
/// The `avcodec_parameters_from_context` call failed.
#[error("avcodec_parameters_from_context: {0}")]
CodecParametersFrom(FFmpegError),
/// The `avio_open` call failed.
#[error("avio_open: {0}")]
AvioOpen(FFmpegError),
/// The `avformat_write_header` call failed.
#[error("avformat_write_header: {0}")]
WriteHeader(FFmpegError),
/// The `av_write_trailer` call failed.
#[error("av_write_trailer: {0}")]
WriteTrailer(FFmpegError),
/// The `av_interleaved_write_frame` call failed.
#[error("av_interleaved_write_frame: {0}")]
WriteFrame(FFmpegError),
/// The `avcodec_send_frame` call failed.
#[error("avcodec_send_frame: {0}")]
SendFrame(FFmpegError),
/// The `avcodec_receive_packet` call failed.
#[error("avcodec_receive_packet: {0}")]
ReceivePacket(FFmpegError),
/// `av_audio_fifo_alloc` returned NULL.
#[error("av_audio_fifo_alloc returned NULL")]
AudioFifoAlloc,
/// An `av_audio_fifo_realloc` / `av_audio_fifo_write` call failed.
#[error("av_audio_fifo write: {0}")]
AudioFifoWrite(FFmpegError),
/// The `av_audio_fifo_read` call failed.
#[error("av_audio_fifo_read: {0}")]
AudioFifoRead(FFmpegError),
/// The `av_frame_get_buffer` call failed.
#[error("av_frame_get_buffer: {0}")]
FrameGetBuffer(FFmpegError),
}
/// FFmpeg error code.
#[derive(Debug, Clone, Copy)]
pub struct FFmpegError(pub i32);
impl fmt::Display for FFmpegError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buf = [0i8; sys::AV_ERROR_MAX_STRING_SIZE as usize];
let msg = unsafe {
if sys::av_strerror(self.0, buf.as_mut_ptr() as *mut _, buf.len()) == 0 {
CStr::from_ptr(buf.as_ptr() as *const _)
.to_string_lossy()
.into_owned()
} else {
format!("unknown FFmpeg error {}", self.0)
}
};
write!(f, "{msg} ({})", self.0)
}
}