Add support for CapsFeatures

Fixes https://github.com/sdroege/gstreamer-rs/issues/13
This commit is contained in:
Sebastian Dröge 2018-09-28 12:00:08 +03:00
parent 857ed8609c
commit 564f9faf84
5 changed files with 1049 additions and 73 deletions

View file

@ -6,8 +6,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use caps_features::*;
use miniobject::*; use miniobject::*;
use std::fmt; use std::fmt;
use std::ptr;
use std::str; use std::str;
use structure::*; use structure::*;
@ -68,12 +70,27 @@ impl GstRc<CapsRef> {
unsafe { from_glib_full(ffi::gst_caps_merge(caps.into_ptr(), other.into_ptr())) } unsafe { from_glib_full(ffi::gst_caps_merge(caps.into_ptr(), other.into_ptr())) }
} }
pub fn merge_structure(caps: Self, other: Structure) -> Self { pub fn merge_structure(caps: Self, structure: Structure) -> Self {
skip_assert_initialized!(); skip_assert_initialized!();
unsafe { unsafe {
from_glib_full(ffi::gst_caps_merge_structure( from_glib_full(ffi::gst_caps_merge_structure(
caps.into_ptr(), caps.into_ptr(),
other.into_ptr(), structure.into_ptr(),
))
}
}
pub fn merge_structure_full(
caps: Self,
structure: Structure,
features: Option<CapsFeatures>,
) -> Self {
skip_assert_initialized!();
unsafe {
from_glib_full(ffi::gst_caps_merge_structure_full(
caps.into_ptr(),
structure.into_ptr(),
features.map(|f| f.into_ptr()).unwrap_or(ptr::null_mut()),
)) ))
} }
} }
@ -133,9 +150,7 @@ impl CapsRef {
return None; return None;
} }
Some(StructureRef::from_glib_borrow( Some(StructureRef::from_glib_borrow(structure))
structure as *const ffi::GstStructure,
))
} }
} }
@ -150,9 +165,41 @@ impl CapsRef {
return None; return None;
} }
Some(StructureRef::from_glib_borrow_mut( Some(StructureRef::from_glib_borrow_mut(structure))
structure as *mut ffi::GstStructure, }
)) }
pub fn get_features(&self, idx: u32) -> Option<&CapsFeaturesRef> {
if idx >= self.get_size() {
return None;
}
unsafe {
let features = ffi::gst_caps_get_features(self.as_ptr(), idx);
Some(CapsFeaturesRef::from_glib_borrow(features))
}
}
pub fn get_mut_features(&mut self, idx: u32) -> Option<&mut CapsFeaturesRef> {
if idx >= self.get_size() {
return None;
}
unsafe {
let features = ffi::gst_caps_get_features(self.as_ptr(), idx);
Some(CapsFeaturesRef::from_glib_borrow_mut(features))
}
}
pub fn set_features(&mut self, idx: u32, features: Option<CapsFeatures>) {
assert!(idx < self.get_size());
unsafe {
ffi::gst_caps_set_features(
self.as_mut_ptr(),
idx,
features.map(|f| f.into_ptr()).unwrap_or(ptr::null_mut()),
)
} }
} }
@ -168,10 +215,28 @@ impl CapsRef {
IterMut::new(self) IterMut::new(self)
} }
pub fn iter_with_features(&self) -> IterFeatures {
IterFeatures::new(self)
}
pub fn iter_with_features_mut(&mut self) -> IterFeaturesMut {
IterFeaturesMut::new(self)
}
pub fn append_structure(&mut self, structure: Structure) { pub fn append_structure(&mut self, structure: Structure) {
unsafe { ffi::gst_caps_append_structure(self.as_mut_ptr(), structure.into_ptr()) } unsafe { ffi::gst_caps_append_structure(self.as_mut_ptr(), structure.into_ptr()) }
} }
pub fn append_structure_full(&mut self, structure: Structure, features: Option<CapsFeatures>) {
unsafe {
ffi::gst_caps_append_structure_full(
self.as_mut_ptr(),
structure.into_ptr(),
features.map(|f| f.into_ptr()).unwrap_or(ptr::null_mut()),
)
}
}
pub fn remove_structure(&mut self, idx: u32) { pub fn remove_structure(&mut self, idx: u32) {
unsafe { ffi::gst_caps_remove_structure(self.as_mut_ptr(), idx) } unsafe { ffi::gst_caps_remove_structure(self.as_mut_ptr(), idx) }
} }
@ -250,6 +315,20 @@ impl CapsRef {
} }
} }
pub fn is_subset_structure_full(
&self,
structure: &StructureRef,
features: Option<&CapsFeaturesRef>,
) -> bool {
unsafe {
from_glib(ffi::gst_caps_is_subset_structure_full(
self.as_ptr(),
structure.as_ptr(),
features.map(|f| f.as_ptr()).unwrap_or(ptr::null()),
))
}
}
pub fn subtract(&self, other: &Self) -> Caps { pub fn subtract(&self, other: &Self) -> Caps {
skip_assert_initialized!(); skip_assert_initialized!();
unsafe { unsafe {
@ -268,7 +347,7 @@ impl glib::types::StaticType for CapsRef {
} }
macro_rules! define_iter( macro_rules! define_iter(
($name:ident, $typ:ty, $styp:ty) => { ($name:ident, $typ:ty, $styp:ty, $get_item:expr) => {
pub struct $name<'a> { pub struct $name<'a> {
caps: $typ, caps: $typ,
idx: u32, idx: u32,
@ -297,15 +376,13 @@ macro_rules! define_iter(
} }
unsafe { unsafe {
let structure = ffi::gst_caps_get_structure(self.caps.as_ptr(), self.idx); let item = $get_item(self.caps, self.idx);
if structure.is_null() { if item.is_none() {
return None; return None;
} }
self.idx += 1; self.idx += 1;
Some(StructureRef::from_glib_borrow_mut( item
structure as *mut ffi::GstStructure,
))
} }
} }
@ -329,14 +406,7 @@ macro_rules! define_iter(
self.n_structures -= 1; self.n_structures -= 1;
unsafe { unsafe {
let structure = ffi::gst_caps_get_structure(self.caps.as_ptr(), self.n_structures); $get_item(self.caps, self.n_structures)
if structure.is_null() {
return None;
}
Some(StructureRef::from_glib_borrow_mut(
structure as *mut ffi::GstStructure,
))
} }
} }
} }
@ -345,8 +415,70 @@ macro_rules! define_iter(
} }
); );
define_iter!(Iter, &'a CapsRef, &'a StructureRef); define_iter!(
define_iter!(IterMut, &'a mut CapsRef, &'a mut StructureRef); Iter,
&'a CapsRef,
&'a StructureRef,
|caps: &CapsRef, idx| {
let ptr = ffi::gst_caps_get_structure(caps.as_ptr(), idx);
if ptr.is_null() {
None
} else {
Some(StructureRef::from_glib_borrow(
ptr as *const ffi::GstStructure,
))
}
}
);
define_iter!(
IterMut,
&'a mut CapsRef,
&'a mut StructureRef,
|caps: &CapsRef, idx| {
let ptr = ffi::gst_caps_get_structure(caps.as_ptr(), idx);
if ptr.is_null() {
None
} else {
Some(StructureRef::from_glib_borrow_mut(
ptr as *mut ffi::GstStructure,
))
}
}
);
define_iter!(
IterFeatures,
&'a CapsRef,
(&'a StructureRef, &'a CapsFeaturesRef),
|caps: &CapsRef, idx| {
let ptr1 = ffi::gst_caps_get_structure(caps.as_ptr(), idx);
let ptr2 = ffi::gst_caps_get_features(caps.as_ptr(), idx);
if ptr1.is_null() || ptr2.is_null() {
None
} else {
Some((
StructureRef::from_glib_borrow(ptr1 as *const ffi::GstStructure),
CapsFeaturesRef::from_glib_borrow(ptr2 as *const ffi::GstCapsFeatures),
))
}
}
);
define_iter!(
IterFeaturesMut,
&'a mut CapsRef,
(&'a mut StructureRef, &'a mut CapsFeaturesRef),
|caps: &CapsRef, idx| {
let ptr1 = ffi::gst_caps_get_structure(caps.as_ptr(), idx);
let ptr2 = ffi::gst_caps_get_features(caps.as_ptr(), idx);
if ptr1.is_null() || ptr2.is_null() {
None
} else {
Some((
StructureRef::from_glib_borrow_mut(ptr1 as *mut ffi::GstStructure),
CapsFeaturesRef::from_glib_borrow_mut(ptr2 as *mut ffi::GstCapsFeatures),
))
}
}
);
impl fmt::Debug for CapsRef { impl fmt::Debug for CapsRef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -379,25 +511,47 @@ impl ToOwned for CapsRef {
unsafe impl Sync for CapsRef {} unsafe impl Sync for CapsRef {}
unsafe impl Send for CapsRef {} unsafe impl Send for CapsRef {}
pub struct Builder { pub struct Builder<'a> {
s: ::Structure, s: ::Structure,
features: Option<&'a [&'a str]>,
any_features: bool,
} }
impl Builder { impl<'a> Builder<'a> {
fn new(name: &str) -> Self { fn new<'b>(name: &'b str) -> Builder<'a> {
Builder { Builder {
s: ::Structure::new_empty(name), s: ::Structure::new_empty(name),
features: None,
any_features: false,
} }
} }
pub fn field<V: ToSendValue>(mut self, name: &str, value: &V) -> Self { pub fn field<'b, V: ToSendValue>(mut self, name: &'b str, value: &'b V) -> Self {
self.s.set(name, value); self.s.set(name, value);
self self
} }
pub fn features(mut self, features: &'a [&'a str]) -> Self {
self.features = Some(features);
self
}
pub fn any_features(mut self) -> Self {
self.any_features = true;
self
}
pub fn build(self) -> Caps { pub fn build(self) -> Caps {
let mut caps = Caps::new_empty(); let mut caps = Caps::new_empty();
caps.get_mut().unwrap().append_structure(self.s); let features = if self.any_features {
Some(CapsFeatures::new_any())
} else {
self.features.map(|f| CapsFeatures::new(f))
};
caps.get_mut()
.unwrap()
.append_structure_full(self.s, features);
caps caps
} }
} }
@ -412,7 +566,7 @@ mod tests {
fn test_simple() { fn test_simple() {
::init().unwrap(); ::init().unwrap();
let caps = Caps::new_simple( let mut caps = Caps::new_simple(
"foo/bar", "foo/bar",
&[ &[
("int", &12), ("int", &12),
@ -427,19 +581,36 @@ mod tests {
"foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, fraction=(fraction)1/2, array=(int)< 1, 2 >" "foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, fraction=(fraction)1/2, array=(int)< 1, 2 >"
); );
let s = caps.get_structure(0).unwrap(); {
assert_eq!( let s = caps.get_structure(0).unwrap();
s, assert_eq!(
Structure::new( s,
"foo/bar", Structure::new(
&[ "foo/bar",
("int", &12), &[
("bool", &true), ("int", &12),
("string", &"bla"), ("bool", &true),
("fraction", &Fraction::new(1, 2)), ("string", &"bla"),
("array", &Array::new(&[&1, &2])), ("fraction", &Fraction::new(1, 2)),
], ("array", &Array::new(&[&1, &2])),
).as_ref() ],
).as_ref()
);
}
assert!(
caps.get_features(0)
.unwrap()
.is_equal(::CAPS_FEATURES_MEMORY_SYSTEM_MEMORY.as_ref())
);
{
let caps = caps.get_mut().unwrap();
caps.set_features(0, Some(CapsFeatures::new(&["foo:bla"])));
}
assert!(
caps.get_features(0)
.unwrap()
.is_equal(CapsFeatures::new(&["foo:bla"]).as_ref())
); );
} }
@ -458,5 +629,17 @@ mod tests {
caps.to_string(), caps.to_string(),
"foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, fraction=(fraction)1/2, array=(int)< 1, 2 >" "foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, fraction=(fraction)1/2, array=(int)< 1, 2 >"
); );
let caps = Caps::builder("foo/bar")
.field("int", &12)
.any_features()
.build();
assert_eq!(caps.to_string(), "foo/bar(ANY), int=(int)12");
let caps = Caps::builder("foo/bar")
.field("int", &12)
.features(&["foo:bla", "foo:baz"])
.build();
assert_eq!(caps.to_string(), "foo/bar(foo:bla, foo:baz), int=(int)12");
} }
} }

