pbutils/encoding_profile: Add support for 1.20 element-properties API

This commit is contained in:
SeaDve 2022-08-30 17:35:03 +08:00 committed by Sebastian Dröge
parent 8a6de3ca4f
commit 59efe09fe5
5 changed files with 307 additions and 17 deletions

View file

@ -393,6 +393,11 @@ status = "generate"
[object.function.return]
nullable = false
[[object.function]]
name = "get_element_properties"
# Use custom wrapper types
manual = true
[[object.property]]
name = "restriction-caps"
# encodingprofile is immutable after constructed

View file

@ -80,12 +80,6 @@ pub trait EncodingProfileExt: 'static {
#[doc(alias = "get_description")]
fn description(&self) -> Option<glib::GString>;
#[cfg(any(feature = "v1_20", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))]
#[doc(alias = "gst_encoding_profile_get_element_properties")]
#[doc(alias = "get_element_properties")]
fn element_properties(&self) -> Option<gst::Structure>;
#[doc(alias = "gst_encoding_profile_get_file_extension")]
#[doc(alias = "get_file_extension")]
fn file_extension(&self) -> Option<glib::GString>;
@ -164,16 +158,6 @@ impl<O: IsA<EncodingProfile>> EncodingProfileExt for O {
}
}
#[cfg(any(feature = "v1_20", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))]
fn element_properties(&self) -> Option<gst::Structure> {
unsafe {
from_glib_full(ffi::gst_encoding_profile_get_element_properties(
self.as_ref().to_glib_none().0,
))
}
}
fn file_extension(&self) -> Option<glib::GString> {
unsafe {
from_glib_none(ffi::gst_encoding_profile_get_file_extension(

View file

@ -0,0 +1,238 @@
use gst::prelude::*;
use std::ops::Deref;
// rustdoc-stripper-ignore-next
/// Wrapper around `gst::Structure` for `element-properties`
/// property of `EncodingProfile`.
///
/// # Examples
///
/// ```rust
/// # use gstreamer_pbutils::ElementProperties;
/// # gst::init().unwrap();
/// ElementProperties::builder_general()
/// .field("threads", 16)
/// .build();
/// ```
///
/// ```rust
/// # use gstreamer_pbutils::ElementProperties;
/// # gst::init().unwrap();
/// ElementProperties::builder_map()
/// .item(
/// gst::Structure::builder("vp8enc")
/// .field("max-quantizer", 17)
/// .field("buffer-size", 20000)
/// .field("threads", 16)
/// .build(),
/// )
/// .build();
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ElementProperties(pub(crate) gst::Structure);
impl Default for ElementProperties {
fn default() -> Self {
Self::builder_general().build()
}
}
impl Deref for ElementProperties {
type Target = gst::StructureRef;
fn deref(&self) -> &gst::StructureRef {
self.0.as_ref()
}
}
impl From<ElementProperties> for gst::Structure {
fn from(e: ElementProperties) -> Self {
skip_assert_initialized!();
e.into_inner()
}
}
impl ElementProperties {
// rustdoc-stripper-ignore-next
/// Creates an `ElementProperties` builder that build into
/// something similar to the following:
///
/// [element-properties, boolean-prop=true, string-prop="hi"]
pub fn builder_general() -> ElementPropertiesGeneralBuilder {
assert_initialized_main_thread!();
ElementPropertiesGeneralBuilder {
structure: gst::Structure::new_empty("element-properties"),
}
}
// rustdoc-stripper-ignore-next
/// Creates an `ElementProperties` builder that build into
/// something similar to the following:
///
/// element-properties-map, map = {
/// [openh264enc, gop-size=32, ],
/// [x264enc, key-int-max=32, tune=zerolatency],
/// }
pub fn builder_map() -> ElementPropertiesMapBuilder {
assert_initialized_main_thread!();
ElementPropertiesMapBuilder { map: Vec::new() }
}
// rustdoc-stripper-ignore-next
/// Returns true if self is built with `ElementPropertiesGeneralBuilder`.
pub fn is_general(&self) -> bool {
let structure_name = self.0.name();
if structure_name != "element-properties" {
assert_eq!(structure_name, "element-properties-map");
return false;
}
true
}
// rustdoc-stripper-ignore-next
/// Returns true if self is built with `ElementPropertiesMapBuilder`.
pub fn is_map(&self) -> bool {
!self.is_general()
}
// rustdoc-stripper-ignore-next
/// Returns the inner list of `gst::Structure` if self is_general()
/// or `None` if self is_map().
pub fn map(&self) -> Option<Vec<gst::Structure>> {
if !self.is_map() {
return None;
}
Some(
self.0
.get::<gst::List>("map")
.unwrap()
.as_slice()
.iter()
.map(|props_map| props_map.get::<gst::Structure>().unwrap())
.collect::<Vec<_>>(),
)
}
pub fn into_inner(self) -> gst::Structure {
self.0
}
}
#[must_use = "The builder must be built to be used"]
#[derive(Debug, Clone)]
pub struct ElementPropertiesGeneralBuilder {
structure: gst::Structure,
}
impl ElementPropertiesGeneralBuilder {
pub fn field<T>(mut self, property_name: &str, value: T) -> Self
where
T: ToSendValue + Sync,
{
self.structure.set(property_name, value);
self
}
pub fn build(self) -> ElementProperties {
ElementProperties(self.structure)
}
}
#[must_use = "The builder must be built to be used"]
#[derive(Debug, Clone)]
pub struct ElementPropertiesMapBuilder {
map: Vec<glib::SendValue>,
}
impl ElementPropertiesMapBuilder {
// rustdoc-stripper-ignore-next
/// Insert a new `element-properties-map` map item.
///
/// The `structure`s name is the element factory's name
/// and each field corresponds to a property-value pair.
pub fn item(mut self, structure: gst::Structure) -> Self {
self.map.push(structure.to_send_value());
self
}
pub fn build(self) -> ElementProperties {
ElementProperties(
gst::Structure::builder("element-properties-map")
.field("map", gst::List::from(self.map))
.build(),
)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn element_properties_getters() {
gst::init().unwrap();
let elem_props_general = ElementProperties::builder_general()
.field("string-prop", "hi")
.field("boolean-prop", true)
.build();
assert!(elem_props_general.is_general());
assert!(!elem_props_general.is_map());
assert_eq!(elem_props_general.map(), None);
let elem_factory_props_map = gst::Structure::builder("vp8enc")
.field("cq-level", 13)
.field("resize-allowed", false)
.build();
let elem_props_map = ElementProperties::builder_map()
.item(elem_factory_props_map.clone())
.build();
assert!(elem_props_map.is_map());
assert!(!elem_props_map.is_general());
assert_eq!(elem_props_map.map(), Some(vec![elem_factory_props_map]));
}
#[test]
fn element_properties_general_builder() {
gst::init().unwrap();
let elem_props = ElementProperties::builder_general()
.field("string-prop", "hi")
.field("boolean-prop", true)
.build();
assert_eq!(elem_props.n_fields(), 2);
assert_eq!(elem_props.name(), "element-properties");
assert_eq!(elem_props.get::<String>("string-prop").unwrap(), "hi");
assert!(elem_props.get::<bool>("boolean-prop").unwrap());
}
#[test]
fn element_properties_map_builder() {
gst::init().unwrap();
let props_map = gst::Structure::builder("vp8enc")
.field("cq-level", 13)
.field("resize-allowed", false)
.build();
assert_eq!(props_map.n_fields(), 2);
assert_eq!(props_map.name(), "vp8enc");
assert_eq!(props_map.get::<i32>("cq-level").unwrap(), 13);
assert!(!props_map.get::<bool>("resize-allowed").unwrap());
let elem_props = ElementProperties::builder_map()
.item(props_map.clone())
.build();
assert_eq!(elem_props.n_fields(), 1);
let list = elem_props.map().unwrap();
assert_eq!(list.len(), 1);
assert_eq!(list.get(0).unwrap(), &props_map);
}
}

View file

@ -8,6 +8,30 @@ use crate::auto::EncodingContainerProfile;
use crate::auto::EncodingProfile;
use crate::auto::EncodingVideoProfile;
#[cfg(feature = "v1_20")]
use crate::ElementProperties;
pub trait EncodingProfileExtManual {
#[cfg(any(feature = "v1_20", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))]
#[doc(alias = "gst_encoding_profile_get_element_properties")]
#[doc(alias = "get_element_properties")]
fn element_properties(&self) -> Option<ElementProperties>;
}
impl<O: IsA<EncodingProfile>> EncodingProfileExtManual for O {
#[cfg(any(feature = "v1_20", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))]
fn element_properties(&self) -> Option<ElementProperties> {
unsafe {
from_glib_full::<_, Option<_>>(ffi::gst_encoding_profile_get_element_properties(
self.as_ref().to_glib_none().0,
))
.map(ElementProperties)
}
}
}
trait EncodingProfileBuilderCommon {
fn set_allow_dynamic_output(&self, allow_dynamic_output: bool);
@ -27,6 +51,9 @@ trait EncodingProfileBuilderCommon {
#[cfg(feature = "v1_18")]
fn set_single_segment(&self, single_segment: bool);
#[cfg(feature = "v1_20")]
fn set_element_properties(&self, element_properties: ElementProperties);
}
impl<O: IsA<EncodingProfile>> EncodingProfileBuilderCommon for O {
@ -115,6 +142,17 @@ impl<O: IsA<EncodingProfile>> EncodingProfileBuilderCommon for O {
);
}
}
// checker-ignore-item
#[cfg(feature = "v1_20")]
fn set_element_properties(&self, element_properties: ElementProperties) {
unsafe {
ffi::gst_encoding_profile_set_element_properties(
self.as_ref().to_glib_none().0,
element_properties.into_inner().into_glib_ptr(),
);
}
}
}
// Split the trait as only the getter is public
@ -294,6 +332,8 @@ struct EncodingProfileBuilderCommonData<'a> {
enabled: bool,
#[cfg(feature = "v1_18")]
single_segment: bool,
#[cfg(feature = "v1_20")]
element_properties: Option<ElementProperties>,
}
impl<'a> EncodingProfileBuilderCommonData<'a> {
@ -310,6 +350,8 @@ impl<'a> EncodingProfileBuilderCommonData<'a> {
enabled: true,
#[cfg(feature = "v1_18")]
single_segment: false,
#[cfg(feature = "v1_20")]
element_properties: None,
}
}
}
@ -340,6 +382,10 @@ pub trait EncodingProfileBuilder<'a>: Sized {
#[doc(alias = "gst_encoding_profile_set_single_segment")]
#[must_use]
fn single_segment(self, single_segment: bool) -> Self;
#[cfg(feature = "v1_20")]
#[doc(alias = "gst_encoding_profile_set_element_properties")]
#[must_use]
fn element_properties(self, element_properties: ElementProperties) -> Self;
}
macro_rules! declare_encoding_profile_builder_common(
@ -385,6 +431,12 @@ macro_rules! declare_encoding_profile_builder_common(
self.base.single_segment = single_segment;
self
}
#[cfg(feature = "v1_20")]
fn element_properties(mut self, element_properties: ElementProperties) -> $name<'a> {
self.base.element_properties = Some(element_properties);
self
}
}
}
);
@ -405,6 +457,12 @@ fn set_common_fields<T: EncodingProfileBuilderCommon>(
{
profile.set_single_segment(base_data.single_segment);
}
#[cfg(feature = "v1_20")]
{
if let Some(ref element_properties) = base_data.element_properties {
profile.set_element_properties(element_properties.clone());
}
}
}
#[derive(Debug)]

View file

@ -43,6 +43,11 @@ mod auto;
pub use crate::auto::functions::*;
pub use crate::auto::*;
#[cfg(feature = "v1_20")]
mod element_properties;
#[cfg(feature = "v1_20")]
pub use crate::element_properties::ElementProperties;
#[cfg(feature = "serde")]
mod flag_serde;
@ -70,7 +75,7 @@ pub mod prelude {
pub use crate::audio_visualizer::*;
pub use crate::auto::traits::*;
pub use crate::encoding_profile::{
EncodingProfileBuilder, EncodingProfileHasRestrictionGetter,
EncodingProfileBuilder, EncodingProfileExtManual, EncodingProfileHasRestrictionGetter,
};
pub use crate::functions::CodecTag;