mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2024-12-23 08:36:31 +00:00
Implement support for buffer Metas
Fixes https://github.com/sdroege/gstreamer-rs/issues/103
This commit is contained in:
parent
ad62d08d65
commit
cb23d20270
3 changed files with 430 additions and 1 deletions
|
@ -15,13 +15,14 @@ use std::slice;
|
|||
use std::u64;
|
||||
use std::usize;
|
||||
|
||||
use meta::*;
|
||||
use miniobject::*;
|
||||
use BufferFlags;
|
||||
use ClockTime;
|
||||
|
||||
use ffi;
|
||||
use glib;
|
||||
use glib::translate::{from_glib, from_glib_full, from_glib_none, ToGlib, ToGlibPtr};
|
||||
use glib::translate::{from_glib, from_glib_full, from_glib_none, FromGlib, ToGlib, ToGlibPtr};
|
||||
use glib_ffi;
|
||||
|
||||
pub enum Readable {}
|
||||
|
@ -367,8 +368,99 @@ impl BufferRef {
|
|||
pub fn set_flags(&mut self, flags: BufferFlags) {
|
||||
self.0.mini_object.flags = flags.bits();
|
||||
}
|
||||
|
||||
pub fn get_meta<T: MetaAPI>(&self) -> Option<MetaRef<T>> {
|
||||
unsafe {
|
||||
let meta = ffi::gst_buffer_get_meta(self.as_mut_ptr(), T::get_meta_api().to_glib());
|
||||
if meta.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(T::from_ptr(
|
||||
self.as_ptr(),
|
||||
meta as *const <T as MetaAPI>::GstType,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_meta_mut<T: MetaAPI>(&mut self) -> Option<MetaRefMut<T, ::meta::Standalone>> {
|
||||
unsafe {
|
||||
let meta = ffi::gst_buffer_get_meta(self.as_mut_ptr(), T::get_meta_api().to_glib());
|
||||
if meta.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(T::from_mut_ptr(
|
||||
self.as_mut_ptr(),
|
||||
meta as *mut <T as MetaAPI>::GstType,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter_meta<T: MetaAPI>(&self) -> MetaIter<T> {
|
||||
MetaIter::new(self)
|
||||
}
|
||||
|
||||
pub fn iter_meta_mut<T: MetaAPI>(&mut self) -> MetaIterMut<T> {
|
||||
MetaIterMut::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_iter(
|
||||
($name:ident, $typ:ty, $mtyp:ty, $from_ptr:expr) => {
|
||||
pub struct $name<'a, T: MetaAPI + 'a> {
|
||||
buffer: $typ,
|
||||
state: glib_ffi::gpointer,
|
||||
meta_api: glib::Type,
|
||||
items: PhantomData<$mtyp>,
|
||||
}
|
||||
|
||||
impl<'a, T: MetaAPI> $name<'a, T> {
|
||||
fn new(buffer: $typ) -> $name<'a, T> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
$name {
|
||||
buffer,
|
||||
state: ptr::null_mut(),
|
||||
meta_api: T::get_meta_api(),
|
||||
items: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: MetaAPI> Iterator for $name<'a, T> {
|
||||
type Item = $mtyp;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
unsafe {
|
||||
let meta = ffi::gst_buffer_iterate_meta(self.buffer.as_mut_ptr(), &mut self.state);
|
||||
|
||||
if meta.is_null() {
|
||||
return None;
|
||||
} else if self.meta_api == glib::Type::Invalid || glib::Type::from_glib((*(*meta).info).api) == self.meta_api {
|
||||
let item = $from_ptr(self.buffer.as_mut_ptr(), meta);
|
||||
return Some(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: MetaAPI> ExactSizeIterator for $name<'a, T> {}
|
||||
}
|
||||
);
|
||||
|
||||
define_iter!(MetaIter, &'a BufferRef, MetaRef<'a, T>, |buffer, meta| {
|
||||
T::from_ptr(buffer, meta as *const <T as MetaAPI>::GstType)
|
||||
});
|
||||
define_iter!(
|
||||
MetaIterMut,
|
||||
&'a mut BufferRef,
|
||||
MetaRefMut<'a, T, ::meta::Iterated>,
|
||||
|buffer, meta| T::from_mut_ptr(buffer, meta as *mut <T as MetaAPI>::GstType)
|
||||
);
|
||||
|
||||
impl fmt::Debug for BufferRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Buffer")
|
||||
|
|
|
@ -105,6 +105,8 @@ pub use tags::{Tag, TagList, TagListRef};
|
|||
#[cfg(feature = "ser_de")]
|
||||
mod tags_serde;
|
||||
|
||||
pub mod meta;
|
||||
pub use meta::{Meta, MetaAPI, MetaRef, MetaRefMut, ParentBufferMeta};
|
||||
pub mod buffer;
|
||||
pub use buffer::{
|
||||
Buffer, BufferMap, BufferRef, MappedBuffer, BUFFER_COPY_ALL, BUFFER_COPY_METADATA,
|
||||
|
@ -290,6 +292,8 @@ pub mod prelude {
|
|||
|
||||
pub use auto::traits::*;
|
||||
|
||||
pub use meta::MetaAPI;
|
||||
|
||||
pub use bin::BinExtManual;
|
||||
pub use element::ElementExtManual;
|
||||
|
||||
|
|
333
gstreamer/src/meta.rs
Normal file
333
gstreamer/src/meta.rs
Normal file
|
@ -0,0 +1,333 @@
|
|||
// 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::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ops;
|
||||
|
||||
use miniobject::MiniObject;
|
||||
use BufferRef;
|
||||
|
||||
use ffi;
|
||||
use glib;
|
||||
use glib::translate::{from_glib, FromGlib};
|
||||
use glib_ffi;
|
||||
|
||||
pub unsafe trait MetaAPI: Sized {
|
||||
type GstType;
|
||||
|
||||
fn get_meta_api() -> glib::Type;
|
||||
|
||||
unsafe fn from_ptr<'a>(
|
||||
buffer: *const ffi::GstBuffer,
|
||||
ptr: *const Self::GstType,
|
||||
) -> MetaRef<'a, Self> {
|
||||
assert!(!ptr.is_null());
|
||||
|
||||
let meta_api = Self::get_meta_api();
|
||||
if meta_api != glib::Type::Invalid {
|
||||
assert_eq!(
|
||||
meta_api,
|
||||
from_glib((*(*(ptr as *const ffi::GstMeta)).info).api)
|
||||
)
|
||||
}
|
||||
|
||||
MetaRef {
|
||||
meta: mem::transmute(ptr),
|
||||
buffer,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn from_mut_ptr<'a, T>(
|
||||
buffer: *mut ffi::GstBuffer,
|
||||
ptr: *mut Self::GstType,
|
||||
) -> MetaRefMut<'a, Self, T> {
|
||||
assert!(!ptr.is_null());
|
||||
|
||||
let meta_api = Self::get_meta_api();
|
||||
if meta_api != glib::Type::Invalid {
|
||||
assert_eq!(
|
||||
meta_api,
|
||||
from_glib((*(*(ptr as *const ffi::GstMeta)).info).api)
|
||||
)
|
||||
}
|
||||
|
||||
MetaRefMut {
|
||||
meta: mem::transmute(ptr),
|
||||
buffer,
|
||||
mode: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MetaRef<'a, T: MetaAPI + 'a> {
|
||||
meta: &'a T,
|
||||
buffer: *const ffi::GstBuffer,
|
||||
}
|
||||
|
||||
pub enum Standalone {}
|
||||
pub enum Iterated {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MetaRefMut<'a, T: MetaAPI + 'a, U> {
|
||||
meta: &'a mut T,
|
||||
buffer: *mut ffi::GstBuffer,
|
||||
mode: PhantomData<U>,
|
||||
}
|
||||
|
||||
impl<'a, T: MetaAPI> ops::Deref for MetaRef<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
self.meta
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: MetaAPI> AsRef<MetaRef<'a, T>> for MetaRef<'a, T> {
|
||||
fn as_ref(&self) -> &MetaRef<'a, T> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: MetaAPI, U> ops::Deref for MetaRefMut<'a, T, U> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
self.meta
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: MetaAPI, U> ops::DerefMut for MetaRefMut<'a, T, U> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
self.meta
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: MetaAPI, U> AsRef<MetaRef<'a, T>> for MetaRefMut<'a, T, U> {
|
||||
fn as_ref(&self) -> &MetaRef<'a, T> {
|
||||
unsafe { mem::transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: MetaAPI> MetaRef<'a, T> {
|
||||
pub fn get_api(&self) -> glib::Type {
|
||||
unsafe {
|
||||
let meta = self.meta as *const _ as *const ffi::GstMeta;
|
||||
let info = (*meta).info;
|
||||
glib::Type::from_glib((*info).api)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const T::GstType {
|
||||
self.meta as *const _ as *const <T as MetaAPI>::GstType
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MetaRef<'a, Meta<'a>> {
|
||||
pub fn downcast_ref<T: MetaAPI>(&self) -> Option<&MetaRef<'a, T>> {
|
||||
let target_type = T::get_meta_api();
|
||||
let type_ = self.get_api();
|
||||
|
||||
if type_ == glib::Type::Invalid || target_type == type_ {
|
||||
Some(unsafe { mem::transmute(self) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: MetaAPI, U> MetaRefMut<'a, T, U> {
|
||||
pub fn get_api(&self) -> glib::Type {
|
||||
unsafe {
|
||||
let meta = self.meta as *const _ as *const ffi::GstMeta;
|
||||
let info = (*meta).info;
|
||||
glib::Type::from_glib((*info).api)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const T::GstType {
|
||||
self.meta as *const _ as *const <T as MetaAPI>::GstType
|
||||
}
|
||||
|
||||
pub fn as_mut_ptr(&mut self) -> *mut T::GstType {
|
||||
self.meta as *mut _ as *mut <T as MetaAPI>::GstType
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: MetaAPI> MetaRefMut<'a, T, Standalone> {
|
||||
pub fn remove(mut self) {
|
||||
unsafe {
|
||||
let res =
|
||||
ffi::gst_buffer_remove_meta(self.buffer, self.as_mut_ptr() as *mut ffi::GstMeta);
|
||||
assert_ne!(res, glib_ffi::GFALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, U> MetaRefMut<'a, Meta<'a>, U> {
|
||||
pub fn downcast_ref<T: MetaAPI>(&mut self) -> Option<&MetaRefMut<'a, T, U>> {
|
||||
let target_type = T::get_meta_api();
|
||||
let type_ = self.get_api();
|
||||
|
||||
if type_ == glib::Type::Invalid || target_type == type_ {
|
||||
Some(unsafe { mem::transmute(self) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Meta<'a>(ffi::GstMeta, PhantomData<&'a ()>);
|
||||
|
||||
impl<'a> Meta<'a> {
|
||||
fn get_api(&self) -> glib::Type {
|
||||
unsafe { glib::Type::from_glib((*self.0.info).api) }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a> MetaAPI for Meta<'a> {
|
||||
type GstType = ffi::GstMeta;
|
||||
|
||||
fn get_meta_api() -> glib::Type {
|
||||
glib::Type::Invalid
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for Meta<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Meta")
|
||||
.field("api", &self.get_api())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ParentBufferMeta<'a>(ffi::GstParentBufferMeta, PhantomData<&'a ()>);
|
||||
|
||||
impl<'a> ParentBufferMeta<'a> {
|
||||
pub fn add(buffer: &'a mut BufferRef, parent: &BufferRef) -> MetaRefMut<'a, Self, Standalone> {
|
||||
unsafe {
|
||||
let meta =
|
||||
ffi::gst_buffer_add_parent_buffer_meta(buffer.as_mut_ptr(), parent.as_mut_ptr());
|
||||
|
||||
Self::from_mut_ptr(buffer.as_mut_ptr(), meta)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_parent(&self) -> &BufferRef {
|
||||
unsafe { BufferRef::from_ptr(self.0.buffer) }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a> MetaAPI for ParentBufferMeta<'a> {
|
||||
type GstType = ffi::GstParentBufferMeta;
|
||||
|
||||
fn get_meta_api() -> glib::Type {
|
||||
unsafe { from_glib(ffi::gst_parent_buffer_meta_api_get_type()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for ParentBufferMeta<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("ParentBufferMeta")
|
||||
.field("parent", &self.get_parent())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_add_get_iterate_meta() {
|
||||
gst::init().unwrap();
|
||||
|
||||
let mut buffer = ::Buffer::new();
|
||||
let parent = ::Buffer::new();
|
||||
{
|
||||
let meta = ParentBufferMeta::add(buffer.get_mut().unwrap(), &*parent);
|
||||
unsafe {
|
||||
assert_eq!(meta.get_parent().as_ptr(), parent.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let metas = buffer.iter_meta::<Meta>().collect::<Vec<_>>();
|
||||
assert_eq!(metas.len(), 1);
|
||||
}
|
||||
{
|
||||
let metas = buffer
|
||||
.get_mut()
|
||||
.unwrap()
|
||||
.iter_meta_mut::<Meta>()
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(metas.len(), 1);
|
||||
}
|
||||
{
|
||||
let metas = buffer.iter_meta::<ParentBufferMeta>().collect::<Vec<_>>();
|
||||
assert_eq!(metas.len(), 1);
|
||||
unsafe {
|
||||
assert_eq!(metas[0].get_parent().as_ptr(), parent.as_ptr());
|
||||
}
|
||||
}
|
||||
{
|
||||
let metas = buffer
|
||||
.get_mut()
|
||||
.unwrap()
|
||||
.iter_meta_mut::<ParentBufferMeta>()
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(metas.len(), 1);
|
||||
unsafe {
|
||||
assert_eq!(metas[0].get_parent().as_ptr(), parent.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let meta = buffer
|
||||
.get_mut()
|
||||
.unwrap()
|
||||
.get_meta_mut::<ParentBufferMeta>()
|
||||
.unwrap();
|
||||
unsafe {
|
||||
assert_eq!(meta.get_parent().as_ptr(), parent.as_ptr());
|
||||
}
|
||||
meta.remove();
|
||||
}
|
||||
|
||||
{
|
||||
let metas = buffer.iter_meta::<Meta>().collect::<Vec<_>>();
|
||||
assert_eq!(metas.len(), 0);
|
||||
}
|
||||
{
|
||||
let metas = buffer
|
||||
.get_mut()
|
||||
.unwrap()
|
||||
.iter_meta_mut::<Meta>()
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(metas.len(), 0);
|
||||
}
|
||||
{
|
||||
let metas = buffer.iter_meta::<ParentBufferMeta>().collect::<Vec<_>>();
|
||||
assert_eq!(metas.len(), 0);
|
||||
}
|
||||
{
|
||||
let metas = buffer
|
||||
.get_mut()
|
||||
.unwrap()
|
||||
.iter_meta_mut::<ParentBufferMeta>()
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(metas.len(), 0);
|
||||
}
|
||||
|
||||
assert!(buffer.get_meta::<ParentBufferMeta>().is_none());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue