ffmpeg_the_third/codec/
descriptor.rs1use 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 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}