diff --git a/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json b/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json index d0c983fe6e..fb957b11b1 100644 --- a/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json +++ b/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json @@ -230371,8 +230371,7 @@ "GObject" ], "interfaces": [ - "GstVideoOverlay", - "GstWaylandVideo" + "GstVideoOverlay" ], "klass": "Sink/Video", "long-name": "wayland video sink", @@ -230414,15 +230413,7 @@ }, "filename": "gstwaylandsink", "license": "LGPL", - "other-types": { - "GstWaylandVideo": { - "hierarchy": [ - "GstWaylandVideo", - "GInterface" - ], - "kind": "interface" - } - }, + "other-types": {}, "package": "GStreamer Bad Plug-ins", "source": "gst-plugins-bad", "tracers": {}, diff --git a/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.c b/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.c index 0761304ce3..2f2a21f30b 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.c +++ b/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.c @@ -43,12 +43,8 @@ #endif #include "gstwaylandsink.h" -#include "wlvideoformat.h" -#include "wlbuffer.h" -#include "wlshmallocator.h" -#include "wllinuxdmabuf.h" +#include -#include #include /* signals */ @@ -110,60 +106,13 @@ static void gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay, gint x, gint y, gint w, gint h); static void gst_wayland_sink_expose (GstVideoOverlay * overlay); -/* WaylandVideo interface */ -static void gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * - iface); -static void gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video); -static void gst_wayland_sink_end_geometry_change (GstWaylandVideo * video); - #define gst_wayland_sink_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstWaylandSink, gst_wayland_sink, GST_TYPE_VIDEO_SINK, G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY, - gst_wayland_sink_videooverlay_init) - G_IMPLEMENT_INTERFACE (GST_TYPE_WAYLAND_VIDEO, - gst_wayland_sink_waylandvideo_init)); + gst_wayland_sink_videooverlay_init)); GST_ELEMENT_REGISTER_DEFINE (waylandsink, "waylandsink", GST_RANK_MARGINAL, GST_TYPE_WAYLAND_SINK); -/* A tiny GstVideoBufferPool subclass that modify the options to remove - * VideoAlignment. To support VideoAlignment we would need to pass the padded - * width/height + stride and use the viewporter interface to crop, a bit like - * we use to do with XV. It would still be quite limited. It's a bit retro, - * hopefully there will be a better Wayland interface in the future. */ - -GType gst_wayland_pool_get_type (void); - -typedef struct -{ - GstVideoBufferPool parent; -} GstWaylandPool; - -typedef struct -{ - GstVideoBufferPoolClass parent; -} GstWaylandPoolClass; - -G_DEFINE_TYPE (GstWaylandPool, gst_wayland_pool, GST_TYPE_VIDEO_BUFFER_POOL); - -static const gchar ** -gst_wayland_pool_get_options (GstBufferPool * pool) -{ - static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL }; - return options; -} - -static void -gst_wayland_pool_class_init (GstWaylandPoolClass * klass) -{ - GstBufferPoolClass *pool_class = GST_BUFFER_POOL_CLASS (klass); - pool_class->get_options = gst_wayland_pool_get_options; -} - -static void -gst_wayland_pool_init (GstWaylandPool * pool) -{ -} - static void gst_wayland_sink_class_init (GstWaylandSinkClass * klass) { @@ -211,8 +160,6 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass) g_param_spec_boolean ("fullscreen", "Fullscreen", "Whether the surface should be made fullscreen ", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - gst_type_mark_as_plugin_api (GST_TYPE_WAYLAND_VIDEO, 0); } static void @@ -312,7 +259,7 @@ gst_wayland_sink_set_display_from_context (GstWaylandSink * sink, struct wl_display *display; GError *error = NULL; - display = gst_wayland_display_handle_context_get_handle (context); + display = gst_wl_display_handle_context_get_handle (context); sink->display = gst_wl_display_new_existing (display, FALSE, &error); if (error) { @@ -336,7 +283,7 @@ gst_wayland_sink_find_display (GstWaylandSink * sink) if (!sink->display) { /* first query upstream for the needed display handle */ - query = gst_query_new_context (GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE); + query = gst_query_new_context (GST_WL_DISPLAY_HANDLE_CONTEXT_TYPE); if (gst_pad_peer_query (GST_VIDEO_SINK_PAD (sink), query)) { gst_query_parse_context (query, &context); gst_wayland_sink_set_display_from_context (sink, context); @@ -346,7 +293,7 @@ gst_wayland_sink_find_display (GstWaylandSink * sink) if (G_LIKELY (!sink->display)) { /* now ask the application to set the display handle */ msg = gst_message_new_need_context (GST_OBJECT_CAST (sink), - GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE); + GST_WL_DISPLAY_HANDLE_CONTEXT_TYPE); g_mutex_unlock (&sink->display_lock); gst_element_post_message (GST_ELEMENT_CAST (sink), msg); @@ -446,7 +393,7 @@ gst_wayland_sink_set_context (GstElement * element, GstContext * context) GstWaylandSink *sink = GST_WAYLAND_SINK (element); if (gst_context_has_context_type (context, - GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE)) { + GST_WL_DISPLAY_HANDLE_CONTEXT_TYPE)) { g_mutex_lock (&sink->display_lock); if (G_LIKELY (!sink->display)) { gst_wayland_sink_set_display_from_context (sink, context); @@ -487,7 +434,7 @@ gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) g_value_init (&dmabuf_list, GST_TYPE_LIST); /* Add corresponding shm formats */ - formats = sink->display->shm_formats; + formats = gst_wl_display_get_shm_formats (sink->display); for (i = 0; i < formats->len; i++) { fmt = g_array_index (formats, uint32_t, i); gfmt = gst_wl_shm_format_to_video_format (fmt); @@ -502,7 +449,7 @@ gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) &shm_list); /* Add corresponding dmabuf formats */ - formats = sink->display->dmabuf_formats; + formats = gst_wl_display_get_dmabuf_formats (sink->display); for (i = 0; i < formats->len; i++) { fmt = g_array_index (formats, uint32_t, i); gfmt = gst_wl_dmabuf_format_to_video_format (fmt); @@ -541,7 +488,7 @@ gst_wayland_create_pool (GstWaylandSink * sink, GstCaps * caps) gsize size = sink->video_info.size; GstAllocator *alloc; - pool = g_object_new (gst_wayland_pool_get_type (), NULL); + pool = gst_wl_video_buffer_pool_new (); structure = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (structure, caps, size, 2, 0); @@ -731,12 +678,13 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer) } /* make sure that the application has called set_render_rectangle() */ - if (G_UNLIKELY (sink->window->render_rectangle.w == 0)) + if (G_UNLIKELY (gst_wl_window_get_render_rectangle (sink->window)->w == 0)) goto no_window_size; wlbuffer = gst_buffer_get_wl_buffer (sink->display, buffer); - if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) { + if (G_LIKELY (wlbuffer && + gst_wl_buffer_get_display (wlbuffer) == sink->display)) { GST_LOG_OBJECT (sink, "buffer %p has a wl_buffer from our display, " "writing directly", buffer); to_render = buffer; @@ -954,7 +902,7 @@ gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle) if (handle) { if (G_LIKELY (gst_wayland_sink_find_display (sink))) { /* we cannot use our own display with an external window handle */ - if (G_UNLIKELY (sink->display->own_display)) { + if (G_UNLIKELY (gst_wl_display_has_own_display (sink->display))) { GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ_WRITE, ("Application did not provide a wayland display handle"), ("waylandsink cannot use an externally-supplied surface without " @@ -1013,57 +961,12 @@ gst_wayland_sink_expose (GstVideoOverlay * overlay) g_mutex_unlock (&sink->render_lock); } -static void -gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface) -{ - iface->begin_geometry_change = gst_wayland_sink_begin_geometry_change; - iface->end_geometry_change = gst_wayland_sink_end_geometry_change; -} - -static void -gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video) -{ - GstWaylandSink *sink = GST_WAYLAND_SINK (video); - g_return_if_fail (sink != NULL); - - g_mutex_lock (&sink->render_lock); - if (!sink->window || !sink->window->area_subsurface) { - g_mutex_unlock (&sink->render_lock); - GST_INFO_OBJECT (sink, - "begin_geometry_change called without window, ignoring"); - return; - } - - wl_subsurface_set_sync (sink->window->area_subsurface); - g_mutex_unlock (&sink->render_lock); -} - -static void -gst_wayland_sink_end_geometry_change (GstWaylandVideo * video) -{ - GstWaylandSink *sink = GST_WAYLAND_SINK (video); - g_return_if_fail (sink != NULL); - - g_mutex_lock (&sink->render_lock); - if (!sink->window || !sink->window->area_subsurface) { - g_mutex_unlock (&sink->render_lock); - GST_INFO_OBJECT (sink, - "end_geometry_change called without window, ignoring"); - return; - } - - wl_subsurface_set_desync (sink->window->area_subsurface); - g_mutex_unlock (&sink->render_lock); -} - static gboolean plugin_init (GstPlugin * plugin) { GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "waylandsink", 0, " wayland video sink"); - gst_wl_shm_allocator_register (); - return GST_ELEMENT_REGISTER (waylandsink, plugin); } diff --git a/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.h b/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.h index 7aabb6ff0e..f36c639289 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.h +++ b/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.h @@ -19,16 +19,11 @@ * Boston, MA 02110-1301 USA. */ -#ifndef __GST_WAYLAND_VIDEO_SINK_H__ -#define __GST_WAYLAND_VIDEO_SINK_H__ +#pragma once #include #include - -#include - -#include "wldisplay.h" -#include "wlwindow.h" +#include G_BEGIN_DECLS @@ -81,5 +76,3 @@ GType gst_wayland_sink_get_type (void) G_GNUC_CONST; GST_ELEMENT_REGISTER_DECLARE (waylandsink); G_END_DECLS - -#endif /* __GST_WAYLAND_VIDEO_SINK_H__ */ diff --git a/subprojects/gst-plugins-bad/ext/wayland/meson.build b/subprojects/gst-plugins-bad/ext/wayland/meson.build index a3ffb70d84..4ee046dccc 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/meson.build +++ b/subprojects/gst-plugins-bad/ext/wayland/meson.build @@ -1,48 +1,14 @@ wl_sources = [ - 'gstwaylandsink.c', - 'wlshmallocator.c', - 'wlbuffer.c', - 'wldisplay.c', - 'wlwindow.c', - 'wlvideoformat.c', - 'wllinuxdmabuf.c' + 'gstwaylandsink.c' ] -libdrm_dep = dependency('libdrm', version: '>= 2.4.55', required:get_option('wayland')) - if use_wayland - protocols_datadir = wl_protocol_dep.get_variable('pkgdatadir') - - protocol_defs = [ - ['/stable/viewporter/viewporter.xml', 'viewporter-protocol.c', 'viewporter-client-protocol.h'], - ['/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml', - 'linux-dmabuf-unstable-v1-protocol.c', 'linux-dmabuf-unstable-v1-client-protocol.h'], - ['/unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml', - 'fullscreen-shell-unstable-v1-protocol.c', 'fullscreen-shell-unstable-v1-client-protocol.h'], - ['/stable/xdg-shell/xdg-shell.xml', 'xdg-shell-protocol.c', 'xdg-shell-client-protocol.h'], - ] - protocols_files = [] - - foreach protodef: protocol_defs - xmlfile = protocols_datadir + protodef.get(0) - - protocols_files += [custom_target(protodef.get(1), - output : protodef.get(1), - input : xmlfile, - command : [wl_scanner, 'code', '@INPUT@', '@OUTPUT@'])] - - protocols_files += [custom_target(protodef.get(2), - output : protodef.get(2), - input : xmlfile, - command : [wl_scanner, 'client-header', '@INPUT@', '@OUTPUT@'])] - endforeach gstwaylandsink = library('gstwaylandsink', - wl_sources + protocols_files, + wl_sources, c_args : gst_plugins_bad_args + ['-DGST_USE_UNSTABLE_API'], include_directories : [configinc], - dependencies : [gst_dep, gstvideo_dep, gstwayland_dep, gstallocators_dep, - wl_client_dep, wl_protocol_dep, libdrm_dep], + dependencies : [gst_dep, gstvideo_dep, gstwayland_dep], install : true, install_dir : plugins_install_dir, ) diff --git a/subprojects/gst-plugins-bad/ext/wayland/wldisplay.c b/subprojects/gst-plugins-bad/ext/wayland/wldisplay.c deleted file mode 100644 index f326091990..0000000000 --- a/subprojects/gst-plugins-bad/ext/wayland/wldisplay.c +++ /dev/null @@ -1,420 +0,0 @@ -/* GStreamer Wayland video sink - * - * Copyright (C) 2014 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "wldisplay.h" -#include "wlbuffer.h" -#include "wlvideoformat.h" - -#include - -GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug - -G_DEFINE_TYPE (GstWlDisplay, gst_wl_display, G_TYPE_OBJECT); - -static void gst_wl_display_finalize (GObject * gobject); - -static void -gst_wl_display_class_init (GstWlDisplayClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - gobject_class->finalize = gst_wl_display_finalize; -} - -static void -gst_wl_display_init (GstWlDisplay * self) -{ - self->shm_formats = g_array_new (FALSE, FALSE, sizeof (uint32_t)); - self->dmabuf_formats = g_array_new (FALSE, FALSE, sizeof (uint32_t)); - self->wl_fd_poll = gst_poll_new (TRUE); - self->buffers = g_hash_table_new (g_direct_hash, g_direct_equal); - g_mutex_init (&self->buffers_mutex); -} - -static void -gst_wl_ref_wl_buffer (gpointer key, gpointer value, gpointer user_data) -{ - g_object_ref (value); -} - -static void -gst_wl_display_finalize (GObject * gobject) -{ - GstWlDisplay *self = GST_WL_DISPLAY (gobject); - - gst_poll_set_flushing (self->wl_fd_poll, TRUE); - if (self->thread) - g_thread_join (self->thread); - - /* to avoid buffers being unregistered from another thread - * at the same time, take their ownership */ - g_mutex_lock (&self->buffers_mutex); - self->shutting_down = TRUE; - g_hash_table_foreach (self->buffers, gst_wl_ref_wl_buffer, NULL); - g_mutex_unlock (&self->buffers_mutex); - - g_hash_table_foreach (self->buffers, - (GHFunc) gst_wl_buffer_force_release_and_unref, NULL); - g_hash_table_remove_all (self->buffers); - - g_array_unref (self->shm_formats); - g_array_unref (self->dmabuf_formats); - gst_poll_free (self->wl_fd_poll); - g_hash_table_unref (self->buffers); - g_mutex_clear (&self->buffers_mutex); - - if (self->viewporter) - wp_viewporter_destroy (self->viewporter); - - if (self->shm) - wl_shm_destroy (self->shm); - - if (self->dmabuf) - zwp_linux_dmabuf_v1_destroy (self->dmabuf); - - if (self->wl_shell) - wl_shell_destroy (self->wl_shell); - - if (self->xdg_wm_base) - xdg_wm_base_destroy (self->xdg_wm_base); - - if (self->fullscreen_shell) - zwp_fullscreen_shell_v1_release (self->fullscreen_shell); - - if (self->compositor) - wl_compositor_destroy (self->compositor); - - if (self->subcompositor) - wl_subcompositor_destroy (self->subcompositor); - - if (self->registry) - wl_registry_destroy (self->registry); - - if (self->display_wrapper) - wl_proxy_wrapper_destroy (self->display_wrapper); - - if (self->queue) - wl_event_queue_destroy (self->queue); - - if (self->own_display) { - wl_display_flush (self->display); - wl_display_disconnect (self->display); - } - - G_OBJECT_CLASS (gst_wl_display_parent_class)->finalize (gobject); -} - -static void -shm_format (void *data, struct wl_shm *wl_shm, uint32_t format) -{ - GstWlDisplay *self = data; - - g_array_append_val (self->shm_formats, format); -} - -static const struct wl_shm_listener shm_listener = { - shm_format -}; - -static void -dmabuf_format (void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, - uint32_t format) -{ - GstWlDisplay *self = data; - - if (gst_wl_dmabuf_format_to_video_format (format) != GST_VIDEO_FORMAT_UNKNOWN) - g_array_append_val (self->dmabuf_formats, format); -} - -static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { - dmabuf_format, -}; - -gboolean -gst_wl_display_check_format_for_shm (GstWlDisplay * display, - GstVideoFormat format) -{ - enum wl_shm_format shm_fmt; - GArray *formats; - guint i; - - shm_fmt = gst_video_format_to_wl_shm_format (format); - if (shm_fmt == (enum wl_shm_format) -1) - return FALSE; - - formats = display->shm_formats; - for (i = 0; i < formats->len; i++) { - if (g_array_index (formats, uint32_t, i) == shm_fmt) - return TRUE; - } - - return FALSE; -} - -gboolean -gst_wl_display_check_format_for_dmabuf (GstWlDisplay * display, - GstVideoFormat format) -{ - GArray *formats; - guint i, dmabuf_fmt; - - if (!display->dmabuf) - return FALSE; - - dmabuf_fmt = gst_video_format_to_wl_dmabuf_format (format); - if (dmabuf_fmt == (guint) - 1) - return FALSE; - - formats = display->dmabuf_formats; - for (i = 0; i < formats->len; i++) { - if (g_array_index (formats, uint32_t, i) == dmabuf_fmt) - return TRUE; - } - - return FALSE; -} - -static void -handle_xdg_wm_base_ping (void *user_data, struct xdg_wm_base *xdg_wm_base, - uint32_t serial) -{ - xdg_wm_base_pong (xdg_wm_base, serial); -} - -static const struct xdg_wm_base_listener xdg_wm_base_listener = { - handle_xdg_wm_base_ping -}; - -static void -registry_handle_global (void *data, struct wl_registry *registry, - uint32_t id, const char *interface, uint32_t version) -{ - GstWlDisplay *self = data; - - if (g_strcmp0 (interface, "wl_compositor") == 0) { - self->compositor = wl_registry_bind (registry, id, &wl_compositor_interface, - MIN (version, 4)); - } else if (g_strcmp0 (interface, "wl_subcompositor") == 0) { - self->subcompositor = - wl_registry_bind (registry, id, &wl_subcompositor_interface, 1); - } else if (g_strcmp0 (interface, "wl_shell") == 0) { - self->wl_shell = wl_registry_bind (registry, id, &wl_shell_interface, 1); - } else if (g_strcmp0 (interface, "xdg_wm_base") == 0) { - self->xdg_wm_base = - wl_registry_bind (registry, id, &xdg_wm_base_interface, 1); - xdg_wm_base_add_listener (self->xdg_wm_base, &xdg_wm_base_listener, self); - } else if (g_strcmp0 (interface, "zwp_fullscreen_shell_v1") == 0) { - self->fullscreen_shell = wl_registry_bind (registry, id, - &zwp_fullscreen_shell_v1_interface, 1); - } else if (g_strcmp0 (interface, "wl_shm") == 0) { - self->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1); - wl_shm_add_listener (self->shm, &shm_listener, self); - } else if (g_strcmp0 (interface, "wp_viewporter") == 0) { - self->viewporter = - wl_registry_bind (registry, id, &wp_viewporter_interface, 1); - } else if (g_strcmp0 (interface, "zwp_linux_dmabuf_v1") == 0) { - self->dmabuf = - wl_registry_bind (registry, id, &zwp_linux_dmabuf_v1_interface, 1); - zwp_linux_dmabuf_v1_add_listener (self->dmabuf, &dmabuf_listener, self); - } -} - -static void -registry_handle_global_remove (void *data, struct wl_registry *registry, - uint32_t name) -{ - /* temporarily do nothing */ -} - -static const struct wl_registry_listener registry_listener = { - registry_handle_global, - registry_handle_global_remove -}; - -static gpointer -gst_wl_display_thread_run (gpointer data) -{ - GstWlDisplay *self = data; - GstPollFD pollfd = GST_POLL_FD_INIT; - - pollfd.fd = wl_display_get_fd (self->display); - gst_poll_add_fd (self->wl_fd_poll, &pollfd); - gst_poll_fd_ctl_read (self->wl_fd_poll, &pollfd, TRUE); - - /* main loop */ - while (1) { - while (wl_display_prepare_read_queue (self->display, self->queue) != 0) - wl_display_dispatch_queue_pending (self->display, self->queue); - wl_display_flush (self->display); - - if (gst_poll_wait (self->wl_fd_poll, GST_CLOCK_TIME_NONE) < 0) { - gboolean normal = (errno == EBUSY); - wl_display_cancel_read (self->display); - if (normal) - break; - else - goto error; - } - if (wl_display_read_events (self->display) == -1) - goto error; - wl_display_dispatch_queue_pending (self->display, self->queue); - } - - return NULL; - -error: - GST_ERROR ("Error communicating with the wayland server"); - return NULL; -} - -GstWlDisplay * -gst_wl_display_new (const gchar * name, GError ** error) -{ - struct wl_display *display; - - display = wl_display_connect (name); - - if (!display) { - *error = g_error_new (g_quark_from_static_string ("GstWlDisplay"), 0, - "Failed to connect to the wayland display '%s'", - name ? name : "(default)"); - return NULL; - } else { - return gst_wl_display_new_existing (display, TRUE, error); - } -} - -GstWlDisplay * -gst_wl_display_new_existing (struct wl_display * display, - gboolean take_ownership, GError ** error) -{ - GstWlDisplay *self; - GError *err = NULL; - gint i; - - g_return_val_if_fail (display != NULL, NULL); - - self = g_object_new (GST_TYPE_WL_DISPLAY, NULL); - self->display = display; - self->display_wrapper = wl_proxy_create_wrapper (display); - self->own_display = take_ownership; - - self->queue = wl_display_create_queue (self->display); - wl_proxy_set_queue ((struct wl_proxy *) self->display_wrapper, self->queue); - self->registry = wl_display_get_registry (self->display_wrapper); - wl_registry_add_listener (self->registry, ®istry_listener, self); - - /* we need exactly 2 roundtrips to discover global objects and their state */ - for (i = 0; i < 2; i++) { - if (wl_display_roundtrip_queue (self->display, self->queue) < 0) { - *error = g_error_new (g_quark_from_static_string ("GstWlDisplay"), 0, - "Error communicating with the wayland display"); - g_object_unref (self); - return NULL; - } - } - - /* verify we got all the required interfaces */ -#define VERIFY_INTERFACE_EXISTS(var, interface) \ - if (!self->var) { \ - g_set_error (error, g_quark_from_static_string ("GstWlDisplay"), 0, \ - "Could not bind to " interface ". Either it is not implemented in " \ - "the compositor, or the implemented version doesn't match"); \ - g_object_unref (self); \ - return NULL; \ - } - - VERIFY_INTERFACE_EXISTS (compositor, "wl_compositor"); - VERIFY_INTERFACE_EXISTS (subcompositor, "wl_subcompositor"); - VERIFY_INTERFACE_EXISTS (shm, "wl_shm"); - -#undef VERIFY_INTERFACE_EXISTS - - /* We make the viewporter optional even though it may cause bad display. - * This is so one can test wayland display on older compositor or on - * compositor that don't implement this extension. */ - if (!self->viewporter) { - g_warning ("Wayland compositor is missing the ability to scale, video " - "display may not work properly."); - } - - if (!self->dmabuf) { - g_warning ("Could not bind to zwp_linux_dmabuf_v1"); - } - - if (!self->wl_shell && !self->xdg_wm_base && !self->fullscreen_shell) { - /* If wl_surface and wl_display are passed via GstContext - * wl_shell, xdg_shell and zwp_fullscreen_shell are not used. - * In this case is correct to continue. - */ - g_warning ("Could not bind to either wl_shell, xdg_wm_base or " - "zwp_fullscreen_shell, video display may not work properly."); - } - - self->thread = g_thread_try_new ("GstWlDisplay", gst_wl_display_thread_run, - self, &err); - if (err) { - g_propagate_prefixed_error (error, err, - "Failed to start thread for the display's events"); - g_object_unref (self); - return NULL; - } - - return self; -} - -void -gst_wl_display_register_buffer (GstWlDisplay * self, gpointer gstmem, - gpointer wlbuffer) -{ - g_assert (!self->shutting_down); - - GST_TRACE_OBJECT (self, "registering GstWlBuffer %p to GstMem %p", - wlbuffer, gstmem); - - g_mutex_lock (&self->buffers_mutex); - g_hash_table_replace (self->buffers, gstmem, wlbuffer); - g_mutex_unlock (&self->buffers_mutex); -} - -gpointer -gst_wl_display_lookup_buffer (GstWlDisplay * self, gpointer gstmem) -{ - gpointer wlbuffer; - g_mutex_lock (&self->buffers_mutex); - wlbuffer = g_hash_table_lookup (self->buffers, gstmem); - g_mutex_unlock (&self->buffers_mutex); - return wlbuffer; -} - -void -gst_wl_display_unregister_buffer (GstWlDisplay * self, gpointer gstmem) -{ - GST_TRACE_OBJECT (self, "unregistering GstWlBuffer owned by %p", gstmem); - - g_mutex_lock (&self->buffers_mutex); - if (G_LIKELY (!self->shutting_down)) - g_hash_table_remove (self->buffers, gstmem); - g_mutex_unlock (&self->buffers_mutex); -} diff --git a/subprojects/gst-plugins-bad/ext/wayland/wldisplay.h b/subprojects/gst-plugins-bad/ext/wayland/wldisplay.h deleted file mode 100644 index f2025a6a03..0000000000 --- a/subprojects/gst-plugins-bad/ext/wayland/wldisplay.h +++ /dev/null @@ -1,100 +0,0 @@ -/* GStreamer Wayland video sink - * - * Copyright (C) 2014 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - */ - -#ifndef __GST_WL_DISPLAY_H__ -#define __GST_WL_DISPLAY_H__ - -#include -#include -#include -#include "xdg-shell-client-protocol.h" -#include "viewporter-client-protocol.h" -#include "linux-dmabuf-unstable-v1-client-protocol.h" -#include "fullscreen-shell-unstable-v1-client-protocol.h" - -G_BEGIN_DECLS - -#define GST_TYPE_WL_DISPLAY (gst_wl_display_get_type ()) -#define GST_WL_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_DISPLAY, GstWlDisplay)) -#define GST_IS_WL_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_DISPLAY)) -#define GST_WL_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_DISPLAY, GstWlDisplayClass)) -#define GST_IS_WL_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_DISPLAY)) -#define GST_WL_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_DISPLAY, GstWlDisplayClass)) - -typedef struct _GstWlDisplay GstWlDisplay; -typedef struct _GstWlDisplayClass GstWlDisplayClass; - -struct _GstWlDisplay -{ - GObject parent_instance; - - /* public objects */ - struct wl_display *display; - struct wl_display *display_wrapper; - struct wl_event_queue *queue; - - /* globals */ - struct wl_registry *registry; - struct wl_compositor *compositor; - struct wl_subcompositor *subcompositor; - struct wl_shell *wl_shell; - struct xdg_wm_base *xdg_wm_base; - struct zwp_fullscreen_shell_v1 *fullscreen_shell; - struct wl_shm *shm; - struct wp_viewporter *viewporter; - struct zwp_linux_dmabuf_v1 *dmabuf; - GArray *shm_formats; - GArray *dmabuf_formats; - - /* private */ - gboolean own_display; - GThread *thread; - GstPoll *wl_fd_poll; - - GMutex buffers_mutex; - GHashTable *buffers; - gboolean shutting_down; -}; - -struct _GstWlDisplayClass -{ - GObjectClass parent_class; -}; - -GType gst_wl_display_get_type (void); - -GstWlDisplay *gst_wl_display_new (const gchar * name, GError ** error); -GstWlDisplay *gst_wl_display_new_existing (struct wl_display * display, - gboolean take_ownership, GError ** error); - -/* see wlbuffer.c for explanation */ -void gst_wl_display_register_buffer (GstWlDisplay * self, gpointer gstmem, - gpointer wlbuffer); -void gst_wl_display_unregister_buffer (GstWlDisplay * self, gpointer gstmem); -gpointer gst_wl_display_lookup_buffer (GstWlDisplay * self, gpointer gstmem); - -gboolean gst_wl_display_check_format_for_shm (GstWlDisplay * display, - GstVideoFormat format); -gboolean gst_wl_display_check_format_for_dmabuf (GstWlDisplay * display, - GstVideoFormat format); - -G_END_DECLS - -#endif /* __GST_WL_DISPLAY_H__ */ diff --git a/subprojects/gst-plugins-bad/ext/wayland/wlwindow.c b/subprojects/gst-plugins-bad/ext/wayland/wlwindow.c deleted file mode 100644 index 66df0fce7b..0000000000 --- a/subprojects/gst-plugins-bad/ext/wayland/wlwindow.c +++ /dev/null @@ -1,574 +0,0 @@ -/* GStreamer Wayland video sink - * - * Copyright (C) 2011 Intel Corporation - * Copyright (C) 2011 Sreerenj Balachandran - * Copyright (C) 2014 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "wlwindow.h" -#include "wlshmallocator.h" -#include "wlbuffer.h" - -GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug - -enum -{ - CLOSED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE (GstWlWindow, gst_wl_window, G_TYPE_OBJECT); - -static void gst_wl_window_finalize (GObject * gobject); - -static void gst_wl_window_update_borders (GstWlWindow * window); - -static void -handle_xdg_toplevel_close (void *data, struct xdg_toplevel *xdg_toplevel) -{ - GstWlWindow *window = data; - - GST_DEBUG ("XDG toplevel got a \"close\" event."); - g_signal_emit (window, signals[CLOSED], 0); -} - -static void -handle_xdg_toplevel_configure (void *data, struct xdg_toplevel *xdg_toplevel, - int32_t width, int32_t height, struct wl_array *states) -{ - GstWlWindow *window = data; - const uint32_t *state; - - GST_DEBUG ("XDG toplevel got a \"configure\" event, [ %d, %d ].", - width, height); - - wl_array_for_each (state, states) { - switch (*state) { - case XDG_TOPLEVEL_STATE_FULLSCREEN: - case XDG_TOPLEVEL_STATE_MAXIMIZED: - case XDG_TOPLEVEL_STATE_RESIZING: - case XDG_TOPLEVEL_STATE_ACTIVATED: - break; - } - } - - if (width <= 0 || height <= 0) - return; - - gst_wl_window_set_render_rectangle (window, 0, 0, width, height); -} - -static const struct xdg_toplevel_listener xdg_toplevel_listener = { - handle_xdg_toplevel_configure, - handle_xdg_toplevel_close, -}; - -static void -handle_xdg_surface_configure (void *data, struct xdg_surface *xdg_surface, - uint32_t serial) -{ - GstWlWindow *window = data; - xdg_surface_ack_configure (xdg_surface, serial); - - g_mutex_lock (&window->configure_mutex); - window->configured = TRUE; - g_cond_signal (&window->configure_cond); - g_mutex_unlock (&window->configure_mutex); -} - -static const struct xdg_surface_listener xdg_surface_listener = { - handle_xdg_surface_configure, -}; - -static void -handle_ping (void *data, struct wl_shell_surface *wl_shell_surface, - uint32_t serial) -{ - wl_shell_surface_pong (wl_shell_surface, serial); -} - -static void -handle_configure (void *data, struct wl_shell_surface *wl_shell_surface, - uint32_t edges, int32_t width, int32_t height) -{ - GstWlWindow *window = data; - - GST_DEBUG ("Windows configure: edges %x, width = %i, height %i", edges, - width, height); - - if (width == 0 || height == 0) - return; - - gst_wl_window_set_render_rectangle (window, 0, 0, width, height); -} - -static void -handle_popup_done (void *data, struct wl_shell_surface *wl_shell_surface) -{ - GST_DEBUG ("Window popup done."); -} - -static const struct wl_shell_surface_listener wl_shell_surface_listener = { - handle_ping, - handle_configure, - handle_popup_done -}; - -static void -gst_wl_window_class_init (GstWlWindowClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - gobject_class->finalize = gst_wl_window_finalize; - - signals[CLOSED] = g_signal_new ("closed", G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); -} - -static void -gst_wl_window_init (GstWlWindow * self) -{ - self->configured = TRUE; - g_cond_init (&self->configure_cond); - g_mutex_init (&self->configure_mutex); -} - -static void -gst_wl_window_finalize (GObject * gobject) -{ - GstWlWindow *self = GST_WL_WINDOW (gobject); - - if (self->wl_shell_surface) - wl_shell_surface_destroy (self->wl_shell_surface); - - if (self->xdg_toplevel) - xdg_toplevel_destroy (self->xdg_toplevel); - if (self->xdg_surface) - xdg_surface_destroy (self->xdg_surface); - - if (self->video_viewport) - wp_viewport_destroy (self->video_viewport); - - wl_proxy_wrapper_destroy (self->video_surface_wrapper); - wl_subsurface_destroy (self->video_subsurface); - wl_surface_destroy (self->video_surface); - - if (self->area_subsurface) - wl_subsurface_destroy (self->area_subsurface); - - if (self->area_viewport) - wp_viewport_destroy (self->area_viewport); - - wl_proxy_wrapper_destroy (self->area_surface_wrapper); - wl_surface_destroy (self->area_surface); - - g_clear_object (&self->display); - - G_OBJECT_CLASS (gst_wl_window_parent_class)->finalize (gobject); -} - -static GstWlWindow * -gst_wl_window_new_internal (GstWlDisplay * display, GMutex * render_lock) -{ - GstWlWindow *window; - struct wl_region *region; - - window = g_object_new (GST_TYPE_WL_WINDOW, NULL); - window->display = g_object_ref (display); - window->render_lock = render_lock; - g_cond_init (&window->configure_cond); - - window->area_surface = wl_compositor_create_surface (display->compositor); - window->video_surface = wl_compositor_create_surface (display->compositor); - - window->area_surface_wrapper = wl_proxy_create_wrapper (window->area_surface); - window->video_surface_wrapper = - wl_proxy_create_wrapper (window->video_surface); - - wl_proxy_set_queue ((struct wl_proxy *) window->area_surface_wrapper, - display->queue); - wl_proxy_set_queue ((struct wl_proxy *) window->video_surface_wrapper, - display->queue); - - /* embed video_surface in area_surface */ - window->video_subsurface = - wl_subcompositor_get_subsurface (display->subcompositor, - window->video_surface, window->area_surface); - wl_subsurface_set_desync (window->video_subsurface); - - if (display->viewporter) { - window->area_viewport = wp_viewporter_get_viewport (display->viewporter, - window->area_surface); - window->video_viewport = wp_viewporter_get_viewport (display->viewporter, - window->video_surface); - } - - /* never accept input events on the video surface */ - region = wl_compositor_create_region (display->compositor); - wl_surface_set_input_region (window->video_surface, region); - wl_region_destroy (region); - - return window; -} - -void -gst_wl_window_ensure_fullscreen (GstWlWindow * window, gboolean fullscreen) -{ - if (!window) - return; - - if (window->display->xdg_wm_base) { - if (fullscreen) - xdg_toplevel_set_fullscreen (window->xdg_toplevel, NULL); - else - xdg_toplevel_unset_fullscreen (window->xdg_toplevel); - } else { - if (fullscreen) - wl_shell_surface_set_fullscreen (window->wl_shell_surface, - WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE, 0, NULL); - else - wl_shell_surface_set_toplevel (window->wl_shell_surface); - } -} - -GstWlWindow * -gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info, - gboolean fullscreen, GMutex * render_lock) -{ - GstWlWindow *window; - - window = gst_wl_window_new_internal (display, render_lock); - - /* Check which protocol we will use (in order of preference) */ - if (display->xdg_wm_base) { - gint64 timeout; - - /* First create the XDG surface */ - window->xdg_surface = xdg_wm_base_get_xdg_surface (display->xdg_wm_base, - window->area_surface); - if (!window->xdg_surface) { - GST_ERROR ("Unable to get xdg_surface"); - goto error; - } - xdg_surface_add_listener (window->xdg_surface, &xdg_surface_listener, - window); - - /* Then the toplevel */ - window->xdg_toplevel = xdg_surface_get_toplevel (window->xdg_surface); - if (!window->xdg_toplevel) { - GST_ERROR ("Unable to get xdg_toplevel"); - goto error; - } - xdg_toplevel_add_listener (window->xdg_toplevel, - &xdg_toplevel_listener, window); - - gst_wl_window_ensure_fullscreen (window, fullscreen); - - /* Finally, commit the xdg_surface state as toplevel */ - window->configured = FALSE; - wl_surface_commit (window->area_surface); - wl_display_flush (display->display); - - g_mutex_lock (&window->configure_mutex); - timeout = g_get_monotonic_time () + 100 * G_TIME_SPAN_MILLISECOND; - while (!window->configured) { - if (!g_cond_wait_until (&window->configure_cond, &window->configure_mutex, - timeout)) { - GST_WARNING ("The compositor did not send configure event."); - break; - } - } - g_mutex_unlock (&window->configure_mutex); - } else if (display->wl_shell) { - /* go toplevel */ - window->wl_shell_surface = wl_shell_get_shell_surface (display->wl_shell, - window->area_surface); - if (!window->wl_shell_surface) { - GST_ERROR ("Unable to get wl_shell_surface"); - goto error; - } - - wl_shell_surface_add_listener (window->wl_shell_surface, - &wl_shell_surface_listener, window); - gst_wl_window_ensure_fullscreen (window, fullscreen); - } else if (display->fullscreen_shell) { - zwp_fullscreen_shell_v1_present_surface (display->fullscreen_shell, - window->area_surface, ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM, - NULL); - } else { - GST_ERROR ("Unable to use either wl_shell, xdg_wm_base or " - "zwp_fullscreen_shell."); - goto error; - } - - /* render_rectangle is already set via toplevel_configure in - * xdg_shell fullscreen mode */ - if (!(display->xdg_wm_base && fullscreen)) { - /* set the initial size to be the same as the reported video size */ - gint width = - gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d); - gst_wl_window_set_render_rectangle (window, 0, 0, width, info->height); - } - - return window; - -error: - g_object_unref (window); - return NULL; -} - -GstWlWindow * -gst_wl_window_new_in_surface (GstWlDisplay * display, - struct wl_surface * parent, GMutex * render_lock) -{ - GstWlWindow *window; - struct wl_region *region; - window = gst_wl_window_new_internal (display, render_lock); - - /* do not accept input events on the area surface when embedded */ - region = wl_compositor_create_region (display->compositor); - wl_surface_set_input_region (window->area_surface, region); - wl_region_destroy (region); - - /* embed in parent */ - window->area_subsurface = - wl_subcompositor_get_subsurface (display->subcompositor, - window->area_surface, parent); - wl_subsurface_set_desync (window->area_subsurface); - - wl_surface_commit (parent); - - return window; -} - -GstWlDisplay * -gst_wl_window_get_display (GstWlWindow * window) -{ - g_return_val_if_fail (window != NULL, NULL); - - return g_object_ref (window->display); -} - -struct wl_surface * -gst_wl_window_get_wl_surface (GstWlWindow * window) -{ - g_return_val_if_fail (window != NULL, NULL); - - return window->video_surface_wrapper; -} - -gboolean -gst_wl_window_is_toplevel (GstWlWindow * window) -{ - g_return_val_if_fail (window != NULL, FALSE); - - if (window->display->xdg_wm_base) - return (window->xdg_toplevel != NULL); - else - return (window->wl_shell_surface != NULL); -} - -static void -gst_wl_window_resize_video_surface (GstWlWindow * window, gboolean commit) -{ - GstVideoRectangle src = { 0, }; - GstVideoRectangle dst = { 0, }; - GstVideoRectangle res; - - /* center the video_subsurface inside area_subsurface */ - src.w = window->video_width; - src.h = window->video_height; - dst.w = window->render_rectangle.w; - dst.h = window->render_rectangle.h; - - if (window->video_viewport) { - gst_video_sink_center_rect (src, dst, &res, TRUE); - wp_viewport_set_destination (window->video_viewport, res.w, res.h); - } else { - gst_video_sink_center_rect (src, dst, &res, FALSE); - } - - wl_subsurface_set_position (window->video_subsurface, res.x, res.y); - - if (commit) - wl_surface_commit (window->video_surface_wrapper); - - window->video_rectangle = res; -} - -static void -gst_wl_window_set_opaque (GstWlWindow * window, const GstVideoInfo * info) -{ - struct wl_region *region; - - /* Set area opaque */ - region = wl_compositor_create_region (window->display->compositor); - wl_region_add (region, 0, 0, G_MAXINT32, G_MAXINT32); - wl_surface_set_opaque_region (window->area_surface, region); - wl_region_destroy (region); - - if (!GST_VIDEO_INFO_HAS_ALPHA (info)) { - /* Set video opaque */ - region = wl_compositor_create_region (window->display->compositor); - wl_region_add (region, 0, 0, G_MAXINT32, G_MAXINT32); - wl_surface_set_opaque_region (window->video_surface, region); - wl_region_destroy (region); - } -} - -void -gst_wl_window_render (GstWlWindow * window, GstWlBuffer * buffer, - const GstVideoInfo * info) -{ - if (G_UNLIKELY (info)) { - window->video_width = - gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d); - window->video_height = info->height; - - wl_subsurface_set_sync (window->video_subsurface); - gst_wl_window_resize_video_surface (window, FALSE); - gst_wl_window_set_opaque (window, info); - } - - if (G_LIKELY (buffer)) { - gst_wl_buffer_attach (buffer, window->video_surface_wrapper); - wl_surface_damage_buffer (window->video_surface_wrapper, 0, 0, G_MAXINT32, - G_MAXINT32); - wl_surface_commit (window->video_surface_wrapper); - - if (!window->is_area_surface_mapped) { - gst_wl_window_update_borders (window); - wl_surface_commit (window->area_surface_wrapper); - window->is_area_surface_mapped = TRUE; - } - } else { - /* clear both video and parent surfaces */ - wl_surface_attach (window->video_surface_wrapper, NULL, 0, 0); - wl_surface_commit (window->video_surface_wrapper); - wl_surface_attach (window->area_surface_wrapper, NULL, 0, 0); - wl_surface_commit (window->area_surface_wrapper); - window->is_area_surface_mapped = FALSE; - } - - if (G_UNLIKELY (info)) { - /* commit also the parent (area_surface) in order to change - * the position of the video_subsurface */ - wl_surface_commit (window->area_surface_wrapper); - wl_subsurface_set_desync (window->video_subsurface); - } - - wl_display_flush (window->display->display); -} - -/* Update the buffer used to draw black borders. When we have viewporter - * support, this is a scaled up 1x1 image, and without we need an black image - * the size of the rendering areay. */ -static void -gst_wl_window_update_borders (GstWlWindow * window) -{ - GstVideoFormat format; - GstVideoInfo info; - gint width, height; - GstBuffer *buf; - struct wl_buffer *wlbuf; - GstWlBuffer *gwlbuf; - GstAllocator *alloc; - - if (window->display->viewporter) { - wp_viewport_set_destination (window->area_viewport, - window->render_rectangle.w, window->render_rectangle.h); - - if (window->is_area_surface_mapped) { - /* The area_surface is already visible and only needed to get resized. - * We don't need to attach a new buffer and are done here. */ - return; - } - } - - if (window->display->viewporter) { - width = height = 1; - } else { - width = window->render_rectangle.w; - height = window->render_rectangle.h; - } - - /* we want WL_SHM_FORMAT_XRGB8888 */ - format = GST_VIDEO_FORMAT_BGRx; - - /* draw the area_subsurface */ - gst_video_info_set_format (&info, format, width, height); - - alloc = gst_wl_shm_allocator_get (); - - buf = gst_buffer_new_allocate (alloc, info.size, NULL); - gst_buffer_memset (buf, 0, 0, info.size); - wlbuf = - gst_wl_shm_memory_construct_wl_buffer (gst_buffer_peek_memory (buf, 0), - window->display, &info); - gwlbuf = gst_buffer_add_wl_buffer (buf, wlbuf, window->display); - gst_wl_buffer_attach (gwlbuf, window->area_surface_wrapper); - wl_surface_damage_buffer (window->area_surface_wrapper, 0, 0, G_MAXINT32, - G_MAXINT32); - - /* at this point, the GstWlBuffer keeps the buffer - * alive and will free it on wl_buffer::release */ - gst_buffer_unref (buf); - g_object_unref (alloc); -} - -void -gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y, - gint w, gint h) -{ - g_return_if_fail (window != NULL); - - if (window->render_rectangle.x == x && window->render_rectangle.y == y && - window->render_rectangle.w == w && window->render_rectangle.h == h) - return; - - window->render_rectangle.x = x; - window->render_rectangle.y = y; - window->render_rectangle.w = w; - window->render_rectangle.h = h; - - /* position the area inside the parent - needs a parent commit to apply */ - if (window->area_subsurface) - wl_subsurface_set_position (window->area_subsurface, x, y); - - if (window->is_area_surface_mapped) - gst_wl_window_update_borders (window); - - if (!window->configured) - return; - - if (window->video_width != 0) { - wl_subsurface_set_sync (window->video_subsurface); - gst_wl_window_resize_video_surface (window, TRUE); - } - - wl_surface_commit (window->area_surface_wrapper); - - if (window->video_width != 0) - wl_subsurface_set_desync (window->video_subsurface); -} diff --git a/subprojects/gst-plugins-bad/ext/wayland/wlwindow.h b/subprojects/gst-plugins-bad/ext/wayland/wlwindow.h deleted file mode 100644 index 303c336ddd..0000000000 --- a/subprojects/gst-plugins-bad/ext/wayland/wlwindow.h +++ /dev/null @@ -1,101 +0,0 @@ -/* GStreamer Wayland video sink - * - * Copyright (C) 2014 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - */ - -#ifndef __GST_WL_WINDOW_H__ -#define __GST_WL_WINDOW_H__ - -#include "wldisplay.h" -#include "wlbuffer.h" -#include - -G_BEGIN_DECLS - -#define GST_TYPE_WL_WINDOW (gst_wl_window_get_type ()) -#define GST_WL_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_WINDOW, GstWlWindow)) -#define GST_IS_WL_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_WINDOW)) -#define GST_WL_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_WINDOW, GstWlWindowClass)) -#define GST_IS_WL_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_WINDOW)) -#define GST_WL_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_WINDOW, GstWlWindowClass)) - -typedef struct _GstWlWindow GstWlWindow; -typedef struct _GstWlWindowClass GstWlWindowClass; - -struct _GstWlWindow -{ - GObject parent_instance; - - GMutex *render_lock; - - GstWlDisplay *display; - struct wl_surface *area_surface; - struct wl_surface *area_surface_wrapper; - struct wl_subsurface *area_subsurface; - struct wp_viewport *area_viewport; - struct wl_surface *video_surface; - struct wl_surface *video_surface_wrapper; - struct wl_subsurface *video_subsurface; - struct wp_viewport *video_viewport; - struct wl_shell_surface *wl_shell_surface; - struct xdg_surface *xdg_surface; - struct xdg_toplevel *xdg_toplevel; - gboolean configured; - GCond configure_cond; - GMutex configure_mutex; - - /* the size and position of the area_(sub)surface */ - GstVideoRectangle render_rectangle; - - /* the size and position of the video_subsurface */ - GstVideoRectangle video_rectangle; - - /* the size of the video in the buffers */ - gint video_width, video_height; - - /* when this is not set both the area_surface and the video_surface are not - * visible and certain steps should be skipped */ - gboolean is_area_surface_mapped; -}; - -struct _GstWlWindowClass -{ - GObjectClass parent_class; -}; - -GType gst_wl_window_get_type (void); - -void gst_wl_window_ensure_fullscreen (GstWlWindow * window, - gboolean fullscreen); -GstWlWindow *gst_wl_window_new_toplevel (GstWlDisplay * display, - const GstVideoInfo * info, gboolean fullscreen, GMutex * render_lock); -GstWlWindow *gst_wl_window_new_in_surface (GstWlDisplay * display, - struct wl_surface * parent, GMutex * render_lock); - -GstWlDisplay *gst_wl_window_get_display (GstWlWindow * window); -struct wl_surface *gst_wl_window_get_wl_surface (GstWlWindow * window); -gboolean gst_wl_window_is_toplevel (GstWlWindow *window); - -void gst_wl_window_render (GstWlWindow * window, GstWlBuffer * buffer, - const GstVideoInfo * info); -void gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y, - gint w, gint h); - -G_END_DECLS - -#endif /* __GST_WL_WINDOW_H__ */ diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwl_fwd.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwl_fwd.h new file mode 100644 index 0000000000..564f790684 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwl_fwd.h @@ -0,0 +1,31 @@ +/* GStreamer Wayland Library + * + * Copyright (C) 2022 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +G_BEGIN_DECLS + +typedef struct _GstWlBuffer GstWlBuffer; +typedef struct _GstWlDisplay GstWlDisplay; +typedef struct _GstWlShmAllocator GstWlShmAllocator; +typedef struct _GstWlVideoBufferPool GstWlVideoBufferPool; +typedef struct _GstWlWindow GstWlWindow; + +G_END_DECLS diff --git a/subprojects/gst-plugins-bad/ext/wayland/wlbuffer.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlbuffer.c similarity index 75% rename from subprojects/gst-plugins-bad/ext/wayland/wlbuffer.c rename to subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlbuffer.c index caab58d352..6bf6778be9 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/wlbuffer.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlbuffer.c @@ -1,4 +1,4 @@ -/* GStreamer Wayland video sink +/* GStreamer Wayland Library * * Copyright (C) 2014 Collabora Ltd. * @@ -76,17 +76,37 @@ * as soon as we remove the reference that GstWlDisplay holds. */ -#include "wlbuffer.h" +#ifdef HAVE_CONFIG_H +#include +#endif -GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug +#include "gstwlbuffer.h" -G_DEFINE_TYPE (GstWlBuffer, gst_wl_buffer, G_TYPE_OBJECT); +#define GST_CAT_DEFAULT gst_wl_buffer_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +typedef struct _GstWlBufferPrivate +{ + struct wl_buffer *wlbuffer; + GstBuffer *current_gstbuffer; + GstMemory *gstmem; + + GstWlDisplay *display; + + gboolean used_by_compositor; +} GstWlBufferPrivate; + +G_DEFINE_TYPE_WITH_CODE (GstWlBuffer, gst_wl_buffer, G_TYPE_OBJECT, + G_ADD_PRIVATE (GstWlBuffer) + GST_DEBUG_CATEGORY_INIT (gst_wl_buffer_debug, + "wlbuffer", 0, "wlbuffer library"); + ); static void gst_wl_buffer_dispose (GObject * gobject) { GstWlBuffer *self = GST_WL_BUFFER (gobject); + GstWlBufferPrivate *priv = gst_wl_buffer_get_instance_private (self); GST_TRACE_OBJECT (self, "dispose"); @@ -94,8 +114,8 @@ gst_wl_buffer_dispose (GObject * gobject) * the GstWlBuffer from another thread, unregister_buffer() will * block and in the end the display will increase the refcount * of this GstWlBuffer, so it will not be finalized */ - if (self->display) { - gst_wl_display_unregister_buffer (self->display, self->gstmem); + if (priv->display) { + gst_wl_display_unregister_buffer (priv->display, priv->gstmem); } G_OBJECT_CLASS (gst_wl_buffer_parent_class)->dispose (gobject); @@ -105,11 +125,12 @@ static void gst_wl_buffer_finalize (GObject * gobject) { GstWlBuffer *self = GST_WL_BUFFER (gobject); + GstWlBufferPrivate *priv = gst_wl_buffer_get_instance_private (self); GST_TRACE_OBJECT (self, "finalize"); - if (self->wlbuffer) - wl_buffer_destroy (self->wlbuffer); + if (priv->wlbuffer) + wl_buffer_destroy (priv->wlbuffer); G_OBJECT_CLASS (gst_wl_buffer_parent_class)->finalize (gobject); } @@ -132,12 +153,13 @@ static void buffer_release (void *data, struct wl_buffer *wl_buffer) { GstWlBuffer *self = data; - GstBuffer *buf = self->current_gstbuffer; + GstWlBufferPrivate *priv = gst_wl_buffer_get_instance_private (self); + GstBuffer *buf = priv->current_gstbuffer; GST_LOG_OBJECT (self, "wl_buffer::release (GstBuffer: %p)", buf); - self->used_by_compositor = FALSE; - self->current_gstbuffer = NULL; + priv->used_by_compositor = FALSE; + priv->current_gstbuffer = NULL; /* unref should be last, because it may end up destroying the GstWlBuffer */ gst_buffer_unref (buf); @@ -150,7 +172,9 @@ static const struct wl_buffer_listener buffer_listener = { static void gstmemory_disposed (GstWlBuffer * self) { - g_assert (!self->used_by_compositor); + GstWlBufferPrivate *priv = gst_wl_buffer_get_instance_private (self); + + g_assert (!priv->used_by_compositor); GST_TRACE_OBJECT (self, "owning GstMemory was finalized"); @@ -164,18 +188,20 @@ gst_buffer_add_wl_buffer (GstBuffer * gstbuffer, struct wl_buffer *wlbuffer, GstWlDisplay * display) { GstWlBuffer *self; + GstWlBufferPrivate *priv; self = g_object_new (GST_TYPE_WL_BUFFER, NULL); - self->current_gstbuffer = gstbuffer; - self->wlbuffer = wlbuffer; - self->display = display; - self->gstmem = gst_buffer_peek_memory (gstbuffer, 0); + priv = gst_wl_buffer_get_instance_private (self); + priv->current_gstbuffer = gstbuffer; + priv->wlbuffer = wlbuffer; + priv->display = display; + priv->gstmem = gst_buffer_peek_memory (gstbuffer, 0); - gst_wl_display_register_buffer (self->display, self->gstmem, self); + gst_wl_display_register_buffer (priv->display, priv->gstmem, self); - wl_buffer_add_listener (self->wlbuffer, &buffer_listener, self); + wl_buffer_add_listener (priv->wlbuffer, &buffer_listener, self); - gst_mini_object_weak_ref (GST_MINI_OBJECT (self->gstmem), + gst_mini_object_weak_ref (GST_MINI_OBJECT (priv->gstmem), (GstMiniObjectNotify) gstmemory_disposed, self); @@ -194,8 +220,11 @@ gst_buffer_get_wl_buffer (GstWlDisplay * display, GstBuffer * gstbuffer) mem0 = gst_buffer_peek_memory (gstbuffer, 0); wlbuf = gst_wl_display_lookup_buffer (display, mem0); - if (wlbuf) - wlbuf->current_gstbuffer = gstbuffer; + if (wlbuf) { + GstWlBufferPrivate *priv = gst_wl_buffer_get_instance_private (wlbuf); + + priv->current_gstbuffer = gstbuffer; + } return wlbuf; } @@ -203,15 +232,17 @@ gst_buffer_get_wl_buffer (GstWlDisplay * display, GstBuffer * gstbuffer) void gst_wl_buffer_force_release_and_unref (GstBuffer * buf, GstWlBuffer * self) { + GstWlBufferPrivate *priv = gst_wl_buffer_get_instance_private (self); + /* Force a buffer release. * At this point, the GstWlDisplay has killed its event loop, * so we don't need to worry about buffer_release() being called * at the same time from the event loop thread */ - if (self->used_by_compositor) { + if (priv->used_by_compositor) { GST_DEBUG_OBJECT (self, "forcing wl_buffer::release (GstBuffer: %p)", - self->current_gstbuffer); - self->used_by_compositor = FALSE; - gst_buffer_unref (self->current_gstbuffer); + priv->current_gstbuffer); + priv->used_by_compositor = FALSE; + gst_buffer_unref (priv->current_gstbuffer); } /* Finalize this GstWlBuffer early. @@ -222,10 +253,10 @@ gst_wl_buffer_force_release_and_unref (GstBuffer * buf, GstWlBuffer * self) * The last reference is either owned by the GstBuffer or by us and * it will be released at the end of this function. */ GST_TRACE_OBJECT (self, "finalizing early"); - wl_buffer_destroy (self->wlbuffer); - self->wlbuffer = NULL; - self->display = NULL; - self->current_gstbuffer = NULL; + wl_buffer_destroy (priv->wlbuffer); + priv->wlbuffer = NULL; + priv->display = NULL; + priv->current_gstbuffer = NULL; /* remove the reference that the caller (GstWlDisplay) owns */ g_object_unref (self); @@ -234,17 +265,27 @@ gst_wl_buffer_force_release_and_unref (GstBuffer * buf, GstWlBuffer * self) void gst_wl_buffer_attach (GstWlBuffer * self, struct wl_surface *surface) { - if (self->used_by_compositor) { + GstWlBufferPrivate *priv = gst_wl_buffer_get_instance_private (self); + + if (priv->used_by_compositor) { GST_DEBUG_OBJECT (self, "buffer used by compositor %p", - self->current_gstbuffer); + priv->current_gstbuffer); return; } - wl_surface_attach (surface, self->wlbuffer, 0, 0); + wl_surface_attach (surface, priv->wlbuffer, 0, 0); /* Add a reference to the buffer. This represents the fact that * the compositor is using the buffer and it should not return * back to the pool and be re-used until the compositor releases it. */ - gst_buffer_ref (self->current_gstbuffer); - self->used_by_compositor = TRUE; + gst_buffer_ref (priv->current_gstbuffer); + priv->used_by_compositor = TRUE; +} + +GstWlDisplay * +gst_wl_buffer_get_display (GstWlBuffer * self) +{ + GstWlBufferPrivate *priv = gst_wl_buffer_get_instance_private (self); + + return priv->display; } diff --git a/subprojects/gst-plugins-bad/ext/wayland/wlbuffer.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlbuffer.h similarity index 53% rename from subprojects/gst-plugins-bad/ext/wayland/wlbuffer.h rename to subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlbuffer.h index 95433f21d7..07034919b0 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/wlbuffer.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlbuffer.h @@ -1,4 +1,4 @@ -/* GStreamer Wayland video sink +/* GStreamer Wayland Library * * Copyright (C) 2014 Collabora Ltd. * @@ -18,51 +18,34 @@ * Boston, MA 02110-1301 USA. */ -#ifndef __GST_WL_BUFFER_H__ -#define __GST_WL_BUFFER_H__ +#pragma once -#include "wldisplay.h" +#include G_BEGIN_DECLS -#define GST_TYPE_WL_BUFFER (gst_wl_buffer_get_type ()) -#define GST_WL_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_BUFFER, GstWlBuffer)) -#define GST_IS_WL_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_BUFFER)) -#define GST_WL_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_BUFFER, GstWlBufferClass)) -#define GST_IS_WL_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_BUFFER)) -#define GST_WL_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_BUFFER, GstWlBufferClass)) - -typedef struct _GstWlBuffer GstWlBuffer; -typedef struct _GstWlBufferClass GstWlBufferClass; +#define GST_TYPE_WL_BUFFER gst_wl_buffer_get_type () +G_DECLARE_FINAL_TYPE (GstWlBuffer, gst_wl_buffer, GST, WL_BUFFER, GObject); struct _GstWlBuffer { GObject parent_instance; - - struct wl_buffer * wlbuffer; - GstBuffer *current_gstbuffer; - GstMemory *gstmem; - - GstWlDisplay *display; - - gboolean used_by_compositor; }; -struct _GstWlBufferClass -{ - GObjectClass parent_class; -}; - -GType gst_wl_buffer_get_type (void); - +GST_WL_API GstWlBuffer * gst_buffer_add_wl_buffer (GstBuffer * gstbuffer, struct wl_buffer * wlbuffer, GstWlDisplay * display); + +GST_WL_API GstWlBuffer * gst_buffer_get_wl_buffer (GstWlDisplay * display, GstBuffer * gstbuffer); +GST_WL_API void gst_wl_buffer_force_release_and_unref (GstBuffer *buf, GstWlBuffer * self); +GST_WL_API void gst_wl_buffer_attach (GstWlBuffer * self, struct wl_surface *surface); -G_END_DECLS +GST_WL_API +GstWlDisplay *gst_wl_buffer_get_display (GstWlBuffer * self); -#endif /* __GST_WL_BUFFER_H__ */ +G_END_DECLS diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlcontext.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlcontext.c new file mode 100644 index 0000000000..bc7ccf684a --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlcontext.c @@ -0,0 +1,66 @@ +/* GStreamer Wayland Library + * + * Copyright (C) 2022 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "gstwlcontext.h" + +gboolean +gst_is_wl_display_handle_need_context_message (GstMessage * msg) +{ + const gchar *type = NULL; + + g_return_val_if_fail (GST_IS_MESSAGE (msg), FALSE); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_NEED_CONTEXT && + gst_message_parse_context_type (msg, &type)) { + return !g_strcmp0 (type, GST_WL_DISPLAY_HANDLE_CONTEXT_TYPE); + } + + return FALSE; +} + +GstContext * +gst_wl_display_handle_context_new (struct wl_display * display) +{ + GstContext *context = + gst_context_new (GST_WL_DISPLAY_HANDLE_CONTEXT_TYPE, TRUE); + gst_structure_set (gst_context_writable_structure (context), + "display", G_TYPE_POINTER, display, NULL); + return context; +} + +struct wl_display * +gst_wl_display_handle_context_get_handle (GstContext * context) +{ + const GstStructure *s; + struct wl_display *display; + + g_return_val_if_fail (GST_IS_CONTEXT (context), NULL); + + s = gst_context_get_structure (context); + if (gst_structure_get (s, "display", G_TYPE_POINTER, &display, NULL)) + return display; + if (gst_structure_get (s, "handle", G_TYPE_POINTER, &display, NULL)) + return display; + return NULL; +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlcontext.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlcontext.h new file mode 100644 index 0000000000..a7b703394f --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlcontext.h @@ -0,0 +1,42 @@ +/* GStreamer Wayland Library + * + * Copyright (C) 2022 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +/* The type of GstContext used to pass the wl_display pointer + * from the application to the sink */ +#define GST_WL_DISPLAY_HANDLE_CONTEXT_TYPE "GstWlDisplayHandleContextType" + +GST_WL_API +gboolean gst_is_wl_display_handle_need_context_message (GstMessage * msg); + +GST_WL_API +GstContext * +gst_wl_display_handle_context_new (struct wl_display * display); + +GST_WL_API +struct wl_display * +gst_wl_display_handle_context_get_handle (GstContext * context); + +G_END_DECLS diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwldisplay.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwldisplay.c new file mode 100644 index 0000000000..1f83cb24b7 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwldisplay.c @@ -0,0 +1,567 @@ +/* GStreamer Wayland Library + * + * Copyright (C) 2014 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "gstwldisplay.h" + +#include "fullscreen-shell-unstable-v1-client-protocol.h" +#include "linux-dmabuf-unstable-v1-client-protocol.h" +#include "viewporter-client-protocol.h" +#include "xdg-shell-client-protocol.h" + +#include + +#define GST_CAT_DEFAULT gst_wl_display_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +typedef struct _GstWlDisplayPrivate +{ + /* public objects */ + struct wl_display *display; + struct wl_display *display_wrapper; + struct wl_event_queue *queue; + + /* globals */ + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_subcompositor *subcompositor; + struct xdg_wm_base *xdg_wm_base; + struct zwp_fullscreen_shell_v1 *fullscreen_shell; + struct wl_shm *shm; + struct wp_viewporter *viewporter; + struct zwp_linux_dmabuf_v1 *dmabuf; + GArray *shm_formats; + GArray *dmabuf_formats; + + /* private */ + gboolean own_display; + GThread *thread; + GstPoll *wl_fd_poll; + + GMutex buffers_mutex; + GHashTable *buffers; + gboolean shutting_down; +} GstWlDisplayPrivate; + +G_DEFINE_TYPE_WITH_CODE (GstWlDisplay, gst_wl_display, G_TYPE_OBJECT, + G_ADD_PRIVATE (GstWlDisplay) + GST_DEBUG_CATEGORY_INIT (gst_wl_display_debug, + "wldisplay", 0, "wldisplay library"); + ); + +static void gst_wl_display_finalize (GObject * gobject); + +static void +gst_wl_display_class_init (GstWlDisplayClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = gst_wl_display_finalize; +} + +static void +gst_wl_display_init (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + priv->shm_formats = g_array_new (FALSE, FALSE, sizeof (uint32_t)); + priv->dmabuf_formats = g_array_new (FALSE, FALSE, sizeof (uint32_t)); + priv->wl_fd_poll = gst_poll_new (TRUE); + priv->buffers = g_hash_table_new (g_direct_hash, g_direct_equal); + g_mutex_init (&priv->buffers_mutex); + + gst_wl_linux_dmabuf_init_once (); + gst_wl_shm_allocator_init_once (); + gst_wl_videoformat_init_once (); +} + +static void +gst_wl_ref_wl_buffer (gpointer key, gpointer value, gpointer user_data) +{ + g_object_ref (value); +} + +static void +gst_wl_display_finalize (GObject * gobject) +{ + GstWlDisplay *self = GST_WL_DISPLAY (gobject); + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + gst_poll_set_flushing (priv->wl_fd_poll, TRUE); + if (priv->thread) + g_thread_join (priv->thread); + + /* to avoid buffers being unregistered from another thread + * at the same time, take their ownership */ + g_mutex_lock (&priv->buffers_mutex); + priv->shutting_down = TRUE; + g_hash_table_foreach (priv->buffers, gst_wl_ref_wl_buffer, NULL); + g_mutex_unlock (&priv->buffers_mutex); + + g_hash_table_foreach (priv->buffers, + (GHFunc) gst_wl_buffer_force_release_and_unref, NULL); + g_hash_table_remove_all (priv->buffers); + + g_array_unref (priv->shm_formats); + g_array_unref (priv->dmabuf_formats); + gst_poll_free (priv->wl_fd_poll); + g_hash_table_unref (priv->buffers); + g_mutex_clear (&priv->buffers_mutex); + + if (priv->viewporter) + wp_viewporter_destroy (priv->viewporter); + + if (priv->shm) + wl_shm_destroy (priv->shm); + + if (priv->dmabuf) + zwp_linux_dmabuf_v1_destroy (priv->dmabuf); + + if (priv->xdg_wm_base) + xdg_wm_base_destroy (priv->xdg_wm_base); + + if (priv->fullscreen_shell) + zwp_fullscreen_shell_v1_release (priv->fullscreen_shell); + + if (priv->compositor) + wl_compositor_destroy (priv->compositor); + + if (priv->subcompositor) + wl_subcompositor_destroy (priv->subcompositor); + + if (priv->registry) + wl_registry_destroy (priv->registry); + + if (priv->display_wrapper) + wl_proxy_wrapper_destroy (priv->display_wrapper); + + if (priv->queue) + wl_event_queue_destroy (priv->queue); + + if (priv->own_display) { + wl_display_flush (priv->display); + wl_display_disconnect (priv->display); + } + + G_OBJECT_CLASS (gst_wl_display_parent_class)->finalize (gobject); +} + +static void +shm_format (void *data, struct wl_shm *wl_shm, uint32_t format) +{ + GstWlDisplay *self = data; + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + g_array_append_val (priv->shm_formats, format); +} + +static const struct wl_shm_listener shm_listener = { + shm_format +}; + +static void +dmabuf_format (void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, + uint32_t format) +{ + GstWlDisplay *self = data; + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + if (gst_wl_dmabuf_format_to_video_format (format) != GST_VIDEO_FORMAT_UNKNOWN) + g_array_append_val (priv->dmabuf_formats, format); +} + +static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { + dmabuf_format, +}; + +gboolean +gst_wl_display_check_format_for_shm (GstWlDisplay * self, GstVideoFormat format) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + enum wl_shm_format shm_fmt; + GArray *formats; + guint i; + + shm_fmt = gst_video_format_to_wl_shm_format (format); + if (shm_fmt == (enum wl_shm_format) -1) + return FALSE; + + formats = priv->shm_formats; + for (i = 0; i < formats->len; i++) { + if (g_array_index (formats, uint32_t, i) == shm_fmt) + return TRUE; + } + + return FALSE; +} + +gboolean +gst_wl_display_check_format_for_dmabuf (GstWlDisplay * self, + GstVideoFormat format) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + GArray *formats; + guint i, dmabuf_fmt; + + if (!priv->dmabuf) + return FALSE; + + dmabuf_fmt = gst_video_format_to_wl_dmabuf_format (format); + if (dmabuf_fmt == (guint) - 1) + return FALSE; + + formats = priv->dmabuf_formats; + for (i = 0; i < formats->len; i++) { + if (g_array_index (formats, uint32_t, i) == dmabuf_fmt) + return TRUE; + } + + return FALSE; +} + +static void +handle_xdg_wm_base_ping (void *user_data, struct xdg_wm_base *xdg_wm_base, + uint32_t serial) +{ + xdg_wm_base_pong (xdg_wm_base, serial); +} + +static const struct xdg_wm_base_listener xdg_wm_base_listener = { + handle_xdg_wm_base_ping +}; + +static void +registry_handle_global (void *data, struct wl_registry *registry, + uint32_t id, const char *interface, uint32_t version) +{ + GstWlDisplay *self = data; + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + if (g_strcmp0 (interface, "wl_compositor") == 0) { + priv->compositor = wl_registry_bind (registry, id, &wl_compositor_interface, + MIN (version, 4)); + } else if (g_strcmp0 (interface, "wl_subcompositor") == 0) { + priv->subcompositor = + wl_registry_bind (registry, id, &wl_subcompositor_interface, 1); + } else if (g_strcmp0 (interface, "xdg_wm_base") == 0) { + priv->xdg_wm_base = + wl_registry_bind (registry, id, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener (priv->xdg_wm_base, &xdg_wm_base_listener, self); + } else if (g_strcmp0 (interface, "zwp_fullscreen_shell_v1") == 0) { + priv->fullscreen_shell = wl_registry_bind (registry, id, + &zwp_fullscreen_shell_v1_interface, 1); + } else if (g_strcmp0 (interface, "wl_shm") == 0) { + priv->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1); + wl_shm_add_listener (priv->shm, &shm_listener, self); + } else if (g_strcmp0 (interface, "wp_viewporter") == 0) { + priv->viewporter = + wl_registry_bind (registry, id, &wp_viewporter_interface, 1); + } else if (g_strcmp0 (interface, "zwp_linux_dmabuf_v1") == 0) { + priv->dmabuf = + wl_registry_bind (registry, id, &zwp_linux_dmabuf_v1_interface, 1); + zwp_linux_dmabuf_v1_add_listener (priv->dmabuf, &dmabuf_listener, self); + } +} + +static void +registry_handle_global_remove (void *data, struct wl_registry *registry, + uint32_t name) +{ + /* temporarily do nothing */ +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +static gpointer +gst_wl_display_thread_run (gpointer data) +{ + GstWlDisplay *self = data; + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + GstPollFD pollfd = GST_POLL_FD_INIT; + + pollfd.fd = wl_display_get_fd (priv->display); + gst_poll_add_fd (priv->wl_fd_poll, &pollfd); + gst_poll_fd_ctl_read (priv->wl_fd_poll, &pollfd, TRUE); + + /* main loop */ + while (1) { + while (wl_display_prepare_read_queue (priv->display, priv->queue) != 0) + wl_display_dispatch_queue_pending (priv->display, priv->queue); + wl_display_flush (priv->display); + + if (gst_poll_wait (priv->wl_fd_poll, GST_CLOCK_TIME_NONE) < 0) { + gboolean normal = (errno == EBUSY); + wl_display_cancel_read (priv->display); + if (normal) + break; + else + goto error; + } + if (wl_display_read_events (priv->display) == -1) + goto error; + wl_display_dispatch_queue_pending (priv->display, priv->queue); + } + + return NULL; + +error: + GST_ERROR ("Error communicating with the wayland server"); + return NULL; +} + +GstWlDisplay * +gst_wl_display_new (const gchar * name, GError ** error) +{ + struct wl_display *display; + + display = wl_display_connect (name); + + if (!display) { + *error = g_error_new (g_quark_from_static_string ("GstWlDisplay"), 0, + "Failed to connect to the wayland display '%s'", + name ? name : "(default)"); + return NULL; + } else { + return gst_wl_display_new_existing (display, TRUE, error); + } +} + +GstWlDisplay * +gst_wl_display_new_existing (struct wl_display * display, + gboolean take_ownership, GError ** error) +{ + GstWlDisplay *self; + GstWlDisplayPrivate *priv; + GError *err = NULL; + gint i; + + g_return_val_if_fail (display != NULL, NULL); + + self = g_object_new (GST_TYPE_WL_DISPLAY, NULL); + priv = gst_wl_display_get_instance_private (self); + priv->display = display; + priv->display_wrapper = wl_proxy_create_wrapper (display); + priv->own_display = take_ownership; + + priv->queue = wl_display_create_queue (priv->display); + wl_proxy_set_queue ((struct wl_proxy *) priv->display_wrapper, priv->queue); + priv->registry = wl_display_get_registry (priv->display_wrapper); + wl_registry_add_listener (priv->registry, ®istry_listener, self); + + /* we need exactly 2 roundtrips to discover global objects and their state */ + for (i = 0; i < 2; i++) { + if (wl_display_roundtrip_queue (priv->display, priv->queue) < 0) { + *error = g_error_new (g_quark_from_static_string ("GstWlDisplay"), 0, + "Error communicating with the wayland display"); + g_object_unref (self); + return NULL; + } + } + + /* verify we got all the required interfaces */ +#define VERIFY_INTERFACE_EXISTS(var, interface) \ + if (!priv->var) { \ + g_set_error (error, g_quark_from_static_string ("GstWlDisplay"), 0, \ + "Could not bind to " interface ". Either it is not implemented in " \ + "the compositor, or the implemented version doesn't match"); \ + g_object_unref (self); \ + return NULL; \ + } + + VERIFY_INTERFACE_EXISTS (compositor, "wl_compositor"); + VERIFY_INTERFACE_EXISTS (subcompositor, "wl_subcompositor"); + VERIFY_INTERFACE_EXISTS (shm, "wl_shm"); + +#undef VERIFY_INTERFACE_EXISTS + + /* We make the viewporter optional even though it may cause bad display. + * This is so one can test wayland display on older compositor or on + * compositor that don't implement this extension. */ + if (!priv->viewporter) { + g_warning ("Wayland compositor is missing the ability to scale, video " + "display may not work properly."); + } + + if (!priv->dmabuf) { + g_warning ("Could not bind to zwp_linux_dmabuf_v1"); + } + + if (!priv->xdg_wm_base && !priv->fullscreen_shell) { + /* If wl_surface and wl_display are passed via GstContext + * xdg_shell and zwp_fullscreen_shell are not used. + * In this case is correct to continue. + */ + g_warning ("Could not bind to either xdg_wm_base or zwp_fullscreen_shell, " + "video display may not work properly."); + } + + priv->thread = g_thread_try_new ("GstWlDisplay", gst_wl_display_thread_run, + self, &err); + if (err) { + g_propagate_prefixed_error (error, err, + "Failed to start thread for the display's events"); + g_object_unref (self); + return NULL; + } + + return self; +} + +void +gst_wl_display_register_buffer (GstWlDisplay * self, gpointer gstmem, + gpointer wlbuffer) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + g_assert (!priv->shutting_down); + + GST_TRACE_OBJECT (self, "registering GstWlBuffer %p to GstMem %p", + wlbuffer, gstmem); + + g_mutex_lock (&priv->buffers_mutex); + g_hash_table_replace (priv->buffers, gstmem, wlbuffer); + g_mutex_unlock (&priv->buffers_mutex); +} + +gpointer +gst_wl_display_lookup_buffer (GstWlDisplay * self, gpointer gstmem) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + gpointer wlbuffer; + + g_mutex_lock (&priv->buffers_mutex); + wlbuffer = g_hash_table_lookup (priv->buffers, gstmem); + g_mutex_unlock (&priv->buffers_mutex); + return wlbuffer; +} + +void +gst_wl_display_unregister_buffer (GstWlDisplay * self, gpointer gstmem) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + GST_TRACE_OBJECT (self, "unregistering GstWlBuffer owned by %p", gstmem); + + g_mutex_lock (&priv->buffers_mutex); + if (G_LIKELY (!priv->shutting_down)) + g_hash_table_remove (priv->buffers, gstmem); + g_mutex_unlock (&priv->buffers_mutex); +} + +struct wl_display * +gst_wl_display_get_display (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + return priv->display; +} + +struct wl_event_queue * +gst_wl_display_get_event_queue (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + return priv->queue; +} + +struct wl_compositor * +gst_wl_display_get_compositor (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + return priv->compositor; +} + +struct wl_subcompositor * +gst_wl_display_get_subcompositor (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + return priv->subcompositor; +} + +struct xdg_wm_base * +gst_wl_display_get_xdg_wm_base (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + return priv->xdg_wm_base; +} + +struct zwp_fullscreen_shell_v1 * +gst_wl_display_get_fullscreen_shell_v1 (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + return priv->fullscreen_shell; +} + +struct wp_viewporter * +gst_wl_display_get_viewporter (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + return priv->viewporter; +} + +struct wl_shm * +gst_wl_display_get_shm (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + return priv->shm; +} + +GArray * +gst_wl_display_get_shm_formats (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + return priv->shm_formats; +} + +struct zwp_linux_dmabuf_v1 * +gst_wl_display_get_dmabuf_v1 (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + return priv->dmabuf; +} + +GArray * +gst_wl_display_get_dmabuf_formats (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + return priv->dmabuf_formats; +} + +gboolean +gst_wl_display_has_own_display (GstWlDisplay * self) +{ + GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); + + return priv->own_display; +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwldisplay.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwldisplay.h new file mode 100644 index 0000000000..eb07e4f875 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwldisplay.h @@ -0,0 +1,100 @@ +/* GStreamer Wayland Library + * + * Copyright (C) 2014 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_WL_DISPLAY (gst_wl_display_get_type ()) +G_DECLARE_FINAL_TYPE (GstWlDisplay, gst_wl_display, GST, WL_DISPLAY, GObject); + +struct _GstWlDisplay +{ + GObject parent_instance; +}; + +GST_WL_API +GstWlDisplay *gst_wl_display_new (const gchar * name, GError ** error); + +GST_WL_API +GstWlDisplay *gst_wl_display_new_existing (struct wl_display * display, + gboolean take_ownership, GError ** error); + +/* see wlbuffer.c for explanation */ +GST_WL_API +void gst_wl_display_register_buffer (GstWlDisplay * self, gpointer gstmem, + gpointer wlbuffer); + +GST_WL_API +void gst_wl_display_unregister_buffer (GstWlDisplay * self, gpointer gstmem); + +GST_WL_API +gpointer gst_wl_display_lookup_buffer (GstWlDisplay * self, gpointer gstmem); + +GST_WL_API +gboolean gst_wl_display_check_format_for_shm (GstWlDisplay * self, + GstVideoFormat format); + +GST_WL_API +gboolean gst_wl_display_check_format_for_dmabuf (GstWlDisplay * self, + GstVideoFormat format); + +GST_WL_API +struct wl_display *gst_wl_display_get_display (GstWlDisplay * self); + +GST_WL_API +struct wl_event_queue *gst_wl_display_get_event_queue (GstWlDisplay * self); + +GST_WL_API +struct wl_compositor *gst_wl_display_get_compositor (GstWlDisplay * self); + +GST_WL_API +struct wl_subcompositor *gst_wl_display_get_subcompositor (GstWlDisplay * self); + +GST_WL_API +struct xdg_wm_base *gst_wl_display_get_xdg_wm_base (GstWlDisplay * self); + +GST_WL_API +struct zwp_fullscreen_shell_v1 *gst_wl_display_get_fullscreen_shell_v1 (GstWlDisplay * self); + +GST_WL_API +struct wp_viewporter *gst_wl_display_get_viewporter (GstWlDisplay * self); + +GST_WL_API +struct wl_shm *gst_wl_display_get_shm (GstWlDisplay * self); + +GST_WL_API +GArray *gst_wl_display_get_shm_formats (GstWlDisplay * self); + +GST_WL_API +GArray *gst_wl_display_get_dmabuf_formats (GstWlDisplay * self); + +GST_WL_API +struct zwp_linux_dmabuf_v1 *gst_wl_display_get_dmabuf_v1 (GstWlDisplay * self); + +GST_WL_API +gboolean gst_wl_display_has_own_display (GstWlDisplay * self); + +G_END_DECLS diff --git a/subprojects/gst-plugins-bad/ext/wayland/wllinuxdmabuf.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwllinuxdmabuf.c similarity index 88% rename from subprojects/gst-plugins-bad/ext/wayland/wllinuxdmabuf.c rename to subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwllinuxdmabuf.c index 96487d142a..d6ee6ec371 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/wllinuxdmabuf.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwllinuxdmabuf.c @@ -1,7 +1,8 @@ -/* GStreamer Wayland video sink +/* GStreamer Wayland Library * * Copyright (C) 2016 STMicroelectronics SA * Copyright (C) 2016 Fabien Dessenne + * Copyright (C) 2022 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,13 +24,25 @@ #include #endif -#include +#include "gstwllinuxdmabuf.h" -#include "wllinuxdmabuf.h" -#include "wlvideoformat.h" +#include "linux-dmabuf-unstable-v1-client-protocol.h" -GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug +GST_DEBUG_CATEGORY (gst_wl_dmabuf_debug); +#define GST_CAT_DEFAULT gst_wl_dmabuf_debug + +void +gst_wl_linux_dmabuf_init_once (void) +{ + static gsize _init = 0; + + if (g_once_init_enter (&_init)) { + GST_DEBUG_CATEGORY_INIT (gst_wl_dmabuf_debug, "wl_dmabuf", 0, + "wl_dmabuf library"); + + g_once_init_leave (&_init, 1); + } +} typedef struct { @@ -99,7 +112,8 @@ gst_wl_linux_dmabuf_construct_wl_buffer (GstBuffer * buf, gst_wl_dmabuf_format_to_string (format)); /* Creation and configuration of planes */ - params = zwp_linux_dmabuf_v1_create_params (display->dmabuf); + params = zwp_linux_dmabuf_v1_create_params (gst_wl_display_get_dmabuf_v1 + (display)); for (i = 0; i < nplanes; i++) { guint offset, stride, mem_idx, length; @@ -136,7 +150,7 @@ gst_wl_linux_dmabuf_construct_wl_buffer (GstBuffer * buf, zwp_linux_buffer_params_v1_create (params, width, height, format, flags); /* Wait for the request answer */ - wl_display_flush (display->display); + wl_display_flush (gst_wl_display_get_display (display)); data.wbuf = (gpointer) 0x1; timeout = g_get_monotonic_time () + G_TIME_SPAN_SECOND; while (data.wbuf == (gpointer) 0x1) { diff --git a/subprojects/gst-plugins-bad/ext/wayland/wllinuxdmabuf.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwllinuxdmabuf.h similarity index 84% rename from subprojects/gst-plugins-bad/ext/wayland/wllinuxdmabuf.h rename to subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwllinuxdmabuf.h index 45ddb17282..d20eb41107 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/wllinuxdmabuf.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwllinuxdmabuf.h @@ -1,7 +1,8 @@ -/* GStreamer Wayland video sink +/* GStreamer Wayland Library * * Copyright (C) 2016 STMicroelectronics SA * Copyright (C) 2016 Fabien Dessenne + * Copyright (C) 2022 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,10 +20,11 @@ * Boston, MA 02110-1301 USA. */ -#ifndef __GST_WL_LINUX_DMABUF_H__ -#define __GST_WL_LINUX_DMABUF_H__ +#pragma once -#include "gstwaylandsink.h" +#include + +#include G_BEGIN_DECLS @@ -30,9 +32,11 @@ G_BEGIN_DECLS #define GST_CAPS_FEATURE_MEMORY_DMABUF "memory:DMABuf" #endif +GST_WL_API +void gst_wl_linux_dmabuf_init_once (void); + +GST_WL_API struct wl_buffer * gst_wl_linux_dmabuf_construct_wl_buffer (GstBuffer * buf, GstWlDisplay * display, const GstVideoInfo * info); G_END_DECLS - -#endif /* __GST_WL_LINUX_DMABUF_H__ */ diff --git a/subprojects/gst-plugins-bad/ext/wayland/wlshmallocator.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.c similarity index 87% rename from subprojects/gst-plugins-bad/ext/wayland/wlshmallocator.c rename to subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.c index 611e2fbdf0..de7e3d8b10 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/wlshmallocator.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.c @@ -1,4 +1,4 @@ -/* GStreamer Wayland video sink +/* GStreamer Wayland Library * * Copyright (C) 2012 Intel Corporation * Copyright (C) 2012 Sreerenj Balachandran @@ -20,21 +20,28 @@ * Boston, MA 02110-1301, USA. */ -#include "wlshmallocator.h" -#include "wlvideoformat.h" +#ifdef HAVE_CONFIG_H +#include +#endif +#include "gstwlshmallocator.h" + +#include +#include #include #include #include -#include -#include #include #include +#include -GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug +#define GST_CAT_DEFAULT gst_wl_shm_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); -G_DEFINE_TYPE (GstWlShmAllocator, gst_wl_shm_allocator, GST_TYPE_FD_ALLOCATOR); +G_DEFINE_TYPE_WITH_CODE (GstWlShmAllocator, gst_wl_shm_allocator, + GST_TYPE_FD_ALLOCATOR, + GST_DEBUG_CATEGORY_INIT (gst_wl_shm_debug, "wlshm", 0, "wlshm library"); + ); static GstMemory * gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size, @@ -123,13 +130,19 @@ gst_wl_shm_allocator_init (GstWlShmAllocator * self) } void -gst_wl_shm_allocator_register (void) +gst_wl_shm_allocator_init_once (void) { - GstAllocator *alloc; + static gsize _init = 0; - alloc = g_object_new (GST_TYPE_WL_SHM_ALLOCATOR, NULL); - gst_object_ref_sink (alloc); - gst_allocator_register (GST_ALLOCATOR_WL_SHM, alloc); + if (g_once_init_enter (&_init)) { + GstAllocator *alloc; + + alloc = g_object_new (GST_TYPE_WL_SHM_ALLOCATOR, NULL); + gst_object_ref_sink (alloc); + gst_allocator_register (GST_ALLOCATOR_WL_SHM, alloc); + + g_once_init_leave (&_init, 1); + } } GstAllocator * @@ -212,8 +225,8 @@ gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display, G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height, stride, gst_wl_shm_format_to_string (format)); - wl_pool = wl_shm_create_pool (display->shm, gst_fd_memory_get_fd (mem), - memsize); + wl_pool = wl_shm_create_pool (gst_wl_display_get_shm (display), + gst_fd_memory_get_fd (mem), memsize); wbuffer = wl_shm_pool_create_buffer (wl_pool, offset, width, height, stride, format); wl_shm_pool_destroy (wl_pool); diff --git a/subprojects/gst-plugins-bad/ext/wayland/wlshmallocator.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.h similarity index 52% rename from subprojects/gst-plugins-bad/ext/wayland/wlshmallocator.h rename to subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.h index 07ae17fbf5..0e7e15da93 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/wlshmallocator.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.h @@ -1,4 +1,4 @@ -/* GStreamer Wayland video sink +/* GStreamer Wayland Library * * Copyright (C) 2012 Intel Corporation * Copyright (C) 2012 Sreerenj Balachandran @@ -20,47 +20,36 @@ * Boston, MA 02110-1301, USA. */ -#ifndef __GST_WL_SHM_ALLOCATOR_H__ -#define __GST_WL_SHM_ALLOCATOR_H__ +#pragma once + +#include -#include #include -#include -#include "wldisplay.h" +#include G_BEGIN_DECLS -#define GST_TYPE_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get_type ()) -#define GST_WL_SHM_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocator)) -#define GST_IS_WL_SHM_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_SHM_ALLOCATOR)) -#define GST_WL_SHM_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocatorClass)) -#define GST_IS_WL_SHM_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_SHM_ALLOCATOR)) -#define GST_WL_SHM_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocatorClass)) +#define GST_TYPE_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get_type ()) +G_DECLARE_FINAL_TYPE (GstWlShmAllocator, gst_wl_shm_allocator, GST, WL_SHM_ALLOCATOR, GstFdAllocator); #define GST_ALLOCATOR_WL_SHM "wl_shm" -typedef struct _GstWlShmAllocator GstWlShmAllocator; -typedef struct _GstWlShmAllocatorClass GstWlShmAllocatorClass; - struct _GstWlShmAllocator { GstFdAllocator parent_instance; }; -struct _GstWlShmAllocatorClass -{ - GstFdAllocatorClass parent_class; -}; +GST_WL_API +void gst_wl_shm_allocator_init_once (void); -GType gst_wl_shm_allocator_get_type (void); - -void gst_wl_shm_allocator_register (void); +GST_WL_API GstAllocator * gst_wl_shm_allocator_get (void); +GST_WL_API gboolean gst_is_wl_shm_memory (GstMemory * mem); + +GST_WL_API struct wl_buffer * gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display, const GstVideoInfo * info); G_END_DECLS - -#endif /* __GST_WL_SHM_ALLOCATOR_H__ */ diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlvideobufferpool.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlvideobufferpool.c new file mode 100644 index 0000000000..b367d9f2d6 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlvideobufferpool.c @@ -0,0 +1,53 @@ +/* GStreamer Wayland Library + * + * Copyright (C) 2017 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "gstwlvideobufferpool.h" + +G_DEFINE_TYPE (GstWlVideoBufferPool, gst_wl_video_buffer_pool, + GST_TYPE_VIDEO_BUFFER_POOL); + +static const gchar ** +gst_wl_video_buffer_pool_get_options (GstBufferPool * pool) +{ + static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL }; + return options; +} + +static void +gst_wl_video_buffer_pool_class_init (GstWlVideoBufferPoolClass * klass) +{ + GstBufferPoolClass *pool_class = GST_BUFFER_POOL_CLASS (klass); + pool_class->get_options = gst_wl_video_buffer_pool_get_options; +} + +static void +gst_wl_video_buffer_pool_init (GstWlVideoBufferPool * pool) +{ +} + +GstBufferPool * +gst_wl_video_buffer_pool_new (void) +{ + return (GstBufferPool *) g_object_new (GST_TYPE_WL_VIDEO_BUFFER_POOL, NULL); +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlvideobufferpool.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlvideobufferpool.h new file mode 100644 index 0000000000..297afbccaa --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlvideobufferpool.h @@ -0,0 +1,46 @@ +/* GStreamer Wayland Library + * + * Copyright (C) 2017 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include + +#include + +G_BEGIN_DECLS + +/* A tiny GstVideoBufferPool subclass that modify the options to remove + * VideoAlignment. To support VideoAlignment we would need to pass the padded + * width/height + stride and use the viewporter interface to crop, a bit like + * we use to do with XV. It would still be quite limited. It's a bit retro, + * hopefully there will be a better Wayland interface in the future. */ + +#define GST_TYPE_WL_VIDEO_BUFFER_POOL (gst_wl_video_buffer_pool_get_type ()) +G_DECLARE_FINAL_TYPE (GstWlVideoBufferPool, gst_wl_video_buffer_pool, GST, WL_VIDEO_BUFFER_POOL, GstVideoBufferPool); + +struct _GstWlVideoBufferPool +{ + GstVideoBufferPool parent; +}; + +GST_WL_API +GstBufferPool * gst_wl_video_buffer_pool_new (void); + +G_END_DECLS diff --git a/subprojects/gst-plugins-bad/ext/wayland/wlvideoformat.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlvideoformat.c similarity index 91% rename from subprojects/gst-plugins-bad/ext/wayland/wlvideoformat.c rename to subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlvideoformat.c index 68cec50932..44a95365d9 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/wlvideoformat.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlvideoformat.c @@ -1,4 +1,4 @@ -/* GStreamer Wayland video sink +/* GStreamer Wayland Library * * Copyright (C) 2011 Intel Corporation * Copyright (C) 2011 Sreerenj Balachandran @@ -25,10 +25,25 @@ #include #endif -#include "wlvideoformat.h" +#include "gstwlvideoformat.h" -GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug +#include + +#define GST_CAT_DEFAULT gst_wl_videoformat_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +void +gst_wl_videoformat_init_once (void) +{ + static gsize _init = 0; + + if (g_once_init_enter (&_init)) { + GST_DEBUG_CATEGORY_INIT (gst_wl_videoformat_debug, "wl_videoformat", 0, + "wl_videoformat library"); + + g_once_init_leave (&_init, 1); + } +} typedef struct { diff --git a/subprojects/gst-plugins-bad/ext/wayland/wlvideoformat.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlvideoformat.h similarity index 87% rename from subprojects/gst-plugins-bad/ext/wayland/wlvideoformat.h rename to subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlvideoformat.h index 331f582b1b..bc36a089df 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/wlvideoformat.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlvideoformat.h @@ -1,4 +1,4 @@ -/* GStreamer Wayland video sink +/* GStreamer Wayland Library * * Copyright (C) 2011 Intel Corporation * Copyright (C) 2011 Sreerenj Balachandran @@ -21,22 +21,33 @@ * Boston, MA 02110-1301 USA. */ -#ifndef __GST_WL_VIDEO_FORMAT_H__ -#define __GST_WL_VIDEO_FORMAT_H__ +#pragma once + +#include -#include #include -#include G_BEGIN_DECLS +GST_WL_API +void gst_wl_videoformat_init_once (void); + +GST_WL_API enum wl_shm_format gst_video_format_to_wl_shm_format (GstVideoFormat format); + +GST_WL_API gint gst_video_format_to_wl_dmabuf_format (GstVideoFormat format); + +GST_WL_API GstVideoFormat gst_wl_shm_format_to_video_format (enum wl_shm_format wl_format); + +GST_WL_API GstVideoFormat gst_wl_dmabuf_format_to_video_format (guint wl_format); + +GST_WL_API const gchar *gst_wl_shm_format_to_string (enum wl_shm_format wl_format); + +GST_WL_API const gchar *gst_wl_dmabuf_format_to_string (guint wl_format); G_END_DECLS - -#endif diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.c new file mode 100644 index 0000000000..d50dc6a991 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.c @@ -0,0 +1,612 @@ +/* GStreamer Wayland Library + * + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Sreerenj Balachandran + * Copyright (C) 2014 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "gstwlwindow.h" + +#include "fullscreen-shell-unstable-v1-client-protocol.h" +#include "viewporter-client-protocol.h" +#include "xdg-shell-client-protocol.h" + +#define GST_CAT_DEFAULT gst_wl_window_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +typedef struct _GstWlWindowPrivate +{ + GObject parent_instance; + + GMutex *render_lock; + + GstWlDisplay *display; + struct wl_surface *area_surface; + struct wl_surface *area_surface_wrapper; + struct wl_subsurface *area_subsurface; + struct wp_viewport *area_viewport; + struct wl_surface *video_surface; + struct wl_surface *video_surface_wrapper; + struct wl_subsurface *video_subsurface; + struct wp_viewport *video_viewport; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; + gboolean configured; + GCond configure_cond; + GMutex configure_mutex; + + /* the size and position of the area_(sub)surface */ + GstVideoRectangle render_rectangle; + + /* the size and position of the video_subsurface */ + GstVideoRectangle video_rectangle; + + /* the size of the video in the buffers */ + gint video_width, video_height; + + /* when this is not set both the area_surface and the video_surface are not + * visible and certain steps should be skipped */ + gboolean is_area_surface_mapped; +} GstWlWindowPrivate; + +G_DEFINE_TYPE_WITH_CODE (GstWlWindow, gst_wl_window, G_TYPE_OBJECT, + G_ADD_PRIVATE (GstWlWindow) + GST_DEBUG_CATEGORY_INIT (gst_wl_window_debug, + "wlwindow", 0, "wlwindow library"); + ); + +enum +{ + CLOSED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void gst_wl_window_finalize (GObject * gobject); + +static void gst_wl_window_update_borders (GstWlWindow * self); + +static void +handle_xdg_toplevel_close (void *data, struct xdg_toplevel *xdg_toplevel) +{ + GstWlWindow *self = data; + + GST_DEBUG ("XDG toplevel got a \"close\" event."); + g_signal_emit (self, signals[CLOSED], 0); +} + +static void +handle_xdg_toplevel_configure (void *data, struct xdg_toplevel *xdg_toplevel, + int32_t width, int32_t height, struct wl_array *states) +{ + GstWlWindow *self = data; + const uint32_t *state; + + GST_DEBUG ("XDG toplevel got a \"configure\" event, [ %d, %d ].", + width, height); + + wl_array_for_each (state, states) { + switch (*state) { + case XDG_TOPLEVEL_STATE_FULLSCREEN: + case XDG_TOPLEVEL_STATE_MAXIMIZED: + case XDG_TOPLEVEL_STATE_RESIZING: + case XDG_TOPLEVEL_STATE_ACTIVATED: + break; + } + } + + if (width <= 0 || height <= 0) + return; + + gst_wl_window_set_render_rectangle (self, 0, 0, width, height); +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + handle_xdg_toplevel_configure, + handle_xdg_toplevel_close, +}; + +static void +handle_xdg_surface_configure (void *data, struct xdg_surface *xdg_surface, + uint32_t serial) +{ + GstWlWindow *self = data; + GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self); + + xdg_surface_ack_configure (xdg_surface, serial); + + g_mutex_lock (&priv->configure_mutex); + priv->configured = TRUE; + g_cond_signal (&priv->configure_cond); + g_mutex_unlock (&priv->configure_mutex); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + handle_xdg_surface_configure, +}; + +static void +gst_wl_window_class_init (GstWlWindowClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = gst_wl_window_finalize; + + signals[CLOSED] = g_signal_new ("closed", G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); +} + +static void +gst_wl_window_init (GstWlWindow * self) +{ + GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self); + + priv->configured = TRUE; + g_cond_init (&priv->configure_cond); + g_mutex_init (&priv->configure_mutex); +} + +static void +gst_wl_window_finalize (GObject * gobject) +{ + GstWlWindow *self = GST_WL_WINDOW (gobject); + GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self); + + if (priv->xdg_toplevel) + xdg_toplevel_destroy (priv->xdg_toplevel); + if (priv->xdg_surface) + xdg_surface_destroy (priv->xdg_surface); + + if (priv->video_viewport) + wp_viewport_destroy (priv->video_viewport); + + wl_proxy_wrapper_destroy (priv->video_surface_wrapper); + wl_subsurface_destroy (priv->video_subsurface); + wl_surface_destroy (priv->video_surface); + + if (priv->area_subsurface) + wl_subsurface_destroy (priv->area_subsurface); + + if (priv->area_viewport) + wp_viewport_destroy (priv->area_viewport); + + wl_proxy_wrapper_destroy (priv->area_surface_wrapper); + wl_surface_destroy (priv->area_surface); + + g_clear_object (&priv->display); + + G_OBJECT_CLASS (gst_wl_window_parent_class)->finalize (gobject); +} + +static GstWlWindow * +gst_wl_window_new_internal (GstWlDisplay * display, GMutex * render_lock) +{ + GstWlWindow *self; + GstWlWindowPrivate *priv; + struct wl_compositor *compositor; + struct wl_event_queue *event_queue; + struct wl_region *region; + struct wp_viewporter *viewporter; + + self = g_object_new (GST_TYPE_WL_WINDOW, NULL); + priv = gst_wl_window_get_instance_private (self); + priv->display = g_object_ref (display); + priv->render_lock = render_lock; + g_cond_init (&priv->configure_cond); + + compositor = gst_wl_display_get_compositor (display); + priv->area_surface = wl_compositor_create_surface (compositor); + priv->video_surface = wl_compositor_create_surface (compositor); + + priv->area_surface_wrapper = wl_proxy_create_wrapper (priv->area_surface); + priv->video_surface_wrapper = wl_proxy_create_wrapper (priv->video_surface); + + event_queue = gst_wl_display_get_event_queue (display); + wl_proxy_set_queue ((struct wl_proxy *) priv->area_surface_wrapper, + event_queue); + wl_proxy_set_queue ((struct wl_proxy *) priv->video_surface_wrapper, + event_queue); + + /* embed video_surface in area_surface */ + priv->video_subsurface = + wl_subcompositor_get_subsurface (gst_wl_display_get_subcompositor + (display), priv->video_surface, priv->area_surface); + wl_subsurface_set_desync (priv->video_subsurface); + + viewporter = gst_wl_display_get_viewporter (display); + if (viewporter) { + priv->area_viewport = wp_viewporter_get_viewport (viewporter, + priv->area_surface); + priv->video_viewport = wp_viewporter_get_viewport (viewporter, + priv->video_surface); + } + + /* never accept input events on the video surface */ + region = wl_compositor_create_region (compositor); + wl_surface_set_input_region (priv->video_surface, region); + wl_region_destroy (region); + + return self; +} + +void +gst_wl_window_ensure_fullscreen (GstWlWindow * self, gboolean fullscreen) +{ + GstWlWindowPrivate *priv; + + g_return_if_fail (self); + + priv = gst_wl_window_get_instance_private (self); + if (fullscreen) + xdg_toplevel_set_fullscreen (priv->xdg_toplevel, NULL); + else + xdg_toplevel_unset_fullscreen (priv->xdg_toplevel); +} + +GstWlWindow * +gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info, + gboolean fullscreen, GMutex * render_lock) +{ + GstWlWindow *self; + GstWlWindowPrivate *priv; + struct xdg_wm_base *xdg_wm_base; + struct zwp_fullscreen_shell_v1 *fullscreen_shell; + + self = gst_wl_window_new_internal (display, render_lock); + priv = gst_wl_window_get_instance_private (self); + + xdg_wm_base = gst_wl_display_get_xdg_wm_base (display); + fullscreen_shell = gst_wl_display_get_fullscreen_shell_v1 (display); + + /* Check which protocol we will use (in order of preference) */ + if (xdg_wm_base) { + gint64 timeout; + + /* First create the XDG surface */ + priv->xdg_surface = xdg_wm_base_get_xdg_surface (xdg_wm_base, + priv->area_surface); + if (!priv->xdg_surface) { + GST_ERROR ("Unable to get xdg_surface"); + goto error; + } + xdg_surface_add_listener (priv->xdg_surface, &xdg_surface_listener, self); + + /* Then the toplevel */ + priv->xdg_toplevel = xdg_surface_get_toplevel (priv->xdg_surface); + if (!priv->xdg_toplevel) { + GST_ERROR ("Unable to get xdg_toplevel"); + goto error; + } + xdg_toplevel_add_listener (priv->xdg_toplevel, + &xdg_toplevel_listener, self); + + gst_wl_window_ensure_fullscreen (self, fullscreen); + + /* Finally, commit the xdg_surface state as toplevel */ + priv->configured = FALSE; + wl_surface_commit (priv->area_surface); + wl_display_flush (gst_wl_display_get_display (display)); + + g_mutex_lock (&priv->configure_mutex); + timeout = g_get_monotonic_time () + 100 * G_TIME_SPAN_MILLISECOND; + while (!priv->configured) { + if (!g_cond_wait_until (&priv->configure_cond, &priv->configure_mutex, + timeout)) { + GST_WARNING ("The compositor did not send configure event."); + break; + } + } + g_mutex_unlock (&priv->configure_mutex); + } else if (fullscreen_shell) { + zwp_fullscreen_shell_v1_present_surface (fullscreen_shell, + priv->area_surface, ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM, NULL); + } else { + GST_ERROR ("Unable to use either xdg_wm_base or zwp_fullscreen_shell."); + goto error; + } + + /* render_rectangle is already set via toplevel_configure in + * xdg_shell fullscreen mode */ + if (!(xdg_wm_base && fullscreen)) { + /* set the initial size to be the same as the reported video size */ + gint width = + gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d); + gst_wl_window_set_render_rectangle (self, 0, 0, width, info->height); + } + + return self; + +error: + g_object_unref (self); + return NULL; +} + +GstWlWindow * +gst_wl_window_new_in_surface (GstWlDisplay * display, + struct wl_surface * parent, GMutex * render_lock) +{ + GstWlWindow *self; + GstWlWindowPrivate *priv; + struct wl_region *region; + + self = gst_wl_window_new_internal (display, render_lock); + priv = gst_wl_window_get_instance_private (self); + + /* do not accept input events on the area surface when embedded */ + region = + wl_compositor_create_region (gst_wl_display_get_compositor (display)); + wl_surface_set_input_region (priv->area_surface, region); + wl_region_destroy (region); + + /* embed in parent */ + priv->area_subsurface = + wl_subcompositor_get_subsurface (gst_wl_display_get_subcompositor + (display), priv->area_surface, parent); + wl_subsurface_set_desync (priv->area_subsurface); + + wl_surface_commit (parent); + + return self; +} + +GstWlDisplay * +gst_wl_window_get_display (GstWlWindow * self) +{ + GstWlWindowPrivate *priv; + + g_return_val_if_fail (self != NULL, NULL); + + priv = gst_wl_window_get_instance_private (self); + return g_object_ref (priv->display); +} + +struct wl_surface * +gst_wl_window_get_wl_surface (GstWlWindow * self) +{ + GstWlWindowPrivate *priv; + + g_return_val_if_fail (self != NULL, NULL); + + priv = gst_wl_window_get_instance_private (self); + return priv->video_surface_wrapper; +} + +struct wl_subsurface * +gst_wl_window_get_subsurface (GstWlWindow * self) +{ + GstWlWindowPrivate *priv; + + g_return_val_if_fail (self != NULL, NULL); + + priv = gst_wl_window_get_instance_private (self); + return priv->area_subsurface; +} + +gboolean +gst_wl_window_is_toplevel (GstWlWindow * self) +{ + GstWlWindowPrivate *priv; + + g_return_val_if_fail (self != NULL, FALSE); + + priv = gst_wl_window_get_instance_private (self); + return (priv->xdg_toplevel != NULL); +} + +static void +gst_wl_window_resize_video_surface (GstWlWindow * self, gboolean commit) +{ + GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self); + GstVideoRectangle src = { 0, }; + GstVideoRectangle dst = { 0, }; + GstVideoRectangle res; + + /* center the video_subsurface inside area_subsurface */ + src.w = priv->video_width; + src.h = priv->video_height; + dst.w = priv->render_rectangle.w; + dst.h = priv->render_rectangle.h; + + if (priv->video_viewport) { + gst_video_center_rect (&src, &dst, &res, TRUE); + wp_viewport_set_destination (priv->video_viewport, res.w, res.h); + } else { + gst_video_center_rect (&src, &dst, &res, FALSE); + } + + wl_subsurface_set_position (priv->video_subsurface, res.x, res.y); + + if (commit) + wl_surface_commit (priv->video_surface_wrapper); + + priv->video_rectangle = res; +} + +static void +gst_wl_window_set_opaque (GstWlWindow * self, const GstVideoInfo * info) +{ + GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self); + struct wl_compositor *compositor; + struct wl_region *region; + + /* Set area opaque */ + compositor = gst_wl_display_get_compositor (priv->display); + region = wl_compositor_create_region (compositor); + wl_region_add (region, 0, 0, G_MAXINT32, G_MAXINT32); + wl_surface_set_opaque_region (priv->area_surface, region); + wl_region_destroy (region); + + if (!GST_VIDEO_INFO_HAS_ALPHA (info)) { + /* Set video opaque */ + region = wl_compositor_create_region (compositor); + wl_region_add (region, 0, 0, G_MAXINT32, G_MAXINT32); + wl_surface_set_opaque_region (priv->video_surface, region); + wl_region_destroy (region); + } +} + +void +gst_wl_window_render (GstWlWindow * self, GstWlBuffer * buffer, + const GstVideoInfo * info) +{ + GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self); + + if (G_UNLIKELY (info)) { + priv->video_width = + gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d); + priv->video_height = info->height; + + wl_subsurface_set_sync (priv->video_subsurface); + gst_wl_window_resize_video_surface (self, FALSE); + gst_wl_window_set_opaque (self, info); + } + + if (G_LIKELY (buffer)) { + gst_wl_buffer_attach (buffer, priv->video_surface_wrapper); + wl_surface_damage_buffer (priv->video_surface_wrapper, 0, 0, G_MAXINT32, + G_MAXINT32); + wl_surface_commit (priv->video_surface_wrapper); + + if (!priv->is_area_surface_mapped) { + gst_wl_window_update_borders (self); + wl_surface_commit (priv->area_surface_wrapper); + priv->is_area_surface_mapped = TRUE; + } + } else { + /* clear both video and parent surfaces */ + wl_surface_attach (priv->video_surface_wrapper, NULL, 0, 0); + wl_surface_commit (priv->video_surface_wrapper); + wl_surface_attach (priv->area_surface_wrapper, NULL, 0, 0); + wl_surface_commit (priv->area_surface_wrapper); + priv->is_area_surface_mapped = FALSE; + } + + if (G_UNLIKELY (info)) { + /* commit also the parent (area_surface) in order to change + * the position of the video_subsurface */ + wl_surface_commit (priv->area_surface_wrapper); + wl_subsurface_set_desync (priv->video_subsurface); + } + + wl_display_flush (gst_wl_display_get_display (priv->display)); +} + +/* Update the buffer used to draw black borders. When we have viewporter + * support, this is a scaled up 1x1 image, and without we need an black image + * the size of the rendering areay. */ +static void +gst_wl_window_update_borders (GstWlWindow * self) +{ + GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self); + GstVideoFormat format; + GstVideoInfo info; + gint width, height; + GstBuffer *buf; + struct wl_buffer *wlbuf; + GstWlBuffer *gwlbuf; + GstAllocator *alloc; + + if (gst_wl_display_get_viewporter (priv->display)) { + wp_viewport_set_destination (priv->area_viewport, + priv->render_rectangle.w, priv->render_rectangle.h); + + if (priv->is_area_surface_mapped) { + /* The area_surface is already visible and only needed to get resized. + * We don't need to attach a new buffer and are done here. */ + return; + } + } + + if (gst_wl_display_get_viewporter (priv->display)) { + width = height = 1; + } else { + width = priv->render_rectangle.w; + height = priv->render_rectangle.h; + } + + /* we want WL_SHM_FORMAT_XRGB8888 */ + format = GST_VIDEO_FORMAT_BGRx; + + /* draw the area_subsurface */ + gst_video_info_set_format (&info, format, width, height); + + alloc = gst_wl_shm_allocator_get (); + + buf = gst_buffer_new_allocate (alloc, info.size, NULL); + gst_buffer_memset (buf, 0, 0, info.size); + wlbuf = + gst_wl_shm_memory_construct_wl_buffer (gst_buffer_peek_memory (buf, 0), + priv->display, &info); + gwlbuf = gst_buffer_add_wl_buffer (buf, wlbuf, priv->display); + gst_wl_buffer_attach (gwlbuf, priv->area_surface_wrapper); + wl_surface_damage_buffer (priv->area_surface_wrapper, 0, 0, G_MAXINT32, + G_MAXINT32); + + /* at this point, the GstWlBuffer keeps the buffer + * alive and will free it on wl_buffer::release */ + gst_buffer_unref (buf); + g_object_unref (alloc); +} + +void +gst_wl_window_set_render_rectangle (GstWlWindow * self, gint x, gint y, + gint w, gint h) +{ + GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self); + + if (priv->render_rectangle.x == x && priv->render_rectangle.y == y && + priv->render_rectangle.w == w && priv->render_rectangle.h == h) + return; + + priv->render_rectangle.x = x; + priv->render_rectangle.y = y; + priv->render_rectangle.w = w; + priv->render_rectangle.h = h; + + /* position the area inside the parent - needs a parent commit to apply */ + if (priv->area_subsurface) + wl_subsurface_set_position (priv->area_subsurface, x, y); + + if (priv->is_area_surface_mapped) + gst_wl_window_update_borders (self); + + if (!priv->configured) + return; + + if (priv->video_width != 0) { + wl_subsurface_set_sync (priv->video_subsurface); + gst_wl_window_resize_video_surface (self, TRUE); + } + + wl_surface_commit (priv->area_surface_wrapper); + + if (priv->video_width != 0) + wl_subsurface_set_desync (priv->video_subsurface); +} + +const GstVideoRectangle * +gst_wl_window_get_render_rectangle (GstWlWindow * self) +{ + GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self); + + return &priv->render_rectangle; +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.h new file mode 100644 index 0000000000..78871d759f --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.h @@ -0,0 +1,71 @@ +/* GStreamer Wayland Library + * + * Copyright (C) 2014 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_WL_WINDOW (gst_wl_window_get_type ()) +G_DECLARE_FINAL_TYPE (GstWlWindow, gst_wl_window, GST, WL_WINDOW, GObject); + +struct _GstWlWindow +{ + GObject parent_instance; +}; + +GST_WL_API +void gst_wl_window_ensure_fullscreen (GstWlWindow * self, + gboolean fullscreen); + +GST_WL_API +GstWlWindow *gst_wl_window_new_toplevel (GstWlDisplay * display, + const GstVideoInfo * info, gboolean fullscreen, GMutex * render_lock); + +GST_WL_API +GstWlWindow *gst_wl_window_new_in_surface (GstWlDisplay * display, + struct wl_surface * parent, GMutex * render_lock); + +GST_WL_API +GstWlDisplay *gst_wl_window_get_display (GstWlWindow * self); + +GST_WL_API +struct wl_surface *gst_wl_window_get_wl_surface (GstWlWindow * self); + +GST_WL_API +struct wl_subsurface *gst_wl_window_get_subsurface (GstWlWindow * self); + +GST_WL_API +gboolean gst_wl_window_is_toplevel (GstWlWindow * self); + +GST_WL_API +void gst_wl_window_render (GstWlWindow * self, GstWlBuffer * buffer, + const GstVideoInfo * info); + +GST_WL_API +void gst_wl_window_set_render_rectangle (GstWlWindow * self, gint x, gint y, + gint w, gint h); + +GST_WL_API +const GstVideoRectangle *gst_wl_window_get_render_rectangle (GstWlWindow * self); + +G_END_DECLS diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/meson.build b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/meson.build index 6a05edb70a..4c12e346da 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/meson.build +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/meson.build @@ -7,15 +7,74 @@ wl_scanner = find_program('wayland-scanner', required: get_option('wayland')) use_wayland = wl_protocol_dep.found() and wl_client_dep.found() and wl_scanner.found() and libdrm_dep.found() if use_wayland + wl_sources = [ + 'gstwlbuffer.c', + 'gstwlcontext.c', + 'gstwldisplay.c', + 'gstwllinuxdmabuf.c', + 'gstwlshmallocator.c', + 'gstwlvideobufferpool.c', + 'gstwlvideoformat.c', + 'gstwlwindow.c', + ] + + wl_headers = [ + 'gstwl_fwd.h', + 'gstwlbuffer.h', + 'gstwlcontext.h', + 'gstwldisplay.h', + 'gstwllinuxdmabuf.h', + 'gstwlshmallocator.h', + 'gstwlvideobufferpool.h', + 'gstwlvideoformat.h', + 'gstwlwindow.h', + 'wayland.h', + 'wayland-prelude.h', + ] + + protocols_datadir = wl_protocol_dep.get_variable('pkgdatadir') + + protocol_defs = [ + ['/stable/viewporter/viewporter.xml', 'viewporter-protocol.c', 'viewporter-client-protocol.h'], + ['/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml', + 'linux-dmabuf-unstable-v1-protocol.c', 'linux-dmabuf-unstable-v1-client-protocol.h'], + ['/unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml', + 'fullscreen-shell-unstable-v1-protocol.c', 'fullscreen-shell-unstable-v1-client-protocol.h'], + ['/stable/xdg-shell/xdg-shell.xml', 'xdg-shell-protocol.c', 'xdg-shell-client-protocol.h'], + ] + protocols_files = [] + + foreach protodef: protocol_defs + xmlfile = protocols_datadir + protodef.get(0) + + protocols_files += [custom_target(protodef.get(1), + output : protodef.get(1), + input : xmlfile, + command : [wl_scanner, 'code', '@INPUT@', '@OUTPUT@'])] + + protocols_files += [custom_target(protodef.get(2), + output : protodef.get(2), + input : xmlfile, + command : [wl_scanner, 'client-header', '@INPUT@', '@OUTPUT@'])] + endforeach + + extra_c_args = [ + '-DGST_USE_UNSTABLE_API', + '-DBUILDING_GST_WL', + '-DG_LOG_DOMAIN="GStreamer-Wayland"', + '-D_GNU_SOURCE' + ] + gstwayland = library('gstwayland-' + api_version, - 'wayland.c', - c_args : gst_plugins_bad_args + ['-DGST_USE_UNSTABLE_API', '-DBUILDING_GST_WAYLAND', '-DG_LOG_DOMAIN="GStreamer-Wayland"'], + wl_sources + protocols_files, + c_args : gst_plugins_bad_args + extra_c_args, include_directories : [configinc, libsinc], version : libversion, soversion : soversion, darwin_versions : osxversion, install : true, - dependencies : [gst_dep, gstvideo_dep, wl_client_dep] + dependencies : [gst_dep, gstallocators_dep, gstvideo_dep, libdrm_dep, + wl_client_dep, wl_protocol_dep] ) pkg_name = 'gstreamer-wayland-1.0' @@ -30,8 +89,9 @@ if use_wayland gstwayland_dep = declare_dependency(link_with : gstwayland, include_directories : [libsinc], - dependencies : [gst_dep, gstvideo_dep]) + dependencies : [gst_dep, gstallocators_dep, gstvideo_dep, libdrm_dep, + wl_client_dep, wl_protocol_dep]) - install_headers('wayland.h', subdir: 'gstreamer-1.0/gst/wayland') + install_headers(wl_headers, subdir: 'gstreamer-1.0/gst/wayland') meson.override_dependency(pkg_name, gstwayland_dep) endif diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/wayland-prelude.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/wayland-prelude.h new file mode 100644 index 0000000000..1f58601ae2 --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/wayland-prelude.h @@ -0,0 +1,29 @@ +/* GStreamer Wayland Library + * + * Copyright (C) 2022 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include + +#ifdef BUILDING_GST_WL +# define GST_WL_API GST_API_EXPORT /* from config.h */ +#else +# define GST_WL_API GST_API_IMPORT +#endif diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/wayland.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/wayland.c deleted file mode 100644 index 3ee7a98d33..0000000000 --- a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/wayland.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * GStreamer Wayland Library - * Copyright (C) 2014 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -gboolean -gst_is_wayland_display_handle_need_context_message (GstMessage * msg) -{ - const gchar *type = NULL; - - g_return_val_if_fail (GST_IS_MESSAGE (msg), FALSE); - - if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_NEED_CONTEXT && - gst_message_parse_context_type (msg, &type)) { - return !g_strcmp0 (type, GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE); - } - - return FALSE; -} - -GstContext * -gst_wayland_display_handle_context_new (struct wl_display * display) -{ - GstContext *context = - gst_context_new (GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE, TRUE); - gst_structure_set (gst_context_writable_structure (context), - "display", G_TYPE_POINTER, display, NULL); - return context; -} - -struct wl_display * -gst_wayland_display_handle_context_get_handle (GstContext * context) -{ - const GstStructure *s; - struct wl_display *display; - - g_return_val_if_fail (GST_IS_CONTEXT (context), NULL); - - s = gst_context_get_structure (context); - if (gst_structure_get (s, "display", G_TYPE_POINTER, &display, NULL)) - return display; - if (gst_structure_get (s, "handle", G_TYPE_POINTER, &display, NULL)) - return display; - return NULL; -} - - -G_DEFINE_INTERFACE (GstWaylandVideo, gst_wayland_video, GST_TYPE_VIDEO_OVERLAY); - -static void -gst_wayland_video_default_init (GstWaylandVideoInterface * klass) -{ - (void) klass; -} - -/** - * gst_wayland_video_begin_geometry_change: - * - * Notifies the video sink that we are about to change its - * geometry (probably using set_render_rectangle()). This is useful - * in order to allow the sink to synchronize resizing/moving of the - * video area with the parent surface and avoid glitches, in cases - * where the video area is being painted asynchronously from another - * thread, like in waylandsink. - * - * Please note that any calls to this method MUST be matched by - * calls to end_geometry_change() and AFTER the parent surface has - * committed its geometry changes. - */ -void -gst_wayland_video_begin_geometry_change (GstWaylandVideo * video) -{ - GstWaylandVideoInterface *iface; - - g_return_if_fail (video != NULL); - g_return_if_fail (GST_IS_WAYLAND_VIDEO (video)); - - iface = GST_WAYLAND_VIDEO_GET_INTERFACE (video); - - if (iface->begin_geometry_change) { - iface->begin_geometry_change (video); - } -} - -/** - * gst_wayland_video_end_geometry_change: - * - * Notifies the video sink that we just finished changing the - * geometry of both itself and its parent surface. This should - * have been earlier preceded by a call to begin_geometry_change() - * which notified the sink before any of these changes had happened. - * - * It is important to call this method only AFTER the parent surface - * has committed its geometry changes, otherwise no synchronization - * is actually achieved. - */ -void -gst_wayland_video_end_geometry_change (GstWaylandVideo * video) -{ - GstWaylandVideoInterface *iface; - - g_return_if_fail (video != NULL); - g_return_if_fail (GST_IS_WAYLAND_VIDEO (video)); - - iface = GST_WAYLAND_VIDEO_GET_INTERFACE (video); - - if (iface->end_geometry_change) { - iface->end_geometry_change (video); - } -} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/wayland.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/wayland.h index c60c57ccdf..7a45845b4e 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/wayland.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/wayland.h @@ -18,85 +18,22 @@ * Boston, MA 02110-1301, USA. */ -#ifndef __GST_WAYLAND_H__ -#define __GST_WAYLAND_H__ +#pragma once #ifndef GST_USE_UNSTABLE_API #warning "The GStreamer wayland library is unstable API and may change in future." #warning "You can define GST_USE_UNSTABLE_API to avoid this warning." #endif -#include #include -#ifndef GST_WAYLAND_API -# ifdef BUILDING_GST_WAYLAND -# define GST_WAYLAND_API GST_API_EXPORT /* from config.h */ -# else -# define GST_WAYLAND_API GST_API_IMPORT -# endif -#endif - -G_BEGIN_DECLS - -/* The type of GstContext used to pass the wl_display pointer - * from the application to the sink */ -#define GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE "GstWaylandDisplayHandleContextType" - -GST_WAYLAND_API -gboolean gst_is_wayland_display_handle_need_context_message (GstMessage * msg); - -GST_WAYLAND_API -GstContext * -gst_wayland_display_handle_context_new (struct wl_display * display); - -GST_WAYLAND_API -struct wl_display * -gst_wayland_display_handle_context_get_handle (GstContext * context); - - -#define GST_TYPE_WAYLAND_VIDEO \ - (gst_wayland_video_get_type ()) -#define GST_WAYLAND_VIDEO(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WAYLAND_VIDEO, GstWaylandVideo)) -#define GST_IS_WAYLAND_VIDEO(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WAYLAND_VIDEO)) -#define GST_WAYLAND_VIDEO_GET_INTERFACE(inst) \ - (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_WAYLAND_VIDEO, GstWaylandVideoInterface)) - -/** - * GstWaylandVideo: - * - * Opaque #GstWaylandVideo interface structure - */ -typedef struct _GstWaylandVideo GstWaylandVideo; -typedef struct _GstWaylandVideoInterface GstWaylandVideoInterface; - - -/** - * GstWaylandVideoInterface: - * @iface: parent interface type. - * - * #GstWaylandVideo interface - */ -struct _GstWaylandVideoInterface { - GTypeInterface iface; - - /* virtual functions */ - void (*begin_geometry_change) (GstWaylandVideo *video); - void (*end_geometry_change) (GstWaylandVideo *video); -}; - -GST_WAYLAND_API -GType gst_wayland_video_get_type (void); - -/* virtual function wrappers */ -GST_WAYLAND_API -void gst_wayland_video_begin_geometry_change (GstWaylandVideo * video); - -GST_WAYLAND_API -void gst_wayland_video_end_geometry_change (GstWaylandVideo * video); - -G_END_DECLS - -#endif /* __GST_WAYLAND_H__ */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/subprojects/gst-plugins-bad/tests/examples/waylandsink/main.c b/subprojects/gst-plugins-bad/tests/examples/waylandsink/main.c index d52a7097d3..2ed5fca28a 100644 --- a/subprojects/gst-plugins-bad/tests/examples/waylandsink/main.c +++ b/subprojects/gst-plugins-bad/tests/examples/waylandsink/main.c @@ -86,14 +86,14 @@ bus_sync_handler (GstBus * bus, GstMessage * message, gpointer user_data) { DemoApp *d = user_data; - if (gst_is_wayland_display_handle_need_context_message (message)) { + if (gst_is_wl_display_handle_need_context_message (message)) { GstContext *context; GdkDisplay *display; struct wl_display *display_handle; display = gtk_widget_get_display (d->video_widget); display_handle = gdk_wayland_display_get_wl_display (display); - context = gst_wayland_display_handle_context_new (display_handle); + context = gst_wl_display_handle_context_new (display_handle); gst_element_set_context (GST_ELEMENT (GST_MESSAGE_SRC (message)), context); gst_context_unref (context); diff --git a/subprojects/gst-plugins-bad/tests/examples/waylandsink/wayland-threads.c b/subprojects/gst-plugins-bad/tests/examples/waylandsink/wayland-threads.c index 082309e5cd..a2fde962b0 100644 --- a/subprojects/gst-plugins-bad/tests/examples/waylandsink/wayland-threads.c +++ b/subprojects/gst-plugins-bad/tests/examples/waylandsink/wayland-threads.c @@ -76,9 +76,9 @@ bus_sync_handler (GstBus * bus, GstMessage * message, gpointer user_data) { App *app = user_data; - if (gst_is_wayland_display_handle_need_context_message (message)) { + if (gst_is_wl_display_handle_need_context_message (message)) { GstContext *context; - context = gst_wayland_display_handle_context_new (app->display); + context = gst_wl_display_handle_context_new (app->display); gst_element_set_context (GST_ELEMENT (GST_MESSAGE_SRC (message)), context); gst_context_unref (context);