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    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}