1use ffmpeg_sys_next::{
2 av_codec_is_decoder, av_codec_is_encoder, av_codec_iterate, avcodec_descriptor_next,
3 AVCodecDescriptor, AVCodecID, AVMediaType,
4};
5use std::ffi::{c_void, CStr};
6use std::ptr::{null, null_mut};
7
8#[derive(Clone)]
9pub(crate) struct Codec {
10 inner: *const ffmpeg_sys_next::AVCodec,
11}
12unsafe impl Send for Codec {}
15
16impl Codec {
17 #[inline]
18 pub(crate) fn null() -> Self {
19 Self { inner: null() }
20 }
21 #[inline]
22 pub(crate) fn is_null(&self) -> bool {
23 self.inner.is_null()
24 }
25
26 #[inline]
27 pub(crate) fn new(avcodec: *const ffmpeg_sys_next::AVCodec) -> Self {
28 Self { inner: avcodec }
29 }
30
31 #[inline]
32 pub(crate) fn as_ptr(&self) -> *const ffmpeg_sys_next::AVCodec {
33 self.inner
34 }
35}
36
37#[derive(Clone, Debug)]
51pub struct CodecInfo {
52 pub codec_name: String,
54 pub codec_long_name: String,
56 pub desc_name: String,
58
59 pub media_type: AVMediaType,
61 pub codec_id: AVCodecID,
63 pub codec_capabilities: i32,
65}
66
67pub fn get_encoders() -> Vec<CodecInfo> {
82 get_codec_infos(1)
83}
84
85pub fn get_decoders() -> Vec<CodecInfo> {
100 get_codec_infos(0)
101}
102
103fn get_codec_infos(encoder: i32) -> Vec<CodecInfo> {
104 let mut codec_infos = Vec::new();
105 let descs = get_codecs_sorted();
106 for desc in descs {
107 let mut iter = null_mut();
108 unsafe {
109 loop {
110 let codec = next_codec_for_id((*desc).id, &mut iter, encoder);
111 if codec.is_null() {
112 break;
113 }
114
115 let codec_name = (*codec.inner).name;
116 let codec_name = CStr::from_ptr(codec_name).to_str();
117 let codec_long_name = (*codec.inner).long_name;
118 let codec_long_name = CStr::from_ptr(codec_long_name).to_str();
119 let desc_name = (*desc).name;
120 let desc_name = CStr::from_ptr(desc_name).to_str();
121
122 if let (Ok(codec_name), Ok(codec_long_name), Ok(desc_name)) =
123 (codec_name, codec_long_name, desc_name)
124 {
125 let codec_info = CodecInfo {
126 codec_name: codec_name.to_string(),
127 codec_long_name: codec_long_name.to_string(),
128 desc_name: desc_name.to_string(),
129 media_type: (*codec.inner).type_,
130 codec_id: (*codec.inner).id,
131 codec_capabilities: (*codec.inner).capabilities,
132 };
133 codec_infos.push(codec_info);
134 }
135 }
136 }
137 }
138 codec_infos
139}
140
141fn get_codecs_sorted() -> Vec<*const AVCodecDescriptor> {
142 let mut desc = null();
143 let mut codecs = Vec::new();
144
145 unsafe {
146 loop {
147 desc = avcodec_descriptor_next(desc);
148 if desc.is_null() {
149 break;
150 }
151 codecs.push(desc)
152 }
153 }
154 if !codecs.is_empty() {
155 codecs.sort_by(|&a, &b| compare_codec_desc(a, b));
156 }
157
158 codecs
159}
160
161fn compare_codec_desc(
162 a: *const AVCodecDescriptor,
163 b: *const AVCodecDescriptor,
164) -> std::cmp::Ordering {
165 unsafe {
166 match ((*a).type_ as i32).cmp(&((*b).type_ as i32)) {
167 std::cmp::Ordering::Equal => (*a).name.cmp(&(*b).name),
168 other => other,
169 }
170 }
171}
172
173fn next_codec_for_id(id: AVCodecID, iter: *mut *mut c_void, encoder: i32) -> Codec {
174 loop {
175 unsafe {
176 let c = av_codec_iterate(iter);
177 if c.is_null() {
178 break;
179 }
180
181 if (*c).id == id {
182 let result = if encoder != 0 {
183 av_codec_is_encoder(c)
184 } else {
185 av_codec_is_decoder(c)
186 };
187 if result != 0 {
188 return Codec::new(c);
189 }
190 }
191 }
192 }
193
194 Codec::null()
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200
201 #[test]
202 fn test_print_codes() {
203 let encoders = get_encoders();
204 for encoder in encoders {
205 println!("{:?}", encoder);
206 }
207
208 println!("----------------------");
209
210 let decoders = get_decoders();
211 for decoder in decoders {
212 println!("{:?}", decoder);
213 }
214 }
215}