Skip to main content

gstreamer_pbutils/
functions.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use 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")]
73pub fn codec_utils_aac_caps_set_level_and_profile(
74    caps: &mut gst::CapsRef,
75    audio_config: &[u8],
76) -> Result<(), glib::BoolError> {
77    assert_initialized_main_thread!();
78
79    assert_eq!(caps.size(), 1);
80
81    let s = caps.structure(0).unwrap();
82    assert_eq!(s.name(), "audio/mpeg");
83    assert!(s.get::<i32>("mpegversion").is_ok_and(|v| v == 2 || v == 4));
84
85    let len = audio_config.len() as u32;
86    unsafe {
87        let res: bool = from_glib(ffi::gst_codec_utils_aac_caps_set_level_and_profile(
88            caps.as_mut_ptr(),
89            audio_config.to_glib_none().0,
90            len,
91        ));
92
93        if res {
94            Ok(())
95        } else {
96            Err(glib::bool_error!("Failed to set AAC level/profile to caps"))
97        }
98    }
99}
100
101#[doc(alias = "gst_codec_utils_h264_caps_set_level_and_profile")]
102pub fn codec_utils_h264_caps_set_level_and_profile(
103    caps: &mut gst::CapsRef,
104    sps: &[u8],
105) -> Result<(), glib::BoolError> {
106    assert_initialized_main_thread!();
107
108    assert_eq!(caps.size(), 1);
109
110    let s = caps.structure(0).unwrap();
111    assert_eq!(s.name(), "video/x-h264");
112
113    let len = sps.len() as u32;
114    unsafe {
115        let res: bool = from_glib(ffi::gst_codec_utils_h264_caps_set_level_and_profile(
116            caps.as_mut_ptr(),
117            sps.to_glib_none().0,
118            len,
119        ));
120
121        if res {
122            Ok(())
123        } else {
124            Err(glib::bool_error!(
125                "Failed to set H264 level/profile to caps"
126            ))
127        }
128    }
129}
130
131#[cfg(feature = "v1_20")]
132#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
133#[doc(alias = "gst_codec_utils_h264_get_profile_flags_level")]
134pub fn codec_utils_h264_get_profile_flags_level(
135    codec_data: &[u8],
136) -> Result<(u8, u8, u8), glib::BoolError> {
137    assert_initialized_main_thread!();
138    let len = codec_data.len() as u32;
139    unsafe {
140        let mut profile = mem::MaybeUninit::uninit();
141        let mut flags = mem::MaybeUninit::uninit();
142        let mut level = mem::MaybeUninit::uninit();
143        glib::result_from_gboolean!(
144            ffi::gst_codec_utils_h264_get_profile_flags_level(
145                codec_data.to_glib_none().0,
146                len,
147                profile.as_mut_ptr(),
148                flags.as_mut_ptr(),
149                level.as_mut_ptr()
150            ),
151            "Failed to get H264 profile, flags and level"
152        )?;
153        let profile = profile.assume_init();
154        let flags = flags.assume_init();
155        let level = level.assume_init();
156        Ok((profile, flags, level))
157    }
158}
159
160#[cfg(feature = "v1_30")]
161#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
162#[doc(alias = "GstH264LevelLimits")]
163#[derive(Debug, Clone, PartialEq, Eq)]
164pub struct H264LevelLimits {
165    pub name: &'static glib::GStr,
166    pub level_idc: u8,
167    pub max_mbps: u32,
168    pub max_fs: u32,
169    pub max_dpb_mbs: u32,
170    pub max_br: u32,
171    pub max_cpb: u32,
172    pub min_cr: u32,
173}
174
175#[cfg(feature = "v1_30")]
176#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
177#[doc(alias = "gst_codec_utils_h264_get_level_limits")]
178pub fn codec_utils_h264_get_level_limits(
179    width: i32,
180    height: i32,
181    fps_n: i32,
182    fps_d: i32,
183    bitrate: u32,
184    max_dec_frame_buffering: u32,
185    profile_idc: u8,
186) -> Option<H264LevelLimits> {
187    assert_initialized_main_thread!();
188    unsafe {
189        let limits = ffi::gst_codec_utils_h264_get_level_limits(
190            width,
191            height,
192            fps_n,
193            fps_d,
194            bitrate,
195            max_dec_frame_buffering,
196            profile_idc,
197        )
198        .as_ref()?;
199
200        Some(H264LevelLimits {
201            name: glib::GStr::from_ptr(limits.name),
202            level_idc: limits.level_idc,
203            max_mbps: limits.max_mbps,
204            max_fs: limits.max_fs,
205            max_dpb_mbs: limits.max_dpb_mbs,
206            max_br: limits.max_br,
207            max_cpb: limits.max_cpb,
208            min_cr: limits.min_cr,
209        })
210    }
211}
212
213#[doc(alias = "gst_codec_utils_h265_caps_set_level_tier_and_profile")]
214pub fn codec_utils_h265_caps_set_level_tier_and_profile(
215    caps: &mut gst::CapsRef,
216    profile_tier_level: &[u8],
217) -> Result<(), glib::BoolError> {
218    assert_initialized_main_thread!();
219
220    assert_eq!(caps.size(), 1);
221
222    let s = caps.structure(0).unwrap();
223    assert_eq!(s.name(), "video/x-h265");
224
225    let len = profile_tier_level.len() as u32;
226    unsafe {
227        let res: bool = from_glib(ffi::gst_codec_utils_h265_caps_set_level_tier_and_profile(
228            caps.as_mut_ptr(),
229            profile_tier_level.to_glib_none().0,
230            len,
231        ));
232
233        if res {
234            Ok(())
235        } else {
236            Err(glib::bool_error!(
237                "Failed to set H265 level/tier/profile to caps"
238            ))
239        }
240    }
241}
242
243#[doc(alias = "gst_codec_utils_mpeg4video_caps_set_level_and_profile")]
244pub fn codec_utils_mpeg4video_caps_set_level_and_profile(
245    caps: &mut gst::CapsRef,
246    vis_obj_seq: &[u8],
247) -> Result<(), glib::BoolError> {
248    assert_initialized_main_thread!();
249
250    assert_eq!(caps.size(), 1);
251
252    let s = caps.structure(0).unwrap();
253    assert_eq!(s.name(), "video/mpeg");
254    assert!(s.get::<i32>("mpegversion").is_ok_and(|v| v == 4));
255
256    let len = vis_obj_seq.len() as u32;
257    unsafe {
258        let res: bool = from_glib(ffi::gst_codec_utils_mpeg4video_caps_set_level_and_profile(
259            caps.as_mut_ptr(),
260            vis_obj_seq.to_glib_none().0,
261            len,
262        ));
263
264        if res {
265            Ok(())
266        } else {
267            Err(glib::bool_error!(
268                "Failed to set MPEG4 video level/profile to caps"
269            ))
270        }
271    }
272}
273
274#[doc(alias = "gst_codec_utils_opus_create_caps")]
275pub fn codec_utils_opus_create_caps(
276    rate: u32,
277    channels: u8,
278    channel_mapping_family: u8,
279    stream_count: u8,
280    coupled_count: u8,
281    channel_mapping: &[u8],
282) -> Result<gst::Caps, glib::BoolError> {
283    assert_initialized_main_thread!();
284
285    assert!(channel_mapping.is_empty() || channel_mapping.len() == channels as usize);
286
287    unsafe {
288        let caps = ffi::gst_codec_utils_opus_create_caps(
289            rate,
290            channels,
291            channel_mapping_family,
292            stream_count,
293            coupled_count,
294            if channel_mapping.is_empty() {
295                ptr::null()
296            } else {
297                channel_mapping.to_glib_none().0
298            },
299        );
300
301        if caps.is_null() {
302            Err(glib::bool_error!(
303                "Failed to create caps from Opus configuration"
304            ))
305        } else {
306            Ok(from_glib_full(caps))
307        }
308    }
309}
310
311#[doc(alias = "gst_codec_utils_opus_create_caps_from_header")]
312pub fn codec_utils_opus_create_caps_from_header(
313    header: &gst::BufferRef,
314    comments: Option<&gst::BufferRef>,
315) -> Result<gst::Caps, glib::BoolError> {
316    assert_initialized_main_thread!();
317    unsafe {
318        Option::<_>::from_glib_full(ffi::gst_codec_utils_opus_create_caps_from_header(
319            mut_override(header.as_ptr()),
320            comments
321                .map(|b| mut_override(b.as_ptr()))
322                .unwrap_or(ptr::null_mut()),
323        ))
324        .ok_or_else(|| glib::bool_error!("Failed to create caps from Opus headers"))
325    }
326}
327
328#[doc(alias = "gst_codec_utils_opus_create_header")]
329#[allow(clippy::too_many_arguments)]
330pub fn codec_utils_opus_create_header(
331    rate: u32,
332    channels: u8,
333    channel_mapping_family: u8,
334    stream_count: u8,
335    coupled_count: u8,
336    channel_mapping: &[u8],
337    pre_skip: u16,
338    output_gain: i16,
339) -> Result<gst::Buffer, glib::BoolError> {
340    assert_initialized_main_thread!();
341
342    assert!(channel_mapping.is_empty() || channel_mapping.len() == channels as usize);
343
344    unsafe {
345        let header = ffi::gst_codec_utils_opus_create_header(
346            rate,
347            channels,
348            channel_mapping_family,
349            stream_count,
350            coupled_count,
351            if channel_mapping.is_empty() {
352                ptr::null()
353            } else {
354                channel_mapping.to_glib_none().0
355            },
356            pre_skip,
357            output_gain,
358        );
359
360        if header.is_null() {
361            Err(glib::bool_error!(
362                "Failed to create header from Opus configuration"
363            ))
364        } else {
365            Ok(from_glib_full(header))
366        }
367    }
368}
369
370#[doc(alias = "gst_codec_utils_opus_parse_caps")]
371pub fn codec_utils_opus_parse_caps(
372    caps: &gst::CapsRef,
373    channel_mapping: Option<&mut [u8; 256]>,
374) -> Result<(u32, u8, u8, u8, u8), glib::BoolError> {
375    assert_initialized_main_thread!();
376
377    unsafe {
378        let mut rate = mem::MaybeUninit::uninit();
379        let mut channels = mem::MaybeUninit::uninit();
380        let mut channel_mapping_family = mem::MaybeUninit::uninit();
381        let mut stream_count = mem::MaybeUninit::uninit();
382        let mut coupled_count = mem::MaybeUninit::uninit();
383
384        let res: bool = from_glib(ffi::gst_codec_utils_opus_parse_caps(
385            mut_override(caps.as_ptr()),
386            rate.as_mut_ptr(),
387            channels.as_mut_ptr(),
388            channel_mapping_family.as_mut_ptr(),
389            stream_count.as_mut_ptr(),
390            coupled_count.as_mut_ptr(),
391            if let Some(channel_mapping) = channel_mapping {
392                channel_mapping.as_mut_ptr() as *mut [u8; 256]
393            } else {
394                ptr::null_mut()
395            },
396        ));
397
398        if res {
399            Ok((
400                rate.assume_init(),
401                channels.assume_init(),
402                channel_mapping_family.assume_init(),
403                stream_count.assume_init(),
404                coupled_count.assume_init(),
405            ))
406        } else {
407            Err(glib::bool_error!("Failed to parse Opus caps"))
408        }
409    }
410}
411
412#[doc(alias = "gst_codec_utils_opus_parse_header")]
413#[allow(clippy::type_complexity)]
414pub fn codec_utils_opus_parse_header(
415    header: &gst::BufferRef,
416    channel_mapping: Option<&mut [u8; 256]>,
417) -> Result<(u32, u8, u8, u8, u8, u16, i16), glib::BoolError> {
418    assert_initialized_main_thread!();
419
420    unsafe {
421        let mut rate = mem::MaybeUninit::uninit();
422        let mut channels = mem::MaybeUninit::uninit();
423        let mut channel_mapping_family = mem::MaybeUninit::uninit();
424        let mut stream_count = mem::MaybeUninit::uninit();
425        let mut coupled_count = mem::MaybeUninit::uninit();
426        let mut pre_skip = mem::MaybeUninit::uninit();
427        let mut output_gain = mem::MaybeUninit::uninit();
428
429        let res: bool = from_glib(ffi::gst_codec_utils_opus_parse_header(
430            mut_override(header.as_ptr()),
431            rate.as_mut_ptr(),
432            channels.as_mut_ptr(),
433            channel_mapping_family.as_mut_ptr(),
434            stream_count.as_mut_ptr(),
435            coupled_count.as_mut_ptr(),
436            if let Some(channel_mapping) = channel_mapping {
437                channel_mapping.as_mut_ptr() as *mut [u8; 256]
438            } else {
439                ptr::null_mut()
440            },
441            pre_skip.as_mut_ptr(),
442            output_gain.as_mut_ptr(),
443        ));
444
445        if res {
446            Ok((
447                rate.assume_init(),
448                channels.assume_init(),
449                channel_mapping_family.assume_init(),
450                stream_count.assume_init(),
451                coupled_count.assume_init(),
452                pre_skip.assume_init(),
453                output_gain.assume_init(),
454            ))
455        } else {
456            Err(glib::bool_error!("Failed to parse Opus header"))
457        }
458    }
459}
460
461#[cfg(feature = "v1_20")]
462#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
463#[doc(alias = "gst_codec_utils_caps_get_mime_codec")]
464pub fn codec_utils_caps_get_mime_codec(
465    caps: &gst::CapsRef,
466) -> Result<glib::GString, glib::BoolError> {
467    assert_initialized_main_thread!();
468    unsafe {
469        Option::<_>::from_glib_full(ffi::gst_codec_utils_caps_get_mime_codec(mut_override(
470            caps.as_ptr(),
471        )))
472        .ok_or_else(|| glib::bool_error!("Unsupported caps"))
473    }
474}
475
476#[cfg(feature = "v1_20")]
477#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
478#[doc(alias = "gst_pb_utils_get_caps_description_flags")]
479pub fn pb_utils_get_caps_description_flags(
480    caps: &gst::CapsRef,
481) -> crate::PbUtilsCapsDescriptionFlags {
482    assert_initialized_main_thread!();
483    unsafe { from_glib(ffi::gst_pb_utils_get_caps_description_flags(caps.as_ptr())) }
484}
485
486#[cfg(feature = "v1_20")]
487#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
488#[doc(alias = "gst_pb_utils_get_file_extension_from_caps")]
489pub fn pb_utils_get_file_extension_from_caps(caps: &gst::CapsRef) -> Option<glib::GString> {
490    assert_initialized_main_thread!();
491    unsafe {
492        from_glib_full(ffi::gst_pb_utils_get_file_extension_from_caps(
493            caps.as_ptr(),
494        ))
495    }
496}
497
498#[cfg(feature = "v1_26")]
499#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
500#[doc(alias = "gst_codec_utils_av1_create_caps_from_av1c")]
501pub fn codec_utils_av1_create_caps_from_av1c(
502    av1c: &gst::BufferRef,
503) -> Result<gst::Caps, glib::BoolError> {
504    assert_initialized_main_thread!();
505    unsafe {
506        Option::<_>::from_glib_full(ffi::gst_codec_utils_av1_create_caps_from_av1c(
507            mut_override(av1c.as_ptr()),
508        ))
509        .ok_or_else(|| glib::bool_error!("Failed to create caps from AV1C header"))
510    }
511}
512
513#[cfg(feature = "v1_26")]
514#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
515#[doc(alias = "gst_codec_utils_av1_create_av1c_from_caps")]
516pub fn codec_utils_av1_create_av1c_from_caps(
517    caps: &gst::CapsRef,
518) -> Result<gst::Buffer, glib::BoolError> {
519    assert_initialized_main_thread!();
520    unsafe {
521        Option::<_>::from_glib_full(ffi::gst_codec_utils_av1_create_av1c_from_caps(
522            mut_override(caps.as_ptr()),
523        ))
524        .ok_or_else(|| glib::bool_error!("Failed to create AV1C header from caps"))
525    }
526}
527
528#[cfg(feature = "v1_26")]
529#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
530#[doc(alias = "gst_codec_utils_h266_caps_set_level_tier_and_profile")]
531pub fn codec_utils_h266_caps_set_level_tier_and_profile(
532    caps: &mut gst::CapsRef,
533    decoder_configuration: &[u8],
534) -> Result<(), glib::BoolError> {
535    assert_initialized_main_thread!();
536    let len = decoder_configuration.len() as _;
537    unsafe {
538        let res: bool = from_glib(ffi::gst_codec_utils_h266_caps_set_level_tier_and_profile(
539            mut_override(caps.as_ptr()),
540            decoder_configuration.to_glib_none().0,
541            len,
542        ));
543
544        if res {
545            Ok(())
546        } else {
547            Err(glib::bool_error!(
548                "Failed to set H266 level/tier/profile to caps"
549            ))
550        }
551    }
552}
553
554#[cfg(feature = "v1_30")]
555#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
556pub type CodecUtilsVpxConfig = (i32, u8, u8, u8, u8, Option<bool>, u8, u8, u8);
557
558#[cfg(feature = "v1_30")]
559#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
560#[doc(alias = "gst_codec_utils_vpx_caps_get_config")]
561pub fn codec_utils_vpx_caps_get_config(caps: &gst::CapsRef) -> Option<CodecUtilsVpxConfig> {
562    assert_initialized_main_thread!();
563    unsafe {
564        let mut vpx_version = std::mem::MaybeUninit::uninit();
565        let mut profile = std::mem::MaybeUninit::uninit();
566        let mut level = std::mem::MaybeUninit::uninit();
567        let mut bit_depth = std::mem::MaybeUninit::uninit();
568        let mut chroma_subsampling = std::mem::MaybeUninit::uninit();
569        let mut video_full_range = std::mem::MaybeUninit::uninit();
570        let mut colour_primaries = std::mem::MaybeUninit::uninit();
571        let mut transfer_characteristics = std::mem::MaybeUninit::uninit();
572        let mut matrix_coefficients = std::mem::MaybeUninit::uninit();
573
574        let ret: bool = from_glib(ffi::gst_codec_utils_vpx_caps_get_config(
575            mut_override(caps.as_ptr()),
576            vpx_version.as_mut_ptr(),
577            profile.as_mut_ptr(),
578            level.as_mut_ptr(),
579            bit_depth.as_mut_ptr(),
580            chroma_subsampling.as_mut_ptr(),
581            video_full_range.as_mut_ptr(),
582            colour_primaries.as_mut_ptr(),
583            transfer_characteristics.as_mut_ptr(),
584            matrix_coefficients.as_mut_ptr(),
585        ));
586
587        if ret {
588            let video_full_range = match video_full_range.assume_init() {
589                -1 => None,
590                0 => Some(false),
591                _ => Some(true),
592            };
593
594            Some((
595                vpx_version.assume_init(),
596                profile.assume_init(),
597                level.assume_init(),
598                bit_depth.assume_init(),
599                chroma_subsampling.assume_init(),
600                video_full_range,
601                colour_primaries.assume_init(),
602                transfer_characteristics.assume_init(),
603                matrix_coefficients.assume_init(),
604            ))
605        } else {
606            None
607        }
608    }
609}
610
611#[cfg(feature = "v1_30")]
612#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
613#[doc(alias = "gst_codec_utils_vp9_estimate_level_idc_from_caps")]
614pub fn codec_utils_vp9_estimate_level_idc_from_caps(caps: &gst::CapsRef) -> u8 {
615    assert_initialized_main_thread!();
616    unsafe { ffi::gst_codec_utils_vp9_estimate_level_idc_from_caps(mut_override(caps.as_ptr())) }
617}
618
619#[cfg(feature = "v1_30")]
620#[cfg_attr(docsrs, doc(cfg(feature = "v1_30")))]
621#[doc(alias = "gst_codec_utils_vpx_create_vpcc_from_caps")]
622pub fn codec_utils_vpx_create_vpcc_from_caps(caps: &gst::CapsRef) -> Option<gst::Buffer> {
623    assert_initialized_main_thread!();
624    unsafe {
625        from_glib_full(ffi::gst_codec_utils_vpx_create_vpcc_from_caps(
626            mut_override(caps.as_ptr()),
627        ))
628    }
629}