View file

@ -0,0 +1,472 @@
// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::borrow::{Borrow, BorrowMut, ToOwned};
use std::ffi::CStr;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::str;
use ffi;
use glib;
use glib::translate::{
from_glib, from_glib_full, from_glib_none, FromGlibPtrFull, FromGlibPtrNone, GlibPtrDefault,
Stash, StashMut, ToGlibPtr, ToGlibPtrMut,
};
use glib_ffi::gpointer;
use gobject_ffi;
pub struct CapsFeatures(ptr::NonNull<CapsFeaturesRef>, PhantomData<CapsFeaturesRef>);
unsafe impl Send for CapsFeatures {}
unsafe impl Sync for CapsFeatures {}
impl CapsFeatures {
pub fn new(features: &[&str]) -> Self {
let mut f = Self::new_empty();
for feature in features {
f.add(feature);
}
f
}
pub fn new_empty() -> Self {
assert_initialized_main_thread!();
unsafe {
CapsFeatures(
ptr::NonNull::new_unchecked(
ffi::gst_caps_features_new_empty() as *mut CapsFeaturesRef
),
PhantomData,
)
}
}
pub fn new_any() -> Self {
assert_initialized_main_thread!();
unsafe {
CapsFeatures(
ptr::NonNull::new_unchecked(
ffi::gst_caps_features_new_any() as *mut CapsFeaturesRef
),
PhantomData,
)
}
}
pub fn from_string(value: &str) -> Option<Self> {
assert_initialized_main_thread!();
unsafe {
let ptr = ffi::gst_caps_features_from_string(value.to_glib_none().0);
if ptr.is_null() {
return None;
}
Some(CapsFeatures(
ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef),
PhantomData,
))
}
}
pub unsafe fn into_ptr(self) -> *mut ffi::GstCapsFeatures {
let ptr = self.0.as_ptr() as *mut CapsFeaturesRef as *mut ffi::GstCapsFeatures;
mem::forget(self);
ptr
}
}
impl Deref for CapsFeatures {
type Target = CapsFeaturesRef;
fn deref(&self) -> &CapsFeaturesRef {
unsafe { self.0.as_ref() }
}
}
impl DerefMut for CapsFeatures {
fn deref_mut(&mut self) -> &mut CapsFeaturesRef {
unsafe { self.0.as_mut() }
}
}
impl AsRef<CapsFeaturesRef> for CapsFeatures {
fn as_ref(&self) -> &CapsFeaturesRef {
self.deref()
}
}
impl AsMut<CapsFeaturesRef> for CapsFeatures {
fn as_mut(&mut self) -> &mut CapsFeaturesRef {
self.deref_mut()
}
}
impl Clone for CapsFeatures {
fn clone(&self) -> Self {
unsafe {
let ptr = ffi::gst_caps_features_copy(&self.0.as_ref().0) as *mut CapsFeaturesRef;
assert!(!ptr.is_null());
CapsFeatures(ptr::NonNull::new_unchecked(ptr), PhantomData)
}
}
}
impl Drop for CapsFeatures {
fn drop(&mut self) {
unsafe { ffi::gst_caps_features_free(&mut self.0.as_mut().0) }
}
}
impl fmt::Debug for CapsFeatures {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("CapsFeatures")
.field(&self.to_string())
.finish()
}
}
impl fmt::Display for CapsFeatures {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Need to make sure to not call ToString::to_string() here, which
// we have because of the Display impl. We need CapsFeaturesRef::to_string()
f.write_str(&CapsFeaturesRef::to_string(self.as_ref()))
}
}
impl str::FromStr for CapsFeatures {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
skip_assert_initialized!();
CapsFeatures::from_string(s).ok_or(())
}
}
impl Borrow<CapsFeaturesRef> for CapsFeatures {
fn borrow(&self) -> &CapsFeaturesRef {
unsafe { self.0.as_ref() }
}
}
impl BorrowMut<CapsFeaturesRef> for CapsFeatures {
fn borrow_mut(&mut self) -> &mut CapsFeaturesRef {
unsafe { self.0.as_mut() }
}
}
impl glib::types::StaticType for CapsFeatures {
fn static_type() -> glib::types::Type {
unsafe { from_glib(ffi::gst_caps_features_get_type()) }
}
}
impl<'a> ToGlibPtr<'a, *const ffi::GstCapsFeatures> for CapsFeatures {
type Storage = &'a Self;
fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GstCapsFeatures, Self> {
unsafe { Stash(&self.0.as_ref().0, self) }
}
fn to_glib_full(&self) -> *const ffi::GstCapsFeatures {
unsafe { ffi::gst_caps_features_copy(&self.0.as_ref().0) }
}
}
impl<'a> ToGlibPtr<'a, *mut ffi::GstCapsFeatures> for CapsFeatures {
type Storage = &'a Self;
fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GstCapsFeatures, Self> {
unsafe { Stash(&self.0.as_ref().0 as *const _ as *mut _, self) }
}
fn to_glib_full(&self) -> *mut ffi::GstCapsFeatures {
unsafe { ffi::gst_caps_features_copy(&self.0.as_ref().0) }
}
}
impl<'a> ToGlibPtrMut<'a, *mut ffi::GstCapsFeatures> for CapsFeatures {
type Storage = &'a mut Self;
fn to_glib_none_mut(&'a mut self) -> StashMut<*mut ffi::GstCapsFeatures, Self> {
unsafe { StashMut(&mut self.0.as_mut().0, self) }
}
}
impl FromGlibPtrNone<*const ffi::GstCapsFeatures> for CapsFeatures {
unsafe fn from_glib_none(ptr: *const ffi::GstCapsFeatures) -> Self {
assert!(!ptr.is_null());
let ptr = ffi::gst_caps_features_copy(ptr);
assert!(!ptr.is_null());
CapsFeatures(
ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef),
PhantomData,
)
}
}
impl FromGlibPtrNone<*mut ffi::GstCapsFeatures> for CapsFeatures {
unsafe fn from_glib_none(ptr: *mut ffi::GstCapsFeatures) -> Self {
assert!(!ptr.is_null());
let ptr = ffi::gst_caps_features_copy(ptr);
assert!(!ptr.is_null());
CapsFeatures(
ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef),
PhantomData,
)
}
}
impl FromGlibPtrFull<*const ffi::GstCapsFeatures> for CapsFeatures {
unsafe fn from_glib_full(ptr: *const ffi::GstCapsFeatures) -> Self {
assert!(!ptr.is_null());
CapsFeatures(
ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef),
PhantomData,
)
}
}
impl FromGlibPtrFull<*mut ffi::GstCapsFeatures> for CapsFeatures {
unsafe fn from_glib_full(ptr: *mut ffi::GstCapsFeatures) -> Self {
assert!(!ptr.is_null());
CapsFeatures(
ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef),
PhantomData,
)
}
}
impl<'a> glib::value::FromValueOptional<'a> for CapsFeatures {
unsafe fn from_value_optional(v: &'a glib::Value) -> Option<Self> {
let ptr = gobject_ffi::g_value_get_boxed(v.to_glib_none().0);
assert!(!ptr.is_null());
from_glib_none(ptr as *const ffi::GstCapsFeatures)
}
}
impl glib::value::SetValue for CapsFeatures {
unsafe fn set_value(v: &mut glib::Value, s: &Self) {
gobject_ffi::g_value_set_boxed(v.to_glib_none_mut().0, s.0.as_ptr() as gpointer);
}
}
impl glib::value::SetValueOptional for CapsFeatures {
unsafe fn set_value_optional(v: &mut glib::Value, s: Option<&Self>) {
if let Some(s) = s {
gobject_ffi::g_value_set_boxed(v.to_glib_none_mut().0, s.as_ptr() as gpointer);
} else {
gobject_ffi::g_value_set_boxed(v.to_glib_none_mut().0, ptr::null_mut());
}
}
}
impl GlibPtrDefault for CapsFeatures {
type GlibType = *mut ffi::GstCapsFeatures;
}
#[repr(C)]
pub struct CapsFeaturesRef(ffi::GstCapsFeatures);
impl CapsFeaturesRef {
pub unsafe fn from_glib_borrow<'a>(ptr: *const ffi::GstCapsFeatures) -> &'a CapsFeaturesRef {
assert!(!ptr.is_null());
&*(ptr as *mut CapsFeaturesRef)
}
pub unsafe fn from_glib_borrow_mut<'a>(
ptr: *mut ffi::GstCapsFeatures,
) -> &'a mut CapsFeaturesRef {
assert!(!ptr.is_null());
&mut *(ptr as *mut CapsFeaturesRef)
}
pub unsafe fn as_ptr(&self) -> *const ffi::GstCapsFeatures {
self as *const Self as *const ffi::GstCapsFeatures
}
pub unsafe fn as_mut_ptr(&self) -> *mut ffi::GstCapsFeatures {
self as *const Self as *mut ffi::GstCapsFeatures
}
pub fn to_string(&self) -> String {
unsafe { from_glib_full(ffi::gst_caps_features_to_string(self.as_ptr())) }
}
pub fn is_empty(&self) -> bool {
self.get_size() == 0 && !self.is_any()
}
pub fn is_any(&self) -> bool {
unsafe { from_glib(ffi::gst_caps_features_is_any(self.as_ptr())) }
}
pub fn contains(&self, feature: &str) -> bool {
unsafe {
from_glib(ffi::gst_caps_features_contains(
self.as_ptr(),
feature.to_glib_none().0,
))
}
}
pub fn get_size(&self) -> u32 {
unsafe { ffi::gst_caps_features_get_size(self.as_ptr()) }
}
pub fn get_nth(&self, idx: u32) -> Option<&str> {
if idx >= self.get_size() {
return None;
}
unsafe {
let feature = ffi::gst_caps_features_get_nth(self.as_ptr(), idx);
if feature.is_null() {
return None;
}
Some(CStr::from_ptr(feature).to_str().unwrap())
}
}
pub fn add(&mut self, feature: &str) {
unsafe { ffi::gst_caps_features_add(self.as_mut_ptr(), feature.to_glib_none().0) }
}
pub fn remove(&mut self, feature: &str) {
unsafe { ffi::gst_caps_features_remove(self.as_mut_ptr(), feature.to_glib_none().0) }
}
pub fn iter(&self) -> Iter {
Iter::new(self)
}
// This is not an equivalence relation with regards to ANY. Everything is equal to ANY
pub fn is_equal(&self, other: &CapsFeaturesRef) -> bool {
unsafe {
from_glib(ffi::gst_caps_features_is_equal(
self.as_ptr(),
other.as_ptr(),
))
}
}
}
pub struct Iter<'a> {
caps_features: &'a CapsFeaturesRef,
idx: u32,
n_features: u32,
}
impl<'a> Iter<'a> {
fn new(caps_features: &'a CapsFeaturesRef) -> Iter<'a> {
skip_assert_initialized!();
let n_features = caps_features.get_size();
Iter {
caps_features,
idx: 0,
n_features,
}
}
}
impl<'a> Iterator for Iter<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
if self.idx >= self.n_features {
return None;
}
unsafe {
let feature = ffi::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.idx);
if feature.is_null() {
return None;
}
self.idx += 1;
Some(CStr::from_ptr(feature).to_str().unwrap())
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
if self.idx == self.n_features {
return (0, Some(0));
}
let remaining = (self.n_features - self.idx) as usize;
(remaining, Some(remaining))
}
}
impl<'a> DoubleEndedIterator for Iter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.idx == self.n_features {
return None;
}
self.n_features -= 1;
unsafe {
let feature =
ffi::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.n_features);
if feature.is_null() {
return None;
}
Some(CStr::from_ptr(feature).to_str().unwrap())
}
}
}
impl<'a> ExactSizeIterator for Iter<'a> {}
impl fmt::Debug for CapsFeaturesRef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("CapsFeatures")
.field(&self.to_string())
.finish()
}
}
impl fmt::Display for CapsFeaturesRef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.to_string())
}
}
impl ToOwned for CapsFeaturesRef {
type Owned = CapsFeatures;
fn to_owned(&self) -> CapsFeatures {
unsafe { from_glib_full(ffi::gst_caps_features_copy(self.as_ptr() as *const _) as *mut _) }
}
}
unsafe impl Sync for CapsFeaturesRef {}
unsafe impl Send for CapsFeaturesRef {}
lazy_static! {
pub static ref CAPS_FEATURE_MEMORY_SYSTEM_MEMORY: &'static str = unsafe {
CStr::from_ptr(ffi::GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY)
.to_str()
.unwrap()
};
pub static ref CAPS_FEATURES_MEMORY_SYSTEM_MEMORY: CapsFeatures =
CapsFeatures::new(&[*CAPS_FEATURE_MEMORY_SYSTEM_MEMORY]);
}

