Skip to main content

ffmpeg_the_third/codec/
descriptor.rs

1use std::ptr::NonNull;
2
3use crate::ffi::*;
4use crate::media;
5use crate::utils;
6
7use super::profile::ProfileIter;
8use super::{CodecProperties, Id};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct CodecDescriptor {
12    ptr: NonNull<AVCodecDescriptor>,
13}
14
15impl CodecDescriptor {
16    pub unsafe fn from_raw(ptr: *const AVCodecDescriptor) -> Option<Self> {
17        NonNull::new(ptr as *mut _).map(|ptr| Self { ptr })
18    }
19
20    pub fn as_ptr(self) -> *const AVCodecDescriptor {
21        self.ptr.as_ptr()
22    }
23
24    pub fn id(self) -> Id {
25        unsafe { (*self.as_ptr()).id.into() }
26    }
27
28    pub fn kind(self) -> media::Type {
29        unsafe { (*self.as_ptr()).type_.into() }
30    }
31
32    pub fn name(self) -> &'static str {
33        unsafe { utils::str_from_c_ptr((*self.as_ptr()).name) }
34    }
35
36    pub fn description(self) -> Option<&'static str> {
37        unsafe { utils::optional_str_from_c_ptr((*self.as_ptr()).long_name) }
38    }
39
40    pub fn props(self) -> CodecProperties {
41        unsafe { CodecProperties::from_bits_truncate((*self.as_ptr()).props) }
42    }
43
44    pub fn mime_types(self) -> Option<MimeTypeIter> {
45        unsafe { MimeTypeIter::from_raw((*self.as_ptr()).mime_types) }
46    }
47
48    pub fn profiles(self) -> Option<ProfileIter> {
49        unsafe {
50            if (*self.as_ptr()).profiles.is_null() {
51                None
52            } else {
53                Some(ProfileIter::new(self.id(), (*self.as_ptr()).profiles))
54            }
55        }
56    }
57}
58
59pub struct CodecDescriptorIter {
60    ptr: *const AVCodecDescriptor,
61}
62
63impl CodecDescriptorIter {
64    pub fn new() -> Self {
65        Self {
66            ptr: std::ptr::null(),
67        }
68    }
69}
70
71impl Default for CodecDescriptorIter {
72    fn default() -> Self {
73        Self::new()
74    }
75}
76
77impl Iterator for CodecDescriptorIter {
78    type Item = CodecDescriptor;
79
80    fn next(&mut self) -> Option<Self::Item> {
81        unsafe {
82            let next = avcodec_descriptor_next(self.ptr);
83            if let Some(desc) = CodecDescriptor::from_raw(next) {
84                self.ptr = next;
85                Some(desc)
86            } else {
87                None
88            }
89        }
90    }
91}
92
93pub struct MimeTypeIter {
94    ptr: NonNull<*const libc::c_char>,
95}
96
97impl MimeTypeIter {
98    pub unsafe fn from_raw(ptr: *const *const libc::c_char) -> Option<Self> {
99        NonNull::new(ptr as *mut _).map(|ptr| Self { ptr })
100    }
101}
102
103impl Iterator for MimeTypeIter {
104    type Item = &'static str;
105
106    fn next(&mut self) -> Option<Self::Item> {
107        unsafe {
108            let next = *self.ptr.as_ptr();
109            if next.is_null() {
110                return None;
111            }
112
113            self.ptr = self.ptr.add(1);
114            Some(utils::str_from_c_ptr(next))
115        }
116    }
117}
118
119#[cfg(test)]
120mod test {
121    use super::*;
122    use crate::decoder::find;
123
124    #[test]
125    fn descriptor() {
126        let targa = find(Id::TARGA).expect("can find targa decoder");
127        let desc = targa.descriptor().expect("targa has descriptor");
128        assert_eq!(desc.id(), Id::TARGA);
129        assert_eq!(desc.kind(), media::Type::Video);
130        assert_eq!(desc.name(), "targa");
131
132        // --enable-small will remove all `long_name`s. So this can either be null/None
133        // or the correct description
134        assert!(matches!(
135            desc.description(),
136            None | Some("Truevision Targa image")
137        ));
138
139        let props = desc.props();
140        assert!(
141            props.contains(CodecProperties::INTRA_ONLY)
142                && props.contains(CodecProperties::LOSSLESS)
143        );
144
145        let mut mime_types = desc.mime_types().expect("has mime types");
146        assert_eq!(mime_types.next(), Some("image/x-targa"));
147        assert_eq!(mime_types.next(), Some("image/x-tga"));
148        assert_eq!(mime_types.next(), None);
149    }
150}