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 T::ensure();
23 let codec_tag = T::TAG_NAME;
24 unsafe {
25 glib::result_from_gboolean!(
26 ffi::gst_pb_utils_add_codec_description_to_tag_list(
27 taglist.as_mut_ptr(),
28 codec_tag.as_ptr(),
29 caps.as_ptr(),
30 ),
31 "Failed to find codec description",
32 )
33 }
34}
35
36#[doc(alias = "gst_pb_utils_add_codec_description_to_tag_list")]
37pub fn pb_utils_add_codec_description_to_tag_list(
38 taglist: &mut gst::TagListRef,
39 caps: &gst::CapsRef,
40) -> Result<(), glib::BoolError> {
41 assert_initialized_main_thread!();
42 unsafe {
43 glib::result_from_gboolean!(
44 ffi::gst_pb_utils_add_codec_description_to_tag_list(
45 taglist.as_mut_ptr(),
46 ptr::null_mut(),
47 caps.as_ptr(),
48 ),
49 "Failed to find codec description",
50 )
51 }
52}
53
54#[doc(alias = "gst_pb_utils_get_encoder_description")]
55pub fn pb_utils_get_encoder_description(caps: &gst::CapsRef) -> glib::GString {
56 assert_initialized_main_thread!();
57 unsafe { from_glib_full(ffi::gst_pb_utils_get_encoder_description(caps.as_ptr())) }
58}
59
60#[doc(alias = "gst_pb_utils_get_decoder_description")]
61pub fn pb_utils_get_decoder_description(caps: &gst::CapsRef) -> glib::GString {
62 assert_initialized_main_thread!();
63 unsafe { from_glib_full(ffi::gst_pb_utils_get_decoder_description(caps.as_ptr())) }
64}
65
66#[doc(alias = "gst_pb_utils_get_codec_description")]
67pub fn pb_utils_get_codec_description(caps: &gst::CapsRef) -> glib::GString {
68 assert_initialized_main_thread!();
69 unsafe { from_glib_full(ffi::gst_pb_utils_get_codec_description(caps.as_ptr())) }
70}
71
72#[doc(alias = "gst_codec_utils_aac_caps_set_level_and_profile")]
88pub fn codec_utils_aac_caps_set_level_and_profile(
89 caps: &mut gst::CapsRef,
90 audio_config: &[u8],
91) -> Result<(), glib::BoolError> {
92 assert_initialized_main_thread!();
93
94 assert_eq!(caps.size(), 1);
95
96 let s = caps.structure(0).unwrap();
97 assert_eq!(s.name(), "audio/mpeg");
98 assert!(s.get::<i32>("mpegversion").is_ok_and(|v| v == 2 || v == 4));
99
100 let len = audio_config.len() as u32;
101 unsafe {
102 let res: bool = from_glib(ffi::gst_codec_utils_aac_caps_set_level_and_profile(
103 caps.as_mut_ptr(),
104 audio_config.to_glib_none().0,
105 len,
106 ));
107
108 if res {
109 Ok(())
110 } else {
111 Err(glib::bool_error!("Failed to set AAC level/profile to caps"))
112 }
113 }
114}
115
116#[doc(alias = "gst_codec_utils_h264_caps_set_level_and_profile")]
128pub fn codec_utils_h264_caps_set_level_and_profile(
129 caps: &mut gst::CapsRef,
130 sps: &[u8],
131) -> Result<(), glib::BoolError> {
132 assert_initialized_main_thread!();
133
134 assert_eq!(caps.size(), 1);
135
136 let s = caps.structure(0).unwrap();
137 assert_eq!(s.name(), "video/x-h264");
138
139 let len = sps.len() as u32;
140 unsafe {
141 let res: bool = from_glib(ffi::gst_codec_utils_h264_caps_set_level_and_profile(
142 caps.as_mut_ptr(),
143 sps.to_glib_none().0,
144 len,
145 ));
146
147 if res {
148 Ok(())
149 } else {
150 Err(glib::bool_error!(
151 "Failed to set H264 level/profile to caps"
152 ))
153 }
154 }
155}
156
157#[cfg(feature = "v1_20")]
180#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
181#[doc(alias = "gst_codec_utils_h264_get_profile_flags_level")]
182pub fn codec_utils_h264_get_profile_flags_level(
183 codec_data: &[u8],
184) -> Result<(u8, u8, u8), glib::BoolError> {
185 assert_initialized_main_thread!();
186 let len = codec_data.len() as u32;
187 unsafe {
188 let mut profile = mem::MaybeUninit::uninit();
189 let mut flags = mem::MaybeUninit::uninit();
190 let mut level = mem::MaybeUninit::uninit();
191 glib::result_from_gboolean!(
192 ffi::gst_codec_utils_h264_get_profile_flags_level(
193 codec_data.to_glib_none().0,
194 len,
195 profile.as_mut_ptr(),
196 flags.as_mut_ptr(),
197 level.as_mut_ptr()
198 ),
199 "Failed to get H264 profile, flags and level"
200 )?;
201 let profile = profile.assume_init();
202 let flags = flags.assume_init();
203 let level = level.assume_init();
204 Ok((profile, flags, level))
205 }
206}
207
208#[cfg(feature = "v1_30")]
209#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
210#[doc(alias = "GstH264LevelLimits")]
211#[derive(Debug, Clone, PartialEq, Eq)]
212pub struct H264LevelLimits {
213 pub name: &'static glib::GStr,
214 pub level_idc: u8,
215 pub max_mbps: u32,
216 pub max_fs: u32,
217 pub max_dpb_mbs: u32,
218 pub max_br: u32,
219 pub max_cpb: u32,
220 pub min_cr: u32,
221}
222
223#[cfg(feature = "v1_30")]
246#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
247#[doc(alias = "gst_codec_utils_h264_get_level_limits")]
248pub fn codec_utils_h264_get_level_limits(
249 width: i32,
250 height: i32,
251 fps_n: i32,
252 fps_d: i32,
253 bitrate: u32,
254 max_dec_frame_buffering: u32,
255 profile_idc: u8,
256) -> Option<H264LevelLimits> {
257 assert_initialized_main_thread!();
258 unsafe {
259 let limits = ffi::gst_codec_utils_h264_get_level_limits(
260 width,
261 height,
262 fps_n,
263 fps_d,
264 bitrate,
265 max_dec_frame_buffering,
266 profile_idc,
267 )
268 .as_ref()?;
269
270 Some(H264LevelLimits {
271 name: glib::GStr::from_ptr(limits.name),
272 level_idc: limits.level_idc,
273 max_mbps: limits.max_mbps,
274 max_fs: limits.max_fs,
275 max_dpb_mbs: limits.max_dpb_mbs,
276 max_br: limits.max_br,
277 max_cpb: limits.max_cpb,
278 min_cr: limits.min_cr,
279 })
280 }
281}
282
283#[doc(alias = "gst_codec_utils_h265_caps_set_level_tier_and_profile")]
297pub fn codec_utils_h265_caps_set_level_tier_and_profile(
298 caps: &mut gst::CapsRef,
299 profile_tier_level: &[u8],
300) -> Result<(), glib::BoolError> {
301 assert_initialized_main_thread!();
302
303 assert_eq!(caps.size(), 1);
304
305 let s = caps.structure(0).unwrap();
306 assert_eq!(s.name(), "video/x-h265");
307
308 let len = profile_tier_level.len() as u32;
309 unsafe {
310 let res: bool = from_glib(ffi::gst_codec_utils_h265_caps_set_level_tier_and_profile(
311 caps.as_mut_ptr(),
312 profile_tier_level.to_glib_none().0,
313 len,
314 ));
315
316 if res {
317 Ok(())
318 } else {
319 Err(glib::bool_error!(
320 "Failed to set H265 level/tier/profile to caps"
321 ))
322 }
323 }
324}
325
326#[doc(alias = "gst_codec_utils_mpeg4video_caps_set_level_and_profile")]
340pub fn codec_utils_mpeg4video_caps_set_level_and_profile(
341 caps: &mut gst::CapsRef,
342 vis_obj_seq: &[u8],
343) -> Result<(), glib::BoolError> {
344 assert_initialized_main_thread!();
345
346 assert_eq!(caps.size(), 1);
347
348 let s = caps.structure(0).unwrap();
349 assert_eq!(s.name(), "video/mpeg");
350 assert!(s.get::<i32>("mpegversion").is_ok_and(|v| v == 4));
351
352 let len = vis_obj_seq.len() as u32;
353 unsafe {
354 let res: bool = from_glib(ffi::gst_codec_utils_mpeg4video_caps_set_level_and_profile(
355 caps.as_mut_ptr(),
356 vis_obj_seq.to_glib_none().0,
357 len,
358 ));
359
360 if res {
361 Ok(())
362 } else {
363 Err(glib::bool_error!(
364 "Failed to set MPEG4 video level/profile to caps"
365 ))
366 }
367 }
368}
369
370#[doc(alias = "gst_codec_utils_opus_create_caps")]
389pub fn codec_utils_opus_create_caps(
390 rate: u32,
391 channels: u8,
392 channel_mapping_family: u8,
393 stream_count: u8,
394 coupled_count: u8,
395 channel_mapping: &[u8],
396) -> Result<gst::Caps, glib::BoolError> {
397 assert_initialized_main_thread!();
398
399 assert!(channel_mapping.is_empty() || channel_mapping.len() == channels as usize);
400
401 unsafe {
402 let caps = ffi::gst_codec_utils_opus_create_caps(
403 rate,
404 channels,
405 channel_mapping_family,
406 stream_count,
407 coupled_count,
408 if channel_mapping.is_empty() {
409 ptr::null()
410 } else {
411 channel_mapping.to_glib_none().0
412 },
413 );
414
415 if caps.is_null() {
416 Err(glib::bool_error!(
417 "Failed to create caps from Opus configuration"
418 ))
419 } else {
420 Ok(from_glib_full(caps))
421 }
422 }
423}
424
425#[doc(alias = "gst_codec_utils_opus_create_caps_from_header")]
436pub fn codec_utils_opus_create_caps_from_header(
437 header: &gst::BufferRef,
438 comments: Option<&gst::BufferRef>,
439) -> Result<gst::Caps, glib::BoolError> {
440 assert_initialized_main_thread!();
441 unsafe {
442 Option::<_>::from_glib_full(ffi::gst_codec_utils_opus_create_caps_from_header(
443 mut_override(header.as_ptr()),
444 comments
445 .map(|b| mut_override(b.as_ptr()))
446 .unwrap_or(ptr::null_mut()),
447 ))
448 .ok_or_else(|| glib::bool_error!("Failed to create caps from Opus headers"))
449 }
450}
451
452#[doc(alias = "gst_codec_utils_opus_create_header")]
474#[allow(clippy::too_many_arguments)]
475pub fn codec_utils_opus_create_header(
476 rate: u32,
477 channels: u8,
478 channel_mapping_family: u8,
479 stream_count: u8,
480 coupled_count: u8,
481 channel_mapping: &[u8],
482 pre_skip: u16,
483 output_gain: i16,
484) -> Result<gst::Buffer, glib::BoolError> {
485 assert_initialized_main_thread!();
486
487 assert!(channel_mapping.is_empty() || channel_mapping.len() == channels as usize);
488
489 unsafe {
490 let header = ffi::gst_codec_utils_opus_create_header(
491 rate,
492 channels,
493 channel_mapping_family,
494 stream_count,
495 coupled_count,
496 if channel_mapping.is_empty() {
497 ptr::null()
498 } else {
499 channel_mapping.to_glib_none().0
500 },
501 pre_skip,
502 output_gain,
503 );
504
505 if header.is_null() {
506 Err(glib::bool_error!(
507 "Failed to create header from Opus configuration"
508 ))
509 } else {
510 Ok(from_glib_full(header))
511 }
512 }
513}
514
515#[doc(alias = "gst_codec_utils_opus_parse_caps")]
541pub fn codec_utils_opus_parse_caps(
542 caps: &gst::CapsRef,
543 channel_mapping: Option<&mut [u8; 256]>,
544) -> Result<(u32, u8, u8, u8, u8), glib::BoolError> {
545 assert_initialized_main_thread!();
546
547 unsafe {
548 let mut rate = mem::MaybeUninit::uninit();
549 let mut channels = mem::MaybeUninit::uninit();
550 let mut channel_mapping_family = mem::MaybeUninit::uninit();
551 let mut stream_count = mem::MaybeUninit::uninit();
552 let mut coupled_count = mem::MaybeUninit::uninit();
553
554 let res: bool = from_glib(ffi::gst_codec_utils_opus_parse_caps(
555 mut_override(caps.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 ));
567
568 if res {
569 Ok((
570 rate.assume_init(),
571 channels.assume_init(),
572 channel_mapping_family.assume_init(),
573 stream_count.assume_init(),
574 coupled_count.assume_init(),
575 ))
576 } else {
577 Err(glib::bool_error!("Failed to parse Opus caps"))
578 }
579 }
580}
581
582#[doc(alias = "gst_codec_utils_opus_parse_header")]
614#[allow(clippy::type_complexity)]
615pub fn codec_utils_opus_parse_header(
616 header: &gst::BufferRef,
617 channel_mapping: Option<&mut [u8; 256]>,
618) -> Result<(u32, u8, u8, u8, u8, u16, i16), glib::BoolError> {
619 assert_initialized_main_thread!();
620
621 unsafe {
622 let mut rate = mem::MaybeUninit::uninit();
623 let mut channels = mem::MaybeUninit::uninit();
624 let mut channel_mapping_family = mem::MaybeUninit::uninit();
625 let mut stream_count = mem::MaybeUninit::uninit();
626 let mut coupled_count = mem::MaybeUninit::uninit();
627 let mut pre_skip = mem::MaybeUninit::uninit();
628 let mut output_gain = mem::MaybeUninit::uninit();
629
630 let res: bool = from_glib(ffi::gst_codec_utils_opus_parse_header(
631 mut_override(header.as_ptr()),
632 rate.as_mut_ptr(),
633 channels.as_mut_ptr(),
634 channel_mapping_family.as_mut_ptr(),
635 stream_count.as_mut_ptr(),
636 coupled_count.as_mut_ptr(),
637 if let Some(channel_mapping) = channel_mapping {
638 channel_mapping.as_mut_ptr() as *mut [u8; 256]
639 } else {
640 ptr::null_mut()
641 },
642 pre_skip.as_mut_ptr(),
643 output_gain.as_mut_ptr(),
644 ));
645
646 if res {
647 Ok((
648 rate.assume_init(),
649 channels.assume_init(),
650 channel_mapping_family.assume_init(),
651 stream_count.assume_init(),
652 coupled_count.assume_init(),
653 pre_skip.assume_init(),
654 output_gain.assume_init(),
655 ))
656 } else {
657 Err(glib::bool_error!("Failed to parse Opus header"))
658 }
659 }
660}
661
662#[cfg(feature = "v1_20")]
675#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
676#[doc(alias = "gst_codec_utils_caps_get_mime_codec")]
677pub fn codec_utils_caps_get_mime_codec(
678 caps: &gst::CapsRef,
679) -> Result<glib::GString, glib::BoolError> {
680 assert_initialized_main_thread!();
681 unsafe {
682 Option::<_>::from_glib_full(ffi::gst_codec_utils_caps_get_mime_codec(mut_override(
683 caps.as_ptr(),
684 )))
685 .ok_or_else(|| glib::bool_error!("Unsupported caps"))
686 }
687}
688
689#[cfg(feature = "v1_20")]
699#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
700#[doc(alias = "gst_pb_utils_get_caps_description_flags")]
701pub fn pb_utils_get_caps_description_flags(
702 caps: &gst::CapsRef,
703) -> crate::PbUtilsCapsDescriptionFlags {
704 assert_initialized_main_thread!();
705 unsafe { from_glib(ffi::gst_pb_utils_get_caps_description_flags(caps.as_ptr())) }
706}
707
708#[cfg(feature = "v1_20")]
717#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
718#[doc(alias = "gst_pb_utils_get_file_extension_from_caps")]
719pub fn pb_utils_get_file_extension_from_caps(caps: &gst::CapsRef) -> Option<glib::GString> {
720 assert_initialized_main_thread!();
721 unsafe {
722 from_glib_full(ffi::gst_pb_utils_get_file_extension_from_caps(
723 caps.as_ptr(),
724 ))
725 }
726}
727
728#[cfg(feature = "v1_26")]
737#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
738#[doc(alias = "gst_codec_utils_av1_create_caps_from_av1c")]
739pub fn codec_utils_av1_create_caps_from_av1c(
740 av1c: &gst::BufferRef,
741) -> Result<gst::Caps, glib::BoolError> {
742 assert_initialized_main_thread!();
743 unsafe {
744 Option::<_>::from_glib_full(ffi::gst_codec_utils_av1_create_caps_from_av1c(
745 mut_override(av1c.as_ptr()),
746 ))
747 .ok_or_else(|| glib::bool_error!("Failed to create caps from AV1C header"))
748 }
749}
750
751#[cfg(feature = "v1_26")]
760#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
761#[doc(alias = "gst_codec_utils_av1_create_av1c_from_caps")]
762pub fn codec_utils_av1_create_av1c_from_caps(
763 caps: &gst::CapsRef,
764) -> Result<gst::Buffer, glib::BoolError> {
765 assert_initialized_main_thread!();
766 unsafe {
767 Option::<_>::from_glib_full(ffi::gst_codec_utils_av1_create_av1c_from_caps(
768 mut_override(caps.as_ptr()),
769 ))
770 .ok_or_else(|| glib::bool_error!("Failed to create AV1C header from caps"))
771 }
772}
773
774#[cfg(feature = "v1_26")]
787#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
788#[doc(alias = "gst_codec_utils_h266_caps_set_level_tier_and_profile")]
789pub fn codec_utils_h266_caps_set_level_tier_and_profile(
790 caps: &mut gst::CapsRef,
791 decoder_configuration: &[u8],
792) -> Result<(), glib::BoolError> {
793 assert_initialized_main_thread!();
794 let len = decoder_configuration.len() as _;
795 unsafe {
796 let res: bool = from_glib(ffi::gst_codec_utils_h266_caps_set_level_tier_and_profile(
797 mut_override(caps.as_ptr()),
798 decoder_configuration.to_glib_none().0,
799 len,
800 ));
801
802 if res {
803 Ok(())
804 } else {
805 Err(glib::bool_error!(
806 "Failed to set H266 level/tier/profile to caps"
807 ))
808 }
809 }
810}
811
812#[cfg(feature = "v1_30")]
813#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
814pub type CodecUtilsVpxConfig = (i32, u8, u8, u8, u8, Option<bool>, u8, u8, u8);
815
816#[cfg(feature = "v1_30")]
853#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
854#[doc(alias = "gst_codec_utils_vpx_caps_get_config")]
855pub fn codec_utils_vpx_caps_get_config(caps: &gst::CapsRef) -> Option<CodecUtilsVpxConfig> {
856 assert_initialized_main_thread!();
857 unsafe {
858 let mut vpx_version = std::mem::MaybeUninit::uninit();
859 let mut profile = std::mem::MaybeUninit::uninit();
860 let mut level = std::mem::MaybeUninit::uninit();
861 let mut bit_depth = std::mem::MaybeUninit::uninit();
862 let mut chroma_subsampling = std::mem::MaybeUninit::uninit();
863 let mut video_full_range = std::mem::MaybeUninit::uninit();
864 let mut colour_primaries = std::mem::MaybeUninit::uninit();
865 let mut transfer_characteristics = std::mem::MaybeUninit::uninit();
866 let mut matrix_coefficients = std::mem::MaybeUninit::uninit();
867
868 let ret: bool = from_glib(ffi::gst_codec_utils_vpx_caps_get_config(
869 mut_override(caps.as_ptr()),
870 vpx_version.as_mut_ptr(),
871 profile.as_mut_ptr(),
872 level.as_mut_ptr(),
873 bit_depth.as_mut_ptr(),
874 chroma_subsampling.as_mut_ptr(),
875 video_full_range.as_mut_ptr(),
876 colour_primaries.as_mut_ptr(),
877 transfer_characteristics.as_mut_ptr(),
878 matrix_coefficients.as_mut_ptr(),
879 ));
880
881 if ret {
882 let video_full_range = match video_full_range.assume_init() {
883 -1 => None,
884 0 => Some(false),
885 _ => Some(true),
886 };
887
888 Some((
889 vpx_version.assume_init(),
890 profile.assume_init(),
891 level.assume_init(),
892 bit_depth.assume_init(),
893 chroma_subsampling.assume_init(),
894 video_full_range,
895 colour_primaries.assume_init(),
896 transfer_characteristics.assume_init(),
897 matrix_coefficients.assume_init(),
898 ))
899 } else {
900 None
901 }
902 }
903}
904
905#[cfg(feature = "v1_30")]
917#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
918#[doc(alias = "gst_codec_utils_vp9_estimate_level_idc_from_caps")]
919pub fn codec_utils_vp9_estimate_level_idc_from_caps(caps: &gst::CapsRef) -> u8 {
920 assert_initialized_main_thread!();
921 unsafe { ffi::gst_codec_utils_vp9_estimate_level_idc_from_caps(mut_override(caps.as_ptr())) }
922}
923
924#[cfg(feature = "v1_30")]
935#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
936#[doc(alias = "gst_codec_utils_vpx_create_vpcc_from_caps")]
937pub fn codec_utils_vpx_create_vpcc_from_caps(caps: &gst::CapsRef) -> Option<gst::Buffer> {
938 assert_initialized_main_thread!();
939 unsafe {
940 from_glib_full(ffi::gst_codec_utils_vpx_create_vpcc_from_caps(
941 mut_override(caps.as_ptr()),
942 ))
943 }
944}