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