diff --git a/Gir_Gst.toml b/Gir_Gst.toml index e497d5754..b70cc5177 100644 --- a/Gir_Gst.toml +++ b/Gir_Gst.toml @@ -52,6 +52,7 @@ generate = [ "Gst.PadProbeType", "Gst.PadProbeReturn", "Gst.CapsIntersectMode", + "Gst.BufferFlags", ] manual = [ diff --git a/gstreamer/src/auto/flags.rs b/gstreamer/src/auto/flags.rs index fe7f243e7..b4b5af455 100644 --- a/gstreamer/src/auto/flags.rs +++ b/gstreamer/src/auto/flags.rs @@ -8,6 +8,65 @@ use glib::value::{Value, SetValue, FromValue, FromValueOptional}; use gobject_ffi; use glib::translate::*; +bitflags! { + pub struct BufferFlags: u32 { + const BUFFER_FLAG_LIVE = 16; + const BUFFER_FLAG_DECODE_ONLY = 32; + const BUFFER_FLAG_DISCONT = 64; + const BUFFER_FLAG_RESYNC = 128; + const BUFFER_FLAG_CORRUPTED = 256; + const BUFFER_FLAG_MARKER = 512; + const BUFFER_FLAG_HEADER = 1024; + const BUFFER_FLAG_GAP = 2048; + const BUFFER_FLAG_DROPPABLE = 4096; + const BUFFER_FLAG_DELTA_UNIT = 8192; + const BUFFER_FLAG_TAG_MEMORY = 16384; + const BUFFER_FLAG_SYNC_AFTER = 32768; + const BUFFER_FLAG_LAST = 1048576; + } +} + +#[doc(hidden)] +impl ToGlib for BufferFlags { + type GlibType = ffi::GstBufferFlags; + + fn to_glib(&self) -> ffi::GstBufferFlags { + ffi::GstBufferFlags::from_bits_truncate(self.bits()) + } +} + +#[doc(hidden)] +impl FromGlib for BufferFlags { + fn from_glib(value: ffi::GstBufferFlags) -> BufferFlags { + skip_assert_initialized!(); + BufferFlags::from_bits_truncate(value.bits()) + } +} + +impl StaticType for BufferFlags { + fn static_type() -> Type { + unsafe { from_glib(ffi::gst_buffer_flags_get_type()) } + } +} + +impl<'a> FromValueOptional<'a> for BufferFlags { + unsafe fn from_value_optional(value: &Value) -> Option { + Some(FromValue::from_value(value)) + } +} + +impl<'a> FromValue<'a> for BufferFlags { + unsafe fn from_value(value: &Value) -> Self { + from_glib(ffi::GstBufferFlags::from_bits_truncate(gobject_ffi::g_value_get_flags(value.to_glib_none().0))) + } +} + +impl SetValue for BufferFlags { + unsafe fn set_value(value: &mut Value, this: &Self) { + gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, this.to_glib().bits()) + } +} + bitflags! { pub struct PadProbeType: u32 { const PAD_PROBE_TYPE_INVALID = 0; diff --git a/gstreamer/src/auto/mod.rs b/gstreamer/src/auto/mod.rs index b6835cd6b..1a52bf968 100644 --- a/gstreamer/src/auto/mod.rs +++ b/gstreamer/src/auto/mod.rs @@ -100,6 +100,20 @@ pub use self::enums::URIError; pub use self::enums::URIType; mod flags; +pub use self::flags::BufferFlags; +pub use self::flags::BUFFER_FLAG_LIVE; +pub use self::flags::BUFFER_FLAG_DECODE_ONLY; +pub use self::flags::BUFFER_FLAG_DISCONT; +pub use self::flags::BUFFER_FLAG_RESYNC; +pub use self::flags::BUFFER_FLAG_CORRUPTED; +pub use self::flags::BUFFER_FLAG_MARKER; +pub use self::flags::BUFFER_FLAG_HEADER; +pub use self::flags::BUFFER_FLAG_GAP; +pub use self::flags::BUFFER_FLAG_DROPPABLE; +pub use self::flags::BUFFER_FLAG_DELTA_UNIT; +pub use self::flags::BUFFER_FLAG_TAG_MEMORY; +pub use self::flags::BUFFER_FLAG_SYNC_AFTER; +pub use self::flags::BUFFER_FLAG_LAST; pub use self::flags::PadProbeType; pub use self::flags::PAD_PROBE_TYPE_INVALID; pub use self::flags::PAD_PROBE_TYPE_IDLE; diff --git a/gstreamer/src/buffer.rs b/gstreamer/src/buffer.rs new file mode 100644 index 000000000..ec9a180a5 --- /dev/null +++ b/gstreamer/src/buffer.rs @@ -0,0 +1,524 @@ +// Copyright (C) 2016-2017 Sebastian Dröge +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ptr; +use std::mem; +use std::fmt; +use std::slice; +use std::u64; +use std::usize; + +use miniobject::*; +use BufferFlags; + +use glib; +use glib_ffi; +use ffi; +use glib::translate::{from_glib, from_glib_full}; + +#[repr(C)] +pub struct BufferRef(ffi::GstBuffer); +pub type Buffer = GstRc; + +unsafe impl MiniObject for BufferRef { + type GstType = ffi::GstBuffer; +} + +//#[derive(Derivative)] +//#[derivative(Debug)] +pub struct ReadBufferMap<'a> { + buffer: &'a BufferRef, + //#[derivative(Debug = "ignore")] + map_info: ffi::GstMapInfo, +} + +//#[derive(Derivative)] +//#[derivative(Debug)] +pub struct ReadWriteBufferMap<'a> { + buffer: &'a BufferRef, + //#[derivative(Debug = "ignore")] + map_info: ffi::GstMapInfo, +} + +//#[derive(Derivative)] +//#[derivative(Debug)] +pub struct ReadMappedBuffer { + buffer: Buffer, + //#[derivative(Debug = "ignore")] + map_info: ffi::GstMapInfo, +} + +//#[derive(Derivative)] +//#[derivative(Debug)] +pub struct ReadWriteMappedBuffer { + buffer: Buffer, + //#[derivative(Debug = "ignore")] + map_info: ffi::GstMapInfo, +} + +impl GstRc { + pub fn new() -> Self { + assert_initialized_main_thread!(); + + unsafe { from_glib_full(ffi::gst_buffer_new()) } + } + + pub fn new_with_size(size: usize) -> Option { + let raw = unsafe { ffi::gst_buffer_new_allocate(ptr::null_mut(), size, ptr::null_mut()) }; + if raw.is_null() { + None + } else { + Some(unsafe { from_glib_full(raw) }) + } + } + + unsafe extern "C" fn vec_drop(vec: glib_ffi::gpointer) { + let vec: Box> = Box::from_raw(vec as *mut Vec); + drop(vec); + } + + pub fn from_vec(vec: Vec) -> Option { + let raw = unsafe { + let mut vec = Box::new(vec); + let maxsize = vec.capacity(); + let size = vec.len(); + let data = vec.as_mut_ptr(); + let user_data = Box::into_raw(vec); + ffi::gst_buffer_new_wrapped_full( + ffi::GstMemoryFlags::empty(), + data as glib_ffi::gpointer, + maxsize, + 0, + size, + user_data as glib_ffi::gpointer, + Some(Buffer::vec_drop), + ) + }; + + if raw.is_null() { + None + } else { + Some(unsafe { from_glib_full(raw) }) + } + } + + pub fn into_read_mapped_buffer(buffer: Self) -> Result { + let mut map_info: ffi::GstMapInfo = unsafe { mem::zeroed() }; + let res: bool = unsafe { + from_glib(ffi::gst_buffer_map( + buffer.as_mut_ptr(), + &mut map_info, + ffi::GST_MAP_READ, + )) + }; + if res { + Ok(ReadMappedBuffer { + buffer: buffer, + map_info: map_info, + }) + } else { + Err(buffer) + } + } + + pub fn into_readwrite_mapped_buffer(buffer: Self) -> Result { + let mut map_info: ffi::GstMapInfo = unsafe { mem::zeroed() }; + let res: bool = unsafe { + from_glib(ffi::gst_buffer_map( + buffer.as_mut_ptr(), + &mut map_info, + ffi::GST_MAP_READWRITE, + )) + }; + if res { + Ok(ReadWriteMappedBuffer { + buffer: buffer, + map_info: map_info, + }) + } else { + Err(buffer) + } + } + + pub fn append(buffer: Self, other: Self) -> Self { + unsafe { from_glib_full(ffi::gst_buffer_append(buffer.into_ptr(), other.into_ptr())) } + } +} + +impl BufferRef { + pub fn map_read(&self) -> Option { + let mut map_info: ffi::GstMapInfo = unsafe { mem::zeroed() }; + let res = + unsafe { ffi::gst_buffer_map(self.as_mut_ptr(), &mut map_info, ffi::GST_MAP_READ) }; + if res == glib_ffi::GTRUE { + Some(ReadBufferMap { + buffer: self, + map_info: map_info, + }) + } else { + None + } + } + + pub fn map_readwrite(&mut self) -> Option { + let mut map_info: ffi::GstMapInfo = unsafe { mem::zeroed() }; + let res = unsafe { + ffi::gst_buffer_map(self.as_mut_ptr(), &mut map_info, ffi::GST_MAP_READWRITE) + }; + if res == glib_ffi::GTRUE { + Some(ReadWriteBufferMap { + buffer: self, + map_info: map_info, + }) + } else { + None + } + } + + pub fn copy_region(&self, offset: usize, size: Option) -> Option { + let size_real = size.unwrap_or(usize::MAX); + let ptr = unsafe { + ffi::gst_buffer_copy_region( + self.as_mut_ptr(), + ffi::GST_BUFFER_COPY_ALL, + offset, + size_real, + ) + }; + + if ptr.is_null() { + None + } else { + Some(unsafe { from_glib_full(ptr) }) + } + } + + pub fn copy_from_slice(&mut self, offset: usize, slice: &[u8]) -> Result<(), usize> { + let maxsize = self.get_maxsize(); + let size = slice.len(); + + assert!(maxsize >= offset && maxsize - offset >= size); + + let copied = unsafe { + let src = slice.as_ptr(); + ffi::gst_buffer_fill( + self.as_mut_ptr(), + offset, + src as glib_ffi::gconstpointer, + size, + ) + }; + + if copied == size { + Ok(()) + } else { + Err(copied) + } + } + + pub fn copy_to_slice(&self, offset: usize, slice: &mut [u8]) -> Result<(), usize> { + let maxsize = self.get_size(); + let size = slice.len(); + + assert!(maxsize >= offset && maxsize - offset >= size); + + let copied = unsafe { + let dest = slice.as_mut_ptr(); + ffi::gst_buffer_extract(self.as_mut_ptr(), offset, dest as glib_ffi::gpointer, size) + }; + + if copied == size { + Ok(()) + } else { + Err(copied) + } + } + + pub fn get_size(&self) -> usize { + unsafe { ffi::gst_buffer_get_size(self.as_mut_ptr()) } + } + + pub fn get_maxsize(&self) -> usize { + let mut maxsize: usize = 0; + + unsafe { + ffi::gst_buffer_get_sizes_range( + self.as_mut_ptr(), + 0, + -1, + ptr::null_mut(), + &mut maxsize, + ); + }; + + maxsize + } + + pub fn set_size(&mut self, size: usize) { + assert!(self.get_maxsize() >= size); + + unsafe { + ffi::gst_buffer_set_size(self.as_mut_ptr(), size as isize); + } + } + + pub fn get_offset(&self) -> u64 { + self.0.offset + } + + pub fn set_offset(&mut self, offset: u64) { + self.0.offset = offset; + } + + pub fn get_offset_end(&self) -> u64 { + self.0.offset_end + } + + pub fn set_offset_end(&mut self, offset_end: u64) { + self.0.offset_end = offset_end; + } + + pub fn get_pts(&self) -> u64 { + self.0.pts + } + + pub fn set_pts(&mut self, pts: u64) { + self.0.pts = pts; + } + + pub fn get_dts(&self) -> u64 { + self.0.dts + } + + pub fn set_dts(&mut self, dts: u64) { + self.0.dts = dts; + } + + pub fn get_duration(&self) -> u64 { + self.0.duration + } + + pub fn set_duration(&mut self, duration: u64) { + self.0.duration = duration; + } + + pub fn get_flags(&self) -> BufferFlags { + BufferFlags::from_bits_truncate(self.0.mini_object.flags) + } + + pub fn set_flags(&mut self, flags: BufferFlags) { + self.0.mini_object.flags = flags.bits(); + } +} + +unsafe impl Sync for BufferRef {} +unsafe impl Send for BufferRef {} + +impl glib::types::StaticType for Buffer { + fn static_type() -> glib::types::Type { + unsafe { from_glib(ffi::gst_buffer_get_type()) } + } +} + +impl fmt::Debug for BufferRef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", unsafe { self.as_ptr() }) + } +} + +impl PartialEq for BufferRef { + fn eq(&self, other: &BufferRef) -> bool { + if self.get_size() != other.get_size() { + return false; + } + + let self_map = self.map_read(); + let other_map = other.map_read(); + + match (self_map, other_map) { + (Some(self_map), Some(other_map)) => self_map.as_slice().eq(other_map.as_slice()), + _ => false, + } + } +} + +impl Eq for BufferRef {} + +impl<'a> ReadBufferMap<'a> { + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.map_info.data as *const u8, self.map_info.size) } + } + + pub fn get_size(&self) -> usize { + self.map_info.size + } + + pub fn get_buffer(&self) -> &BufferRef { + self.buffer + } +} + +impl<'a> Drop for ReadBufferMap<'a> { + fn drop(&mut self) { + unsafe { + ffi::gst_buffer_unmap(self.buffer.as_mut_ptr(), &mut self.map_info); + } + } +} + +impl<'a> ReadWriteBufferMap<'a> { + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.map_info.data as *mut u8, self.map_info.size) } + } + + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.map_info.data as *const u8, self.map_info.size) } + } + + pub fn get_size(&self) -> usize { + self.map_info.size + } + + pub fn get_buffer(&self) -> &BufferRef { + self.buffer + } +} + +impl<'a> Drop for ReadWriteBufferMap<'a> { + fn drop(&mut self) { + unsafe { + ffi::gst_buffer_unmap(self.buffer.as_mut_ptr(), &mut self.map_info); + } + } +} + +impl ReadMappedBuffer { + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.map_info.data as *const u8, self.map_info.size) } + } + + pub fn get_size(&self) -> usize { + self.map_info.size + } + + pub fn get_buffer(&self) -> &BufferRef { + self.buffer.as_ref() + } +} + +impl Drop for ReadMappedBuffer { + fn drop(&mut self) { + unsafe { + ffi::gst_buffer_unmap(self.buffer.as_mut_ptr(), &mut self.map_info); + } + } +} + +unsafe impl Sync for ReadMappedBuffer {} +unsafe impl Send for ReadMappedBuffer {} + +impl ReadWriteMappedBuffer { + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.map_info.data as *mut u8, self.map_info.size) } + } + + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.map_info.data as *const u8, self.map_info.size) } + } + + pub fn get_size(&self) -> usize { + self.map_info.size + } + + pub fn get_buffer(&self) -> &BufferRef { + self.buffer.as_ref() + } +} + +impl Drop for ReadWriteMappedBuffer { + fn drop(&mut self) { + unsafe { + ffi::gst_buffer_unmap(self.buffer.as_mut_ptr(), &mut self.map_info); + } + } +} + +unsafe impl Send for ReadWriteMappedBuffer {} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_fields() { + ::init().unwrap(); + + let mut buffer = Buffer::new(); + + { + let buffer = buffer.get_mut().unwrap(); + buffer.set_pts(1); + buffer.set_dts(2); + buffer.set_offset(3); + buffer.set_offset_end(4); + buffer.set_duration(5); + } + assert_eq!(buffer.get_pts(), 1); + assert_eq!(buffer.get_dts(), 2); + assert_eq!(buffer.get_offset(), 3); + assert_eq!(buffer.get_offset_end(), 4); + assert_eq!(buffer.get_duration(), 5); + } + + #[test] + fn test_writability() { + ::init().unwrap(); + + let mut buffer = Buffer::from_vec(vec![1, 2, 3, 4]).unwrap(); + { + let data = buffer.map_read().unwrap(); + assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); + } + assert_ne!(buffer.get_mut(), None); + { + let buffer = buffer.get_mut().unwrap(); + buffer.set_pts(1); + } + + let mut buffer2 = buffer.clone(); + assert_eq!(buffer.get_mut(), None); + + unsafe { + assert_eq!(buffer2.as_ptr(), buffer.as_ptr()); + } + + { + let buffer2 = buffer2.make_mut(); + unsafe { + assert_ne!(buffer2.as_ptr(), buffer.as_ptr()); + } + + buffer2.set_pts(2); + + let mut data = buffer2.map_readwrite().unwrap(); + assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); + data.as_mut_slice()[0] = 0; + } + + assert_eq!(buffer.get_pts(), 1); + assert_eq!(buffer2.get_pts(), 2); + + { + let data = buffer.map_read().unwrap(); + assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); + + let data = buffer2.map_read().unwrap(); + assert_eq!(data.as_slice(), vec![0, 2, 3, 4].as_slice()); + } + } +} diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 51c5a1fbc..e3d95ea5c 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -56,6 +56,8 @@ pub mod caps; pub use caps::{Caps, CapsRef}; pub mod tags; pub use tags::*; +pub mod buffer; +pub use buffer::{Buffer, BufferRef, ReadBufferMap, ReadWriteBufferMap, ReadMappedBuffer, ReadWriteMappedBuffer}; mod element; mod bin; diff --git a/gstreamer/src/miniobject.rs b/gstreamer/src/miniobject.rs index af438c5b2..9d116a82e 100644 --- a/gstreamer/src/miniobject.rs +++ b/gstreamer/src/miniobject.rs @@ -145,8 +145,8 @@ impl Drop for GstRc { } } -unsafe impl Sync for GstRc {} -unsafe impl Send for GstRc {} +unsafe impl Sync for GstRc {} +unsafe impl Send for GstRc {} impl fmt::Display for GstRc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {