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