1use rusty_ffmpeg::ffi::*;
2
3use crate::AVCodecID;
4
5#[derive(Clone, Copy, PartialEq, Eq)]
9pub struct DecoderCodec(*const AVCodec);
10
11impl std::fmt::Debug for DecoderCodec {
12 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13 if let Some(codec) = unsafe { self.0.as_ref() } {
15 let name = unsafe { std::ffi::CStr::from_ptr(codec.name) };
17
18 f.debug_struct("DecoderCodec")
19 .field("name", &name)
20 .field("id", &codec.id)
21 .finish()
22 } else {
23 f.debug_struct("DecoderCodec")
24 .field("name", &"null")
25 .field("id", &AVCodecID::None)
26 .finish()
27 }
28 }
29}
30
31impl DecoderCodec {
32 pub const fn empty() -> Self {
34 Self(std::ptr::null())
35 }
36
37 pub const fn is_empty(&self) -> bool {
39 self.0.is_null()
40 }
41
42 pub fn new(codec_id: AVCodecID) -> Option<Self> {
44 let codec = unsafe { avcodec_find_decoder(codec_id.0 as crate::ffi::AVCodecID) };
46 if codec.is_null() {
47 None
48 } else {
49 Some(Self(codec))
50 }
51 }
52
53 pub fn by_name(name: &str) -> Option<Self> {
55 let c_name = std::ffi::CString::new(name).ok()?;
56
57 let codec = unsafe { avcodec_find_decoder_by_name(c_name.as_ptr()) };
59 if codec.is_null() {
60 None
61 } else {
62 Some(Self(codec))
63 }
64 }
65
66 pub const fn as_ptr(&self) -> *const AVCodec {
68 self.0
69 }
70
71 pub const unsafe fn from_ptr(ptr: *const AVCodec) -> Self {
76 Self(ptr)
77 }
78}
79
80#[derive(Clone, Copy, PartialEq, Eq)]
84pub struct EncoderCodec(*const AVCodec);
85
86impl std::fmt::Debug for EncoderCodec {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 if let Some(codec) = unsafe { self.0.as_ref() } {
90 let name = unsafe { std::ffi::CStr::from_ptr(codec.name) };
92
93 f.debug_struct("EncoderCodec")
94 .field("name", &name)
95 .field("id", &codec.id)
96 .finish()
97 } else {
98 f.debug_struct("EncoderCodec")
99 .field("name", &"null")
100 .field("id", &AVCodecID::None)
101 .finish()
102 }
103 }
104}
105
106impl EncoderCodec {
107 pub const fn empty() -> Self {
109 Self(std::ptr::null())
110 }
111
112 pub const fn is_empty(&self) -> bool {
114 self.0.is_null()
115 }
116
117 pub fn new(codec_id: AVCodecID) -> Option<Self> {
119 let codec = unsafe { avcodec_find_encoder(codec_id.0 as crate::ffi::AVCodecID) };
121 if codec.is_null() {
122 None
123 } else {
124 Some(Self(codec))
125 }
126 }
127
128 pub fn by_name(name: &str) -> Option<Self> {
130 let c_name = std::ffi::CString::new(name).ok()?;
131 let codec = unsafe { avcodec_find_encoder_by_name(c_name.as_ptr()) };
133 if codec.is_null() {
134 None
135 } else {
136 Some(Self(codec))
137 }
138 }
139
140 pub const fn as_ptr(&self) -> *const AVCodec {
142 self.0
143 }
144
145 pub const unsafe fn from_ptr(ptr: *const AVCodec) -> Self {
150 Self(ptr)
151 }
152}
153
154impl From<EncoderCodec> for *const AVCodec {
155 fn from(codec: EncoderCodec) -> Self {
156 codec.0
157 }
158}
159
160impl From<DecoderCodec> for *const AVCodec {
161 fn from(codec: DecoderCodec) -> Self {
162 codec.0
163 }
164}
165
166#[cfg(test)]
167#[cfg_attr(all(test, coverage_nightly), coverage(off))]
168mod tests {
169 use crate::codec::{AVCodecID, DecoderCodec, EncoderCodec};
170 use crate::ffi::{avcodec_find_decoder, avcodec_find_encoder, AVCodec};
171
172 #[test]
173 fn test_decoder_codec_debug_null() {
174 let decoder_codec = DecoderCodec::empty();
175 let debug_output = format!("{:?}", decoder_codec);
176
177 insta::assert_snapshot!(debug_output, @r#"DecoderCodec { name: "null", id: AVCodecID::None }"#);
178 }
179
180 #[test]
181 fn test_decoder_codec_debug_non_null() {
182 let decoder_codec = DecoderCodec::new(AVCodecID::H264).expect("H264 codec should be available");
183 let debug_output = format!("{:?}", decoder_codec);
184
185 insta::assert_snapshot!(debug_output, @r#"DecoderCodec { name: "h264", id: 27 }"#);
186 }
187
188 #[test]
189 fn test_decoder_codec_new_invalid_codec_id() {
190 let invalid_codec_id = AVCodecID::None;
191 let result = DecoderCodec::new(invalid_codec_id);
192
193 assert!(
194 result.is_none(),
195 "Expected `DecoderCodec::new` to return None for an invalid codec ID"
196 );
197 }
198
199 #[test]
200 fn test_decoder_codec_by_name_valid() {
201 let result = DecoderCodec::by_name("h264");
202
203 assert!(
204 result.is_some(),
205 "Expected `DecoderCodec::by_name` to return Some for a valid codec name"
206 );
207
208 let codec = result.unwrap();
209 assert!(!codec.as_ptr().is_null(), "Expected a non-null codec pointer");
210 }
211
212 #[test]
213 fn test_decoder_codec_by_name_invalid() {
214 let invalid_codec_name = "nonexistent_codec";
215 let result = DecoderCodec::by_name(invalid_codec_name);
216
217 assert!(
218 result.is_none(),
219 "Expected `DecoderCodec::by_name` to return None for an invalid codec name"
220 );
221 }
222
223 #[test]
224 fn test_decoder_codec_from_ptr_valid() {
225 let codec_ptr = unsafe { avcodec_find_decoder(AVCodecID::H264.into()) };
227 assert!(!codec_ptr.is_null(), "Expected a valid codec pointer for H264");
228
229 let decoder_codec = unsafe { DecoderCodec::from_ptr(codec_ptr) };
231 assert_eq!(
232 decoder_codec.as_ptr(),
233 codec_ptr,
234 "Expected the codec pointer in DecoderCodec to match the original pointer"
235 );
236 }
237
238 #[test]
239 fn test_encoder_codec_debug_valid() {
240 let codec_ptr = unsafe { avcodec_find_encoder(AVCodecID::Mpeg4.into()) };
242
243 assert!(!codec_ptr.is_null(), "Expected a valid codec pointer for MPEG4");
244
245 let encoder_codec = EncoderCodec(codec_ptr);
246 insta::assert_debug_snapshot!(encoder_codec, @r#"
247 EncoderCodec {
248 name: "mpeg4",
249 id: 12,
250 }
251 "#);
252 }
253
254 #[test]
255 fn test_encoder_codec_debug_null() {
256 let encoder_codec = EncoderCodec(std::ptr::null());
257 insta::assert_debug_snapshot!(encoder_codec, @r#"
258 EncoderCodec {
259 name: "null",
260 id: AVCodecID::None,
261 }
262 "#);
263 }
264
265 #[test]
266 fn test_encoder_codec_empty() {
267 let encoder_codec = EncoderCodec::empty();
268 assert!(
269 encoder_codec.as_ptr().is_null(),
270 "Expected the encoder codec pointer to be null"
271 );
272
273 insta::assert_debug_snapshot!(encoder_codec, @r#"
274 EncoderCodec {
275 name: "null",
276 id: AVCodecID::None,
277 }
278 "#);
279 }
280
281 #[test]
282 fn test_encoder_codec_new_invalid_codec() {
283 let invalid_codec_id = AVCodecID::None;
284 let result = EncoderCodec::new(invalid_codec_id);
285
286 assert!(result.is_none(), "Expected None for an invalid codec ID");
287 }
288
289 #[test]
290 fn test_encoder_codec_by_name_valid() {
291 let result = EncoderCodec::by_name("mpeg4");
292 assert!(result.is_some(), "Expected a valid encoder codec for the name {}", "mpeg4");
293
294 let encoder_codec = result.unwrap();
295 assert!(!encoder_codec.as_ptr().is_null(), "Expected a non-null encoder codec pointer");
296 }
297
298 #[test]
299 fn test_encoder_codec_by_name_invalid() {
300 let invalid_encoder_name = "invalid_encoder_name";
301 let result = EncoderCodec::by_name(invalid_encoder_name);
302
303 assert!(
304 result.is_none(),
305 "Expected None for an invalid encoder name {}",
306 invalid_encoder_name
307 );
308 }
309
310 #[test]
311 fn test_encoder_codec_into_raw_ptr() {
312 let valid_codec_id = AVCodecID::Aac;
313 let encoder_codec = EncoderCodec::new(valid_codec_id).expect("Expected a valid encoder codec for AAC");
314 let raw_ptr: *const AVCodec = encoder_codec.into();
315
316 assert_eq!(
317 raw_ptr,
318 encoder_codec.as_ptr(),
319 "The raw pointer should match the encoder codec's internal pointer"
320 );
321 }
322
323 #[test]
324 fn test_decoder_codec_into_raw_ptr() {
325 let valid_codec_id = AVCodecID::Aac;
326 let decoder_codec = DecoderCodec::new(valid_codec_id).expect("Expected a valid decoder codec for AAC");
327 let raw_ptr: *const AVCodec = decoder_codec.into();
328
329 assert_eq!(
330 raw_ptr,
331 decoder_codec.as_ptr(),
332 "The raw pointer should match the decoder codec's internal pointer"
333 );
334 }
335
336 #[test]
337 fn test_codec_into_raw_ptr_empty() {
338 let empty_encoder_codec = EncoderCodec::empty();
339 let raw_ptr: *const AVCodec = empty_encoder_codec.into();
340 assert!(raw_ptr.is_null(), "The raw pointer should be null for an empty EncoderCodec");
341
342 let empty_decoder_codec = DecoderCodec::empty();
343 let raw_ptr: *const AVCodec = empty_decoder_codec.into();
344 assert!(raw_ptr.is_null(), "The raw pointer should be null for an empty DecoderCodec");
345 }
346}