1use std::{mem, ptr};
4
5pub use crate::auto::functions::*;
6use crate::ffi;
7use glib::translate::*;
8
9pub unsafe trait CodecTag<'a>: gst::Tag<'a, TagType = &'a str> {}
10
11unsafe impl CodecTag<'_> for gst::tags::ContainerFormat {}
12unsafe impl CodecTag<'_> for gst::tags::AudioCodec {}
13unsafe impl CodecTag<'_> for gst::tags::VideoCodec {}
14unsafe impl CodecTag<'_> for gst::tags::SubtitleCodec {}
15unsafe impl CodecTag<'_> for gst::tags::Codec {}
16
17pub fn pb_utils_add_codec_description_to_tag_list_for_tag<'a, T: CodecTag<'a>>(
18 taglist: &mut gst::TagListRef,
19 caps: &gst::CapsRef,
20) -> Result<(), glib::BoolError> {
21 assert_initialized_main_thread!();
22 let codec_tag = T::TAG_NAME;
23 unsafe {
24 glib::result_from_gboolean!(
25 ffi::gst_pb_utils_add_codec_description_to_tag_list(
26 taglist.as_mut_ptr(),
27 codec_tag.as_ptr(),
28 caps.as_ptr(),
29 ),
30 "Failed to find codec description",
31 )
32 }
33}
34
35#[doc(alias = "gst_pb_utils_add_codec_description_to_tag_list")]
36pub fn pb_utils_add_codec_description_to_tag_list(
37 taglist: &mut gst::TagListRef,
38 caps: &gst::CapsRef,
39) -> Result<(), glib::BoolError> {
40 assert_initialized_main_thread!();
41 unsafe {
42 glib::result_from_gboolean!(
43 ffi::gst_pb_utils_add_codec_description_to_tag_list(
44 taglist.as_mut_ptr(),
45 ptr::null_mut(),
46 caps.as_ptr(),
47 ),
48 "Failed to find codec description",
49 )
50 }
51}
52
53#[doc(alias = "gst_pb_utils_get_encoder_description")]
54pub fn pb_utils_get_encoder_description(caps: &gst::CapsRef) -> glib::GString {
55 assert_initialized_main_thread!();
56 unsafe { from_glib_full(ffi::gst_pb_utils_get_encoder_description(caps.as_ptr())) }
57}
58
59#[doc(alias = "gst_pb_utils_get_decoder_description")]
60pub fn pb_utils_get_decoder_description(caps: &gst::CapsRef) -> glib::GString {
61 assert_initialized_main_thread!();
62 unsafe { from_glib_full(ffi::gst_pb_utils_get_decoder_description(caps.as_ptr())) }
63}
64
65#[doc(alias = "gst_pb_utils_get_codec_description")]
66pub fn pb_utils_get_codec_description(caps: &gst::CapsRef) -> glib::GString {
67 assert_initialized_main_thread!();
68 unsafe { from_glib_full(ffi::gst_pb_utils_get_codec_description(caps.as_ptr())) }
69}
70
71#[doc(alias = "gst_codec_utils_aac_caps_set_level_and_profile")]
72pub fn codec_utils_aac_caps_set_level_and_profile(
73 caps: &mut gst::CapsRef,
74 audio_config: &[u8],
75) -> Result<(), glib::BoolError> {
76 assert_initialized_main_thread!();
77
78 assert_eq!(caps.size(), 1);
79
80 let s = caps.structure(0).unwrap();
81 assert_eq!(s.name(), "audio/mpeg");
82 assert!(s.get::<i32>("mpegversion").is_ok_and(|v| v == 2 || v == 4));
83
84 let len = audio_config.len() as u32;
85 unsafe {
86 let res: bool = from_glib(ffi::gst_codec_utils_aac_caps_set_level_and_profile(
87 caps.as_mut_ptr(),
88 audio_config.to_glib_none().0,
89 len,
90 ));
91
92 if res {
93 Ok(())
94 } else {
95 Err(glib::bool_error!("Failed to set AAC level/profile to caps"))
96 }
97 }
98}
99
100#[doc(alias = "gst_codec_utils_h264_caps_set_level_and_profile")]
101pub fn codec_utils_h264_caps_set_level_and_profile(
102 caps: &mut gst::CapsRef,
103 sps: &[u8],
104) -> Result<(), glib::BoolError> {
105 assert_initialized_main_thread!();
106
107 assert_eq!(caps.size(), 1);
108
109 let s = caps.structure(0).unwrap();
110 assert_eq!(s.name(), "video/x-h264");
111
112 let len = sps.len() as u32;
113 unsafe {
114 let res: bool = from_glib(ffi::gst_codec_utils_h264_caps_set_level_and_profile(
115 caps.as_mut_ptr(),
116 sps.to_glib_none().0,
117 len,
118 ));
119
120 if res {
121 Ok(())
122 } else {
123 Err(glib::bool_error!(
124 "Failed to set H264 level/profile to caps"
125 ))
126 }
127 }
128}
129
130#[cfg(feature = "v1_20")]
131#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
132#[doc(alias = "gst_codec_utils_h264_get_profile_flags_level")]
133pub fn codec_utils_h264_get_profile_flags_level(
134 codec_data: &[u8],
135) -> Result<(u8, u8, u8), glib::BoolError> {
136 assert_initialized_main_thread!();
137 let len = codec_data.len() as u32;
138 unsafe {
139 let mut profile = mem::MaybeUninit::uninit();
140 let mut flags = mem::MaybeUninit::uninit();
141 let mut level = mem::MaybeUninit::uninit();
142 glib::result_from_gboolean!(
143 ffi::gst_codec_utils_h264_get_profile_flags_level(
144 codec_data.to_glib_none().0,
145 len,
146 profile.as_mut_ptr(),
147 flags.as_mut_ptr(),
148 level.as_mut_ptr()
149 ),
150 "Failed to get H264 profile, flags and level"
151 )?;
152 let profile = profile.assume_init();
153 let flags = flags.assume_init();
154 let level = level.assume_init();
155 Ok((profile, flags, level))
156 }
157}
158
159#[doc(alias = "gst_codec_utils_h265_caps_set_level_tier_and_profile")]
160pub fn codec_utils_h265_caps_set_level_tier_and_profile(
161 caps: &mut gst::CapsRef,
162 profile_tier_level: &[u8],
163) -> Result<(), glib::BoolError> {
164 assert_initialized_main_thread!();
165
166 assert_eq!(caps.size(), 1);
167
168 let s = caps.structure(0).unwrap();
169 assert_eq!(s.name(), "video/x-h265");
170
171 let len = profile_tier_level.len() as u32;
172 unsafe {
173 let res: bool = from_glib(ffi::gst_codec_utils_h265_caps_set_level_tier_and_profile(
174 caps.as_mut_ptr(),
175 profile_tier_level.to_glib_none().0,
176 len,
177 ));
178
179 if res {
180 Ok(())
181 } else {
182 Err(glib::bool_error!(
183 "Failed to set H265 level/tier/profile to caps"
184 ))
185 }
186 }
187}
188
189#[doc(alias = "gst_codec_utils_mpeg4video_caps_set_level_and_profile")]
190pub fn codec_utils_mpeg4video_caps_set_level_and_profile(
191 caps: &mut gst::CapsRef,
192 vis_obj_seq: &[u8],
193) -> Result<(), glib::BoolError> {
194 assert_initialized_main_thread!();
195
196 assert_eq!(caps.size(), 1);
197
198 let s = caps.structure(0).unwrap();
199 assert_eq!(s.name(), "video/mpeg");
200 assert!(s.get::<i32>("mpegversion").is_ok_and(|v| v == 4));
201
202 let len = vis_obj_seq.len() as u32;
203 unsafe {
204 let res: bool = from_glib(ffi::gst_codec_utils_mpeg4video_caps_set_level_and_profile(
205 caps.as_mut_ptr(),
206 vis_obj_seq.to_glib_none().0,
207 len,
208 ));
209
210 if res {
211 Ok(())
212 } else {
213 Err(glib::bool_error!(
214 "Failed to set MPEG4 video level/profile to caps"
215 ))
216 }
217 }
218}
219
220#[doc(alias = "gst_codec_utils_opus_create_caps")]
221pub fn codec_utils_opus_create_caps(
222 rate: u32,
223 channels: u8,
224 channel_mapping_family: u8,
225 stream_count: u8,
226 coupled_count: u8,
227 channel_mapping: &[u8],
228) -> Result<gst::Caps, glib::BoolError> {
229 assert_initialized_main_thread!();
230
231 assert!(channel_mapping.is_empty() || channel_mapping.len() == channels as usize);
232
233 unsafe {
234 let caps = ffi::gst_codec_utils_opus_create_caps(
235 rate,
236 channels,
237 channel_mapping_family,
238 stream_count,
239 coupled_count,
240 if channel_mapping.is_empty() {
241 ptr::null()
242 } else {
243 channel_mapping.to_glib_none().0
244 },
245 );
246
247 if caps.is_null() {
248 Err(glib::bool_error!(
249 "Failed to create caps from Opus configuration"
250 ))
251 } else {
252 Ok(from_glib_full(caps))
253 }
254 }
255}
256
257#[doc(alias = "gst_codec_utils_opus_create_caps_from_header")]
258pub fn codec_utils_opus_create_caps_from_header(
259 header: &gst::BufferRef,
260 comments: Option<&gst::BufferRef>,
261) -> Result<gst::Caps, glib::BoolError> {
262 assert_initialized_main_thread!();
263 unsafe {
264 Option::<_>::from_glib_full(ffi::gst_codec_utils_opus_create_caps_from_header(
265 mut_override(header.as_ptr()),
266 comments
267 .map(|b| mut_override(b.as_ptr()))
268 .unwrap_or(ptr::null_mut()),
269 ))
270 .ok_or_else(|| glib::bool_error!("Failed to create caps from Opus headers"))
271 }
272}
273
274#[doc(alias = "gst_codec_utils_opus_create_header")]
275#[allow(clippy::too_many_arguments)]
276pub fn codec_utils_opus_create_header(
277 rate: u32,
278 channels: u8,
279 channel_mapping_family: u8,
280 stream_count: u8,
281 coupled_count: u8,
282 channel_mapping: &[u8],
283 pre_skip: u16,
284 output_gain: i16,
285) -> Result<gst::Buffer, glib::BoolError> {
286 assert_initialized_main_thread!();
287
288 assert!(channel_mapping.is_empty() || channel_mapping.len() == channels as usize);
289
290 unsafe {
291 let header = ffi::gst_codec_utils_opus_create_header(
292 rate,
293 channels,
294 channel_mapping_family,
295 stream_count,
296 coupled_count,
297 if channel_mapping.is_empty() {
298 ptr::null()
299 } else {
300 channel_mapping.to_glib_none().0
301 },
302 pre_skip,
303 output_gain,
304 );
305
306 if header.is_null() {
307 Err(glib::bool_error!(
308 "Failed to create header from Opus configuration"
309 ))
310 } else {
311 Ok(from_glib_full(header))
312 }
313 }
314}
315
316#[doc(alias = "gst_codec_utils_opus_parse_caps")]
317pub fn codec_utils_opus_parse_caps(
318 caps: &gst::CapsRef,
319 channel_mapping: Option<&mut [u8; 256]>,
320) -> Result<(u32, u8, u8, u8, u8), glib::BoolError> {
321 assert_initialized_main_thread!();
322
323 unsafe {
324 let mut rate = mem::MaybeUninit::uninit();
325 let mut channels = mem::MaybeUninit::uninit();
326 let mut channel_mapping_family = mem::MaybeUninit::uninit();
327 let mut stream_count = mem::MaybeUninit::uninit();
328 let mut coupled_count = mem::MaybeUninit::uninit();
329
330 let res: bool = from_glib(ffi::gst_codec_utils_opus_parse_caps(
331 mut_override(caps.as_ptr()),
332 rate.as_mut_ptr(),
333 channels.as_mut_ptr(),
334 channel_mapping_family.as_mut_ptr(),
335 stream_count.as_mut_ptr(),
336 coupled_count.as_mut_ptr(),
337 if let Some(channel_mapping) = channel_mapping {
338 channel_mapping.as_mut_ptr() as *mut [u8; 256]
339 } else {
340 ptr::null_mut()
341 },
342 ));
343
344 if res {
345 Ok((
346 rate.assume_init(),
347 channels.assume_init(),
348 channel_mapping_family.assume_init(),
349 stream_count.assume_init(),
350 coupled_count.assume_init(),
351 ))
352 } else {
353 Err(glib::bool_error!("Failed to parse Opus caps"))
354 }
355 }
356}
357
358#[doc(alias = "gst_codec_utils_opus_parse_header")]
359#[allow(clippy::type_complexity)]
360pub fn codec_utils_opus_parse_header(
361 header: &gst::BufferRef,
362 channel_mapping: Option<&mut [u8; 256]>,
363) -> Result<(u32, u8, u8, u8, u8, u16, i16), glib::BoolError> {
364 assert_initialized_main_thread!();
365
366 unsafe {
367 let mut rate = mem::MaybeUninit::uninit();
368 let mut channels = mem::MaybeUninit::uninit();
369 let mut channel_mapping_family = mem::MaybeUninit::uninit();
370 let mut stream_count = mem::MaybeUninit::uninit();
371 let mut coupled_count = mem::MaybeUninit::uninit();
372 let mut pre_skip = mem::MaybeUninit::uninit();
373 let mut output_gain = mem::MaybeUninit::uninit();
374
375 let res: bool = from_glib(ffi::gst_codec_utils_opus_parse_header(
376 mut_override(header.as_ptr()),
377 rate.as_mut_ptr(),
378 channels.as_mut_ptr(),
379 channel_mapping_family.as_mut_ptr(),
380 stream_count.as_mut_ptr(),
381 coupled_count.as_mut_ptr(),
382 if let Some(channel_mapping) = channel_mapping {
383 channel_mapping.as_mut_ptr() as *mut [u8; 256]
384 } else {
385 ptr::null_mut()
386 },
387 pre_skip.as_mut_ptr(),
388 output_gain.as_mut_ptr(),
389 ));
390
391 if res {
392 Ok((
393 rate.assume_init(),
394 channels.assume_init(),
395 channel_mapping_family.assume_init(),
396 stream_count.assume_init(),
397 coupled_count.assume_init(),
398 pre_skip.assume_init(),
399 output_gain.assume_init(),
400 ))
401 } else {
402 Err(glib::bool_error!("Failed to parse Opus header"))
403 }
404 }
405}
406
407#[cfg(feature = "v1_20")]
408#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
409#[doc(alias = "gst_codec_utils_caps_get_mime_codec")]
410pub fn codec_utils_caps_get_mime_codec(
411 caps: &gst::CapsRef,
412) -> Result<glib::GString, glib::BoolError> {
413 assert_initialized_main_thread!();
414 unsafe {
415 Option::<_>::from_glib_full(ffi::gst_codec_utils_caps_get_mime_codec(mut_override(
416 caps.as_ptr(),
417 )))
418 .ok_or_else(|| glib::bool_error!("Unsupported caps"))
419 }
420}
421
422#[cfg(feature = "v1_20")]
423#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
424#[doc(alias = "gst_pb_utils_get_caps_description_flags")]
425pub fn pb_utils_get_caps_description_flags(
426 caps: &gst::CapsRef,
427) -> crate::PbUtilsCapsDescriptionFlags {
428 assert_initialized_main_thread!();
429 unsafe { from_glib(ffi::gst_pb_utils_get_caps_description_flags(caps.as_ptr())) }
430}
431
432#[cfg(feature = "v1_20")]
433#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
434#[doc(alias = "gst_pb_utils_get_file_extension_from_caps")]
435pub fn pb_utils_get_file_extension_from_caps(caps: &gst::CapsRef) -> Option<glib::GString> {
436 assert_initialized_main_thread!();
437 unsafe {
438 from_glib_full(ffi::gst_pb_utils_get_file_extension_from_caps(
439 caps.as_ptr(),
440 ))
441 }
442}
443
444#[cfg(feature = "v1_26")]
445#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
446#[doc(alias = "gst_codec_utils_av1_create_caps_from_av1c")]
447pub fn codec_utils_av1_create_caps_from_av1c(
448 av1c: &gst::BufferRef,
449) -> Result<gst::Caps, glib::BoolError> {
450 assert_initialized_main_thread!();
451 unsafe {
452 Option::<_>::from_glib_full(ffi::gst_codec_utils_av1_create_caps_from_av1c(
453 mut_override(av1c.as_ptr()),
454 ))
455 .ok_or_else(|| glib::bool_error!("Failed to create caps from AV1C header"))
456 }
457}
458
459#[cfg(feature = "v1_26")]
460#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
461#[doc(alias = "gst_codec_utils_av1_create_av1c_from_caps")]
462pub fn codec_utils_av1_create_av1c_from_caps(
463 caps: &gst::CapsRef,
464) -> Result<gst::Buffer, glib::BoolError> {
465 assert_initialized_main_thread!();
466 unsafe {
467 Option::<_>::from_glib_full(ffi::gst_codec_utils_av1_create_av1c_from_caps(
468 mut_override(caps.as_ptr()),
469 ))
470 .ok_or_else(|| glib::bool_error!("Failed to create AV1C header from caps"))
471 }
472}
473
474#[cfg(feature = "v1_26")]
475#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
476#[doc(alias = "gst_codec_utils_h266_caps_set_level_tier_and_profile")]
477pub fn codec_utils_h266_caps_set_level_tier_and_profile(
478 caps: &mut gst::CapsRef,
479 decoder_configuration: &[u8],
480) -> Result<(), glib::BoolError> {
481 assert_initialized_main_thread!();
482 let len = decoder_configuration.len() as _;
483 unsafe {
484 let res: bool = from_glib(ffi::gst_codec_utils_h266_caps_set_level_tier_and_profile(
485 mut_override(caps.as_ptr()),
486 decoder_configuration.to_glib_none().0,
487 len,
488 ));
489
490 if res {
491 Ok(())
492 } else {
493 Err(glib::bool_error!(
494 "Failed to set H266 level/tier/profile to caps"
495 ))
496 }
497 }
498}