pbutils: Add bindings for codec-utils functions

This commit is contained in:
Sebastian Dröge 2022-01-14 16:54:16 +02:00
parent 5151b76729
commit 2bb500db0b
3 changed files with 601 additions and 4 deletions

View file

@ -83,10 +83,89 @@ status = "generate"
pattern = ".+"
ignore = true
# Codec utils need some special care
[[object.function]]
pattern = "codec_utils.*"
ignore = true
pattern = "codec_utils_(aac_caps_set_level_and_profile|h264_caps_set_level_and_profile|h265_caps_set_level_tier_and_profile|mpeg4video_caps_set_level_and_profile)"
# Needs mutable caps references and checks for the caps
manual = true
[[object.function]]
name = "codec_utils_aac_get_level"
[object.function.return]
nullable_return_is_error = "Failed to get AAC level"
[[object.function]]
name = "codec_utils_aac_get_profile"
[object.function.return]
nullable_return_is_error = "Failed to get AAC profile"
[[object.function]]
name = "codec_utils_h264_get_level"
[object.function.return]
nullable_return_is_error = "Failed to get H264 level"
[[object.function]]
name = "codec_utils_h264_get_profile"
[object.function.return]
nullable_return_is_error = "Failed to get H264 profile"
[[object.function]]
name = "codec_utils_h264_get_profile_flags_level"
manual = true
[[object.function]]
name = "codec_utils_h265_get_level"
[object.function.return]
nullable_return_is_error = "Failed to get H265 level"
[[object.function]]
name = "codec_utils_h265_get_profile"
[object.function.return]
nullable_return_is_error = "Failed to get H265 profile"
[[object.function]]
name = "codec_utils_h265_get_tier"
[object.function.return]
nullable_return_is_error = "Failed to get H265 tier"
[[object.function]]
name = "codec_utils_mpeg4video_get_level"
[object.function.return]
nullable_return_is_error = "Failed to get MPEG4 video level"
[[object.function]]
name = "codec_utils_mpeg4video_get_profile"
[object.function.return]
nullable_return_is_error = "Failed to get MPEG4 video profile"
[[object.function]]
name = "codec_utils_caps_get_mime_codec"
[object.function.return]
nullable_return_is_error = "Unsupported caps"
[[object.function]]
name = "codec_utils_opus_create_caps_from_header"
[object.function.return]
nullable_return_is_error = "Failed to create caps from Opus headers"
[[object.function]]
name = "codec_utils_opus_create_caps"
# Manual checks
manual = true
[[object.function]]
name = "codec_utils_opus_create_header"
# Manual checks
manual = true
[[object.function]]
name = "codec_utils_opus_parse_caps"
# Manual checks
manual = true
[[object.function]]
name = "codec_utils_opus_parse_header"
# Manual checks
manual = true
# Plugin installer API needs some manual impls
[[object.function]]

View file

