mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-02-18 05:45:14 +00:00
gtk4: add custom widget automatically updating the window size
Use it in the example and debug window but let's not make it public yet. Plan is to have a proper bin on top of gtk4paintablesink at some point. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1680>
This commit is contained in:
parent
17910dd532
commit
cfe9968a77
6 changed files with 146 additions and 38 deletions
|
@ -62,23 +62,8 @@ fn create_ui(app: >k::Application) {
|
||||||
|
|
||||||
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
||||||
|
|
||||||
let picture = gtk::Picture::new();
|
let gst_widget = gstgtk4::RenderWidget::new(>ksink);
|
||||||
picture.set_paintable(Some(&paintable));
|
vbox.append(&gst_widget);
|
||||||
|
|
||||||
#[cfg(feature = "gtk_v4_14")]
|
|
||||||
{
|
|
||||||
let offload = gtk::GraphicsOffload::new(Some(&picture));
|
|
||||||
offload.set_enabled(gtk::GraphicsOffloadEnabled::Enabled);
|
|
||||||
#[cfg(feature = "gtk_v4_16")]
|
|
||||||
{
|
|
||||||
offload.set_black_background(true);
|
|
||||||
}
|
|
||||||
vbox.append(&offload);
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "gtk_v4_14"))]
|
|
||||||
{
|
|
||||||
vbox.append(&picture);
|
|
||||||
}
|
|
||||||
|
|
||||||
let label = gtk::Label::new(Some("Position: 00:00:00"));
|
let label = gtk::Label::new(Some("Position: 00:00:00"));
|
||||||
vbox.append(&label);
|
vbox.append(&label);
|
||||||
|
|
|
@ -21,6 +21,10 @@ mod sink;
|
||||||
mod utils;
|
mod utils;
|
||||||
pub use sink::frame::Orientation;
|
pub use sink::frame::Orientation;
|
||||||
pub use sink::paintable::Paintable;
|
pub use sink::paintable::Paintable;
|
||||||
|
// The widget needs to be public so it can be used by the example and element debug window but
|
||||||
|
// we don't want it be part of the official API for now.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub use sink::render_widget::RenderWidget;
|
||||||
pub use sink::PaintableSink;
|
pub use sink::PaintableSink;
|
||||||
|
|
||||||
fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
||||||
|
|
|
@ -831,29 +831,11 @@ impl PaintableSink {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let paintable = match &*self_.paintable.lock().unwrap() {
|
|
||||||
Some(paintable) => paintable.get_ref().clone(),
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
let window = gtk::Window::new();
|
let window = gtk::Window::new();
|
||||||
let picture = gtk::Picture::new();
|
|
||||||
picture.set_paintable(Some(&paintable));
|
|
||||||
|
|
||||||
#[cfg(feature = "gtk_v4_14")]
|
let gst_widget = crate::RenderWidget::new(self_.obj().as_ref().upcast_ref());
|
||||||
{
|
window.set_child(Some(&gst_widget));
|
||||||
let offload = gtk::GraphicsOffload::new(Some(&picture));
|
|
||||||
offload.set_enabled(gtk::GraphicsOffloadEnabled::Enabled);
|
|
||||||
#[cfg(feature = "gtk_v4_16")]
|
|
||||||
{
|
|
||||||
offload.set_black_background(true);
|
|
||||||
}
|
|
||||||
window.set_child(Some(&offload));
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "gtk_v4_14"))]
|
|
||||||
{
|
|
||||||
window.set_child(Some(&picture));
|
|
||||||
}
|
|
||||||
window.set_default_size(640, 480);
|
window.set_default_size(640, 480);
|
||||||
if std::env::var("GST_GTK4_WINDOW_FULLSCREEN").as_deref() == Ok("1") {
|
if std::env::var("GST_GTK4_WINDOW_FULLSCREEN").as_deref() == Ok("1") {
|
||||||
window.set_fullscreened(true);
|
window.set_fullscreened(true);
|
||||||
|
|
|
@ -41,6 +41,7 @@ use gtk::glib::prelude::*;
|
||||||
pub(super) mod frame;
|
pub(super) mod frame;
|
||||||
pub(super) mod imp;
|
pub(super) mod imp;
|
||||||
pub(super) mod paintable;
|
pub(super) mod paintable;
|
||||||
|
pub(super) mod render_widget;
|
||||||
|
|
||||||
enum SinkEvent {
|
enum SinkEvent {
|
||||||
FrameChanged,
|
FrameChanged,
|
||||||
|
|
113
video/gtk4/src/sink/render_widget/imp.rs
Normal file
113
video/gtk4/src/sink/render_widget/imp.rs
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
//
|
||||||
|
// Copyright (C) 2024 Guillaume Desmottes <guillaume@desmottes.be>
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
|
||||||
|
// If a copy of the MPL was not distributed with this file, You can obtain one at
|
||||||
|
// <https://mozilla.org/MPL/2.0/>.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use std::cell::{Cell, RefCell};
|
||||||
|
|
||||||
|
use gtk::{gdk, glib, prelude::*, subclass::prelude::*};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct RenderWidget {
|
||||||
|
element: RefCell<Option<crate::PaintableSink>>,
|
||||||
|
window_size: Cell<(u32, u32)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for RenderWidget {
|
||||||
|
const NAME: &'static str = "GstGtk4ExampleRenderWidget";
|
||||||
|
type Type = super::RenderWidget;
|
||||||
|
type ParentType = gtk::Widget;
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.set_layout_manager_type::<gtk::BinLayout>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for RenderWidget {
|
||||||
|
fn properties() -> &'static [glib::ParamSpec] {
|
||||||
|
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||||
|
vec![
|
||||||
|
glib::ParamSpecObject::builder::<crate::PaintableSink>("element")
|
||||||
|
.nick("Element")
|
||||||
|
.blurb("The GTK4 Paintable Sink GStreamer element")
|
||||||
|
.construct_only()
|
||||||
|
.build(),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
PROPERTIES.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||||
|
match pspec.name() {
|
||||||
|
"element" => self.element.borrow().to_value(),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||||
|
match pspec.name() {
|
||||||
|
"element" => {
|
||||||
|
*self.element.borrow_mut() = value.get::<Option<crate::PaintableSink>>().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constructed(&self) {
|
||||||
|
self.parent_constructed();
|
||||||
|
|
||||||
|
let element = self.element.borrow();
|
||||||
|
let element = element.as_ref().unwrap();
|
||||||
|
let paintable = element.property::<gdk::Paintable>("paintable");
|
||||||
|
|
||||||
|
let picture = gtk::Picture::new();
|
||||||
|
picture.set_paintable(Some(&paintable));
|
||||||
|
|
||||||
|
#[cfg(feature = "gtk_v4_14")]
|
||||||
|
{
|
||||||
|
let offload = gtk::GraphicsOffload::new(Some(&picture));
|
||||||
|
offload.set_enabled(gtk::GraphicsOffloadEnabled::Enabled);
|
||||||
|
#[cfg(feature = "gtk_v4_16")]
|
||||||
|
{
|
||||||
|
offload.set_black_background(true);
|
||||||
|
}
|
||||||
|
offload.set_parent(self.obj().as_ref());
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "gtk_v4_14"))]
|
||||||
|
{
|
||||||
|
picture.set_parent(self.obj().as_ref());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dispose(&self) {
|
||||||
|
while let Some(child) = self.obj().first_child() {
|
||||||
|
child.unparent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetImpl for RenderWidget {
|
||||||
|
fn snapshot(&self, snapshot: >k::Snapshot) {
|
||||||
|
let window_width = self.obj().width() as u32;
|
||||||
|
let window_height = self.obj().height() as u32;
|
||||||
|
let new_size = (window_width, window_height);
|
||||||
|
let updated = self.window_size.replace(new_size) != new_size;
|
||||||
|
|
||||||
|
if updated {
|
||||||
|
let element = self.element.borrow();
|
||||||
|
let element = element.as_ref().unwrap();
|
||||||
|
element.set_property("window-width", window_width);
|
||||||
|
element.set_property("window-height", window_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.parent_snapshot(snapshot)
|
||||||
|
}
|
||||||
|
}
|
23
video/gtk4/src/sink/render_widget/mod.rs
Normal file
23
video/gtk4/src/sink/render_widget/mod.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
// Copyright (C) 2024 Guillaume Desmottes <guillaume@desmottes.be>
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
|
||||||
|
// If a copy of the MPL was not distributed with this file, You can obtain one at
|
||||||
|
// <https://mozilla.org/MPL/2.0/>.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use gtk::glib;
|
||||||
|
|
||||||
|
mod imp;
|
||||||
|
|
||||||
|
/// Use a simple container widget to automatically pass the window size to gtk4paintablesink.
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct RenderWidget(ObjectSubclass<imp::RenderWidget>) @extends gtk::Widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderWidget {
|
||||||
|
pub fn new(element: &gst::Element) -> Self {
|
||||||
|
glib::Object::builder().property("element", element).build()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue