From 3dd800ac7728ea4b3cb6ef15213d66c762e5f8ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 24 Apr 2024 15:22:57 +0200 Subject: [PATCH] gtk4paintablesink: Implement child proxy interface This allows setting properties on the paintable from gst-launch-1.0. Part-of: --- docs/plugins/gst_plugins_cache.json | 3 + video/gtk4/src/sink/imp.rs | 89 ++++++++++++++++++++++++----- video/gtk4/src/sink/mod.rs | 3 +- 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/docs/plugins/gst_plugins_cache.json b/docs/plugins/gst_plugins_cache.json index ad9844ab..1c08c051 100644 --- a/docs/plugins/gst_plugins_cache.json +++ b/docs/plugins/gst_plugins_cache.json @@ -2472,6 +2472,9 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy" + ], "klass": "Sink/Video", "long-name": "GTK 4 Paintable Sink", "pad-templates": { diff --git a/video/gtk4/src/sink/imp.rs b/video/gtk4/src/sink/imp.rs index eff4b2ec..8b98c4cb 100644 --- a/video/gtk4/src/sink/imp.rs +++ b/video/gtk4/src/sink/imp.rs @@ -82,6 +82,7 @@ impl ObjectSubclass for PaintableSink { const NAME: &'static str = "GstGtk4PaintableSink"; type Type = super::PaintableSink; type ParentType = gst_video::VideoSink; + type Interfaces = (gst::ChildProxy,); } impl ObjectImpl for PaintableSink { @@ -110,12 +111,14 @@ impl ObjectImpl for PaintableSink { return None::<&gdk::Paintable>.to_value(); } - let mut paintable = self.paintable.lock().unwrap(); - if paintable.is_none() { - self.create_paintable(&mut paintable); + let mut paintable_guard = self.paintable.lock().unwrap(); + let mut created = false; + if paintable_guard.is_none() { + created = true; + self.create_paintable(&mut paintable_guard); } - let paintable = match &*paintable { + let paintable = match &*paintable_guard { Some(ref paintable) => paintable, None => { gst::error!(CAT, imp: self, "Failed to create paintable"); @@ -124,16 +127,31 @@ impl ObjectImpl for PaintableSink { }; // Getter must be called from the main thread - if paintable.is_owner() { - paintable.get_ref().to_value() - } else { + if !paintable.is_owner() { gst::error!( CAT, imp: self, "Can't retrieve Paintable from non-main thread" ); - None::<&gdk::Paintable>.to_value() + return None::<&gdk::Paintable>.to_value(); } + + let paintable = paintable.get_ref().clone(); + drop(paintable_guard); + + if created { + let self_ = self.to_owned(); + glib::MainContext::default().invoke(move || { + let paintable_guard = self_.paintable.lock().unwrap(); + if let Some(paintable) = &*paintable_guard { + let paintable_clone = paintable.get_ref().clone(); + drop(paintable_guard); + self_.obj().child_added(&paintable_clone, "paintable"); + } + }); + } + + paintable.to_value() } _ => unimplemented!(), } @@ -290,18 +308,31 @@ impl ElementImpl for PaintableSink { } } - let mut paintable = self.paintable.lock().unwrap(); - - if paintable.is_none() { - self.create_paintable(&mut paintable); + let mut paintable_guard = self.paintable.lock().unwrap(); + let mut created = false; + if paintable_guard.is_none() { + created = true; + self.create_paintable(&mut paintable_guard); } - if paintable.is_none() { + if paintable_guard.is_none() { gst::error!(CAT, imp: self, "Failed to create paintable"); return Err(gst::StateChangeError); } - drop(paintable); + drop(paintable_guard); + + if created { + let self_ = self.to_owned(); + glib::MainContext::default().invoke(move || { + let paintable_guard = self_.paintable.lock().unwrap(); + if let Some(paintable) = &*paintable_guard { + let paintable_clone = paintable.get_ref().clone(); + drop(paintable_guard); + self_.obj().child_added(&paintable_clone, "paintable"); + } + }); + } // Notify the pipeline about the GL display and wrapped context so that any other // elements in the pipeline ideally use the same / create GL contexts that are @@ -1189,3 +1220,33 @@ impl PaintableSink { } } } + +impl ChildProxyImpl for PaintableSink { + fn child_by_index(&self, index: u32) -> Option { + if index != 0 { + return None; + } + + let paintable = self.paintable.lock().unwrap(); + paintable + .as_ref() + .filter(|p| p.is_owner()) + .map(|p| p.get_ref().upcast_ref::().clone()) + } + + fn child_by_name(&self, name: &str) -> Option { + if name == "paintable" { + return self.child_by_index(0); + } + None + } + + fn children_count(&self) -> u32 { + let paintable = self.paintable.lock().unwrap(); + if paintable.is_some() { + 1 + } else { + 0 + } + } +} diff --git a/video/gtk4/src/sink/mod.rs b/video/gtk4/src/sink/mod.rs index 96ff9299..5008ed00 100644 --- a/video/gtk4/src/sink/mod.rs +++ b/video/gtk4/src/sink/mod.rs @@ -22,7 +22,8 @@ enum SinkEvent { glib::wrapper! { pub struct PaintableSink(ObjectSubclass) - @extends gst_video::VideoSink, gst_base::BaseSink, gst::Element, gst::Object; + @extends gst_video::VideoSink, gst_base::BaseSink, gst::Element, gst::Object, + @implements gst::ChildProxy; } impl PaintableSink {