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")]
87pub fn codec_utils_aac_caps_set_level_and_profile(
88    caps: &mut gst::CapsRef,
89    audio_config: &[u8],
90) -> Result<(), glib::BoolError> {
91    assert_initialized_main_thread!();
92
93    assert_eq!(caps.size(), 1);
94
95    let s = caps.structure(0).unwrap();
96    assert_eq!(s.name(), "audio/mpeg");
97    assert!(s.get::<i32>("mpegversion").is_ok_and(|v| v == 2 || v == 4));
98
99    let len = audio_config.len() as u32;
100    unsafe {
101        let res: bool = from_glib(ffi::gst_codec_utils_aac_caps_set_level_and_profile(
102            caps.as_mut_ptr(),
103            audio_config.to_glib_none().0,
104            len,
105        ));
106
107        if res {
108            Ok(())
109        } else {
110            Err(glib::bool_error!("Failed to set AAC level/profile to caps"))
111        }
112    }
113}
114
115#[doc(alias = "gst_codec_utils_h264_caps_set_level_and_profile")]
127pub fn codec_utils_h264_caps_set_level_and_profile(
128    caps: &mut gst::CapsRef,
129    sps: &[u8],
130) -> Result<(), glib::BoolError> {
131    assert_initialized_main_thread!();
132
133    assert_eq!(caps.size(), 1);
134
135    let s = caps.structure(0).unwrap();
136    assert_eq!(s.name(), "video/x-h264");
137
138    let len = sps.len() as u32;
139    unsafe {
140        let res: bool = from_glib(ffi::gst_codec_utils_h264_caps_set_level_and_profile(
141            caps.as_mut_ptr(),
142            sps.to_glib_none().0,
143            len,
144        ));
145
146        if res {
147            Ok(())
148        } else {
149            Err(glib::bool_error!(
150                "Failed to set H264 level/profile to caps"
151            ))
152        }
153    }
154}
155
156#[cfg(feature = "v1_20")]
179#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
180#[doc(alias = "gst_codec_utils_h264_get_profile_flags_level")]
181pub fn codec_utils_h264_get_profile_flags_level(
182    codec_data: &[u8],
183) -> Result<(u8, u8, u8), glib::BoolError> {
184    assert_initialized_main_thread!();
185    let len = codec_data.len() as u32;
186    unsafe {
187        let mut profile = mem::MaybeUninit::uninit();
188        let mut flags = mem::MaybeUninit::uninit();
189        let mut level = mem::MaybeUninit::uninit();
190        glib::result_from_gboolean!(
191            ffi::gst_codec_utils_h264_get_profile_flags_level(
192                codec_data.to_glib_none().0,
193                len,
194                profile.as_mut_ptr(),
195                flags.as_mut_ptr(),
196                level.as_mut_ptr()
197            ),
198            "Failed to get H264 profile, flags and level"
199        )?;
200        let profile = profile.assume_init();
201        let flags = flags.assume_init();
202        let level = level.assume_init();
203        Ok((profile, flags, level))
204    }
205}
206
207#[doc(alias = "gst_codec_utils_h265_caps_set_level_tier_and_profile")]
221pub fn codec_utils_h265_caps_set_level_tier_and_profile(
222    caps: &mut gst::CapsRef,
223    profile_tier_level: &[u8],
224) -> Result<(), glib::BoolError> {
225    assert_initialized_main_thread!();
226
227    assert_eq!(caps.size(), 1);
228
229    let s = caps.structure(0).unwrap();
230    assert_eq!(s.name(), "video/x-h265");
231
232    let len = profile_tier_level.len() as u32;
233    unsafe {
234        let res: bool = from_glib(ffi::gst_codec_utils_h265_caps_set_level_tier_and_profile(
235            caps.as_mut_ptr(),
236            profile_tier_level.to_glib_none().0,
237            len,
238        ));
239
240        if res {
241            Ok(())
242        } else {
243            Err(glib::bool_error!(
244                "Failed to set H265 level/tier/profile to caps"
245            ))
246        }
247    }
248}
249
250#[doc(alias = "gst_codec_utils_mpeg4video_caps_set_level_and_profile")]
264pub fn codec_utils_mpeg4video_caps_set_level_and_profile(
265    caps: &mut gst::CapsRef,
266    vis_obj_seq: &[u8],
267) -> Result<(), glib::BoolError> {
268    assert_initialized_main_thread!();
269
270    assert_eq!(caps.size(), 1);
271
272    let s = caps.structure(0).unwrap();
273    assert_eq!(s.name(), "video/mpeg");
274    assert!(s.get::<i32>("mpegversion").is_ok_and(|v| v == 4));
275
276    let len = vis_obj_seq.len() as u32;
277    unsafe {
278        let res: bool = from_glib(ffi::gst_codec_utils_mpeg4video_caps_set_level_and_profile(
279            caps.as_mut_ptr(),
280            vis_obj_seq.to_glib_none().0,
281            len,
282        ));
283
284        if res {
285            Ok(())
286        } else {
287            Err(glib::bool_error!(
288                "Failed to set MPEG4 video level/profile to caps"
289            ))
290        }
291    }
292}
293
294#[doc(alias = "gst_codec_utils_opus_create_caps")]
313pub fn codec_utils_opus_create_caps(
314    rate: u32,
315    channels: u8,
316    channel_mapping_family: u8,
317    stream_count: u8,
318    coupled_count: u8,
319    channel_mapping: &[u8],
320) -> Result<gst::Caps, glib::BoolError> {
321    assert_initialized_main_thread!();
322
323    assert!(channel_mapping.is_empty() || channel_mapping.len() == channels as usize);
324
325    unsafe {
326        let caps = ffi::gst_codec_utils_opus_create_caps(
327            rate,
328            channels,
329            channel_mapping_family,
330            stream_count,
331            coupled_count,
332            if channel_mapping.is_empty() {
333                ptr::null()
334            } else {
335                channel_mapping.to_glib_none().0
336            },
337        );
338
339        if caps.is_null() {
340            Err(glib::bool_error!(
341                "Failed to create caps from Opus configuration"
342            ))
343        } else {
344            Ok(from_glib_full(caps))
345        }
346    }
347}
348
349#[doc(alias = "gst_codec_utils_opus_create_caps_from_header")]
360pub fn codec_utils_opus_create_caps_from_header(
361    header: &gst::BufferRef,
362    comments: Option<&gst::BufferRef>,
363) -> Result<gst::Caps, glib::BoolError> {
364    assert_initialized_main_thread!();
365    unsafe {
366        Option::<_>::from_glib_full(ffi::gst_codec_utils_opus_create_caps_from_header(
367            mut_override(header.as_ptr()),
368            comments
369                .map(|b| mut_override(b.as_ptr()))
370                .unwrap_or(ptr::null_mut()),
371        ))
372        .ok_or_else(|| glib::bool_error!("Failed to create caps from Opus headers"))
373    }
374}
375
376#[doc(alias = "gst_codec_utils_opus_create_header")]
398#[allow(clippy::too_many_arguments)]
399pub fn codec_utils_opus_create_header(
400    rate: u32,
401    channels: u8,
402    channel_mapping_family: u8,
403    stream_count: u8,
404    coupled_count: u8,
405    channel_mapping: &[u8],
406    pre_skip: u16,
407    output_gain: i16,
408) -> Result<gst::Buffer, glib::BoolError> {
409    assert_initialized_main_thread!();
410
411    assert!(channel_mapping.is_empty() || channel_mapping.len() == channels as usize);
412
413    unsafe {
414        let header = ffi::gst_codec_utils_opus_create_header(
415            rate,
416            channels,
417            channel_mapping_family,
418            stream_count,
419            coupled_count,
420            if channel_mapping.is_empty() {
421                ptr::null()
422            } else {
423                channel_mapping.to_glib_none().0
424            },
425            pre_skip,
426            output_gain,
427        );
428
429        if header.is_null() {
430            Err(glib::bool_error!(
431                "Failed to create header from Opus configuration"
432            ))
433        } else {
434            Ok(from_glib_full(header))
435        }
436    }
437}
438
439#[doc(alias = "gst_codec_utils_opus_parse_caps")]
465pub fn codec_utils_opus_parse_caps(
466    caps: &gst::CapsRef,
467    channel_mapping: Option<&mut [u8; 256]>,
468) -> Result<(u32, u8, u8, u8, u8), glib::BoolError> {
469    assert_initialized_main_thread!();
470
471    unsafe {
472        let mut rate = mem::MaybeUninit::uninit();
473        let mut channels = mem::MaybeUninit::uninit();
474        let mut channel_mapping_family = mem::MaybeUninit::uninit();
475        let mut stream_count = mem::MaybeUninit::uninit();
476        let mut coupled_count = mem::MaybeUninit::uninit();
477
478        let res: bool = from_glib(ffi::gst_codec_utils_opus_parse_caps(
479            mut_override(caps.as_ptr()),
480            rate.as_mut_ptr(),
481            channels.as_mut_ptr(),
482            channel_mapping_family.as_mut_ptr(),
483            stream_count.as_mut_ptr(),
484            coupled_count.as_mut_ptr(),
485            if let Some(channel_mapping) = channel_mapping {
486                channel_mapping.as_mut_ptr() as *mut [u8; 256]
487            } else {
488                ptr::null_mut()
489            },
490        ));
491
492        if res {
493            Ok((
494                rate.assume_init(),
495                channels.assume_init(),
496                channel_mapping_family.assume_init(),
497                stream_count.assume_init(),
498                coupled_count.assume_init(),
499            ))
500        } else {
501            Err(glib::bool_error!("Failed to parse Opus caps"))
502        }
503    }
504}
505
506#[doc(alias = "gst_codec_utils_opus_parse_header")]
538#[allow(clippy::type_complexity)]
539pub fn codec_utils_opus_parse_header(
540    header: &gst::BufferRef,
541    channel_mapping: Option<&mut [u8; 256]>,
542) -> Result<(u32, u8, u8, u8, u8, u16, i16), glib::BoolError> {
543    assert_initialized_main_thread!();
544
545    unsafe {
546        let mut rate = mem::MaybeUninit::uninit();
547        let mut channels = mem::MaybeUninit::uninit();
548        let mut channel_mapping_family = mem::MaybeUninit::uninit();
549        let mut stream_count = mem::MaybeUninit::uninit();
550        let mut coupled_count = mem::MaybeUninit::uninit();
551        let mut pre_skip = mem::MaybeUninit::uninit();
552        let mut output_gain = mem::MaybeUninit::uninit();
553
554        let res: bool = from_glib(ffi::gst_codec_utils_opus_parse_header(
555            mut_override(header.as_ptr()),
556            rate.as_mut_ptr(),
557            channels.as_mut_ptr(),
558            channel_mapping_family.as_mut_ptr(),
559            stream_count.as_mut_ptr(),
560            coupled_count.as_mut_ptr(),
561            if let Some(channel_mapping) = channel_mapping {
562                channel_mapping.as_mut_ptr() as *mut [u8; 256]
563            } else {
564                ptr::null_mut()
565            },
566            pre_skip.as_mut_ptr(),
567            output_gain.as_mut_ptr(),
568        ));
569
570        if res {
571            Ok((
572                rate.assume_init(),
573                channels.assume_init(),
574                channel_mapping_family.assume_init(),
575                stream_count.assume_init(),
576                coupled_count.assume_init(),
577                pre_skip.assume_init(),
578                output_gain.assume_init(),
579            ))
580        } else {
581            Err(glib::bool_error!("Failed to parse Opus header"))
582        }
583    }
584}
585
586#[cfg(feature = "v1_20")]
599#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
600#[doc(alias = "gst_codec_utils_caps_get_mime_codec")]
601pub fn codec_utils_caps_get_mime_codec(
602    caps: &gst::CapsRef,
603) -> Result<glib::GString, glib::BoolError> {
604    assert_initialized_main_thread!();
605    unsafe {
606        Option::<_>::from_glib_full(ffi::gst_codec_utils_caps_get_mime_codec(mut_override(
607            caps.as_ptr(),
608        )))
609        .ok_or_else(|| glib::bool_error!("Unsupported caps"))
610    }
611}
612
613#[cfg(feature = "v1_20")]
623#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
624#[doc(alias = "gst_pb_utils_get_caps_description_flags")]
625pub fn pb_utils_get_caps_description_flags(
626    caps: &gst::CapsRef,
627) -> crate::PbUtilsCapsDescriptionFlags {
628    assert_initialized_main_thread!();
629    unsafe { from_glib(ffi::gst_pb_utils_get_caps_description_flags(caps.as_ptr())) }
630}
631
632#[cfg(feature = "v1_20")]
641#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
642#[doc(alias = "gst_pb_utils_get_file_extension_from_caps")]
643pub fn pb_utils_get_file_extension_from_caps(caps: &gst::CapsRef) -> Option<glib::GString> {
644    assert_initialized_main_thread!();
645    unsafe {
646        from_glib_full(ffi::gst_pb_utils_get_file_extension_from_caps(
647            caps.as_ptr(),
648        ))
649    }
650}
651
652#[cfg(feature = "v1_26")]
661#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
662#[doc(alias = "gst_codec_utils_av1_create_caps_from_av1c")]
663pub fn codec_utils_av1_create_caps_from_av1c(
664    av1c: &gst::BufferRef,
665) -> Result<gst::Caps, glib::BoolError> {
666    assert_initialized_main_thread!();
667    unsafe {
668        Option::<_>::from_glib_full(ffi::gst_codec_utils_av1_create_caps_from_av1c(
669            mut_override(av1c.as_ptr()),
670        ))
671        .ok_or_else(|| glib::bool_error!("Failed to create caps from AV1C header"))
672    }
673}
674
675#[cfg(feature = "v1_26")]
684#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
685#[doc(alias = "gst_codec_utils_av1_create_av1c_from_caps")]
686pub fn codec_utils_av1_create_av1c_from_caps(
687    caps: &gst::CapsRef,
688) -> Result<gst::Buffer, glib::BoolError> {
689    assert_initialized_main_thread!();
690    unsafe {
691        Option::<_>::from_glib_full(ffi::gst_codec_utils_av1_create_av1c_from_caps(
692            mut_override(caps.as_ptr()),
693        ))
694        .ok_or_else(|| glib::bool_error!("Failed to create AV1C header from caps"))
695    }
696}
697
698#[cfg(feature = "v1_26")]
711#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
712#[doc(alias = "gst_codec_utils_h266_caps_set_level_tier_and_profile")]
713pub fn codec_utils_h266_caps_set_level_tier_and_profile(
714    caps: &mut gst::CapsRef,
715    decoder_configuration: &[u8],
716) -> Result<(), glib::BoolError> {
717    assert_initialized_main_thread!();
718    let len = decoder_configuration.len() as _;
719    unsafe {
720        let res: bool = from_glib(ffi::gst_codec_utils_h266_caps_set_level_tier_and_profile(
721            mut_override(caps.as_ptr()),
722            decoder_configuration.to_glib_none().0,
723            len,
724        ));
725
726        if res {
727            Ok(())
728        } else {
729            Err(glib::bool_error!(
730                "Failed to set H266 level/tier/profile to caps"
731            ))
732        }
733    }
734}