diff --git a/video/gtk4/Cargo.toml b/video/gtk4/Cargo.toml index 7048590a..baf37c8c 100644 --- a/video/gtk4/Cargo.toml +++ b/video/gtk4/Cargo.toml @@ -21,6 +21,7 @@ gst_gl = { package = "gstreamer-gl", git = "https://gitlab.freedesktop.org/gstre gst_gl_wayland = { package = "gstreamer-gl-wayland", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.21", version = "0.21", features = ["v1_16"], optional = true } gst_gl_x11 = { package = "gstreamer-gl-x11", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.21", version = "0.21", features = ["v1_16"], optional = true } gst_gl_egl = { package = "gstreamer-gl-egl", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.21", version = "0.21", features = ["v1_16"], optional = true } +async-channel = "2.0.0" [target.'cfg(target_os = "macos")'.dependencies] diff --git a/video/gtk4/src/sink/imp.rs b/video/gtk4/src/sink/imp.rs index 6b23b71d..fd5b7fd4 100644 --- a/video/gtk4/src/sink/imp.rs +++ b/video/gtk4/src/sink/imp.rs @@ -13,8 +13,7 @@ use super::SinkEvent; use crate::sink::frame::Frame; use crate::sink::paintable::Paintable; -use glib::{thread_guard::ThreadGuard, Sender}; -use gtk::prelude::GLContextExt; +use glib::thread_guard::ThreadGuard; use gtk::prelude::*; use gtk::{gdk, glib}; @@ -61,7 +60,7 @@ static CAT: Lazy = Lazy::new(|| { pub struct PaintableSink { paintable: Mutex>>, info: Mutex>, - sender: Mutex>>, + sender: Mutex>>, pending_frame: Mutex>, cached_caps: Mutex>, } @@ -450,10 +449,16 @@ impl VideoSinkImpl for PaintableSink { gst::FlowError::Flushing })?; - sender.send(SinkEvent::FrameChanged).map_err(|_| { - gst::error!(CAT, imp: self, "Have main thread receiver shut down"); - gst::FlowError::Flushing - })?; + match sender.try_send(SinkEvent::FrameChanged) { + Ok(_) => (), + Err(async_channel::TrySendError::Full(_)) => { + gst::warning!(CAT, imp: self, "Have too many pending frames"); + } + Err(async_channel::TrySendError::Closed(_)) => { + gst::error!(CAT, imp: self, "Have main thread receiver shut down"); + return Err(gst::FlowError::Flushing); + } + } Ok(gst::FlowSuccess::Ok) } @@ -522,20 +527,24 @@ impl PaintableSink { gst::debug!(CAT, imp: self, "Initializing paintable"); // The channel for the SinkEvents - let (sender, receiver) = glib::MainContext::channel(glib::Priority::DEFAULT); - let self_ = self.to_owned(); + let (sender, receiver) = async_channel::bounded(3); + // Spawn an async task on the main context to handle the channel messages + let main_context = glib::MainContext::default(); + + let self_ = self.downgrade(); + main_context.spawn(async move { + while let Ok(action) = receiver.recv().await { + let Some(self_) = self_.upgrade() else { + break; + }; + + self_.do_action(action); + } + }); + + // Create the paintable from the main thread let paintable = utils::invoke_on_main_thread(move || { - // Attach the receiver from the main thread to make sure it is called - // from a place where it can acquire the default main context. - receiver.attach( - Some(&glib::MainContext::default()), - glib::clone!( - @weak self_ => @default-return glib::ControlFlow::Break, - move |action| self_.do_action(action) - ), - ); - #[cfg(any(target_os = "macos", target_os = "windows", feature = "gst_gl"))] { let gdk_context = if let GLContext::Initialized { gdk_context, .. } =