@ -10,6 +10,203 @@ use crate::PbUtilsCapsDescriptionFlags;
use glib::translate::*;
use std::mem;
#[cfg(any(feature = "v1_10", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_10")))]
#[doc(alias = "gst_codec_utils_aac_get_channels")]
pub fn codec_utils_aac_get_channels(audio_config: &[u8]) -> u32 {
assert_initialized_main_thread!();
let len = audio_config.len() as u32;
unsafe { ffi::gst_codec_utils_aac_get_channels(audio_config.to_glib_none().0, len) }
}
#[doc(alias = "gst_codec_utils_aac_get_index_from_sample_rate")]
pub fn codec_utils_aac_get_index_from_sample_rate(rate: u32) -> i32 {
assert_initialized_main_thread!();
unsafe { ffi::gst_codec_utils_aac_get_index_from_sample_rate(rate) }
}
#[doc(alias = "gst_codec_utils_aac_get_level")]
pub fn codec_utils_aac_get_level(audio_config: &[u8]) -> Result<glib::GString, glib::BoolError> {
assert_initialized_main_thread!();
let len = audio_config.len() as u32;
unsafe {
Option::<_>::from_glib_none(ffi::gst_codec_utils_aac_get_level(
audio_config.to_glib_none().0,
len,
))
.ok_or_else(|| glib::bool_error!("Failed to get AAC level"))
}
}
#[doc(alias = "gst_codec_utils_aac_get_profile")]
pub fn codec_utils_aac_get_profile(audio_config: &[u8]) -> Result<glib::GString, glib::BoolError> {
assert_initialized_main_thread!();
let len = audio_config.len() as u32;
unsafe {
Option::<_>::from_glib_none(ffi::gst_codec_utils_aac_get_profile(
audio_config.to_glib_none().0,
len,
))
.ok_or_else(|| glib::bool_error!("Failed to get AAC profile"))
}
}
#[cfg(any(feature = "v1_10", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_10")))]
#[doc(alias = "gst_codec_utils_aac_get_sample_rate")]
pub fn codec_utils_aac_get_sample_rate(audio_config: &[u8]) -> u32 {
assert_initialized_main_thread!();
let len = audio_config.len() as u32;
unsafe { ffi::gst_codec_utils_aac_get_sample_rate(audio_config.to_glib_none().0, len) }
}
#[doc(alias = "gst_codec_utils_aac_get_sample_rate_from_index")]
pub fn codec_utils_aac_get_sample_rate_from_index(sr_idx: u32) -> u32 {
assert_initialized_main_thread!();
unsafe { ffi::gst_codec_utils_aac_get_sample_rate_from_index(sr_idx) }
}
#[cfg(any(feature = "v1_20", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))]
#[doc(alias = "gst_codec_utils_caps_get_mime_codec")]
pub fn codec_utils_caps_get_mime_codec(caps: &gst::Caps) -> Result<glib::GString, glib::BoolError> {
assert_initialized_main_thread!();
unsafe {
Option::<_>::from_glib_full(ffi::gst_codec_utils_caps_get_mime_codec(
caps.to_glib_none().0,
))
.ok_or_else(|| glib::bool_error!("Unsupported caps"))
}
}
#[doc(alias = "gst_codec_utils_h264_get_level")]
pub fn codec_utils_h264_get_level(sps: &[u8]) -> Result<glib::GString, glib::BoolError> {
assert_initialized_main_thread!();
let len = sps.len() as u32;
unsafe {
Option::<_>::from_glib_none(ffi::gst_codec_utils_h264_get_level(
sps.to_glib_none().0,
len,
))
.ok_or_else(|| glib::bool_error!("Failed to get H264 level"))
}
}
#[doc(alias = "gst_codec_utils_h264_get_level_idc")]
pub fn codec_utils_h264_get_level_idc(level: &str) -> u8 {
assert_initialized_main_thread!();
unsafe { ffi::gst_codec_utils_h264_get_level_idc(level.to_glib_none().0) }
}
#[doc(alias = "gst_codec_utils_h264_get_profile")]
pub fn codec_utils_h264_get_profile(sps: &[u8]) -> Result<glib::GString, glib::BoolError> {
assert_initialized_main_thread!();
let len = sps.len() as u32;
unsafe {
Option::<_>::from_glib_none(ffi::gst_codec_utils_h264_get_profile(
sps.to_glib_none().0,
len,
))
.ok_or_else(|| glib::bool_error!("Failed to get H264 profile"))
}
}
#[doc(alias = "gst_codec_utils_h265_get_level")]
pub fn codec_utils_h265_get_level(
profile_tier_level: &[u8],
) -> Result<glib::GString, glib::BoolError> {
assert_initialized_main_thread!();
let len = profile_tier_level.len() as u32;
unsafe {
Option::<_>::from_glib_none(ffi::gst_codec_utils_h265_get_level(
profile_tier_level.to_glib_none().0,
len,
))
.ok_or_else(|| glib::bool_error!("Failed to get H265 level"))
}
}
#[doc(alias = "gst_codec_utils_h265_get_level_idc")]
pub fn codec_utils_h265_get_level_idc(level: &str) -> u8 {
assert_initialized_main_thread!();
unsafe { ffi::gst_codec_utils_h265_get_level_idc(level.to_glib_none().0) }
}
#[doc(alias = "gst_codec_utils_h265_get_profile")]
pub fn codec_utils_h265_get_profile(
profile_tier_level: &[u8],
) -> Result<glib::GString, glib::BoolError> {
assert_initialized_main_thread!();
let len = profile_tier_level.len() as u32;
unsafe {
Option::<_>::from_glib_none(ffi::gst_codec_utils_h265_get_profile(
profile_tier_level.to_glib_none().0,
len,
))
.ok_or_else(|| glib::bool_error!("Failed to get H265 profile"))
}
}
#[doc(alias = "gst_codec_utils_h265_get_tier")]
pub fn codec_utils_h265_get_tier(
profile_tier_level: &[u8],
) -> Result<glib::GString, glib::BoolError> {
assert_initialized_main_thread!();
let len = profile_tier_level.len() as u32;
unsafe {
Option::<_>::from_glib_none(ffi::gst_codec_utils_h265_get_tier(
profile_tier_level.to_glib_none().0,
len,
))
.ok_or_else(|| glib::bool_error!("Failed to get H265 tier"))
}
}
#[doc(alias = "gst_codec_utils_mpeg4video_get_level")]
pub fn codec_utils_mpeg4video_get_level(
vis_obj_seq: &[u8],
) -> Result<glib::GString, glib::BoolError> {
assert_initialized_main_thread!();
let len = vis_obj_seq.len() as u32;
unsafe {
Option::<_>::from_glib_none(ffi::gst_codec_utils_mpeg4video_get_level(
vis_obj_seq.to_glib_none().0,
len,
))
.ok_or_else(|| glib::bool_error!("Failed to get MPEG4 video level"))
}
}
#[doc(alias = "gst_codec_utils_mpeg4video_get_profile")]
pub fn codec_utils_mpeg4video_get_profile(
vis_obj_seq: &[u8],
) -> Result<glib::GString, glib::BoolError> {
assert_initialized_main_thread!();
let len = vis_obj_seq.len() as u32;
unsafe {
Option::<_>::from_glib_none(ffi::gst_codec_utils_mpeg4video_get_profile(
vis_obj_seq.to_glib_none().0,
len,
))
.ok_or_else(|| glib::bool_error!("Failed to get MPEG4 video profile"))
}
}
#[doc(alias = "gst_codec_utils_opus_create_caps_from_header")]
pub fn codec_utils_opus_create_caps_from_header(
header: &gst::Buffer,
comments: Option<&gst::Buffer>,
) -> Result<gst::Caps, glib::BoolError> {
assert_initialized_main_thread!();
unsafe {
Option::<_>::from_glib_full(ffi::gst_codec_utils_opus_create_caps_from_header(
header.to_glib_none().0,
comments.to_glib_none().0,
))
.ok_or_else(|| glib::bool_error!("Failed to create caps from Opus headers"))
}
}
#[doc(alias = "gst_encoding_list_all_targets")]
pub fn encoding_list_all_targets(categoryname: Option<&str>) -> Vec<EncodingTarget> {
assert_initialized_main_thread!();

View file

@ -1,7 +1,7 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use glib::translate::*;
use std::ptr;
use std::{mem, ptr};
pub unsafe trait CodecTag<'a>: gst::Tag<'a, TagType = &'a str> {}
@ -85,3 +85,324 @@ pub fn pb_utils_get_codec_description(
}
}
}
#[doc(alias = "gst_codec_utils_aac_caps_set_level_and_profile")]
pub fn codec_utils_aac_caps_set_level_and_profile(
caps: &mut gst::CapsRef,
audio_config: &[u8],
) -> Result<(), glib::BoolError> {
assert_initialized_main_thread!();
assert_eq!(caps.size(), 1);
let s = caps.structure(0).unwrap();
assert_eq!(s.name(), "audio/mpeg");
assert!(s
.get::<i32>("mpegversion")
.map_or(false, |v| v == 2 || v == 4));
let len = audio_config.len() as u32;
unsafe {
let res: bool = from_glib(ffi::gst_codec_utils_aac_caps_set_level_and_profile(
caps.as_mut_ptr(),
audio_config.to_glib_none().0,
len,
));
if res {
Ok(())
} else {
Err(glib::bool_error!("Failed to set AAC level/profile to caps"))
}
}
}
#[doc(alias = "gst_codec_utils_h264_caps_set_level_and_profile")]
pub fn codec_utils_h264_caps_set_level_and_profile(
caps: &mut gst::CapsRef,
sps: &[u8],
) -> Result<(), glib::BoolError> {
assert_initialized_main_thread!();
assert_eq!(caps.size(), 1);
let s = caps.structure(0).unwrap();
assert_eq!(s.name(), "video/x-h264");
let len = sps.len() as u32;
unsafe {
let res: bool = from_glib(ffi::gst_codec_utils_h264_caps_set_level_and_profile(
caps.as_mut_ptr(),
sps.to_glib_none().0,
len,
));
if res {
Ok(())
} else {
Err(glib::bool_error!(
"Failed to set H264 level/profile to caps"
))
}
}
}
#[cfg(any(feature = "v1_20", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))]
#[doc(alias = "gst_codec_utils_h264_get_profile_flags_level")]
pub fn codec_utils_h264_get_profile_flags_level(
codec_data: &[u8],
) -> Result<(u8, u8, u8), glib::BoolError> {
assert_initialized_main_thread!();
let len = codec_data.len() as u32;
unsafe {
let mut profile = mem::MaybeUninit::uninit();
let mut flags = mem::MaybeUninit::uninit();
let mut level = mem::MaybeUninit::uninit();
glib::result_from_gboolean!(
ffi::gst_codec_utils_h264_get_profile_flags_level(
codec_data.to_glib_none().0,
len,
profile.as_mut_ptr(),
flags.as_mut_ptr(),
level.as_mut_ptr()
),
"Failed to get H264 profile, flags and level"
)?;
let profile = profile.assume_init();
let flags = flags.assume_init();
let level = level.assume_init();
Ok((profile, flags, level))
}
}
#[doc(alias = "gst_codec_utils_h265_caps_set_level_tier_and_profile")]
pub fn codec_utils_h265_caps_set_level_tier_and_profile(
caps: &mut gst::CapsRef,
profile_tier_level: &[u8],
) -> Result<(), glib::BoolError> {
assert_initialized_main_thread!();
assert_eq!(caps.size(), 1);
let s = caps.structure(0).unwrap();
assert_eq!(s.name(), "video/x-h265");
let len = profile_tier_level.len() as u32;
unsafe {
let res: bool = from_glib(ffi::gst_codec_utils_h265_caps_set_level_tier_and_profile(
caps.as_mut_ptr(),
profile_tier_level.to_glib_none().0,
len,
));
if res {
Ok(())
} else {
Err(glib::bool_error!(
"Failed to set H265 level/tier/profile to caps"
))
}
}
}
#[doc(alias = "gst_codec_utils_mpeg4video_caps_set_level_and_profile")]
pub fn codec_utils_mpeg4video_caps_set_level_and_profile(
caps: &mut gst::CapsRef,
vis_obj_seq: &[u8],
) -> Result<(), glib::BoolError> {
assert_initialized_main_thread!();
assert_eq!(caps.size(), 1);
let s = caps.structure(0).unwrap();
assert_eq!(s.name(), "video/mpeg");
assert!(s.get::<i32>("mpegversion").map_or(false, |v| v == 4));
let len = vis_obj_seq.len() as u32;
unsafe {
let res: bool = from_glib(ffi::gst_codec_utils_mpeg4video_caps_set_level_and_profile(
caps.as_mut_ptr(),
vis_obj_seq.to_glib_none().0,
len,
));
if res {
Ok(())
} else {
Err(glib::bool_error!(
"Failed to set MPEG4 video level/profile to caps"
))
}
}
}
#[doc(alias = "gst_codec_utils_opus_create_caps")]
pub fn codec_utils_opus_create_caps(
rate: u32,
channels: u8,
channel_mapping_family: u8,
stream_count: u8,
coupled_count: u8,
channel_mapping: &[u8],
) -> Result<gst::Caps, glib::BoolError> {
assert_initialized_main_thread!();
assert!(channel_mapping.is_empty() || channel_mapping.len() == channels as usize);
unsafe {
let caps = ffi::gst_codec_utils_opus_create_caps(
rate,
channels,
channel_mapping_family,
stream_count,
coupled_count,
if channel_mapping.is_empty() {
ptr::null()
} else {
channel_mapping.to_glib_none().0
},
);
if caps.is_null() {
Err(glib::bool_error!(
"Failed to create caps from Opus configuration"
))
} else {
Ok(from_glib_full(caps))
}
}
}
#[doc(alias = "gst_codec_utils_opus_create_header")]
#[allow(clippy::too_many_arguments)]
pub fn codec_utils_opus_create_header(
rate: u32,
channels: u8,
channel_mapping_family: u8,
stream_count: u8,
coupled_count: u8,
channel_mapping: &[u8],
pre_skip: u16,
output_gain: i16,
) -> Result<gst::Buffer, glib::BoolError> {
assert_initialized_main_thread!();
assert!(channel_mapping.is_empty() || channel_mapping.len() == channels as usize);
unsafe {
let header = ffi::gst_codec_utils_opus_create_header(
rate,
channels,
channel_mapping_family,
stream_count,
coupled_count,
if channel_mapping.is_empty() {
ptr::null()
} else {
channel_mapping.to_glib_none().0
},
pre_skip,
output_gain,
);
if header.is_null() {
Err(glib::bool_error!(
"Failed to create header from Opus configuration"
))
} else {
Ok(from_glib_full(header))
}
}
}
#[doc(alias = "gst_codec_utils_opus_parse_caps")]
pub fn codec_utils_opus_parse_caps(
caps: &gst::Caps,
channel_mapping: Option<&mut [u8; 256]>,
) -> Result<(u32, u8, u8, u8, u8), glib::BoolError> {
assert_initialized_main_thread!();
unsafe {
let mut rate = mem::MaybeUninit::uninit();
let mut channels = mem::MaybeUninit::uninit();
let mut channel_mapping_family = mem::MaybeUninit::uninit();
let mut stream_count = mem::MaybeUninit::uninit();
let mut coupled_count = mem::MaybeUninit::uninit();
let res: bool = from_glib(ffi::gst_codec_utils_opus_parse_caps(
mut_override(caps.as_ptr()),
rate.as_mut_ptr(),
channels.as_mut_ptr(),
channel_mapping_family.as_mut_ptr(),
stream_count.as_mut_ptr(),
coupled_count.as_mut_ptr(),
if let Some(channel_mapping) = channel_mapping {
channel_mapping.as_mut_ptr() as *mut [u8; 256]
} else {
ptr::null_mut()
},
));
if res {
Ok((
rate.assume_init(),
channels.assume_init(),
channel_mapping_family.assume_init(),
stream_count.assume_init(),
coupled_count.assume_init(),
))
} else {
Err(glib::bool_error!("Failed to parse Opus caps"))
}
}
}
#[doc(alias = "gst_codec_utils_opus_parse_header")]
#[allow(clippy::type_complexity)]
pub fn codec_utils_opus_parse_header(
header: &gst::Buffer,
channel_mapping: Option<&mut [u8; 256]>,
) -> Result<(u32, u8, u8, u8, u8, u16, i16), glib::BoolError> {
assert_initialized_main_thread!();
unsafe {
let mut rate = mem::MaybeUninit::uninit();
let mut channels = mem::MaybeUninit::uninit();
let mut channel_mapping_family = mem::MaybeUninit::uninit();
let mut stream_count = mem::MaybeUninit::uninit();
let mut coupled_count = mem::MaybeUninit::uninit();
let mut pre_skip = mem::MaybeUninit::uninit();
let mut output_gain = mem::MaybeUninit::uninit();
let res: bool = from_glib(ffi::gst_codec_utils_opus_parse_header(
mut_override(header.as_ptr()),
rate.as_mut_ptr(),
channels.as_mut_ptr(),
channel_mapping_family.as_mut_ptr(),
stream_count.as_mut_ptr(),
coupled_count.as_mut_ptr(),
if let Some(channel_mapping) = channel_mapping {
channel_mapping.as_mut_ptr() as *mut [u8; 256]
} else {
ptr::null_mut()
},
pre_skip.as_mut_ptr(),
output_gain.as_mut_ptr(),
));
if res {
Ok((
rate.assume_init(),
channels.assume_init(),
channel_mapping_family.assume_init(),
stream_count.assume_init(),
coupled_count.assume_init(),
pre_skip.assume_init(),
output_gain.assume_init(),
))
} else {
Err(glib::bool_error!("Failed to parse Opus header"))
}
}
}