gstreamer/pad: Add support for filling the passed in buffer in the getrange function

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/issues/242
This commit is contained in:
Sebastian Dröge 2020-03-29 20:11:00 +03:00
parent 7c2f3bafa0
commit d7e6c2e37f
2 changed files with 90 additions and 7 deletions

View file

@ -238,7 +238,7 @@ pub use enums::{
StateChangeError, StateChangeSuccess, TagError,
};
pub use gobject::GObjectExtManualGst;
pub use pad::{PadExtManual, PadProbeData, PadProbeId, PadProbeInfo};
pub use pad::{PadExtManual, PadGetRangeSuccess, PadProbeData, PadProbeId, PadProbeInfo};
pub use parse_context::ParseContext;
mod plugin_feature;
pub use plugin_feature::PluginFeatureExtManual;

View file

@ -115,6 +115,12 @@ impl Drop for StreamLock {
}
}
#[derive(Debug)]
pub enum PadGetRangeSuccess {
FilledBuffer,
NewBuffer(::Buffer),
}
pub trait PadExtManual: 'static {
fn add_probe<F>(&self, mask: PadProbeType, func: F) -> Option<PadProbeId>
where
@ -207,7 +213,13 @@ pub trait PadExtManual: 'static {
fn set_getrange_function<F>(&self, func: F)
where
F: Fn(&Self, Option<&::Object>, u64, u32) -> Result<::Buffer, ::FlowError>
F: Fn(
&Self,
Option<&::Object>,
u64,
Option<&mut ::BufferRef>,
u32,
) -> Result<PadGetRangeSuccess, ::FlowError>
+ Send
+ Sync
+ 'static;
@ -680,7 +692,13 @@ impl<O: IsA<Pad>> PadExtManual for O {
fn set_getrange_function<F>(&self, func: F)
where
F: Fn(&Self, Option<&::Object>, u64, u32) -> Result<::Buffer, FlowError>
F: Fn(
&Self,
Option<&::Object>,
u64,
Option<&mut ::BufferRef>,
u32,
) -> Result<PadGetRangeSuccess, ::FlowError>
+ Send
+ Sync
+ 'static,
@ -1344,7 +1362,16 @@ where
unsafe extern "C" fn trampoline_getrange_function<
T,
F: Fn(&T, Option<&::Object>, u64, u32) -> Result<::Buffer, FlowError> + Send + Sync + 'static,
F: Fn(
&T,
Option<&::Object>,
u64,
Option<&mut ::BufferRef>,
u32,
) -> Result<PadGetRangeSuccess, ::FlowError>
+ Send
+ Sync
+ 'static,
>(
pad: *mut gst_sys::GstPad,
parent: *mut gst_sys::GstObject,
@ -1355,16 +1382,72 @@ unsafe extern "C" fn trampoline_getrange_function<
where
T: IsA<Pad>,
{
use std::ops::DerefMut;
let func: &F = &*((*pad).getrangedata as *const F);
assert!(!buffer.is_null());
let pad = Pad::from_glib_borrow(pad).unsafe_cast();
let mut passed_buffer = if (*buffer).is_null() {
None
} else {
Some(::BufferRef::from_mut_ptr(*buffer))
};
match func(
&Pad::from_glib_borrow(pad).unsafe_cast(),
&pad,
Option::<::Object>::from_glib_borrow(parent).as_ref(),
offset,
passed_buffer.as_mut().map(|b| b.deref_mut()),
length,
) {
Ok(new_buffer) => {
*buffer = new_buffer.into_ptr();
Ok(PadGetRangeSuccess::NewBuffer(new_buffer)) => {
if let Some(passed_buffer) = passed_buffer {
gst_debug!(
::CAT_PERFORMANCE,
obj: pad.unsafe_cast_ref::<glib::Object>(),
"Returned new buffer from getrange function, copying into passed buffer"
);
let mut map = match passed_buffer.map_writable() {
Ok(map) => map,
Err(_) => {
gst_error!(
::CAT_RUST,
obj: pad.unsafe_cast_ref::<glib::Object>(),
"Failed to map passed buffer writable"
);
return gst_sys::GST_FLOW_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, ::BUFFER_COPY_METADATA, 0, None) {
Ok(_) => FlowReturn::Ok.to_glib(),
Err(_) => {
gst_error!(
::CAT_RUST,
obj: pad.unsafe_cast_ref::<glib::Object>(),
"Failed to copy buffer metadata"
);
FlowReturn::Error.to_glib()
}
}
} else {
*buffer = new_buffer.into_ptr();
FlowReturn::Ok.to_glib()
}
}
Ok(PadGetRangeSuccess::FilledBuffer) => {
assert!(passed_buffer.is_some());
FlowReturn::Ok.to_glib()
}
Err(ret) => FlowReturn::from_error(ret).to_glib(),