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")]
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}