forked from mirrors/gstreamer-rs
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]
|
[object.function.return]
|
||||||
nullable = false
|
nullable = false
|
||||||
|
|
||||||
|
[[object.function]]
|
||||||
|
name = "get_element_properties"
|
||||||
|
# Use custom wrapper types
|
||||||
|
manual = true
|
||||||
|
|
||||||
[[object.property]]
|
[[object.property]]
|
||||||
name = "restriction-caps"
|
name = "restriction-caps"
|
||||||
# encodingprofile is immutable after constructed
|
# encodingprofile is immutable after constructed
|
||||||
|
|
|
@ -80,12 +80,6 @@ pub trait EncodingProfileExt: 'static {
|
||||||
#[doc(alias = "get_description")]
|
#[doc(alias = "get_description")]
|
||||||
fn description(&self) -> Option<glib::GString>;
|
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 = "gst_encoding_profile_get_file_extension")]
|
||||||
#[doc(alias = "get_file_extension")]
|
#[doc(alias = "get_file_extension")]
|
||||||
fn file_extension(&self) -> Option<glib::GString>;
|
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> {
|
fn file_extension(&self) -> Option<glib::GString> {
|
||||||
unsafe {
|
unsafe {
|
||||||
from_glib_none(ffi::gst_encoding_profile_get_file_extension(
|
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::EncodingProfile;
|
||||||
use crate::auto::EncodingVideoProfile;
|
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 {
|
trait EncodingProfileBuilderCommon {
|
||||||
fn set_allow_dynamic_output(&self, allow_dynamic_output: bool);
|
fn set_allow_dynamic_output(&self, allow_dynamic_output: bool);
|
||||||
|
|
||||||
|
@ -27,6 +51,9 @@ trait EncodingProfileBuilderCommon {
|
||||||
|
|
||||||
#[cfg(feature = "v1_18")]
|
#[cfg(feature = "v1_18")]
|
||||||
fn set_single_segment(&self, single_segment: bool);
|
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 {
|
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
|
// Split the trait as only the getter is public
|
||||||
|
@ -294,6 +332,8 @@ struct EncodingProfileBuilderCommonData<'a> {
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
#[cfg(feature = "v1_18")]
|
#[cfg(feature = "v1_18")]
|
||||||
single_segment: bool,
|
single_segment: bool,
|
||||||
|
#[cfg(feature = "v1_20")]
|
||||||
|
element_properties: Option<ElementProperties>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> EncodingProfileBuilderCommonData<'a> {
|
impl<'a> EncodingProfileBuilderCommonData<'a> {
|
||||||
|
@ -310,6 +350,8 @@ impl<'a> EncodingProfileBuilderCommonData<'a> {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
#[cfg(feature = "v1_18")]
|
#[cfg(feature = "v1_18")]
|
||||||
single_segment: false,
|
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")]
|
#[doc(alias = "gst_encoding_profile_set_single_segment")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn single_segment(self, single_segment: bool) -> Self;
|
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(
|
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.base.single_segment = single_segment;
|
||||||
self
|
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);
|
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)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -43,6 +43,11 @@ mod auto;
|
||||||
pub use crate::auto::functions::*;
|
pub use crate::auto::functions::*;
|
||||||
pub use crate::auto::*;
|
pub use crate::auto::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "v1_20")]
|
||||||
|
mod element_properties;
|
||||||
|
#[cfg(feature = "v1_20")]
|
||||||
|
pub use crate::element_properties::ElementProperties;
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
mod flag_serde;
|
mod flag_serde;
|
||||||
|
|
||||||
|
@ -70,7 +75,7 @@ pub mod prelude {
|
||||||
pub use crate::audio_visualizer::*;
|
pub use crate::audio_visualizer::*;
|
||||||
pub use crate::auto::traits::*;
|
pub use crate::auto::traits::*;
|
||||||
pub use crate::encoding_profile::{
|
pub use crate::encoding_profile::{
|
||||||
EncodingProfileBuilder, EncodingProfileHasRestrictionGetter,
|
EncodingProfileBuilder, EncodingProfileExtManual, EncodingProfileHasRestrictionGetter,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::functions::CodecTag;
|
pub use crate::functions::CodecTag;
|
||||||
|
|
Loading…
Reference in a new issue