gtk4: Create a window if running from gst-launch-1.0 or GST_GTK4_WINDOW=1 is set

Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/issues/482

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1454>
This commit is contained in:
Sebastian Dröge 2024-02-09 12:34:28 +02:00
parent 66ad059a47
commit 7274c725a6

View file

@ -61,6 +61,7 @@ pub(crate) static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
#[derive(Default)] #[derive(Default)]
pub struct PaintableSink { pub struct PaintableSink {
paintable: Mutex<Option<ThreadGuard<Paintable>>>, paintable: Mutex<Option<ThreadGuard<Paintable>>>,
window: Mutex<Option<ThreadGuard<gtk::Window>>>,
info: Mutex<Option<gst_video::VideoInfo>>, info: Mutex<Option<gst_video::VideoInfo>>,
sender: Mutex<Option<async_channel::Sender<SinkEvent>>>, sender: Mutex<Option<async_channel::Sender<SinkEvent>>>,
pending_frame: Mutex<Option<Frame>>, pending_frame: Mutex<Option<Frame>>,
@ -231,6 +232,18 @@ impl ElementImpl for PaintableSink {
) -> Result<gst::StateChangeSuccess, gst::StateChangeError> { ) -> Result<gst::StateChangeSuccess, gst::StateChangeError> {
match transition { match transition {
gst::StateChange::NullToReady => { gst::StateChange::NullToReady => {
let create_window = glib::program_name().as_deref() == Some("gst-launch-1.0")
|| std::env::var("GST_GTK4_WINDOW").as_deref() == Ok("1");
if create_window {
let res = utils::invoke_on_main_thread(gtk::init);
if let Err(err) = res {
gst::error!(CAT, imp: self, "Failed to create initialize GTK: {err}");
return Err(gst::StateChangeError);
}
}
let mut paintable = self.paintable.lock().unwrap(); let mut paintable = self.paintable.lock().unwrap();
if paintable.is_none() { if paintable.is_none() {
@ -273,6 +286,10 @@ impl ElementImpl for PaintableSink {
); );
} }
} }
if create_window {
self.create_window();
}
} }
_ => (), _ => (),
} }
@ -294,6 +311,17 @@ impl ElementImpl for PaintableSink {
} }
}); });
} }
gst::StateChange::ReadyToNull => {
let mut window_guard = self.window.lock().unwrap();
if let Some(window) = window_guard.take() {
drop(window_guard);
glib::MainContext::default().invoke(move || {
let window = window.get_ref();
window.close();
});
}
}
_ => (), _ => (),
} }
@ -520,6 +548,46 @@ impl PaintableSink {
.replace(tmp_caps); .replace(tmp_caps);
} }
fn create_window(&self) {
let self_ = self.to_owned();
glib::MainContext::default().invoke(move || {
let mut window_guard = self_.window.lock().unwrap();
if window_guard.is_some() {
return;
}
let paintable = match &*self_.paintable.lock().unwrap() {
Some(paintable) => paintable.get_ref().clone(),
None => return,
};
let window = gtk::Window::new();
let picture = gtk::Picture::new();
picture.set_paintable(Some(&paintable));
window.set_child(Some(&picture));
window.set_default_size(640, 480);
window.connect_close_request({
let self_ = self_.clone();
move |_window| {
if self_.window.lock().unwrap().is_some() {
gst::element_imp_error!(
self_,
gst::ResourceError::NotFound,
("Output window was closed")
);
}
glib::Propagation::Proceed
}
});
window.show();
*window_guard = Some(ThreadGuard::new(window));
});
}
fn create_paintable(&self, paintable_storage: &mut MutexGuard<Option<ThreadGuard<Paintable>>>) { fn create_paintable(&self, paintable_storage: &mut MutexGuard<Option<ThreadGuard<Paintable>>>) {
#[cfg(any(target_os = "macos", target_os = "windows", feature = "gst-gl"))] #[cfg(any(target_os = "macos", target_os = "windows", feature = "gst-gl"))]
{ {