From 17910dd532b6d991a4608821d21da20761417144 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 25 Jul 2024 13:28:14 +0200 Subject: [PATCH] gtk4: add window-{width,height} property Allow the application to pass the actual rendering size so overlays can be rendered accordingly. Fix #562 Part-of: --- docs/plugins/gst_plugins_cache.json | 28 +++++++++ video/gtk4/src/sink/imp.rs | 90 +++++++++++++++++++++++++++-- 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/docs/plugins/gst_plugins_cache.json b/docs/plugins/gst_plugins_cache.json index 4ea667dd..abf9f84d 100644 --- a/docs/plugins/gst_plugins_cache.json +++ b/docs/plugins/gst_plugins_cache.json @@ -2567,6 +2567,34 @@ "readable": true, "type": "GstGtk4Paintable", "writable": false + }, + "window-height": { + "blurb": "the height of the main widget rendering the paintable", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "playing", + "readable": true, + "type": "guint", + "writable": true + }, + "window-width": { + "blurb": "the width of the main widget rendering the paintable", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "playing", + "readable": true, + "type": "guint", + "writable": true } }, "rank": "none" diff --git a/video/gtk4/src/sink/imp.rs b/video/gtk4/src/sink/imp.rs index 4e397a9c..38c5090b 100644 --- a/video/gtk4/src/sink/imp.rs +++ b/video/gtk4/src/sink/imp.rs @@ -26,10 +26,13 @@ use gst_gl::prelude::*; use gst::prelude::*; use gst::subclass::prelude::*; use gst_base::subclass::prelude::*; -use gst_video::subclass::prelude::*; +use gst_video::{prelude::*, subclass::prelude::*}; use once_cell::sync::Lazy; -use std::sync::{Mutex, MutexGuard}; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Mutex, MutexGuard, +}; use crate::utils; @@ -84,6 +87,14 @@ pub struct PaintableSink { sender: Mutex>>, pending_frame: Mutex>, cached_caps: Mutex>, + settings: Mutex, + window_resized: AtomicBool, +} + +#[derive(Default)] +struct Settings { + window_width: u32, + window_height: u32, } impl Drop for PaintableSink { @@ -112,6 +123,16 @@ impl ObjectImpl for PaintableSink { .blurb("The Paintable the sink renders to") .read_only() .build(), + glib::ParamSpecUInt::builder("window-width") + .nick("Window width") + .blurb("the width of the main widget rendering the paintable") + .mutable_playing() + .build(), + glib::ParamSpecUInt::builder("window-height") + .nick("Window height") + .blurb("the height of the main widget rendering the paintable") + .mutable_playing() + .build(), ] }); @@ -171,6 +192,36 @@ impl ObjectImpl for PaintableSink { paintable.to_value() } + "window-width" => { + let settings = self.settings.lock().unwrap(); + settings.window_width.to_value() + } + "window-height" => { + let settings = self.settings.lock().unwrap(); + settings.window_height.to_value() + } + _ => unimplemented!(), + } + } + + fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { + match pspec.name() { + "window-width" => { + let mut settings = self.settings.lock().unwrap(); + let value = value.get().expect("type checked upstream"); + if settings.window_width != value { + self.window_resized.store(true, Ordering::SeqCst); + } + settings.window_width = value; + } + "window-height" => { + let mut settings = self.settings.lock().unwrap(); + let value = value.get().expect("type checked upstream"); + if settings.window_height != value { + self.window_resized.store(true, Ordering::SeqCst); + } + settings.window_height = value; + } _ => unimplemented!(), } } @@ -495,8 +546,32 @@ impl BaseSinkImpl for PaintableSink { self.parent_propose_allocation(query)?; query.add_allocation_meta::(None); - // TODO: Provide a preferred "window size" here for higher-resolution rendering - query.add_allocation_meta::(None); + + let s = { + let settings = self.settings.lock().unwrap(); + if (settings.window_width, settings.window_height) != (0, 0) { + gst::debug!( + CAT, + imp = self, + "answering alloc query with size {}x{}", + settings.window_width, + settings.window_height + ); + + self.window_resized.store(false, Ordering::SeqCst); + + Some( + gst::Structure::builder("GstVideoOverlayCompositionMeta") + .field("width", settings.window_width) + .field("height", settings.window_height) + .build(), + ) + } else { + None + } + }; + + query.add_allocation_meta::(s.as_deref()); #[cfg(any(target_os = "macos", target_os = "windows", feature = "gst-gl"))] { @@ -583,6 +658,13 @@ impl VideoSinkImpl for PaintableSink { fn show_frame(&self, buffer: &gst::Buffer) -> Result { gst::trace!(CAT, imp = self, "Rendering buffer {:?}", buffer); + if self.window_resized.swap(false, Ordering::SeqCst) { + gst::debug!(CAT, imp = self, "Window size changed, needs to reconfigure"); + let obj = self.obj(); + let sink = obj.sink_pad(); + sink.push_event(gst::event::Reconfigure::builder().build()); + } + // Empty buffer, nothing to render if buffer.n_memory() == 0 { gst::trace!(