forked from mirrors/gstreamer-rs
gstreamer: pad: use ControlFlow with custom enum for sticky_events_foreach() return value
... instead of Result<Option<Event>,Option<Event>> which isn't very nice. And use static dispatch instead of dynamic dispatch. Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/361
This commit is contained in:
parent
1d78ac9323
commit
e0e17b8b25
2 changed files with 142 additions and 27 deletions
|
@ -173,6 +173,7 @@ mod gobject;
|
||||||
mod iterator;
|
mod iterator;
|
||||||
mod object;
|
mod object;
|
||||||
mod pad;
|
mod pad;
|
||||||
|
pub use pad::*;
|
||||||
mod registry;
|
mod registry;
|
||||||
pub use crate::pad::PadBuilder;
|
pub use crate::pad::PadBuilder;
|
||||||
mod control_binding;
|
mod control_binding;
|
||||||
|
|
|
@ -22,6 +22,7 @@ use crate::{SpecificFormattedValue, SpecificFormattedValueIntrinsic};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use glib::ffi::gpointer;
|
use glib::ffi::gpointer;
|
||||||
|
@ -88,6 +89,13 @@ pub enum PadGetRangeSuccess {
|
||||||
NewBuffer(crate::Buffer),
|
NewBuffer(crate::Buffer),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum EventForeachAction {
|
||||||
|
Keep,
|
||||||
|
Remove,
|
||||||
|
Replace(Event),
|
||||||
|
}
|
||||||
|
|
||||||
pub trait PadExtManual: 'static {
|
pub trait PadExtManual: 'static {
|
||||||
#[doc(alias = "gst_pad_add_probe")]
|
#[doc(alias = "gst_pad_add_probe")]
|
||||||
fn add_probe<F>(&self, mask: PadProbeType, func: F) -> Option<PadProbeId>
|
fn add_probe<F>(&self, mask: PadProbeType, func: F) -> Option<PadProbeId>
|
||||||
|
@ -275,9 +283,10 @@ pub trait PadExtManual: 'static {
|
||||||
|
|
||||||
#[doc(alias = "get_mode")]
|
#[doc(alias = "get_mode")]
|
||||||
fn mode(&self) -> crate::PadMode;
|
fn mode(&self) -> crate::PadMode;
|
||||||
|
|
||||||
#[doc(alias = "gst_pad_sticky_events_foreach")]
|
#[doc(alias = "gst_pad_sticky_events_foreach")]
|
||||||
fn sticky_events_foreach<F: FnMut(Event) -> Result<Option<Event>, Option<Event>>>(
|
fn sticky_events_foreach<
|
||||||
|
F: FnMut(&Event) -> ControlFlow<EventForeachAction, EventForeachAction>,
|
||||||
|
>(
|
||||||
&self,
|
&self,
|
||||||
func: F,
|
func: F,
|
||||||
);
|
);
|
||||||
|
@ -969,50 +978,51 @@ impl<O: IsA<Pad>> PadExtManual for O {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sticky_events_foreach<F: FnMut(Event) -> Result<Option<Event>, Option<Event>>>(
|
fn sticky_events_foreach<
|
||||||
|
F: FnMut(&Event) -> ControlFlow<EventForeachAction, EventForeachAction>,
|
||||||
|
>(
|
||||||
&self,
|
&self,
|
||||||
func: F,
|
func: F,
|
||||||
) {
|
) {
|
||||||
unsafe extern "C" fn trampoline(
|
unsafe extern "C" fn trampoline<
|
||||||
|
F: FnMut(&Event) -> ControlFlow<EventForeachAction, EventForeachAction>,
|
||||||
|
>(
|
||||||
_pad: *mut ffi::GstPad,
|
_pad: *mut ffi::GstPad,
|
||||||
event: *mut *mut ffi::GstEvent,
|
event: *mut *mut ffi::GstEvent,
|
||||||
user_data: glib::ffi::gpointer,
|
user_data: glib::ffi::gpointer,
|
||||||
) -> glib::ffi::gboolean {
|
) -> glib::ffi::gboolean {
|
||||||
let func =
|
let func = user_data as *mut F;
|
||||||
user_data as *mut &mut (dyn FnMut(Event) -> Result<Option<Event>, Option<Event>>);
|
let res = (*func)(&from_glib_borrow(*event));
|
||||||
let res = (*func)(from_glib_full(*event));
|
|
||||||
|
|
||||||
match res {
|
let (do_continue, ev_action) = match res {
|
||||||
Ok(Some(ev)) => {
|
ControlFlow::Continue(ev_action) => (glib::ffi::GTRUE, ev_action),
|
||||||
*event = ev.into_ptr();
|
ControlFlow::Break(ev_action) => (glib::ffi::GFALSE, ev_action),
|
||||||
glib::ffi::GTRUE
|
};
|
||||||
}
|
|
||||||
Err(Some(ev)) => {
|
use EventForeachAction::*;
|
||||||
*event = ev.into_ptr();
|
|
||||||
glib::ffi::GFALSE
|
match ev_action {
|
||||||
}
|
Keep => (), // do nothing
|
||||||
Ok(None) => {
|
Remove => {
|
||||||
|
ffi::gst_mini_object_unref(*event as *mut _);
|
||||||
*event = ptr::null_mut();
|
*event = ptr::null_mut();
|
||||||
glib::ffi::GTRUE
|
|
||||||
}
|
}
|
||||||
Err(None) => {
|
Replace(ev) => {
|
||||||
*event = ptr::null_mut();
|
ffi::gst_mini_object_unref(*event as *mut _);
|
||||||
glib::ffi::GFALSE
|
*event = ev.into_ptr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_continue
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut func = func;
|
let mut func = func;
|
||||||
let func_obj: &mut (dyn FnMut(Event) -> Result<Option<Event>, Option<Event>>) =
|
let func_ptr = &mut func as *mut F as glib::ffi::gpointer;
|
||||||
&mut func;
|
|
||||||
let func_ptr = &func_obj
|
|
||||||
as *const &mut (dyn FnMut(Event) -> Result<Option<Event>, Option<Event>>)
|
|
||||||
as glib::ffi::gpointer;
|
|
||||||
|
|
||||||
ffi::gst_pad_sticky_events_foreach(
|
ffi::gst_pad_sticky_events_foreach(
|
||||||
self.as_ref().to_glib_none().0,
|
self.as_ref().to_glib_none().0,
|
||||||
Some(trampoline),
|
Some(trampoline::<F>),
|
||||||
func_ptr,
|
func_ptr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2107,4 +2117,108 @@ mod tests {
|
||||||
"An event ref leaked!"
|
"An event ref leaked!"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sticky_events_foreach() {
|
||||||
|
crate::init().unwrap();
|
||||||
|
|
||||||
|
let pad = crate::Pad::builder(Some("sink"), crate::PadDirection::Sink).build();
|
||||||
|
pad.set_active(true).unwrap();
|
||||||
|
|
||||||
|
// Send some sticky events
|
||||||
|
assert!(pad.send_event(crate::event::StreamStart::new("test")));
|
||||||
|
|
||||||
|
let caps = crate::Caps::builder("some/x-caps").build();
|
||||||
|
assert!(pad.send_event(crate::event::Caps::new(&caps)));
|
||||||
|
|
||||||
|
let segment = crate::FormattedSegment::<crate::ClockTime>::new();
|
||||||
|
assert!(pad.send_event(crate::event::Segment::new(segment.as_ref())));
|
||||||
|
|
||||||
|
let mut sticky_events = Vec::new();
|
||||||
|
pad.sticky_events_foreach(|event| {
|
||||||
|
sticky_events.push(event.clone());
|
||||||
|
ControlFlow::Continue(EventForeachAction::Keep)
|
||||||
|
});
|
||||||
|
assert_eq!(sticky_events.len(), 3);
|
||||||
|
|
||||||
|
// Test early exit from foreach loop
|
||||||
|
let mut sticky_events2 = Vec::new();
|
||||||
|
pad.sticky_events_foreach(|event| {
|
||||||
|
sticky_events2.push(event.clone());
|
||||||
|
if event.type_() == crate::EventType::Caps {
|
||||||
|
ControlFlow::Break(EventForeachAction::Keep)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(EventForeachAction::Keep)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert_eq!(sticky_events2.len(), 2);
|
||||||
|
|
||||||
|
let mut sticky_events3 = Vec::new();
|
||||||
|
pad.sticky_events_foreach(|event| {
|
||||||
|
sticky_events3.push(event.clone());
|
||||||
|
ControlFlow::Continue(EventForeachAction::Keep)
|
||||||
|
});
|
||||||
|
assert_eq!(sticky_events3.len(), 3);
|
||||||
|
|
||||||
|
for (e1, e2) in sticky_events.iter().zip(sticky_events3.iter()) {
|
||||||
|
assert_eq!(e1.as_ref() as *const _, e2.as_ref() as *const _);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace segment event
|
||||||
|
pad.sticky_events_foreach(|event| {
|
||||||
|
let action = if event.type_() == crate::EventType::Segment {
|
||||||
|
let byte_segment = crate::FormattedSegment::<crate::format::Bytes>::new();
|
||||||
|
EventForeachAction::Replace(crate::event::Segment::new(&byte_segment))
|
||||||
|
} else {
|
||||||
|
EventForeachAction::Keep
|
||||||
|
};
|
||||||
|
ControlFlow::Continue(action)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that segment event is different now
|
||||||
|
let mut sticky_events4 = Vec::new();
|
||||||
|
pad.sticky_events_foreach(|event| {
|
||||||
|
sticky_events4.push(event.clone());
|
||||||
|
ControlFlow::Continue(EventForeachAction::Keep)
|
||||||
|
});
|
||||||
|
assert_eq!(sticky_events4.len(), 3);
|
||||||
|
assert_eq!(
|
||||||
|
sticky_events[0].as_ref() as *const _,
|
||||||
|
sticky_events4[0].as_ref() as *const _
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sticky_events[1].as_ref() as *const _,
|
||||||
|
sticky_events4[1].as_ref() as *const _
|
||||||
|
);
|
||||||
|
assert_ne!(
|
||||||
|
sticky_events[2].as_ref() as *const _,
|
||||||
|
sticky_events4[2].as_ref() as *const _
|
||||||
|
);
|
||||||
|
|
||||||
|
// Drop caps event
|
||||||
|
pad.sticky_events_foreach(|event| {
|
||||||
|
let action = if event.type_() == crate::EventType::Caps {
|
||||||
|
EventForeachAction::Remove
|
||||||
|
} else {
|
||||||
|
EventForeachAction::Keep
|
||||||
|
};
|
||||||
|
ControlFlow::Continue(action)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that caps event actually got removed
|
||||||
|
let mut sticky_events5 = Vec::new();
|
||||||
|
pad.sticky_events_foreach(|event| {
|
||||||
|
sticky_events5.push(event.clone());
|
||||||
|
ControlFlow::Continue(EventForeachAction::Keep)
|
||||||
|
});
|
||||||
|
assert_eq!(sticky_events5.len(), 2);
|
||||||
|
assert_eq!(
|
||||||
|
sticky_events4[0].as_ref() as *const _,
|
||||||
|
sticky_events5[0].as_ref() as *const _
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sticky_events4[2].as_ref() as *const _,
|
||||||
|
sticky_events5[1].as_ref() as *const _
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue