gtk4paintablesink: Implement child proxy interface

This allows setting properties on the paintable from gst-launch-1.0.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1547>
This commit is contained in:
Sebastian Dröge 2024-04-24 15:22:57 +02:00
parent c92462b240
commit 3dd800ac77
3 changed files with 80 additions and 15 deletions

View file

@ -2472,6 +2472,9 @@
"GInitiallyUnowned", "GInitiallyUnowned",
"GObject" "GObject"
], ],
"interfaces": [
"GstChildProxy"
],
"klass": "Sink/Video", "klass": "Sink/Video",
"long-name": "GTK 4 Paintable Sink", "long-name": "GTK 4 Paintable Sink",
"pad-templates": { "pad-templates": {

View file

@ -82,6 +82,7 @@ impl ObjectSubclass for PaintableSink {
const NAME: &'static str = "GstGtk4PaintableSink"; const NAME: &'static str = "GstGtk4PaintableSink";
type Type = super::PaintableSink; type Type = super::PaintableSink;
type ParentType = gst_video::VideoSink; type ParentType = gst_video::VideoSink;
type Interfaces = (gst::ChildProxy,);
} }
impl ObjectImpl for PaintableSink { impl ObjectImpl for PaintableSink {
@ -110,12 +111,14 @@ impl ObjectImpl for PaintableSink {
return None::<&gdk::Paintable>.to_value(); return None::<&gdk::Paintable>.to_value();
} }
let mut paintable = self.paintable.lock().unwrap(); let mut paintable_guard = self.paintable.lock().unwrap();
if paintable.is_none() { let mut created = false;
self.create_paintable(&mut paintable); 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, Some(ref paintable) => paintable,
None => { None => {
gst::error!(CAT, imp: self, "Failed to create paintable"); 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 // Getter must be called from the main thread
if paintable.is_owner() { if !paintable.is_owner() {
paintable.get_ref().to_value()
} else {
gst::error!( gst::error!(
CAT, CAT,
imp: self, imp: self,
"Can't retrieve Paintable from non-main thread" "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!(), _ => unimplemented!(),
} }
@ -290,18 +308,31 @@ impl ElementImpl for PaintableSink {
} }
} }
let mut paintable = self.paintable.lock().unwrap(); let mut paintable_guard = self.paintable.lock().unwrap();
let mut created = false;
if paintable.is_none() { if paintable_guard.is_none() {
self.create_paintable(&mut paintable); 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"); gst::error!(CAT, imp: self, "Failed to create paintable");
return Err(gst::StateChangeError); 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 // 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 // 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<glib::Object> {
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::<glib::Object>().clone())
}
fn child_by_name(&self, name: &str) -> Option<glib::Object> {
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
}
}
}

View file

@ -22,7 +22,8 @@ enum SinkEvent {
glib::wrapper! { glib::wrapper! {
pub struct PaintableSink(ObjectSubclass<imp::PaintableSink>) pub struct PaintableSink(ObjectSubclass<imp::PaintableSink>)
@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 { impl PaintableSink {