mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2024-11-25 19:11:06 +00:00
pbutils/encoding_profile: Add support for 1.20 element-properties API
This commit is contained in:
parent
8a6de3ca4f
commit
59efe09fe5
5 changed files with 307 additions and 17 deletions
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
238
gstreamer-pbutils/src/element_properties.rs
Normal file
238
gstreamer-pbutils/src/element_properties.rs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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)]
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue