diff --git a/examples/src/bin/events.rs b/examples/src/bin/events.rs index ceabfa20f..473c41546 100644 --- a/examples/src/bin/events.rs +++ b/examples/src/bin/events.rs @@ -30,9 +30,44 @@ fn example_main() { let main_loop = glib::MainLoop::new(None, false); // This creates a pipeline by parsing the gst-launch pipeline syntax. - let pipeline = gst::parse::launch("audiotestsrc ! fakesink").unwrap(); + let pipeline = gst::parse::launch("audiotestsrc ! identity name=capsmut ! fakesink").unwrap(); let bus = pipeline.bus().unwrap(); + // This is a contrived example to mutate events. This would normally be code inside an element, + // which might transform caps to reflect transformation in the data + let identity = pipeline + .downcast_ref::() + .unwrap() + .by_name("capsmut") + .unwrap(); + let _ = identity.static_pad("sink").unwrap().add_probe( + gst::PadProbeType::EVENT_DOWNSTREAM, + move |_, probe_info| { + let Some(e) = probe_info.event() else { + return gst::PadProbeReturn::Ok; + }; + + if e.type_() != gst::EventType::Caps { + return gst::PadProbeReturn::Ok; + }; + + let mut ev = probe_info.take_event().unwrap(); + let ev_ref = ev.make_mut(); + + let gst::EventViewMut::Caps(caps) = ev_ref.view_mut() else { + unreachable!() + }; + + caps.structure_mut().set("custom-field", true); + identity + .static_pad("src") + .unwrap() + .push_event(ev_ref.to_owned()); + + gst::PadProbeReturn::Drop + }, + ); + pipeline .set_state(gst::State::Playing) .expect("Unable to set the pipeline to the `Playing` state"); diff --git a/gstreamer/src/event.rs b/gstreamer/src/event.rs index 4a4672a62..29bac4bf0 100644 --- a/gstreamer/src/event.rs +++ b/gstreamer/src/event.rs @@ -1,6 +1,8 @@ // Take a look at the license at the top of the repository in the LICENSE file. -use std::{borrow::Borrow, cmp, ffi::CStr, fmt, mem, num::NonZeroU32, ops::Deref, ptr}; +use std::{ + borrow::Borrow, cmp, ffi::CStr, fmt, mem, num::NonZeroU32, ops::Deref, ops::DerefMut, ptr, +}; use glib::{ translate::{FromGlibPtrContainer, *}, @@ -281,6 +283,49 @@ impl EventRef { } } } + + pub fn view_mut(&mut self) -> EventViewMut { + unsafe { + let type_ = (*self.as_ptr()).type_; + + match type_ { + ffi::GST_EVENT_FLUSH_START => FlushStart::view_mut(self), + ffi::GST_EVENT_FLUSH_STOP => FlushStop::view_mut(self), + ffi::GST_EVENT_STREAM_START => StreamStart::view_mut(self), + ffi::GST_EVENT_CAPS => Caps::view_mut(self), + ffi::GST_EVENT_SEGMENT => Segment::view_mut(self), + ffi::GST_EVENT_STREAM_COLLECTION => StreamCollection::view_mut(self), + ffi::GST_EVENT_TAG => Tag::view_mut(self), + ffi::GST_EVENT_BUFFERSIZE => Buffersize::view_mut(self), + ffi::GST_EVENT_SINK_MESSAGE => SinkMessage::view_mut(self), + ffi::GST_EVENT_STREAM_GROUP_DONE => StreamGroupDone::view_mut(self), + ffi::GST_EVENT_EOS => Eos::view_mut(self), + ffi::GST_EVENT_TOC => Toc::view_mut(self), + ffi::GST_EVENT_PROTECTION => Protection::view_mut(self), + ffi::GST_EVENT_SEGMENT_DONE => SegmentDone::view_mut(self), + ffi::GST_EVENT_GAP => Gap::view_mut(self), + #[cfg(feature = "v1_18")] + ffi::GST_EVENT_INSTANT_RATE_CHANGE => InstantRateChange::view_mut(self), + ffi::GST_EVENT_QOS => Qos::view_mut(self), + ffi::GST_EVENT_SEEK => Seek::view_mut(self), + ffi::GST_EVENT_NAVIGATION => Navigation::view_mut(self), + ffi::GST_EVENT_LATENCY => Latency::view_mut(self), + ffi::GST_EVENT_STEP => Step::view_mut(self), + ffi::GST_EVENT_RECONFIGURE => Reconfigure::view_mut(self), + ffi::GST_EVENT_TOC_SELECT => TocSelect::view_mut(self), + ffi::GST_EVENT_SELECT_STREAMS => SelectStreams::view_mut(self), + #[cfg(feature = "v1_18")] + ffi::GST_EVENT_INSTANT_RATE_SYNC_TIME => InstantRateSyncTime::view_mut(self), + ffi::GST_EVENT_CUSTOM_UPSTREAM => CustomUpstream::view_mut(self), + ffi::GST_EVENT_CUSTOM_DOWNSTREAM => CustomDownstream::view_mut(self), + ffi::GST_EVENT_CUSTOM_DOWNSTREAM_OOB => CustomDownstreamOob::view_mut(self), + ffi::GST_EVENT_CUSTOM_DOWNSTREAM_STICKY => CustomDownstreamSticky::view_mut(self), + ffi::GST_EVENT_CUSTOM_BOTH => CustomBoth::view_mut(self), + ffi::GST_EVENT_CUSTOM_BOTH_OOB => CustomBothOob::view_mut(self), + _ => Other::view_mut(self), + } + } + } } impl fmt::Debug for Event { @@ -347,6 +392,47 @@ pub enum EventView<'a> { Other(&'a Other), } +#[derive(Debug)] +#[non_exhaustive] +pub enum EventViewMut<'a> { + FlushStart(&'a mut FlushStart), + FlushStop(&'a mut FlushStop), + StreamStart(&'a mut StreamStart), + Caps(&'a mut Caps), + Segment(&'a mut Segment), + StreamCollection(&'a mut StreamCollection), + Tag(&'a mut Tag), + Buffersize(&'a mut Buffersize), + SinkMessage(&'a mut SinkMessage), + StreamGroupDone(&'a mut StreamGroupDone), + Eos(&'a mut Eos), + Toc(&'a mut Toc), + Protection(&'a mut Protection), + SegmentDone(&'a mut SegmentDone), + Gap(&'a mut Gap), + #[cfg(feature = "v1_18")] + #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] + InstantRateChange(&'a mut InstantRateChange), + Qos(&'a mut Qos), + Seek(&'a mut Seek), + Navigation(&'a mut Navigation), + Latency(&'a mut Latency), + Step(&'a mut Step), + Reconfigure(&'a mut Reconfigure), + TocSelect(&'a mut TocSelect), + SelectStreams(&'a mut SelectStreams), + #[cfg(feature = "v1_18")] + #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] + InstantRateSyncTime(&'a mut InstantRateSyncTime), + CustomUpstream(&'a mut CustomUpstream), + CustomDownstream(&'a mut CustomDownstream), + CustomDownstreamOob(&'a mut CustomDownstreamOob), + CustomDownstreamSticky(&'a mut CustomDownstreamSticky), + CustomBoth(&'a mut CustomBoth), + CustomBothOob(&'a mut CustomBothOob), + Other(&'a mut Other), +} + macro_rules! declare_concrete_event { (@sticky $name:ident, $param:ident) => { declare_concrete_event!($name, $param); @@ -370,11 +456,22 @@ macro_rules! declare_concrete_event { unsafe { &*(self as *const Self as *const EventRef) } } + #[inline] + pub fn event_mut(&mut self) -> &mut EventRef { + unsafe { &mut *(self as *mut Self as *mut EventRef) } + } + #[inline] unsafe fn view(event: &EventRef) -> EventView<'_> { let event = &*(event as *const EventRef as *const Self); EventView::$name(event) } + + #[inline] + unsafe fn view_mut(event: &mut EventRef) -> EventViewMut<'_> { + let event = &mut *(event as *mut EventRef as *mut Self); + EventViewMut::$name(event) + } } impl Deref for $name { @@ -386,6 +483,13 @@ macro_rules! declare_concrete_event { } } + impl DerefMut for $name { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + self.event_mut() + } + } + impl ToOwned for $name { type Owned = $name; @@ -413,6 +517,14 @@ macro_rules! declare_concrete_event { } } + impl DerefMut for $name { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + debug_assert!(self.0.is_writable()); + unsafe { &mut *(self.0.as_mut_ptr() as *mut Self::Target) } + } + } + impl Borrow<$name> for $name { #[inline] fn borrow(&self) -> &$name { diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 885805e7c..4cfdbd440 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -148,7 +148,7 @@ mod bufferlist_serde; pub mod query; pub use crate::query::{Query, QueryRef, QueryView, QueryViewMut}; pub mod event; -pub use crate::event::{Event, EventRef, EventView, GroupId, Seqnum}; +pub use crate::event::{Event, EventRef, EventView, EventViewMut, GroupId, Seqnum}; pub mod context; pub use crate::context::{Context, ContextRef}; mod rank;