From c66287843f46e5fcd66fe16fcbcac6b6e392f830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 19 Sep 2021 15:44:23 +0300 Subject: [PATCH] gstreamer-base: Allow filling a passed in buffer in PushSrc::create() Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/277 --- gstreamer-base/src/subclass/push_src.rs | 153 +++++++++++++++++++++--- 1 file changed, 138 insertions(+), 15 deletions(-) diff --git a/gstreamer-base/src/subclass/push_src.rs b/gstreamer-base/src/subclass/push_src.rs index 7e4bb2e35..0ec7a3bf7 100644 --- a/gstreamer-base/src/subclass/push_src.rs +++ b/gstreamer-base/src/subclass/push_src.rs @@ -4,9 +4,11 @@ use glib::prelude::*; use glib::subclass::prelude::*; use glib::translate::*; +use gst::{gst_debug, gst_error}; + use std::ptr; -use super::base_src::BaseSrcImpl; +use super::base_src::{BaseSrcImpl, CreateSuccess}; use crate::PushSrc; pub trait PushSrcImpl: PushSrcImplExt + BaseSrcImpl { @@ -22,8 +24,12 @@ pub trait PushSrcImpl: PushSrcImplExt + BaseSrcImpl { PushSrcImplExt::parent_alloc(self, element) } - fn create(&self, element: &Self::Type) -> Result { - PushSrcImplExt::parent_create(self, element) + fn create( + &self, + element: &Self::Type, + buffer: Option<&mut gst::BufferRef>, + ) -> Result { + PushSrcImplExt::parent_create(self, element, buffer) } } @@ -36,7 +42,11 @@ pub trait PushSrcImplExt: ObjectSubclass { fn parent_alloc(&self, element: &Self::Type) -> Result; - fn parent_create(&self, element: &Self::Type) -> Result; + fn parent_create( + &self, + element: &Self::Type, + buffer: Option<&mut gst::BufferRef>, + ) -> Result; } impl PushSrcImplExt for T { @@ -83,24 +93,81 @@ impl PushSrcImplExt for T { } } - fn parent_create(&self, element: &Self::Type) -> Result { + fn parent_create( + &self, + element: &Self::Type, + mut buffer: Option<&mut gst::BufferRef>, + ) -> Result { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstPushSrcClass; (*parent_class) .create .map(|f| { - let mut buffer_ptr: *mut gst::ffi::GstBuffer = ptr::null_mut(); + let orig_buffer_ptr = buffer + .as_mut() + .map(|b| b.as_mut_ptr()) + .unwrap_or(ptr::null_mut()); + let mut buffer_ptr = orig_buffer_ptr; // FIXME: Wrong signature in -sys bindings // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3 let buffer_ref = &mut buffer_ptr as *mut _ as *mut gst::ffi::GstBuffer; - gst::FlowSuccess::try_from_glib(f( - element.unsafe_cast_ref::().to_glib_none().0, - buffer_ref, - )) - .map(|_| from_glib_full(buffer_ref)) + gst::FlowSuccess::try_from_glib( + f( + element.unsafe_cast_ref::().to_glib_none().0, + buffer_ref, + ) + )?; + + if let Some(passed_buffer) = buffer { + if buffer_ptr != orig_buffer_ptr { + let new_buffer = gst::BufferRef::from_ptr(buffer_ptr); + + gst_debug!( + gst::CAT_PERFORMANCE, + obj: element.unsafe_cast_ref::(), + "Returned new buffer from parent create function, copying into passed buffer" + ); + + let mut map = match passed_buffer.map_writable() { + Ok(map) => map, + Err(_) => { + gst_error!( + gst::CAT_RUST, + obj: element.unsafe_cast_ref::(), + "Failed to map passed buffer writable" + ); + return Err(gst::FlowError::Error); + } + }; + + let copied_size = new_buffer.copy_to_slice(0, &mut *map); + drop(map); + + if let Err(copied_size) = copied_size { + passed_buffer.set_size(copied_size); + } + + match new_buffer.copy_into(passed_buffer, gst::BUFFER_COPY_METADATA, 0, None) { + Ok(_) => Ok(CreateSuccess::FilledBuffer), + Err(_) => { + gst_error!( + gst::CAT_RUST, + obj: element.unsafe_cast_ref::(), + "Failed to copy buffer metadata" + ); + + Err(gst::FlowError::Error) + } + } + } else { + Ok(CreateSuccess::FilledBuffer) + } + } else { + Ok(CreateSuccess::NewBuffer(from_glib_full(buffer_ptr))) + } }) .unwrap_or(Err(gst::FlowError::NotSupported)) } @@ -170,12 +237,68 @@ unsafe extern "C" fn push_src_create( // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3 let buffer_ptr = buffer_ptr as *mut *mut gst::ffi::GstBuffer; + let mut buffer = if (*buffer_ptr).is_null() { + None + } else { + Some(gst::BufferRef::from_mut_ptr(*buffer_ptr)) + }; + gst::panic_to_error!(&wrap, imp.panicked(), gst::FlowReturn::Error, { - match PushSrcImpl::create(imp, wrap.unsafe_cast_ref()) { - Ok(buffer) => { - *buffer_ptr = buffer.into_ptr(); - gst::FlowReturn::Ok + match PushSrcImpl::create(imp, wrap.unsafe_cast_ref(), buffer.as_deref_mut()) { + Ok(CreateSuccess::NewBuffer(new_buffer)) => { + if let Some(passed_buffer) = buffer { + if passed_buffer.as_ptr() != new_buffer.as_ptr() { + gst_debug!( + gst::CAT_PERFORMANCE, + obj: &*wrap, + "Returned new buffer from create function, copying into passed buffer" + ); + + let mut map = match passed_buffer.map_writable() { + Ok(map) => map, + Err(_) => { + gst_error!( + gst::CAT_RUST, + obj: &*wrap, + "Failed to map passed buffer writable" + ); + return gst::FlowReturn::Error; + } + }; + + let copied_size = new_buffer.copy_to_slice(0, &mut *map); + drop(map); + + if let Err(copied_size) = copied_size { + passed_buffer.set_size(copied_size); + } + + match new_buffer.copy_into( + passed_buffer, + gst::BUFFER_COPY_METADATA, + 0, + None, + ) { + Ok(_) => gst::FlowReturn::Ok, + Err(_) => { + gst_error!( + gst::CAT_RUST, + obj: &*wrap, + "Failed to copy buffer metadata" + ); + + gst::FlowReturn::Error + } + } + } else { + gst::FlowReturn::Ok + } + } else { + *buffer_ptr = new_buffer.into_ptr(); + gst::FlowReturn::Ok + } } + Ok(CreateSuccess::FilledBuffer) => gst::FlowReturn::Ok, Err(err) => gst::FlowReturn::from(err), } })