View file

@ -0,0 +1,166 @@
// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use serde::de;
use serde::de::{Deserialize, Deserializer, EnumAccess, SeqAccess, VariantAccess, Visitor};
use serde::ser::{Serialize, SerializeSeq, Serializer};
use std::fmt;
use CapsFeatures;
use CapsFeaturesRef;
enum CapsFeaturesVariantKinds {
Any,
Some,
}
const CAPS_FEATURES_VARIANT_ANY_ID: u32 = 0;
const CAPS_FEATURES_VARIANT_ANY_STR: &str = "Any";
const CAPS_FEATURES_VARIANT_SOME_ID: u32 = 1;
const CAPS_FEATURES_VARIANT_SOME_STR: &str = "Some";
const CAPS_FEATURES_VARIANT_NAMES: &[&str] = &[
&CAPS_FEATURES_VARIANT_ANY_STR,
&CAPS_FEATURES_VARIANT_SOME_STR,
];
struct CapsFeaturesForIterSe<'a>(&'a CapsFeaturesRef);
impl<'a> Serialize for CapsFeaturesForIterSe<'a> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let iter = self.0.iter();
let size = iter.size_hint().0;
if size > 0 {
let mut seq = serializer.serialize_seq(Some(size))?;
for feature in iter {
seq.serialize_element(feature)?;
}
seq.end()
} else {
let seq = serializer.serialize_seq(None)?;
seq.end()
}
}
}
impl Serialize for CapsFeaturesRef {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if self.is_any() {
serializer.serialize_unit_variant(
stringify!(CapsFeatures),
CAPS_FEATURES_VARIANT_ANY_ID,
CAPS_FEATURES_VARIANT_ANY_STR,
)
} else {
serializer.serialize_newtype_variant(
stringify!(CapsFeatures),
CAPS_FEATURES_VARIANT_SOME_ID,
CAPS_FEATURES_VARIANT_SOME_STR,
&CapsFeaturesForIterSe(&self),
)
}
}
}
impl Serialize for CapsFeatures {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.as_ref().serialize(serializer)
}
}
struct CapsFeaturesSome(CapsFeatures);
struct CapsFeaturesSomeVisitor;
impl<'de> Visitor<'de> for CapsFeaturesSomeVisitor {
type Value = CapsFeaturesSome;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a sequence of `&str`")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut features = CapsFeatures::new_empty();
while let Some(feature) = seq.next_element::<String>()? {
features.add(feature.as_ref());
}
Ok(CapsFeaturesSome(features))
}
}
impl<'de> Deserialize<'de> for CapsFeaturesSome {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<CapsFeaturesSome, D::Error> {
deserializer.deserialize_seq(CapsFeaturesSomeVisitor)
}
}
struct CapsFeaturesVariantKindsVisitor;
impl<'de> Visitor<'de> for CapsFeaturesVariantKindsVisitor {
type Value = CapsFeaturesVariantKinds;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a Caps variant kind (`Any` or `Some`)")
}
fn visit_u32<E: de::Error>(self, value: u32) -> Result<Self::Value, E> {
match value {
CAPS_FEATURES_VARIANT_ANY_ID => Ok(CapsFeaturesVariantKinds::Any),
CAPS_FEATURES_VARIANT_SOME_ID => Ok(CapsFeaturesVariantKinds::Some),
_ => Err(de::Error::invalid_value(
de::Unexpected::Unsigned(value as u64),
&self,
)),
}
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
match value {
CAPS_FEATURES_VARIANT_ANY_STR => Ok(CapsFeaturesVariantKinds::Any),
CAPS_FEATURES_VARIANT_SOME_STR => Ok(CapsFeaturesVariantKinds::Some),
_ => Err(de::Error::unknown_variant(
value,
CAPS_FEATURES_VARIANT_NAMES,
)),
}
}
}
impl<'de> Deserialize<'de> for CapsFeaturesVariantKinds {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_identifier(CapsFeaturesVariantKindsVisitor)
}
}
struct CapsFeaturesVisitor;
impl<'de> Visitor<'de> for CapsFeaturesVisitor {
type Value = CapsFeatures;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a CapsFeatures enum (`Any` or `Some()`)")
}
fn visit_enum<A: EnumAccess<'de>>(self, data: A) -> Result<Self::Value, A::Error> {
let res = match data.variant()? {
(CapsFeaturesVariantKinds::Any, _v) => CapsFeatures::new_any(),
(CapsFeaturesVariantKinds::Some, v) => v
.newtype_variant::<CapsFeaturesSome>()
.map(|caps_features_some| caps_features_some.0)?,
};
Ok(res)
}
}
impl<'de> Deserialize<'de> for CapsFeatures {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_enum(
stringify!(Caps),
CAPS_FEATURES_VARIANT_NAMES,
CapsFeaturesVisitor,
)
}
}

