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/// Sets the level and profile on `caps` if it can be determined from
73/// `audio_config`. See [`codec_utils_aac_get_level()`][crate::codec_utils_aac_get_level()] and
74/// [`codec_utils_aac_get_profile()`][crate::codec_utils_aac_get_profile()] for more details on the parameters.
75/// `caps` must be audio/mpeg caps with an "mpegversion" field of either 2 or 4.
76/// If mpegversion is 4, the "base-profile" field is also set in `caps`.
77/// ## `caps`
78/// the [`gst::Caps`][crate::gst::Caps] to which level and profile fields are to be added
79/// ## `audio_config`
80/// a pointer to the AudioSpecificConfig
81///  as specified in the Elementary Stream Descriptor (esds)
82///  in ISO/IEC 14496-1. (See below for more details)
83///
84/// # Returns
85///
86/// [`true`] if the level and profile could be set, [`false`] otherwise.
87#[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/// Sets the level and profile in `caps` if it can be determined from `sps`. See
117/// [`codec_utils_h264_get_level()`][crate::codec_utils_h264_get_level()] and [`codec_utils_h264_get_profile()`][crate::codec_utils_h264_get_profile()]
118/// for more details on the parameters.
119/// ## `caps`
120/// the [`gst::Caps`][crate::gst::Caps] to which the level and profile are to be added
121/// ## `sps`
122/// Pointer to the sequence parameter set for the stream.
123///
124/// # Returns
125///
126/// [`true`] if the level and profile could be set, [`false`] otherwise.
127#[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/// Parses profile, flags, and level from a H264 AVCC extradata/sequence_header.
158/// These are most commonly retrieved from a video/x-h264 caps with a codec_data
159/// buffer.
160///
161/// The format of H264 AVCC extradata/sequence_header is documented in the
162/// ITU-T H.264 specification section 7.3.2.1.1 as well as in ISO/IEC 14496-15
163/// section 5.3.3.1.2.
164/// ## `codec_data`
165/// H264 AVCC extradata
166///
167/// # Returns
168///
169/// [`true`] on success, [`false`] on failure
170///
171/// ## `profile`
172/// return location for h264 profile_idc or [`None`]
173///
174/// ## `flags`
175/// return location for h264 constraint set flags or [`None`]
176///
177/// ## `level`
178/// return location h264 level_idc or [`None`]
179#[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/// Finds the minimum H.264 level that can handle the given video parameters
224/// based on the constraints defined in H.264 specification Annex A.
225/// ## `width`
226/// the video width in pixels
227/// ## `height`
228/// the video height in pixels
229/// ## `fps_n`
230/// the video frame rate numerator
231/// ## `fps_d`
232/// the video frame rate denominator
233/// ## `bitrate`
234/// the video bitrate in bits per second (0 if unknown)
235/// ## `max_dec_frame_buffering`
236/// the max size of DPB (0 if unknown)
237/// ## `profile_idc`
238/// the H.264 profile idc value (e.g., 66 for Baseline, 77 for Main, 100 for High)
239///
240/// # Returns
241///
242/// the `GstH264LevelLimits` for the
243///  minimum level matching the parameters, or [`None`] if no suitable
244///  level is found.
245#[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/// Sets the level, tier and profile in `caps` if it can be determined from
284/// `profile_tier_level`. See [`codec_utils_h265_get_level()`][crate::codec_utils_h265_get_level()],
285/// [`codec_utils_h265_get_tier()`][crate::codec_utils_h265_get_tier()] and [`codec_utils_h265_get_profile()`][crate::codec_utils_h265_get_profile()]
286/// for more details on the parameters.
287/// ## `caps`
288/// the [`gst::Caps`][crate::gst::Caps] to which the level, tier and profile are to be added
289/// ## `profile_tier_level`
290/// Pointer to the profile_tier_level
291///  struct
292///
293/// # Returns
294///
295/// [`true`] if the level, tier, profile could be set, [`false`] otherwise.
296#[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/// Sets the level and profile in `caps` if it can be determined from
327/// `vis_obj_seq`. See [`codec_utils_mpeg4video_get_level()`][crate::codec_utils_mpeg4video_get_level()] and
328/// [`codec_utils_mpeg4video_get_profile()`][crate::codec_utils_mpeg4video_get_profile()] for more details on the
329/// parameters.
330/// ## `caps`
331/// the [`gst::Caps`][crate::gst::Caps] to which the level and profile are to be added
332/// ## `vis_obj_seq`
333/// Pointer to the visual object
334///  sequence for the stream.
335///
336/// # Returns
337///
338/// [`true`] if the level and profile could be set, [`false`] otherwise.
339#[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/// Creates Opus caps from the given parameters.
371/// ## `rate`
372/// the sample rate
373/// ## `channels`
374/// the number of channels
375/// ## `channel_mapping_family`
376/// the channel mapping family
377/// ## `stream_count`
378/// the number of independent streams
379/// ## `coupled_count`
380/// the number of stereo streams
381/// ## `channel_mapping`
382/// the mapping between the streams
383///
384/// # Returns
385///
386/// The [`gst::Caps`][crate::gst::Caps], or [`None`] if the parameters would lead to
387/// invalid Opus caps.
388#[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/// Creates Opus caps from the given OpusHead `header` and comment header
426/// `comments`.
427/// ## `header`
428/// OpusHead header
429/// ## `comments`
430/// Comment header or NULL
431///
432/// # Returns
433///
434/// The [`gst::Caps`][crate::gst::Caps].
435#[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/// Creates OpusHead header from the given parameters.
453/// ## `rate`
454/// the sample rate
455/// ## `channels`
456/// the number of channels
457/// ## `channel_mapping_family`
458/// the channel mapping family
459/// ## `stream_count`
460/// the number of independent streams
461/// ## `coupled_count`
462/// the number of stereo streams
463/// ## `channel_mapping`
464/// the mapping between the streams
465/// ## `pre_skip`
466/// Pre-skip in 48kHz samples or 0
467/// ## `output_gain`
468/// Output gain or 0
469///
470/// # Returns
471///
472/// The [`gst::Buffer`][crate::gst::Buffer] containing the OpusHead.
473#[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/// Parses Opus caps and fills the different fields with defaults if possible.
516/// ## `caps`
517/// the [`gst::Caps`][crate::gst::Caps] to parse the data from
518///
519/// # Returns
520///
521/// [`true`] if parsing was successful, [`false`] otherwise.
522///
523/// ## `rate`
524/// the sample rate
525///
526/// ## `channels`
527/// the number of channels
528///
529/// ## `channel_mapping_family`
530/// the channel mapping family
531///
532/// ## `stream_count`
533/// the number of independent streams
534///
535/// ## `coupled_count`
536/// the number of stereo streams
537///
538/// ## `channel_mapping`
539/// the mapping between the streams
540#[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/// Parses the OpusHead header.
583/// ## `header`
584/// the OpusHead [`gst::Buffer`][crate::gst::Buffer]
585///
586/// # Returns
587///
588/// [`true`] if parsing was successful, [`false`] otherwise.
589///
590/// ## `rate`
591/// the sample rate
592///
593/// ## `channels`
594/// the number of channels
595///
596/// ## `channel_mapping_family`
597/// the channel mapping family
598///
599/// ## `stream_count`
600/// the number of independent streams
601///
602/// ## `coupled_count`
603/// the number of stereo streams
604///
605/// ## `channel_mapping`
606/// the mapping between the streams
607///
608/// ## `pre_skip`
609/// Pre-skip in 48kHz samples or 0
610///
611/// ## `output_gain`
612/// Output gain or 0
613#[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/// Converts `caps` to a RFC 6381 compatible codec string if possible.
663///
664/// Useful for providing the 'codecs' field inside the 'Content-Type' HTTP
665/// header for containerized formats, such as mp4 or matroska.
666///
667/// Registered codecs can be found at http://mp4ra.org/#/codecs
668/// ## `caps`
669/// A [`gst::Caps`][crate::gst::Caps] to convert to mime codec
670///
671/// # Returns
672///
673/// a RFC 6381 compatible codec string or [`None`]
674#[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/// Returns flags that describe the format of the caps if known. No flags are
690/// set for unknown caps.
691/// ## `caps`
692/// the (fixed) [`gst::Caps`][crate::gst::Caps] for which flags are requested
693///
694/// # Returns
695///
696/// [`PbUtilsCapsDescriptionFlags`][crate::PbUtilsCapsDescriptionFlags] that describe `caps`, or no flags
697///  if the caps are unknown.
698#[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/// Returns a possible file extension for the given caps, if known.
709/// ## `caps`
710/// the (fixed) [`gst::Caps`][crate::gst::Caps] for which a file extension is needed
711///
712/// # Returns
713///
714/// a newly-allocated file extension string, or NULL on error. Free
715///  string with `g_free()` when not needed any longer.
716#[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/// Parses the provided `av1c` and returns the corresponding caps
729/// ## `av1c`
730/// a [`gst::Buffer`][crate::gst::Buffer] containing a AV1CodecConfigurationRecord
731///
732/// # Returns
733///
734/// The parsed AV1 caps, or [`None`] if there
735/// is an error
736#[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/// Creates the corresponding AV1 Codec Configuration Record
752/// ## `caps`
753/// a video/x-av1 [`gst::Caps`][crate::gst::Caps]
754///
755/// # Returns
756///
757/// The AV1 Codec Configuration Record, or
758/// [`None`] if there was an error.
759#[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/// Sets the level, tier and profile in `caps` if it can be determined from
775/// `decoder_configuration`. See [`codec_utils_h266_get_level()`][crate::codec_utils_h266_get_level()],
776/// [`codec_utils_h266_get_tier()`][crate::codec_utils_h266_get_tier()] and [`codec_utils_h266_get_profile()`][crate::codec_utils_h266_get_profile()]
777/// for more details on the parameters.
778/// ## `caps`
779/// the [`gst::Caps`][crate::gst::Caps] to which the level, tier and profile are to be added
780/// ## `decoder_configuration`
781/// Pointer to the VvcDecoderConfigurationRecord struct as defined in ISO/IEC 14496-15
782///
783/// # Returns
784///
785/// [`true`] if the level, tier, profile could be set, [`false`] otherwise.
786#[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/// Parses VP8/VP9 caps and extracts normalized VPX configuration fields.
817/// Unlike [`codec_utils_vpx_caps_set_format_fields()`][crate::codec_utils_vpx_caps_set_format_fields()], this getter includes
818/// the colorimetry-derived fields needed to build a full vpcC record.
819/// ## `caps`
820/// a video/x-vp8 or video/x-vp9 [`gst::Caps`][crate::gst::Caps]
821///
822/// # Returns
823///
824/// [`true`] if extraction succeeded, [`false`] otherwise.
825///
826/// ## `vpx_version`
827/// VPX version described by `caps` (8 or 9)
828///
829/// ## `profile`
830/// profile value
831///
832/// ## `level`
833/// level value
834///
835/// ## `bit_depth`
836/// bit depth value
837///
838/// ## `chroma_subsampling`
839/// chroma subsampling value
840///
841/// ## `video_full_range`
842/// whether full-range signaling is set
843///
844/// ## `colour_primaries`
845/// ISO color primaries value
846///
847/// ## `transfer_characteristics`
848/// ISO transfer characteristics value
849///
850/// ## `matrix_coefficients`
851/// ISO matrix coefficients value
852#[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/// Estimates the vp9 level as defined in
906/// https://www.webmproject.org/vp9/mp4/`vp`-codec-configuration-box, using
907/// the resolution and, if available, frame rate found in the structure passed
908/// in.
909/// ## `caps`
910/// a video/x-vp9 [`gst::Caps`][crate::gst::Caps]
911///
912/// # Returns
913///
914/// The estimated vp9 level indicator, and 0 if it could not be
915/// estimated.
916#[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/// Creates a vpcC record for VP8/VP9 as per the VP Codec ISO Media File Format
925/// Binding definition found at
926/// https://www.webmproject.org/vp9/mp4/`vp`-codec-configuration-box
927/// ## `caps`
928/// a video/x-vp8 or video/x-vp9 [`gst::Caps`][crate::gst::Caps]
929///
930/// # Returns
931///
932/// Buffer containing the vpcC record, or
933/// [`None`] if the record could not be created.
934#[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}