View file

@ -13,6 +13,8 @@ use serde::ser::{Serialize, SerializeSeq, SerializeTuple, Serializer};
use std::fmt; use std::fmt;
use Caps; use Caps;
use CapsFeatures;
use CapsFeaturesRef;
use CapsRef; use CapsRef;
use Structure; use Structure;
use StructureRef; use StructureRef;
@ -36,15 +38,12 @@ const CAPS_VARIANT_NAMES: &[&str] = &[
&CAPS_VARIANT_SOME_STR, &CAPS_VARIANT_SOME_STR,
]; ];
// `CapsFeature` is not available in `gstreamer-rs` yet struct CapsItemSe<'a>(&'a StructureRef, Option<&'a CapsFeaturesRef>);
struct CapsItemSe<'a>(&'a StructureRef);
impl<'a> Serialize for CapsItemSe<'a> { impl<'a> Serialize for CapsItemSe<'a> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut tup = serializer.serialize_tuple(2)?; let mut tup = serializer.serialize_tuple(2)?;
tup.serialize_element(self.0)?; tup.serialize_element(self.0)?;
// `CapsFeature` is not available in `gstreamer-rs` yet tup.serialize_element(&self.1)?;
// Fake the type for now and use `None` as a value
tup.serialize_element::<Option<Structure>>(&None)?;
tup.end() tup.end()
} }
} }
@ -52,12 +51,19 @@ impl<'a> Serialize for CapsItemSe<'a> {
struct CapsForIterSe<'a>(&'a CapsRef); struct CapsForIterSe<'a>(&'a CapsRef);
impl<'a> Serialize for CapsForIterSe<'a> { impl<'a> Serialize for CapsForIterSe<'a> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let iter = self.0.iter(); let iter = self.0.iter_with_features();
let size = iter.size_hint().0; let size = iter.size_hint().0;
if size > 0 { if size > 0 {
let mut seq = serializer.serialize_seq(Some(size))?; let mut seq = serializer.serialize_seq(Some(size))?;
for structure in iter { for (structure, features) in iter {
seq.serialize_element(&CapsItemSe(structure))?; let features = if !features.is_any() && features
.is_equal(::CAPS_FEATURES_MEMORY_SYSTEM_MEMORY.as_ref())
{
None
} else {
Some(features)
};
seq.serialize_element(&CapsItemSe(structure, features))?;
} }
seq.end() seq.end()
} else { } else {
@ -98,13 +104,7 @@ impl Serialize for Caps {
} }
} }
// `CapsFeature` is not available in `gstreamer-rs` yet struct CapsItemDe(Structure, Option<CapsFeatures>);
struct CapsItemDe(Structure);
impl From<CapsItemDe> for Structure {
fn from(caps_item: CapsItemDe) -> Structure {
caps_item.0
}
}
struct CapsItemVisitor; struct CapsItemVisitor;
impl<'de> Visitor<'de> for CapsItemVisitor { impl<'de> Visitor<'de> for CapsItemVisitor {
@ -118,20 +118,13 @@ impl<'de> Visitor<'de> for CapsItemVisitor {
let structure = seq let structure = seq
.next_element::<Structure>()? .next_element::<Structure>()?
.ok_or(de::Error::custom("Expected a `Structure` for `Caps` item"))?; .ok_or(de::Error::custom("Expected a `Structure` for `Caps` item"))?;
// `CapsFeature` is not available in `gstreamer-rs` yet let features_option =
// Fake the type for now and expect `None` as a value seq.next_element::<Option<CapsFeatures>>()?
let feature_option = seq .ok_or(de::Error::custom(
.next_element::<Option<Structure>>()? "Expected an `Option<CapsFeature>` for `Caps` item",
.ok_or(de::Error::custom( ))?;
"Expected an `Option<CapsFeature>` for `Caps` item",
))?; Ok(CapsItemDe(structure, features_option))
if feature_option.is_some() {
Err(de::Error::custom(
"Found a value for `CapsFeature`, expected `None` (not implemented yet)",
))
} else {
Ok(CapsItemDe(structure))
}
} }
} }
@ -156,7 +149,7 @@ impl<'de> Visitor<'de> for CapsSomeVisitor {
{ {
let caps = caps.get_mut().unwrap(); let caps = caps.get_mut().unwrap();
while let Some(caps_item) = seq.next_element::<CapsItemDe>()? { while let Some(caps_item) = seq.next_element::<CapsItemDe>()? {
caps.append_structure(caps_item.into()); caps.append_structure_full(caps_item.0, caps_item.1);
} }
} }
Ok(CapsSome(caps)) Ok(CapsSome(caps))
@ -238,6 +231,7 @@ mod tests {
use Array; use Array;
use Caps; use Caps;
use CapsFeatures;
use Fraction; use Fraction;
#[test] #[test]
@ -274,6 +268,71 @@ mod tests {
res, res,
); );
let caps = Caps::builder("foo/bar")
.field("int", &12)
.field("bool", &true)
.field("string", &"bla")
.field("fraction", &Fraction::new(1, 2))
.field("array", &Array::new(&[&1, &2]))
.features(&["foo:bar", "foo:baz"])
.build();
let mut pretty_config = ron::ser::PrettyConfig::default();
pretty_config.new_line = "".to_string();
let res = ron::ser::to_string_pretty(&caps, pretty_config.clone());
assert_eq!(
Ok(concat!(
"Some([",
" ((\"foo/bar\", [",
" (\"int\", \"i32\", 12),",
" (\"bool\", \"bool\", true),",
" (\"string\", \"String\", \"bla\"),",
" (\"fraction\", \"Fraction\", (1, 2)),",
" (\"array\", \"Array\", [",
" (\"i32\", 1),",
" (\"i32\", 2),",
" ]),",
" ]), Some(Some([",
" \"foo:bar\",",
" \"foo:baz\",",
" ]))),",
"])"
).to_owned()),
res,
);
let caps = Caps::builder("foo/bar")
.field("int", &12)
.field("bool", &true)
.field("string", &"bla")
.field("fraction", &Fraction::new(1, 2))
.field("array", &Array::new(&[&1, &2]))
.any_features()
.build();
let mut pretty_config = ron::ser::PrettyConfig::default();
pretty_config.new_line = "".to_string();
let res = ron::ser::to_string_pretty(&caps, pretty_config.clone());
assert_eq!(
Ok(concat!(
"Some([",
" ((\"foo/bar\", [",
" (\"int\", \"i32\", 12),",
" (\"bool\", \"bool\", true),",
" (\"string\", \"String\", \"bla\"),",
" (\"fraction\", \"Fraction\", (1, 2)),",
" (\"array\", \"Array\", [",
" (\"i32\", 1),",
" (\"i32\", 2),",
" ]),",
" ]), Some(Any)),",
"])"
).to_owned()),
res,
);
let caps_any = Caps::new_any(); let caps_any = Caps::new_any();
let res = ron::ser::to_string_pretty(&caps_any, pretty_config.clone()); let res = ron::ser::to_string_pretty(&caps_any, pretty_config.clone());
assert_eq!(Ok("Any".to_owned()), res); assert_eq!(Ok("Any".to_owned()), res);
@ -328,6 +387,74 @@ mod tests {
], ],
).as_ref() ).as_ref()
); );
let caps_ron = r#"
Some([
(
("foo/bar", [
("int", "i32", 12),
("bool", "bool", true),
("string", "String", "bla"),
("fraction", "Fraction", (1, 2)),
("array", "Array", [
("i32", 1),
("i32", 2),
]),
]),
Some(Some(["foo:bar", "foo:baz"])),
),
])"#;
let caps: Caps = ron::de::from_str(caps_ron).unwrap();
let s = caps.get_structure(0).unwrap();
assert_eq!(
s,
Structure::new(
"foo/bar",
&[
("int", &12),
("bool", &true),
("string", &"bla"),
("fraction", &Fraction::new(1, 2)),
("array", &Array::new(&[&1, &2])),
],
).as_ref()
);
let f = caps.get_features(0).unwrap();
assert!(f.is_equal(CapsFeatures::new(&["foo:bar", "foo:baz"]).as_ref()));
let caps_ron = r#"
Some([
(
("foo/bar", [
("int", "i32", 12),
("bool", "bool", true),
("string", "String", "bla"),
("fraction", "Fraction", (1, 2)),
("array", "Array", [
("i32", 1),
("i32", 2),
]),
]),
Some(Any),
),
])"#;
let caps: Caps = ron::de::from_str(caps_ron).unwrap();
let s = caps.get_structure(0).unwrap();
assert_eq!(
s,
Structure::new(
"foo/bar",
&[
("int", &12),
("bool", &true),
("string", &"bla"),
("fraction", &Fraction::new(1, 2)),
("array", &Array::new(&[&1, &2])),
],
).as_ref()
);
let f = caps.get_features(0).unwrap();
assert!(f.is_any());
} }
#[test] #[test]
@ -354,5 +481,29 @@ mod tests {
let caps_ser = ron::ser::to_string(&caps).unwrap(); let caps_ser = ron::ser::to_string(&caps).unwrap();
let caps_de: Caps = ron::de::from_str(caps_ser.as_str()).unwrap(); let caps_de: Caps = ron::de::from_str(caps_ser.as_str()).unwrap();
assert!(caps_de.is_strictly_equal(&caps)); assert!(caps_de.is_strictly_equal(&caps));
let caps = Caps::builder("foo/bar")
.field("int", &12)
.field("bool", &true)
.field("string", &"bla")
.field("fraction", &Fraction::new(1, 2))
.field("array", &Array::new(&[&1, &2]))
.features(&["foo:bar", "foo:baz"])
.build();
let caps_ser = ron::ser::to_string(&caps).unwrap();
let caps_de: Caps = ron::de::from_str(caps_ser.as_str()).unwrap();
assert!(caps_de.is_strictly_equal(&caps));
let caps = Caps::builder("foo/bar")
.field("int", &12)
.field("bool", &true)
.field("string", &"bla")
.field("fraction", &Fraction::new(1, 2))
.field("array", &Array::new(&[&1, &2]))
.any_features()
.build();
let caps_ser = ron::ser::to_string(&caps).unwrap();
let caps_de: Caps = ron::de::from_str(caps_ser.as_str()).unwrap();
assert!(caps_de.is_strictly_equal(&caps));
} }
} }

View file

@ -91,6 +91,10 @@ pub mod caps;
pub use caps::{Caps, CapsRef}; pub use caps::{Caps, CapsRef};
#[cfg(feature = "ser_de")] #[cfg(feature = "ser_de")]
mod caps_serde; mod caps_serde;
mod caps_features;
pub use caps_features::{CapsFeatures, CapsFeaturesRef, CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, CAPS_FEATURES_MEMORY_SYSTEM_MEMORY};
#[cfg(feature = "ser_de")]
mod caps_features_serde;
pub mod tags; pub mod tags;
pub use tags::{Tag, TagList, TagListRef}; pub use tags::{Tag, TagList, TagListRef};