From ee2a28f3cc5f07bc748a5e5668102d09545e1b52 Mon Sep 17 00:00:00 2001 From: Arturo Buzarra Date: Thu, 30 Jun 2022 13:26:21 +0200 Subject: [PATCH] stm-st-stm32mp: add support to gstreamer1.0 recipes for STM32 paltforms https://onedigi.atlassian.net/browse/DEL-7981 Signed-off-by: Arturo Buzarra --- ...av-disable-decoder-direct-rendering-.patch | 35 + .../gstreamer1.0-libav_1.20.2.bbappend | 3 + ...01-waylandsink-add-dmabuf-bufferpool.patch | 999 +++++++++++ ...x-error-when-mmapping-dmabuf-buffers.patch | 31 + ...wrong-width-when-creating-dmabuf-dum.patch | 34 + ...ot-hardcode-dmabuf-bufferpool-info-s.patch | 44 + ...ease-max-buffers-to-32-to-enable-dma.patch | 43 + ...ink-always-select-dmabuf-buffer-pool.patch | 44 + ...aylandsink-do-not-destroy-pool-twice.patch | 34 + ...-disable-frame-dropping-while-redraw.patch | 62 + ...0009-waylandsink-Uprank-to-secondary.patch | 26 + ...sink-set-video-alignment-to-32-bytes.patch | 41 + ...back-to-shm-if-display-does-not-supp.patch | 39 + ...protocol-does-not-work-in-fullscreen.patch | 56 + ...ndsink-silently-drop-erroneous-frame.patch | 97 + ...dsink-add-waylandpool-on-meson-build.patch | 27 + .../0016-Add-new-gtkwaylandsink-element.patch | 1570 +++++++++++++++++ .../gstreamer1.0-plugins-bad_1.20.2.bbappend | 39 + ...disable-any-default-video-processing.patch | 32 + ...disable-any-default-video-processing.patch | 32 + .../gstreamer1.0-plugins-base_1.20.2.bbappend | 27 + .../gstreamer1.0-plugins-good_1.20.2.bbappend | 19 + 22 files changed, 3334 insertions(+) create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-libav/0001-gstreamer1.0-libav-disable-decoder-direct-rendering-.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-libav_1.20.2.bbappend create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0001-waylandsink-add-dmabuf-bufferpool.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0002-waylandsink-fix-error-when-mmapping-dmabuf-buffers.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0003-waylandsink-fix-wrong-width-when-creating-dmabuf-dum.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0004-waylandsink-do-not-hardcode-dmabuf-bufferpool-info-s.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0005-waylandsink-increase-max-buffers-to-32-to-enable-dma.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0006-waylandsink-always-select-dmabuf-buffer-pool.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0007-waylandsink-do-not-destroy-pool-twice.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0008-waylandsink-HACK-disable-frame-dropping-while-redraw.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0009-waylandsink-Uprank-to-secondary.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0010-waylandsink-set-video-alignment-to-32-bytes.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0011-waylandsink-fallback-to-shm-if-display-does-not-supp.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0012-waylandsink-XDG-protocol-does-not-work-in-fullscreen.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0013-waylandsink-silently-drop-erroneous-frame.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0014-waylandsink-add-waylandpool-on-meson-build.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0016-Add-new-gtkwaylandsink-element.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad_1.20.2.bbappend create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0001-playbin2-disable-any-default-video-processing.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0002-playbin3-disable-any-default-video-processing.patch create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base_1.20.2.bbappend create mode 100644 meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-good_1.20.2.bbappend diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-libav/0001-gstreamer1.0-libav-disable-decoder-direct-rendering-.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-libav/0001-gstreamer1.0-libav-disable-decoder-direct-rendering-.patch new file mode 100644 index 000000000..bb75af4ed --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-libav/0001-gstreamer1.0-libav-disable-decoder-direct-rendering-.patch @@ -0,0 +1,35 @@ +From a01f2526663eee1d98f2e133d076a5dcb556d1ea Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Tue, 26 Apr 2022 11:30:31 +0200 +Subject: [PATCH] gstreamer1.0-libav: disable decoder direct rendering by + default + +DMA-buf 0-copy path and direct-rendering mode are not yet compatible +because of stride and offset issues. +Nevertheless performances are better than with direct-rendering enabled +and virtual memory path. + +This fix is required to reach 30fps on display driver side +with 30fps VGA video content. + +Signed-off-by: Hugues Fruchet +--- + ext/libav/gstavviddec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ext/libav/gstavviddec.c b/ext/libav/gstavviddec.c +index f5197fb..fde599b 100644 +--- a/ext/libav/gstavviddec.c ++++ b/ext/libav/gstavviddec.c +@@ -41,7 +41,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE); + + #define DEFAULT_LOWRES 0 + #define DEFAULT_SKIPFRAME 0 +-#define DEFAULT_DIRECT_RENDERING TRUE ++#define DEFAULT_DIRECT_RENDERING FALSE + #define DEFAULT_MAX_THREADS 0 + #define DEFAULT_OUTPUT_CORRUPT TRUE + #define REQUIRED_POOL_MAX_BUFFERS 32 +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-libav_1.20.2.bbappend b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-libav_1.20.2.bbappend new file mode 100644 index 000000000..0e9942fc7 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-libav_1.20.2.bbappend @@ -0,0 +1,3 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" + +SRC_URI:append = " file://0001-gstreamer1.0-libav-disable-decoder-direct-rendering-.patch " diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0001-waylandsink-add-dmabuf-bufferpool.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0001-waylandsink-add-dmabuf-bufferpool.patch new file mode 100644 index 000000000..6dd37a64e --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0001-waylandsink-add-dmabuf-bufferpool.patch @@ -0,0 +1,999 @@ +From ddeb2fe4af5c62235c31bba257354258ad14d7a1 Mon Sep 17 00:00:00 2001 +From: Pierre-Yves MORDRET +Date: Thu, 5 Sep 2019 16:19:22 +0200 +Subject: [PATCH 01/14] waylandsink: add dmabuf bufferpool + +Add support of DMA-buf allocated buffers through use of +drm/kms kernel driver ioctl DRM_IOCTL_MODE_CREATE_DUMB. +This pool is selected if video/x-raw(memory:DMABuf) +is set in caps. + +Change-Id: I0507752a1a64ee2c657b73d8c802c44fd707f49f +Signed-off-by: Hugues Fruchet +--- + ext/wayland/gstwaylandsink.c | 108 +++++- + ext/wayland/waylandpool.c | 640 +++++++++++++++++++++++++++++++++++ + ext/wayland/waylandpool.h | 105 ++++++ + ext/wayland/wldisplay.c | 3 + + ext/wayland/wldisplay.h | 9 +- + 5 files changed, 853 insertions(+), 12 deletions(-) + create mode 100644 ext/wayland/waylandpool.c + create mode 100644 ext/wayland/waylandpool.h + +diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c +index 0761304..20df1bf 100644 +--- a/ext/wayland/gstwaylandsink.c ++++ b/ext/wayland/gstwaylandsink.c +@@ -47,6 +47,7 @@ + #include "wlbuffer.h" + #include "wlshmallocator.h" + #include "wllinuxdmabuf.h" ++#include "waylandpool.h" + + #include + #include +@@ -557,6 +558,36 @@ gst_wayland_create_pool (GstWaylandSink * sink, GstCaps * caps) + return pool; + } + ++static GstBufferPool * ++gst_wayland_create_dmabuf_pool (GstWaylandSink * sink, GstCaps * caps) ++{ ++ GstBufferPool *pool = NULL; ++ GstStructure *structure; ++ gsize size = sink->video_info.size; ++ GstAllocator *alloc; ++ ++ /* create a new DMABuf pool */ ++ pool = gst_wayland_buffer_pool_new (sink->display); ++ if (!pool) { ++ GST_DEBUG_OBJECT (sink, "Failed to create new pool"); ++ return NULL; ++ } ++ ++ structure = gst_buffer_pool_get_config (pool); ++ gst_buffer_pool_config_set_params (structure, caps, info.size, 2, 0); ++ gst_buffer_pool_config_set_allocator (structure, NULL, ¶ms); ++ alloc = gst_dmabuf_allocator_new (); ++ gst_buffer_pool_config_set_allocator (structure, alloc, NULL); ++ if (!gst_buffer_pool_set_config (pool, structure)) { ++ GST_DEBUG_OBJECT (sink, "failed setting config"); ++ gst_object_unref (pool); ++ return NULL; ++ } ++ g_object_unref (alloc); ++ ++ return pool; ++} ++ + static gboolean + gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) + { +@@ -575,15 +606,9 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) + format = GST_VIDEO_INFO_FORMAT (&sink->video_info); + sink->video_info_changed = TRUE; + +- /* create a new pool for the new caps */ +- if (sink->pool) +- gst_object_unref (sink->pool); +- sink->pool = gst_wayland_create_pool (sink, caps); +- + use_dmabuf = gst_caps_features_contains (gst_caps_get_features (caps, 0), + GST_CAPS_FEATURE_MEMORY_DMABUF); + +- /* validate the format base on the memory type. */ + if (use_dmabuf) { + if (!gst_wl_display_check_format_for_dmabuf (sink->display, format)) + goto unsupported_format; +@@ -591,6 +616,14 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) + goto unsupported_format; + } + ++ /* create a new pool for the new caps */ ++ if (sink->pool) ++ gst_object_unref (sink->pool); ++ if (use_dmabuf) ++ sink->pool = gst_wayland_create_dmabuf_pool (sink, caps); ++ else ++ sink->pool = gst_wayland_create_pool (sink, caps); ++ + sink->use_dmabuf = use_dmabuf; + + return TRUE; +@@ -610,7 +643,7 @@ unsupported_format: + } + + static gboolean +-gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) ++gst_wayland_sink_propose_shm_allocation (GstBaseSink * bsink, GstQuery * query) + { + GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); + GstCaps *caps; +@@ -635,6 +668,67 @@ gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) + return TRUE; + } + ++static gboolean ++gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) ++{ ++ GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); ++ GstCaps *caps; ++ GstBufferPool *pool = NULL; ++ GstStructure *config; ++ guint size; ++ gboolean need_pool; ++ GstAllocator *alloc; ++ GstCaps *pcaps; ++ guint config_min_buf, config_max_buf; ++ ++ if (!sink->use_dmabuf) ++ return gst_wayland_sink_propose_shm_allocation(bsink, query); ++ ++ /* ++ * propose DMA-buf allocator... ++ */ ++ gst_query_parse_allocation (query, &caps, &need_pool); ++ ++ if (need_pool) { ++ /* Fill query with DMABuf pool characteristics, ++ * to do so create a pool, get its characteristics ++ * to fill query and free it... ++ */ ++ pool = gst_wayland_create_dmabuf_pool (sink, caps); ++ if (!pool) ++ goto no_pool; ++ ++ config = gst_buffer_pool_get_config (pool); ++ gst_buffer_pool_config_get_params (config, &pcaps, &size, ++ &config_min_buf, &config_max_buf); ++ gst_query_add_allocation_pool (query, pool, size, ++ config_min_buf, config_max_buf); ++ g_object_unref (pool); ++ } ++ ++ /* ++ * FIXME is there a case where !need_pool and we fill query with an ++ * allocator and alignment ? ++ */ ++ alloc = gst_dmabuf_allocator_new (); ++ gst_query_add_allocation_param (query, alloc, NULL); ++ gst_object_unref (alloc); ++ ++ /* we also support video metadata (alignment) */ ++ gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); ++ ++ GST_WARNING_OBJECT (bsink, "Add dmabuf allocator"); ++ ++ return TRUE; ++ ++ /* ERRORS */ ++no_pool: ++ { ++ GST_DEBUG_OBJECT (bsink, "failed to propose the needed pool"); ++ return FALSE; ++ } ++} ++ + static void + frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time) + { +diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c +new file mode 100644 +index 0000000..70e40b4 +--- /dev/null ++++ b/ext/wayland/waylandpool.c +@@ -0,0 +1,640 @@ ++/* GStreamer ++ * Copyright (C) 2012 Intel Corporation ++ * Copyright (C) 2012 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 St, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "waylandpool.h" ++#include "wldisplay.h" ++#include "wlvideoformat.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); ++#define GST_CAT_DEFAULT gstwayland_debug ++ ++/* wl metadata */ ++GType ++gst_wl_meta_api_get_type (void) ++{ ++ static volatile GType type; ++ static const gchar *tags[] = ++ { "memory", "size", "colorspace", "orientation", NULL }; ++ if (g_once_init_enter (&type)) { ++ GType _type = gst_meta_api_type_register ("GstWlMetaAPI", tags); ++ g_once_init_leave (&type, _type); ++ } ++ return type; ++} ++ ++static void ++gst_wl_meta_free (GstWlMeta * meta, GstBuffer * buffer) ++{ ++ GstMemory *gmem; ++ GST_DEBUG ("destroying wl_buffer %p", meta->wbuffer); ++ ++ gmem = gst_buffer_get_memory (buffer, 0); ++ ++ if ((gmem != NULL) && gst_is_dmabuf_memory (gmem)) { ++ struct drm_mode_destroy_dumb destroy_arg; ++ int prime_fd = gst_dmabuf_memory_get_fd (gmem); ++ ++ memset (&destroy_arg, 0, sizeof destroy_arg); ++ drmPrimeFDToHandle (meta->drm_fd, prime_fd, &destroy_arg.handle); ++ drmIoctl (meta->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg); ++ close (prime_fd); ++ } else { ++ if (meta->data) ++ munmap (meta->data, meta->size); ++ } ++ gst_memory_unref (gmem); ++ ++ if (meta->wbuffer) ++ wl_buffer_destroy (meta->wbuffer); ++} ++ ++static gboolean gst_wl_meta_init(GstMeta *meta, G_GNUC_UNUSED gpointer params, G_GNUC_UNUSED GstBuffer *buffer) ++{ ++ /* Just to avoid a warning */ ++ return TRUE; ++} ++ ++const GstMetaInfo * ++gst_wl_meta_get_info (void) ++{ ++ static const GstMetaInfo *wl_meta_info = NULL; ++ if (g_once_init_enter (&wl_meta_info)) { ++ const GstMetaInfo *meta = ++ gst_meta_register (GST_WL_META_API_TYPE, "GstWlMeta", ++ sizeof (GstWlMeta), (GstMetaInitFunction) gst_wl_meta_init, ++ (GstMetaFreeFunction) gst_wl_meta_free, ++ (GstMetaTransformFunction) NULL); ++ g_once_init_leave (&wl_meta_info, meta); ++ } ++ return wl_meta_info; ++} ++ ++/* bufferpool */ ++static void gst_wayland_buffer_pool_finalize (GObject * object); ++static gboolean gst_wayland_buffer_pool_set_config (GstBufferPool * pool, ++ GstStructure * config); ++static gboolean gst_wayland_buffer_pool_start (GstBufferPool * pool); ++static gboolean gst_wayland_buffer_pool_stop (GstBufferPool * pool); ++static GstFlowReturn gst_wayland_buffer_pool_alloc (GstBufferPool * pool, ++ GstBuffer ** buffer, GstBufferPoolAcquireParams * params); ++ ++#define gst_wayland_buffer_pool_parent_class parent_class ++G_DEFINE_TYPE (GstWaylandBufferPool, gst_wayland_buffer_pool, ++ GST_TYPE_BUFFER_POOL); ++ ++static const gchar ** ++gst_wayland_buffer_pool_get_options (GstBufferPool * pool) ++{ ++ static const gchar *options[] = { ++ GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT, NULL ++ }; ++ return options; ++} ++ ++ ++static void ++gst_wayland_buffer_pool_class_init (GstWaylandBufferPoolClass * klass) ++{ ++ GObjectClass *gobject_class = (GObjectClass *) klass; ++ GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass; ++ gobject_class->finalize = gst_wayland_buffer_pool_finalize; ++ ++ gstbufferpool_class->set_config = gst_wayland_buffer_pool_set_config; ++ gstbufferpool_class->start = gst_wayland_buffer_pool_start; ++ gstbufferpool_class->stop = gst_wayland_buffer_pool_stop; ++ gstbufferpool_class->alloc_buffer = gst_wayland_buffer_pool_alloc; ++ gstbufferpool_class->get_options = gst_wayland_buffer_pool_get_options; ++} ++ ++static void ++gst_wayland_buffer_pool_init (GstWaylandBufferPool * self) ++{ ++ gst_video_info_init (&self->info); ++ g_mutex_init (&self->buffers_map_mutex); ++ self->buffers_map = g_hash_table_new (g_direct_hash, g_direct_equal); ++} ++ ++static void ++gst_wayland_buffer_pool_finalize (GObject * object) ++{ ++ GstWaylandBufferPool *pool = GST_WAYLAND_BUFFER_POOL_CAST (object); ++ if (pool->allocator) ++ gst_object_unref (pool->allocator); ++ pool->allocator = NULL; ++ ++ if (pool->wl_pool) ++ gst_wayland_buffer_pool_stop (GST_BUFFER_POOL (pool)); ++ ++ if (pool->fd != -1) ++ close (pool->fd); ++ ++ g_mutex_clear (&pool->buffers_map_mutex); ++ g_hash_table_unref (pool->buffers_map); ++ ++ g_object_unref (pool->display); ++ ++ G_OBJECT_CLASS (gst_wayland_buffer_pool_parent_class)->finalize (object); ++} ++ ++static void ++buffer_release (void *data, struct wl_buffer *wl_buffer) ++{ ++ GstWaylandBufferPool *self = data; ++ GstBuffer *buffer; ++ GstWlMeta *meta; ++ g_mutex_lock (&self->buffers_map_mutex); ++ buffer = g_hash_table_lookup (self->buffers_map, wl_buffer); ++ ++ GST_LOG_OBJECT (self, "wl_buffer::release (GstBuffer: %p)", buffer); ++ ++ if (buffer) { ++ meta = gst_buffer_get_wl_meta (buffer); ++ if (meta->used_by_compositor) { ++ meta->used_by_compositor = FALSE; ++ /* unlock before unref because stop() may be called from here */ ++ g_mutex_unlock (&self->buffers_map_mutex); ++ gst_buffer_unref (buffer); ++ return; ++ } ++ } ++ g_mutex_unlock (&self->buffers_map_mutex); ++} ++ ++static const struct wl_buffer_listener buffer_listener = { ++ buffer_release ++}; ++ ++void ++gst_wayland_compositor_acquire_buffer (GstWaylandBufferPool * self, ++ GstBuffer * buffer) ++{ ++ GstWlMeta *meta; ++ ++ meta = gst_buffer_get_wl_meta (buffer); ++ g_return_if_fail (meta != NULL); ++ g_return_if_fail (meta->pool == self); ++ g_return_if_fail (meta->used_by_compositor == FALSE); ++ ++ meta->used_by_compositor = TRUE; ++ gst_buffer_ref (buffer); ++ ++} ++ ++static void ++unref_used_buffers (gpointer key, gpointer value, gpointer data) ++{ ++ GstBuffer *buffer = value; ++ GstWlMeta *meta = gst_buffer_get_wl_meta (buffer); ++ GList **to_unref = data; ++ ++ if (meta->used_by_compositor) { ++ meta->used_by_compositor = FALSE; ++ *to_unref = g_list_prepend (*to_unref, buffer); ++ } ++ ++} ++ ++void ++gst_wayland_compositor_release_all_buffers (GstWaylandBufferPool * self) ++{ ++ GList *to_unref = NULL; ++ ++ g_mutex_lock (&self->buffers_map_mutex); ++ g_hash_table_foreach (self->buffers_map, unref_used_buffers, &to_unref); ++ g_mutex_unlock (&self->buffers_map_mutex); ++ ++ /* unref without the lock because stop() may be called from here */ ++ if (to_unref) { ++ g_list_free_full (to_unref, (GDestroyNotify) gst_buffer_unref); ++ } ++} ++ ++static gboolean ++gst_wayland_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) ++{ ++ ++ GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool); ++ GstWlDisplay *display = self->display; ++ GstAllocationParams params; ++ GstVideoInfo info; ++ GstCaps *caps; ++ guint config_min_buf, config_max_buf; ++ gboolean has_alignment = FALSE; ++ GstVideoAlignment video_align; ++ ++ if (self->allocator) ++ gst_object_unref (self->allocator); ++ self->allocator = NULL; ++ ++ if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &config_min_buf, ++ &config_max_buf)) ++ goto wrong_config; ++ ++ if (caps == NULL) ++ goto no_caps; ++ ++ /* now parse the caps from the config */ ++ if (!gst_video_info_from_caps (&info, caps)) ++ goto wrong_caps; ++ ++ /* parse extra alignment info */ ++ has_alignment = gst_buffer_pool_config_has_option (config, ++ GST_BUFFER_POOL_OPTION_VIDEO_META); ++ if (has_alignment) { ++ /* get and apply the alignment to info */ ++ if (gst_buffer_pool_config_get_video_alignment (config, &video_align)) { ++ gst_video_info_align (&info, &video_align); ++ ++ GST_LOG_OBJECT (self, "padding %u-%ux%u-%u", ++ video_align.padding_top, ++ video_align.padding_left, ++ video_align.padding_right, video_align.padding_bottom); ++ } ++ } ++ ++ if (!gst_buffer_pool_config_get_allocator (config, &self->allocator, ¶ms)) ++ goto wrong_allocator; ++ ++ if (self->allocator) ++ gst_object_ref (self->allocator); ++ ++ GST_LOG_OBJECT (self, "%dx%d, caps %" GST_PTR_FORMAT, ++ info.width, info.height, caps); ++ ++ /* FIXME: Enable metadata checking handling based on the config of pool */ ++ self->caps = gst_caps_ref (caps); ++ self->info = info; ++ self->width = info.width; ++ self->height = info.height; ++ self->size = GST_VIDEO_INFO_SIZE (&info); ++ /* Update size in the config to be inline with buffer pool setup */ ++ gst_buffer_pool_config_set_params (config, caps, self->size, config_min_buf, ++ config_max_buf); ++ ++ self->use_linux_dmabuf = (self->allocator ++ && g_strcmp0 (self->allocator->mem_type, GST_ALLOCATOR_DMABUF) == 0); ++ ++ GST_LOG_OBJECT (self, "pool will use %s", ++ self->use_linux_dmabuf ? "linux_dmabuf" : "wl_shm"); ++ ++ if (self->use_linux_dmabuf && display->device_name) { ++ self->fd = open (display->device_name, O_RDWR, 0); ++ ++ if (self->fd == -1) { ++ GST_ERROR_OBJECT (self, "can't open %s", display->device_name); ++ return FALSE; ++ } ++ } ++ ++ ++ return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config); ++ /* ERRORS */ ++wrong_allocator: ++ { ++ GST_WARNING_OBJECT (pool, "no allocator"); ++ return FALSE; ++ } ++wrong_config: ++ { ++ GST_WARNING_OBJECT (pool, "invalid config"); ++ return FALSE; ++ } ++no_caps: ++ { ++ GST_WARNING_OBJECT (pool, "no caps in config"); ++ return FALSE; ++ } ++wrong_caps: ++ { ++ GST_WARNING_OBJECT (pool, ++ "failed getting geometry from caps %" GST_PTR_FORMAT, caps); ++ return FALSE; ++ } ++ ++} ++ ++static gboolean ++gst_wayland_buffer_pool_start (GstBufferPool * pool) ++{ ++ GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool); ++ guint size = 0; ++ int fd; ++ char filename[1024]; ++ static int init = 0; ++ ++ GST_DEBUG_OBJECT (self, "Initializing wayland buffer pool"); ++ ++ /* configure */ ++ size = GST_VIDEO_INFO_SIZE (&self->info) * 15; ++ ++ /* allocate shm pool */ ++ snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (), ++ "wayland-shm", init++, "XXXXXX"); ++ ++ fd = mkstemp (filename); ++ if (fd < 0) { ++ GST_ERROR_OBJECT (pool, "opening temp file %s failed: %s", filename, ++ strerror (errno)); ++ ++ return FALSE; ++ } ++ if (ftruncate (fd, size) < 0) { ++ GST_ERROR_OBJECT (pool, "ftruncate failed: %s", strerror (errno)); ++ close (fd); ++ ++ return FALSE; ++ } ++ ++ self->data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); ++ if (self->data == MAP_FAILED) { ++ GST_ERROR_OBJECT (pool, "mmap failed: %s", strerror (errno)); ++ close (fd); ++ ++ return FALSE; ++ } ++ GST_DEBUG_OBJECT (self, "wl_shm_create_pool"); ++ self->wl_pool = wl_shm_create_pool (self->display->shm, fd, size); ++ unlink (filename); ++ close (fd); ++ ++ self->size = size; ++ self->used = 0; ++ ++ ++ return GST_BUFFER_POOL_CLASS (parent_class)->start (pool); ++} ++ ++static gboolean ++gst_wayland_buffer_pool_stop (GstBufferPool * pool) ++{ ++ GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool); ++ ++ GST_DEBUG_OBJECT (self, "Stopping wayland buffer pool"); ++ ++ munmap (self->data, self->size); ++ wl_shm_pool_destroy (self->wl_pool); ++ ++ self->wl_pool = NULL; ++ self->size = 0; ++ self->used = 0; ++ ++ /* all buffers are about to be destroyed; ++ * we should no longer do anything with them */ ++ g_mutex_lock (&self->buffers_map_mutex); ++ g_hash_table_remove_all (self->buffers_map); ++ g_mutex_unlock (&self->buffers_map_mutex); ++ ++ ++ return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool); ++} ++ ++/* DMABUF buffer functions */ ++static int ++get_format_bpp (int format) ++{ ++ switch (format) { ++ case DRM_FORMAT_YUV420: ++ case DRM_FORMAT_NV12: ++ return 12; ++ case WL_SHM_FORMAT_XRGB8888: ++ case DRM_FORMAT_XRGB8888: ++ case WL_SHM_FORMAT_ARGB8888: ++ case DRM_FORMAT_ARGB8888: ++ return 32; ++ default: ++ GST_WARNING ("Unknown format: %d", format); ++ return 32; ++ } ++} ++ ++static int ++create_dumb (int drm_fd, uint32_t width, uint32_t height, int format, ++ int *prime_fd, guint * stride) ++{ ++ struct drm_mode_create_dumb create_arg; ++ gint ret; ++ ++ *prime_fd = -1; ++ *stride = 0; ++ ++ ++ memset (&create_arg, 0, sizeof (create_arg)); ++ create_arg.bpp = get_format_bpp (format); ++ create_arg.width = width; ++ create_arg.height = height; ++ ++ ret = drmIoctl (drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg); ++ ++ if (ret) { ++ GST_ERROR ("DRM_IOCTL_MODE_CREATE_DUMB failed %s ret =%d on fd %d", ++ strerror (errno), ret, drm_fd); ++ ++ return ret; ++ } ++ ++ *stride = create_arg.pitch; ++ ++ ret = drmPrimeHandleToFD (drm_fd, create_arg.handle, DRM_CLOEXEC, prime_fd); ++ if (ret) { ++ struct drm_mode_destroy_dumb destroy_arg; ++ ++ GST_WARNING ("Can't get fd from handle"); ++ ++ memset (&destroy_arg, 0, sizeof destroy_arg); ++ destroy_arg.handle = create_arg.handle; ++ drmIoctl (drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg); ++ } ++ ++ ++ return ret; ++} ++ ++static GstWlMeta * ++gst_buffer_add_wayland_meta (GstBuffer * buffer, GstWaylandBufferPool * self) ++{ ++ GstWlMeta *meta; ++ gint offset; ++ void *data; ++ guint width, height, stride, dumb_stride; ++ gsize size; ++ int format; ++ ++ width = GST_VIDEO_INFO_WIDTH (&self->info); ++ height = GST_VIDEO_INFO_HEIGHT (&self->info); ++ stride = GST_VIDEO_INFO_PLANE_STRIDE (&self->info, 0); ++ size = GST_VIDEO_INFO_SIZE (&self->info); ++ ++ if (self->display->dmabuf && self->use_linux_dmabuf) { ++ format = ++ gst_video_format_to_wl_dmabuf_format (GST_VIDEO_INFO_FORMAT ++ (&self->info)); ++ GST_DEBUG_OBJECT (self, ++ "Allocating buffer of size %" G_GSSIZE_FORMAT ++ " (%d x %d, stride %d), format : %s", size, width, height, stride, ++ gst_wl_dmabuf_format_to_string (format)); ++ } else { ++ format = ++ gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&self->info)); ++ GST_DEBUG_OBJECT (self, ++ "Allocating buffer of size %" G_GSSIZE_FORMAT ++ " (%d x %d, stride %d), format : %s", size, width, height, stride, ++ gst_wl_shm_format_to_string (format)); ++ } ++ ++ meta = (GstWlMeta *) gst_buffer_add_meta (buffer, GST_WL_META_INFO, NULL); ++ meta->pool = self; ++ meta->size = size; ++ meta->drm_fd = -1; ++ meta->used_by_compositor = FALSE; ++ ++ gst_buffer_add_video_meta_full (buffer, GST_VIDEO_FRAME_FLAG_NONE, ++ GST_VIDEO_INFO_FORMAT (&self->info), ++ GST_VIDEO_INFO_WIDTH (&self->info), ++ GST_VIDEO_INFO_HEIGHT (&self->info), ++ GST_VIDEO_INFO_N_PLANES (&self->info), self->info.offset, ++ self->info.stride); ++ ++ if (self->display->dmabuf && self->use_linux_dmabuf) { ++ int prime_fd, ret, buf_width, buf_height; ++ ++ buf_width = (stride / (get_format_bpp (format) / 8)); ++ buf_height = (size / buf_width) * 8 / get_format_bpp (format); ++ if ((buf_width * buf_height * get_format_bpp (format)) / 8 < size) ++ GST_ERROR_OBJECT (self, "Not allocating enough memory"); ++ ++ ret = ++ create_dumb (self->fd, width, buf_height, format, &prime_fd, ++ &dumb_stride); ++ if (ret || prime_fd == -1) { ++ ++ return NULL; ++ } ++ GST_LOG_OBJECT (self, "drm buffer prime fd %d", prime_fd); ++ ++ /* The wl_buffer will be created at the first render */ ++ meta->wbuffer = NULL; ++ ++ gst_buffer_append_memory (buffer, ++ gst_dmabuf_allocator_alloc (self->allocator, prime_fd, meta->size)); ++ ++ meta->drm_fd = self->fd; ++ } else { ++ /* try to reserve another memory block from the shm pool */ ++ if (self->used + size > self->size) { ++ ++ return NULL; ++ } ++ offset = self->used; ++ self->used += size; ++ data = ((gchar *) self->data) + offset; ++ ++ meta->wbuffer = wl_shm_pool_create_buffer (self->wl_pool, offset, ++ width, height, stride, format); ++ ++ meta->data = data; ++ ++ /* add the allocated memory on the GstBuffer */ ++ gst_buffer_append_memory (buffer, ++ gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data, ++ size, 0, size, NULL, NULL)); ++ ++ /* configure listening to wl_buffer.release */ ++ g_mutex_lock (&self->buffers_map_mutex); ++ g_hash_table_insert (self->buffers_map, meta->wbuffer, buffer); ++ g_mutex_unlock (&self->buffers_map_mutex); ++ ++ wl_buffer_add_listener (meta->wbuffer, &buffer_listener, self); ++ } ++ ++ ++ return meta; ++} ++ ++static GstFlowReturn ++gst_wayland_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer, ++ GstBufferPoolAcquireParams * params) ++{ ++ GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool); ++ GstWlMeta *meta; ++ ++ /* create buffer and its metadata object */ ++ *buffer = gst_buffer_new (); ++ ++ meta = gst_buffer_add_wayland_meta (*buffer, self); ++ ++ if (meta == NULL) { ++ gst_buffer_unref (*buffer); ++ goto no_buffer; ++ } ++ ++ ++ return GST_FLOW_OK; ++ ++ /* ERROR */ ++no_buffer: ++ { ++ GST_WARNING_OBJECT (pool, "can't create buffer"); ++ ++ return GST_FLOW_ERROR; ++ } ++} ++ ++GstBufferPool * ++gst_wayland_buffer_pool_new (GstWlDisplay * display) ++{ ++ GstWaylandBufferPool *pool; ++ GstStructure *s; ++ GstVideoAlignment align; ++ ++ g_return_val_if_fail (GST_IS_WL_DISPLAY (display), NULL); ++ pool = g_object_new (GST_TYPE_WAYLAND_BUFFER_POOL, NULL); ++ pool->display = g_object_ref (display); ++ ++ pool->fd = -1; ++ ++ s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); ++ gst_buffer_pool_config_add_option (s, GST_BUFFER_POOL_OPTION_VIDEO_META); ++ gst_buffer_pool_config_add_option (s, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); ++ /* reset alignment */ ++ gst_video_alignment_reset (&align); ++ gst_buffer_pool_config_set_video_alignment (s, &align); ++ gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), s); ++ ++ return GST_BUFFER_POOL_CAST (pool); ++} +diff --git a/ext/wayland/waylandpool.h b/ext/wayland/waylandpool.h +new file mode 100644 +index 0000000..4afd683 +--- /dev/null ++++ b/ext/wayland/waylandpool.h +@@ -0,0 +1,105 @@ ++/* GStreamer Wayland buffer pool ++ * Copyright (C) 2012 Intel Corporation ++ * Copyright (C) 2012 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 St, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __GST_WAYLAND_BUFFER_POOL_H__ ++#define __GST_WAYLAND_BUFFER_POOL_H__ ++ ++#include ++#include ++ ++#include "wldisplay.h" ++#include "gstwaylandsink.h" ++ ++G_BEGIN_DECLS ++#define GST_TYPE_WAYLAND_BUFFER_POOL (gst_wayland_buffer_pool_get_type()) ++#define GST_IS_WAYLAND_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WAYLAND_BUFFER_POOL)) ++#define GST_WAYLAND_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WAYLAND_BUFFER_POOL, GstWaylandBufferPool)) ++#define GST_WAYLAND_BUFFER_POOL_CAST(obj) ((GstWaylandBufferPool*)(obj)) ++typedef struct _GstWaylandBufferPool GstWaylandBufferPool; ++typedef struct _GstWaylandBufferPoolClass GstWaylandBufferPoolClass; ++ ++/* buffer meta */ ++typedef struct _GstWlMeta GstWlMeta; ++ ++GType gst_wl_meta_api_get_type (void); ++#define GST_WL_META_API_TYPE (gst_wl_meta_api_get_type()) ++ ++const GstMetaInfo *gst_wl_meta_get_info (void); ++#define GST_WL_META_INFO (gst_wl_meta_get_info()) ++ ++#define gst_buffer_get_wl_meta(b) ((GstWlMeta*)gst_buffer_get_meta((b),GST_WL_META_API_TYPE)) ++ ++struct _GstWlMeta ++{ ++ GstMeta meta; ++ ++ GstWaylandBufferPool *pool; ++ struct wl_buffer *wbuffer; ++ gboolean used_by_compositor; ++ ++ void *data; ++ size_t size; ++ int drm_fd; ++}; ++ ++/* buffer pool */ ++struct _GstWaylandBufferPool ++{ ++ GstBufferPool bufferpool; ++ GstWlDisplay *display; ++ ++ GstAllocator *allocator; ++ ++ /* external configuration */ ++ GstVideoInfo info; ++ ++ /* allocation data */ ++ struct wl_shm_pool *wl_pool; ++ size_t size; ++ size_t used; ++ void *data; ++ ++ gboolean use_linux_dmabuf; ++ gint fd; ++ GstCaps *caps; ++ guint width; ++ guint height; ++ ++ GMutex buffers_map_mutex; ++ GHashTable *buffers_map; ++}; ++ ++struct _GstWaylandBufferPoolClass ++{ ++ GstBufferPoolClass parent_class; ++}; ++ ++GType gst_wayland_buffer_pool_get_type (void); ++ ++GstBufferPool *gst_wayland_buffer_pool_new (GstWlDisplay * display); ++ ++void gst_wayland_compositor_acquire_buffer (GstWaylandBufferPool * self, ++ GstBuffer * buffer); ++void gst_wayland_compositor_release_all_buffers (GstWaylandBufferPool * self); ++ ++gboolean gst_buffer_set_wl_buffer (GstBuffer * buf, GstBufferPool * bpool); ++G_END_DECLS ++#endif /*__GST_WAYLAND_BUFFER_POOL_H__*/ +diff --git a/ext/wayland/wldisplay.c b/ext/wayland/wldisplay.c +index f326091..b2e1359 100644 +--- a/ext/wayland/wldisplay.c ++++ b/ext/wayland/wldisplay.c +@@ -50,6 +50,9 @@ gst_wl_display_init (GstWlDisplay * self) + 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); ++ /* Default DRM */ ++ /* TODO : device name is hardcoded. It should come from protocol */ ++ self->device_name = g_strdup ("/dev/dri/card0"); + } + + static void +diff --git a/ext/wayland/wldisplay.h b/ext/wayland/wldisplay.h +index f2025a6..65c754a 100644 +--- a/ext/wayland/wldisplay.h ++++ b/ext/wayland/wldisplay.h +@@ -29,15 +29,15 @@ + #include "linux-dmabuf-unstable-v1-client-protocol.h" + #include "fullscreen-shell-unstable-v1-client-protocol.h" + +-G_BEGIN_DECLS ++#include "gst/allocators/gstdmabuf.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; + +@@ -67,7 +67,7 @@ struct _GstWlDisplay + gboolean own_display; + GThread *thread; + GstPoll *wl_fd_poll; +- ++ char *device_name; + GMutex buffers_mutex; + GHashTable *buffers; + gboolean shutting_down; +@@ -81,7 +81,7 @@ struct _GstWlDisplayClass + 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, ++GstWlDisplay *gst_wl_display_new_existing (struct wl_display *display, + gboolean take_ownership, GError ** error); + + /* see wlbuffer.c for explanation */ +@@ -96,5 +96,4 @@ gboolean gst_wl_display_check_format_for_dmabuf (GstWlDisplay * display, + GstVideoFormat format); + + G_END_DECLS +- + #endif /* __GST_WL_DISPLAY_H__ */ +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0002-waylandsink-fix-error-when-mmapping-dmabuf-buffers.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0002-waylandsink-fix-error-when-mmapping-dmabuf-buffers.patch new file mode 100644 index 000000000..dae756f1a --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0002-waylandsink-fix-error-when-mmapping-dmabuf-buffers.patch @@ -0,0 +1,31 @@ +From a69cd4d027f3b86fd19a87d8139e08614587885c Mon Sep 17 00:00:00 2001 +From: Hugues Fruchet +Date: Mon, 26 Nov 2018 17:38:13 +0100 +Subject: [PATCH 02/14] waylandsink: fix error when mmapping dmabuf buffers + +Linux Kernel 4.10 DRM/KMS requires DRM_RDWR rights +in addition to DRM_CLOEXEC (see drmPrimeHandleToFD()) +in order to mmap in RD/WR. + +Change-Id: I9c26642a47e6f71b56c0a4ad4714a5b85d814e5f +Signed-off-by: Hugues Fruchet +--- + ext/wayland/waylandpool.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c +index 70e40b4..9b20884 100644 +--- a/ext/wayland/waylandpool.c ++++ b/ext/wayland/waylandpool.c +@@ -470,7 +470,7 @@ create_dumb (int drm_fd, uint32_t width, uint32_t height, int format, + + *stride = create_arg.pitch; + +- ret = drmPrimeHandleToFD (drm_fd, create_arg.handle, DRM_CLOEXEC, prime_fd); ++ ret = drmPrimeHandleToFD (drm_fd, create_arg.handle, DRM_CLOEXEC | DRM_RDWR, prime_fd); + if (ret) { + struct drm_mode_destroy_dumb destroy_arg; + +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0003-waylandsink-fix-wrong-width-when-creating-dmabuf-dum.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0003-waylandsink-fix-wrong-width-when-creating-dmabuf-dum.patch new file mode 100644 index 000000000..b82369b49 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0003-waylandsink-fix-wrong-width-when-creating-dmabuf-dum.patch @@ -0,0 +1,34 @@ +From 754625fd6a60fbc529416ba88ff06f542523937a Mon Sep 17 00:00:00 2001 +From: Hugues Fruchet +Date: Thu, 6 Dec 2018 18:08:15 +0100 +Subject: [PATCH 03/14] waylandsink: fix wrong width when creating dmabuf dumb + buffers + +Unaligned width is given in argument of create_dumb(), fix this. + +Change-Id: Ifc57aa24331f58f588aae480baa2099a47d5f31b +Signed-off-by: Hugues Fruchet +--- + ext/wayland/waylandpool.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c +index 9b20884..6e98143 100644 +--- a/ext/wayland/waylandpool.c ++++ b/ext/wayland/waylandpool.c +@@ -537,10 +537,9 @@ gst_buffer_add_wayland_meta (GstBuffer * buffer, GstWaylandBufferPool * self) + buf_height = (size / buf_width) * 8 / get_format_bpp (format); + if ((buf_width * buf_height * get_format_bpp (format)) / 8 < size) + GST_ERROR_OBJECT (self, "Not allocating enough memory"); +- + ret = +- create_dumb (self->fd, width, buf_height, format, &prime_fd, +- &dumb_stride); ++ create_dumb (self->fd, buf_width, buf_height, format, &prime_fd, ++ &dumb_stride); + if (ret || prime_fd == -1) { + + return NULL; +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0004-waylandsink-do-not-hardcode-dmabuf-bufferpool-info-s.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0004-waylandsink-do-not-hardcode-dmabuf-bufferpool-info-s.patch new file mode 100644 index 000000000..ce24df303 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0004-waylandsink-do-not-hardcode-dmabuf-bufferpool-info-s.patch @@ -0,0 +1,44 @@ +From f1e46e02aeac410a4bf1faae5a7dac62c0dfbe1d Mon Sep 17 00:00:00 2001 +From: Hugues Fruchet +Date: Wed, 12 Dec 2018 11:39:33 +0100 +Subject: [PATCH 04/14] waylandsink: do not hardcode dmabuf bufferpool info + size + +Read pool config to get the maximum number of buffers +for info size pool allocation. + +Signed-off-by: Hugues Fruchet +--- + ext/wayland/waylandpool.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c +index 6e98143..1ba1f85 100644 +--- a/ext/wayland/waylandpool.c ++++ b/ext/wayland/waylandpool.c +@@ -357,11 +357,21 @@ gst_wayland_buffer_pool_start (GstBufferPool * pool) + int fd; + char filename[1024]; + static int init = 0; ++ GstStructure *config; ++ guint config_max_buf; + + GST_DEBUG_OBJECT (self, "Initializing wayland buffer pool"); + ++ /* get max size of pool */ ++ config = gst_buffer_pool_get_config (pool); ++ gst_buffer_pool_config_get_params (config, NULL, NULL, ++ NULL, &config_max_buf); ++ ++ if (config_max_buf == 0) ++ config_max_buf = 32; ++ + /* configure */ +- size = GST_VIDEO_INFO_SIZE (&self->info) * 15; ++ size = GST_VIDEO_INFO_SIZE (&self->info) * config_max_buf; + + /* allocate shm pool */ + snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (), +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0005-waylandsink-increase-max-buffers-to-32-to-enable-dma.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0005-waylandsink-increase-max-buffers-to-32-to-enable-dma.patch new file mode 100644 index 000000000..4bc9936f2 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0005-waylandsink-increase-max-buffers-to-32-to-enable-dma.patch @@ -0,0 +1,43 @@ +From 837247993dd5399c0faa95950ab62bd1a1f7d6cb Mon Sep 17 00:00:00 2001 +From: Hugues Fruchet +Date: Thu, 6 Dec 2018 18:08:59 +0100 +Subject: [PATCH 05/14] waylandsink: increase max buffers to 32 to enable + dmabuf with libav decoders + +libav software decoders requires max buffers in pool config to be +at least 32, otherwise this pool is rejected. + +Change-Id: If1a54ee8c1a9f320fd91537e8e2082c4a7a78700 +--- + ext/wayland/gstwaylandsink.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c +index 20df1bf..8b807da 100644 +--- a/ext/wayland/gstwaylandsink.c ++++ b/ext/wayland/gstwaylandsink.c +@@ -52,6 +52,9 @@ + #include + #include + ++#define CONFIG_DMABUF_MIN_BUFFERS 2 ++#define CONFIG_DMABUF_MAX_BUFFERS 32 ++ + /* signals */ + enum + { +@@ -574,8 +577,9 @@ gst_wayland_create_dmabuf_pool (GstWaylandSink * sink, GstCaps * caps) + } + + structure = gst_buffer_pool_get_config (pool); +- gst_buffer_pool_config_set_params (structure, caps, info.size, 2, 0); +- gst_buffer_pool_config_set_allocator (structure, NULL, ¶ms); ++ gst_buffer_pool_config_set_params (structure, caps, size, ++ CONFIG_DMABUF_MIN_BUFFERS, CONFIG_DMABUF_MAX_BUFFERS); ++ + alloc = gst_dmabuf_allocator_new (); + gst_buffer_pool_config_set_allocator (structure, alloc, NULL); + if (!gst_buffer_pool_set_config (pool, structure)) { +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0006-waylandsink-always-select-dmabuf-buffer-pool.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0006-waylandsink-always-select-dmabuf-buffer-pool.patch new file mode 100644 index 000000000..9d13675a3 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0006-waylandsink-always-select-dmabuf-buffer-pool.patch @@ -0,0 +1,44 @@ +From 36a3da1477d9dd5c23b0c47fd45e61a8c0316600 Mon Sep 17 00:00:00 2001 +From: Hugues Fruchet +Date: Thu, 6 Dec 2018 18:09:20 +0100 +Subject: [PATCH 06/14] waylandsink: always select dmabuf buffer pool + +Force usage of dmabuf buffer pool by default, ie +even if video/x-raw(memory:DMABuf) is not set in caps. +This allows 0-copy path with software downstream elements +(use of dmabuf buffers mmapped memory directly instead +of copying). + +Change-Id: Icb6e8ff272c562e829bb3ff91150e7d77b25dfd1 +Signed-off-by: Hugues Fruchet +--- + ext/wayland/gstwaylandsink.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c +index 8b807da..40edff7 100644 +--- a/ext/wayland/gstwaylandsink.c ++++ b/ext/wayland/gstwaylandsink.c +@@ -610,9 +610,17 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) + format = GST_VIDEO_INFO_FORMAT (&sink->video_info); + sink->video_info_changed = TRUE; + +- use_dmabuf = gst_caps_features_contains (gst_caps_get_features (caps, 0), +- GST_CAPS_FEATURE_MEMORY_DMABUF); ++ /* Force usage of dmabuf buffer pool by default, ie ++ * even if video/x-raw(memory:DMABuf) is not set in caps. ++ * This allows 0-copy path with software downstream elements ++ * (use of dmabuf buffers mmapped memory directly instead ++ * of copying) ++ */ ++ /* use_dmabuf = gst_caps_features_contains (gst_caps_get_features (caps, 0), ++ GST_CAPS_FEATURE_MEMORY_DMABUF); */ ++ use_dmabuf = TRUE; + ++ /* validate the format base on the memory type */ + if (use_dmabuf) { + if (!gst_wl_display_check_format_for_dmabuf (sink->display, format)) + goto unsupported_format; +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0007-waylandsink-do-not-destroy-pool-twice.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0007-waylandsink-do-not-destroy-pool-twice.patch new file mode 100644 index 000000000..4fcfaea84 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0007-waylandsink-do-not-destroy-pool-twice.patch @@ -0,0 +1,34 @@ +From 15464502cf5851e29fa5da9c6e1547655865de21 Mon Sep 17 00:00:00 2001 +From: Hugues Fruchet +Date: Mon, 10 Dec 2018 17:36:27 +0100 +Subject: [PATCH 07/14] waylandsink: do not destroy pool twice + +Fix segfault in wayland client due to pool +destroy being called with null pool... +This problem was encountered with GStreamer-1.14. + +Signed-off-by: Hugues Fruchet +--- + ext/wayland/waylandpool.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c +index 1ba1f85..17a94f1 100644 +--- a/ext/wayland/waylandpool.c ++++ b/ext/wayland/waylandpool.c +@@ -417,7 +417,12 @@ gst_wayland_buffer_pool_stop (GstBufferPool * pool) + + GST_DEBUG_OBJECT (self, "Stopping wayland buffer pool"); + ++ /* already stopped... */ ++ if (!self->wl_pool) ++ return FALSE; ++ + munmap (self->data, self->size); ++ + wl_shm_pool_destroy (self->wl_pool); + + self->wl_pool = NULL; +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0008-waylandsink-HACK-disable-frame-dropping-while-redraw.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0008-waylandsink-HACK-disable-frame-dropping-while-redraw.patch new file mode 100644 index 000000000..3048aa783 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0008-waylandsink-HACK-disable-frame-dropping-while-redraw.patch @@ -0,0 +1,62 @@ +From 5cf87e34ad0aa98ceb004f68ea72498f490e6858 Mon Sep 17 00:00:00 2001 +From: Hugues Fruchet +Date: Wed, 12 Dec 2018 12:04:03 +0100 +Subject: [PATCH 08/14] waylandsink: HACK: disable frame dropping while redraw + is pending + +This workaround is needed to reach 30fps video playback. + +Redraw callback is received late, leading to many frames +being dropped and so low framerate on display driver stage. +The fact that redraw callback is received late is not yet understood +but display subsystem is able to sustain a higher framerate +than the one reached with redraw callback mechanism. +This workaround consists to ignore redraw callback allowing to +get back to the expected framerate performances. + +Even if not observed yet, there is a risk of visible decoding artefacts +due to the fact that downstream elements could rewrite in a frame +being currently rendered by display subsystem... + +Signed-off-by: Hugues Fruchet +--- + ext/wayland/gstwaylandsink.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c +index 40edff7..b97570e 100644 +--- a/ext/wayland/gstwaylandsink.c ++++ b/ext/wayland/gstwaylandsink.c +@@ -774,10 +774,29 @@ render_last_buffer (GstWaylandSink * sink, gboolean redraw) + wlbuffer = gst_buffer_get_wl_buffer (sink->display, sink->last_buffer); + surface = gst_wl_window_get_wl_surface (sink->window); + ++ /* ++ * HACK: disable frame dropping while redraw is pending ++ * ++ * This workaround is needed to reach 30fps video playback. ++ * ++ * Redraw callback is received late, leading to many frames ++ * being dropped and so low framerate on display driver stage. ++ * The fact that redraw callback is received late is not yet understood ++ * but display subsystem is able to sustain a higher framerate ++ * than the one reached with redraw callback mechanism. ++ * This workaround consists to ignore redraw callback allowing to ++ * get back to the expected framerate performances. ++ * ++ * Why not observed yet, there is a risk of visible decoding artefacts ++ * due to the fact that downstream elements could rewrite in a frame ++ * being currently rendered by display subsystem... ++ */ ++#if 0 + sink->redraw_pending = TRUE; + callback = wl_surface_frame (surface); + sink->callback = callback; + wl_callback_add_listener (callback, &frame_callback_listener, sink); ++#endif + + if (G_UNLIKELY (sink->video_info_changed && !redraw)) { + info = &sink->video_info; +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0009-waylandsink-Uprank-to-secondary.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0009-waylandsink-Uprank-to-secondary.patch new file mode 100644 index 000000000..b7af3517e --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0009-waylandsink-Uprank-to-secondary.patch @@ -0,0 +1,26 @@ +From cf2dfe7a376d10a3d7815d29ffc1c9efb4d4f19e Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Mon, 21 May 2018 14:26:47 +0200 +Subject: [PATCH 09/14] waylandsink: Uprank to secondary + +Signed-off-by: Christophe Priouzeau +--- + ext/wayland/gstwaylandsink.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c +index b97570e..0dc1f0d 100644 +--- a/ext/wayland/gstwaylandsink.c ++++ b/ext/wayland/gstwaylandsink.c +@@ -126,7 +126,7 @@ G_DEFINE_TYPE_WITH_CODE (GstWaylandSink, gst_wayland_sink, GST_TYPE_VIDEO_SINK, + gst_wayland_sink_videooverlay_init) + G_IMPLEMENT_INTERFACE (GST_TYPE_WAYLAND_VIDEO, + gst_wayland_sink_waylandvideo_init)); +-GST_ELEMENT_REGISTER_DEFINE (waylandsink, "waylandsink", GST_RANK_MARGINAL, ++GST_ELEMENT_REGISTER_DEFINE (waylandsink, "waylandsink", GST_RANK_SECONDARY+1, + GST_TYPE_WAYLAND_SINK); + + /* A tiny GstVideoBufferPool subclass that modify the options to remove +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0010-waylandsink-set-video-alignment-to-32-bytes.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0010-waylandsink-set-video-alignment-to-32-bytes.patch new file mode 100644 index 000000000..260fc1782 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0010-waylandsink-set-video-alignment-to-32-bytes.patch @@ -0,0 +1,41 @@ +From 9eb8fcc53467a575dc3fba3bbeae26ed8752e639 Mon Sep 17 00:00:00 2001 +From: Hugues Fruchet +Date: Mon, 11 Feb 2019 16:00:02 +0100 +Subject: [PATCH 10/14] waylandsink: set video alignment to 32 bytes + +Display subsystem requires at least 32 bytes alignment. + +Signed-off-by: Hugues Fruchet +--- + ext/wayland/waylandpool.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c +index 17a94f1..e04a459 100644 +--- a/ext/wayland/waylandpool.c ++++ b/ext/wayland/waylandpool.c +@@ -635,6 +635,7 @@ gst_wayland_buffer_pool_new (GstWlDisplay * display) + GstWaylandBufferPool *pool; + GstStructure *s; + GstVideoAlignment align; ++ guint i; + + g_return_val_if_fail (GST_IS_WL_DISPLAY (display), NULL); + pool = g_object_new (GST_TYPE_WAYLAND_BUFFER_POOL, NULL); +@@ -645,8 +646,12 @@ gst_wayland_buffer_pool_new (GstWlDisplay * display) + s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); + gst_buffer_pool_config_add_option (s, GST_BUFFER_POOL_OPTION_VIDEO_META); + gst_buffer_pool_config_add_option (s, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); +- /* reset alignment */ ++ ++ /* display subsystem requires at least 32 bytes alignment */ + gst_video_alignment_reset (&align); ++ for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) ++ align.stride_align[i] = 31; ++ + gst_buffer_pool_config_set_video_alignment (s, &align); + gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), s); + +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0011-waylandsink-fallback-to-shm-if-display-does-not-supp.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0011-waylandsink-fallback-to-shm-if-display-does-not-supp.patch new file mode 100644 index 000000000..14f4ed5c2 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0011-waylandsink-fallback-to-shm-if-display-does-not-supp.patch @@ -0,0 +1,39 @@ +From e46e02a4745e20b139a5834d235fe2eeb992be14 Mon Sep 17 00:00:00 2001 +From: Hugues Fruchet +Date: Fri, 22 Mar 2019 15:40:03 +0100 +Subject: [PATCH 11/14] waylandsink: fallback to shm if display does not + support dmabuf + +Fallback to shm if display does not support dmabuf. + +Signed-off-by: Hugues Fruchet +--- + ext/wayland/gstwaylandsink.c | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c +index 0dc1f0d..e4952cb 100644 +--- a/ext/wayland/gstwaylandsink.c ++++ b/ext/wayland/gstwaylandsink.c +@@ -618,15 +618,11 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) + */ + /* use_dmabuf = gst_caps_features_contains (gst_caps_get_features (caps, 0), + GST_CAPS_FEATURE_MEMORY_DMABUF); */ +- use_dmabuf = TRUE; ++ use_dmabuf = gst_wl_display_check_format_for_dmabuf (sink->display, format); + +- /* validate the format base on the memory type */ +- if (use_dmabuf) { +- if (!gst_wl_display_check_format_for_dmabuf (sink->display, format)) ++ if (!use_dmabuf) ++ if (!gst_wl_display_check_format_for_shm (sink->display, format)) + goto unsupported_format; +- } else if (!gst_wl_display_check_format_for_shm (sink->display, format)) { +- goto unsupported_format; +- } + + /* create a new pool for the new caps */ + if (sink->pool) +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0012-waylandsink-XDG-protocol-does-not-work-in-fullscreen.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0012-waylandsink-XDG-protocol-does-not-work-in-fullscreen.patch new file mode 100644 index 000000000..fa8f93757 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0012-waylandsink-XDG-protocol-does-not-work-in-fullscreen.patch @@ -0,0 +1,56 @@ +From 105576bd522f3a751fda51ea35da2147b1adcfe7 Mon Sep 17 00:00:00 2001 +From: Pierre-Yves MORDRET +Date: Fri, 4 Oct 2019 09:47:43 +0200 +Subject: [PATCH 12/14] waylandsink: XDG protocol does not work in fullscreen + +Using new XDG protocol, it turns out to be not working when enabling +fullscreen support. +This patch avoids to over commit surface during configuration and takes +into account render region when provided within wayland callback. + +Signed-off-by: Pierre-Yves MORDRET +--- + ext/wayland/wlwindow.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/ext/wayland/wlwindow.c b/ext/wayland/wlwindow.c +index 66df0fc..cc5de26 100644 +--- a/ext/wayland/wlwindow.c ++++ b/ext/wayland/wlwindow.c +@@ -325,10 +325,18 @@ gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info, + /* render_rectangle is already set via toplevel_configure in + * xdg_shell fullscreen mode */ + if (!(display->xdg_wm_base && fullscreen)) { ++ gint width, height; ++ + /* 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); ++ if ( window->render_rectangle.w == 0 || window->render_rectangle.h == 0) { ++ width = ++ gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d); ++ height = info->height; ++ } else { ++ width = window->render_rectangle.w; ++ height = window->render_rectangle.h; ++ } ++ gst_wl_window_set_render_rectangle (window, 0, 0, width, height); + } + + return window; +@@ -567,7 +575,10 @@ gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y, + gst_wl_window_resize_video_surface (window, TRUE); + } + +- wl_surface_commit (window->area_surface_wrapper); ++ if (window->xdg_surface && window->configured) { ++ wl_surface_damage (window->area_surface_wrapper, 0, 0, w, h); ++ wl_surface_commit (window->area_surface_wrapper); ++ } + + if (window->video_width != 0) + wl_subsurface_set_desync (window->video_subsurface); +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0013-waylandsink-silently-drop-erroneous-frame.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0013-waylandsink-silently-drop-erroneous-frame.patch new file mode 100644 index 000000000..bcdd65c8e --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0013-waylandsink-silently-drop-erroneous-frame.patch @@ -0,0 +1,97 @@ +From e14996eb9c0332aeda6390db207380dd0267e7c2 Mon Sep 17 00:00:00 2001 +From: Hugues Fruchet +Date: Wed, 25 Sep 2019 16:01:49 +0200 +Subject: [PATCH 13/14] waylandsink: silently drop erroneous frame + +Do not stop playback when erroneous frame is received at show_frame(): +- test file descriptors validity, to not let throw erroneous +file descriptor to wayland backend (which may crash on fatal error) +- if file descriptors are not valid, do not fall into general +"GST_ELEMENT_ERROR" nor return FLOW_ERROR. + +Signed-off-by: Hugues Fruchet +--- + ext/wayland/gstwaylandsink.c | 6 +++--- + ext/wayland/wllinuxdmabuf.c | 14 ++++++++++++++ + ext/wayland/wlshmallocator.c | 10 ++++++++++ + 3 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c +index e4952cb..cf355d3 100644 +--- a/ext/wayland/gstwaylandsink.c ++++ b/ext/wayland/gstwaylandsink.c +@@ -1025,9 +1025,9 @@ activate_failed: + } + src_map_failed: + { +- GST_ELEMENT_ERROR (sink, RESOURCE, READ, +- ("Video memory can not be read from userspace."), (NULL)); +- ret = GST_FLOW_ERROR; ++ /* Silently drop in case of erroneous buffer */ ++ GST_ERROR_OBJECT (sink, "Video memory can not be read from userspace," ++ "dropping buffer %p", buffer); + goto done; + } + dst_map_failed: +diff --git a/ext/wayland/wllinuxdmabuf.c b/ext/wayland/wllinuxdmabuf.c +index 96487d1..36815b5 100644 +--- a/ext/wayland/wllinuxdmabuf.c ++++ b/ext/wayland/wllinuxdmabuf.c +@@ -28,6 +28,8 @@ + #include "wllinuxdmabuf.h" + #include "wlvideoformat.h" + ++#include ++ + GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); + #define GST_CAT_DEFAULT gstwayland_debug + +@@ -110,6 +112,18 @@ gst_wl_linux_dmabuf_construct_wl_buffer (GstBuffer * buf, + if (gst_buffer_find_memory (buf, offset, 1, &mem_idx, &length, &skip)) { + GstMemory *m = gst_buffer_peek_memory (buf, mem_idx); + gint fd = gst_dmabuf_memory_get_fd (m); ++ gint dup_fd = dup (fd); ++ ++ /* Test if file descriptor is valid */ ++ if (dup_fd < 0) { ++ GST_ERROR_OBJECT (display, "zwp_linux_dmabuf: dup failed for fd=%d (err=%d) buffer=%p", ++ fd, dup_fd, buf); ++ zwp_linux_buffer_params_v1_destroy (params); ++ data.wbuf = NULL; ++ goto out; ++ } ++ close(dup_fd); ++ + zwp_linux_buffer_params_v1_add (params, fd, i, m->offset + skip, + stride, 0, 0); + } else { +diff --git a/ext/wayland/wlshmallocator.c b/ext/wayland/wlshmallocator.c +index 0a82a35..8659c2f 100644 +--- a/ext/wayland/wlshmallocator.c ++++ b/ext/wayland/wlshmallocator.c +@@ -212,12 +212,22 @@ gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display, + enum wl_shm_format format; + struct wl_shm_pool *wl_pool; + struct wl_buffer *wbuffer; ++ gint fd = gst_fd_memory_get_fd (mem); ++ gint dup_fd = dup(fd); + + if (!gst_wl_shm_validate_video_info (info)) { + GST_DEBUG_OBJECT (display, "Unsupported strides and offsets."); + return NULL; + } + ++ /* Test if file descriptor is valid */ ++ if (dup_fd < 0) { ++ GST_ERROR_OBJECT (display, "wl_shm_memory: dup failed for fd=%d (err=%d) mem=%p", ++ fd, dup_fd, mem); ++ return NULL; ++ } ++ close(dup_fd); ++ + width = GST_VIDEO_INFO_WIDTH (info); + height = GST_VIDEO_INFO_HEIGHT (info); + stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0); +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0014-waylandsink-add-waylandpool-on-meson-build.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0014-waylandsink-add-waylandpool-on-meson-build.patch new file mode 100644 index 000000000..08127b5a1 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0014-waylandsink-add-waylandpool-on-meson-build.patch @@ -0,0 +1,27 @@ +From 678d91a743bb35e202211abc6db495fbf8d75601 Mon Sep 17 00:00:00 2001 +From: Christophe Priouzeau +Date: Tue, 18 Feb 2020 13:33:21 +0100 +Subject: [PATCH 14/14] waylandsink add waylandpool on meson build + +Signed-off-by: Christophe Priouzeau +--- + ext/wayland/meson.build | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ext/wayland/meson.build b/ext/wayland/meson.build +index a3ffb70..66dd148 100644 +--- a/ext/wayland/meson.build ++++ b/ext/wayland/meson.build +@@ -5,7 +5,8 @@ wl_sources = [ + 'wldisplay.c', + 'wlwindow.c', + 'wlvideoformat.c', +- 'wllinuxdmabuf.c' ++ 'wllinuxdmabuf.c', ++ 'waylandpool.c' + ] + + libdrm_dep = dependency('libdrm', version: '>= 2.4.55', required:get_option('wayland')) +-- +2.25.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0016-Add-new-gtkwaylandsink-element.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0016-Add-new-gtkwaylandsink-element.patch new file mode 100644 index 000000000..3ddaf5b27 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0016-Add-new-gtkwaylandsink-element.patch @@ -0,0 +1,1570 @@ +From 33fa3db5ac3c5e3c82df9573dec334ef7bf77ee3 Mon Sep 17 00:00:00 2001 +From: George Kiagiadakis +Date: Fri, 17 Dec 2021 14:02:51 +0200 +Subject: [PATCH 16/16] Add new gtkwaylandsink element + +--- + ext/gtk/gstgtkutils.c | 71 +++++ + ext/gtk/gstgtkutils.h | 29 ++ + ext/gtk/gstgtkwaylandsink.c | 460 +++++++++++++++++++++++++++++ + ext/gtk/gstgtkwaylandsink.h | 51 ++++ + ext/gtk/gstplugin.c | 43 +++ + ext/gtk/gtkgstbasewidget.c | 542 ++++++++++++++++++++++++++++++++++ + ext/gtk/gtkgstbasewidget.h | 100 +++++++ + ext/gtk/gtkgstwaylandwidget.c | 67 +++++ + ext/gtk/gtkgstwaylandwidget.h | 68 +++++ + ext/gtk/meson.build | 22 ++ + ext/meson.build | 1 + + meson_options.txt | 1 + + 12 files changed, 1455 insertions(+) + create mode 100644 ext/gtk/gstgtkutils.c + create mode 100644 ext/gtk/gstgtkutils.h + create mode 100644 ext/gtk/gstgtkwaylandsink.c + create mode 100644 ext/gtk/gstgtkwaylandsink.h + create mode 100644 ext/gtk/gstplugin.c + create mode 100644 ext/gtk/gtkgstbasewidget.c + create mode 100644 ext/gtk/gtkgstbasewidget.h + create mode 100644 ext/gtk/gtkgstwaylandwidget.c + create mode 100644 ext/gtk/gtkgstwaylandwidget.h + create mode 100644 ext/gtk/meson.build + +diff --git a/ext/gtk/gstgtkutils.c b/ext/gtk/gstgtkutils.c +new file mode 100644 +index 0000000..c730f01 +--- /dev/null ++++ b/ext/gtk/gstgtkutils.c +@@ -0,0 +1,71 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2015 Matthew Waters ++ * Copyright (C) 2015 Thibault Saunier ++ * ++ * 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. ++ */ ++ ++#include "gstgtkutils.h" ++ ++struct invoke_context ++{ ++ GThreadFunc func; ++ gpointer data; ++ GMutex lock; ++ GCond cond; ++ gboolean fired; ++ ++ gpointer res; ++}; ++ ++static gboolean ++gst_gtk_invoke_func (struct invoke_context *info) ++{ ++ g_mutex_lock (&info->lock); ++ info->res = info->func (info->data); ++ info->fired = TRUE; ++ g_cond_signal (&info->cond); ++ g_mutex_unlock (&info->lock); ++ ++ return G_SOURCE_REMOVE; ++} ++ ++gpointer ++gst_gtk_invoke_on_main (GThreadFunc func, gpointer data) ++{ ++ GMainContext *main_context = g_main_context_default (); ++ struct invoke_context info; ++ ++ g_mutex_init (&info.lock); ++ g_cond_init (&info.cond); ++ info.fired = FALSE; ++ info.func = func; ++ info.data = data; ++ ++ g_main_context_invoke (main_context, (GSourceFunc) gst_gtk_invoke_func, ++ &info); ++ ++ g_mutex_lock (&info.lock); ++ while (!info.fired) ++ g_cond_wait (&info.cond, &info.lock); ++ g_mutex_unlock (&info.lock); ++ ++ g_mutex_clear (&info.lock); ++ g_cond_clear (&info.cond); ++ ++ return info.res; ++} +diff --git a/ext/gtk/gstgtkutils.h b/ext/gtk/gstgtkutils.h +new file mode 100644 +index 0000000..7584ae2 +--- /dev/null ++++ b/ext/gtk/gstgtkutils.h +@@ -0,0 +1,29 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2015 Matthew Waters ++ * Copyright (C) 2015 Thibault Saunier ++ * ++ * 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. ++ */ ++ ++#ifndef __GST_GTK_UTILS_H__ ++#define __GST_GTK_UTILS_H__ ++ ++#include ++ ++gpointer gst_gtk_invoke_on_main (GThreadFunc func, gpointer data); ++ ++#endif /* __GST_GTK_UTILS_H__ */ +diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c +new file mode 100644 +index 0000000..c38ea51 +--- /dev/null ++++ b/ext/gtk/gstgtkwaylandsink.c +@@ -0,0 +1,460 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2015 Matthew Waters ++ * Copyright (C) 2021 Collabora Ltd. ++ * @author George Kiagiadakis ++ * ++ * 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 "gstgtkwaylandsink.h" ++#include "gtkgstwaylandwidget.h" ++#include "gstgtkutils.h" ++ ++#include ++#include ++ ++#include ++ ++#ifdef GDK_WINDOWING_WAYLAND ++#include ++#else ++#error "Wayland is not supported in GTK+" ++#endif ++ ++GST_DEBUG_CATEGORY (gst_debug_gtk_wayland_sink); ++#define GST_CAT_DEFAULT gst_debug_gtk_wayland_sink ++ ++#ifndef GST_CAPS_FEATURE_MEMORY_DMABUF ++#define GST_CAPS_FEATURE_MEMORY_DMABUF "memory:DMABuf" ++#endif ++ ++#define WL_VIDEO_FORMATS \ ++ "{ BGRx, BGRA, RGBx, xBGR, xRGB, RGBA, ABGR, ARGB, RGB, BGR, " \ ++ "RGB16, BGR16, YUY2, YVYU, UYVY, AYUV, NV12, NV21, NV16, NV61, " \ ++ "YUV9, YVU9, Y41B, I420, YV12, Y42B, v308 }" ++ ++static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", ++ GST_PAD_SINK, ++ GST_PAD_ALWAYS, ++ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (WL_VIDEO_FORMATS) ";" ++ GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_DMABUF, ++ WL_VIDEO_FORMATS)) ++ ); ++ ++static void ++gst_gtk_wayland_sink_navigation_interface_init (GstNavigationInterface * iface); ++ ++static GstPadProbeReturn sink_pad_probe_cb (GstPad * pad, ++ GstPadProbeInfo * info, gpointer user_data); ++ ++enum ++{ ++ PROP_0, ++ PROP_WIDGET, ++}; ++ ++#define gst_gtk_wayland_sink_parent_class parent_class ++G_DEFINE_TYPE_WITH_CODE (GstGtkWaylandSink, gst_gtk_wayland_sink, GST_TYPE_BIN, ++ G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION, ++ gst_gtk_wayland_sink_navigation_interface_init); ++ GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_wayland_sink, "gtkwaylandsink", 0, ++ "Gtk Wayland Video Sink")); ++ ++static void ++gst_gtk_wayland_sink_init (GstGtkWaylandSink * self) ++{ ++ self->waylandsink = gst_element_factory_make ("waylandsink", NULL); ++ if (self->waylandsink) { ++ GstPadTemplate *tmpl; ++ GstPad *pad; ++ ++ gst_bin_add (GST_BIN (self), self->waylandsink); ++ ++ tmpl = gst_static_pad_template_get (&sink_template); ++ pad = gst_element_get_static_pad (self->waylandsink, "sink"); ++ self->ghostpad = gst_ghost_pad_new_from_template ("sink", pad, tmpl); ++ ++ gst_pad_add_probe (self->ghostpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, ++ sink_pad_probe_cb, self, NULL); ++ gst_element_add_pad (GST_ELEMENT (self), self->ghostpad); ++ ++ gst_object_unref (pad); ++ gst_object_unref (tmpl); ++ } ++} ++ ++static void ++gst_gtk_wayland_sink_finalize (GObject * object) ++{ ++ GstGtkWaylandSink *self = GST_GTK_WAYLAND_SINK (object); ++ ++ g_clear_object (&self->widget); ++ ++ G_OBJECT_CLASS (parent_class)->finalize (object); ++} ++ ++static void ++widget_destroy_cb (GtkWidget * widget, GstGtkWaylandSink * self) ++{ ++ GST_OBJECT_LOCK (self); ++ g_clear_object (&self->widget); ++ GST_OBJECT_UNLOCK (self); ++} ++ ++static void ++window_destroy_cb (GtkWidget * widget, GstGtkWaylandSink * self) ++{ ++ GST_OBJECT_LOCK (self); ++ self->window = NULL; ++ GST_OBJECT_UNLOCK (self); ++ ++ GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND, ("Window was closed"), (NULL)); ++} ++ ++/* We use the "draw" callback to change the size of the sink ++ * because the "configure-event" is only sent to top-level widgets. */ ++static gboolean ++widget_draw_cb (GtkWidget * widget, cairo_t * cr, gpointer user_data) ++{ ++ GstGtkWaylandSink *self = user_data; ++ GtkAllocation allocation; ++ ++ gtk_widget_get_allocation (widget, &allocation); ++ gst_video_overlay_set_render_rectangle (GST_VIDEO_OVERLAY (self->waylandsink), ++ allocation.x, allocation.y, allocation.width, allocation.height); ++ ++ return FALSE; ++} ++ ++static GtkWidget * ++gst_gtk_wayland_sink_get_widget (GstGtkWaylandSink * self) ++{ ++ if (self->widget != NULL) ++ return g_object_ref (self->widget); ++ ++ /* Ensure GTK is initialized, this has no side effect if it was already ++ * initialized. Also, we do that lazily, so the application can be first */ ++ if (!gtk_init_check (NULL, NULL)) { ++ GST_INFO_OBJECT (self, "Could not ensure GTK initialization."); ++ return NULL; ++ } ++ ++ self->widget = gtk_gst_wayland_widget_new (); ++ g_signal_connect_object (self->widget, "draw", ++ G_CALLBACK (widget_draw_cb), self, 0); ++ gtk_gst_base_widget_set_element (GTK_GST_BASE_WIDGET (self->widget), ++ GST_ELEMENT (self)); ++ ++ /* Take the floating ref, other wise the destruction of the container will ++ * make this widget disappear possibly before we are done. */ ++ g_object_ref_sink (self->widget); ++ g_signal_connect_object (self->widget, "destroy", ++ G_CALLBACK (widget_destroy_cb), self, 0); ++ ++ return g_object_ref (self->widget); ++} ++ ++static GtkWidget * ++gst_gtk_wayland_sink_acquire_widget (GstGtkWaylandSink * self) ++{ ++ gpointer widget = NULL; ++ ++ GST_OBJECT_LOCK (self); ++ if (self->widget != NULL) ++ widget = g_object_ref (self->widget); ++ GST_OBJECT_UNLOCK (self); ++ ++ if (!widget) ++ widget = ++ gst_gtk_invoke_on_main ((GThreadFunc) gst_gtk_wayland_sink_get_widget, ++ self); ++ ++ return widget; ++} ++ ++static void ++gst_gtk_wayland_sink_get_property (GObject * object, guint prop_id, ++ GValue * value, GParamSpec * pspec) ++{ ++ GstGtkWaylandSink *self = GST_GTK_WAYLAND_SINK (object); ++ ++ switch (prop_id) { ++ case PROP_WIDGET: ++ { ++ g_value_take_object (value, gst_gtk_wayland_sink_acquire_widget (self)); ++ break; ++ } ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static gboolean ++gst_gtk_wayland_sink_start_on_main (GstGtkWaylandSink * self) ++{ ++ GtkWidget *toplevel; ++ GstContext *context; ++ GdkDisplay *display; ++ struct wl_display *display_handle; ++ ++ if ((toplevel = gst_gtk_wayland_sink_get_widget (self)) == NULL) { ++ GST_ERROR_OBJECT (self, "Could not ensure GTK initialization."); ++ return FALSE; ++ } ++ g_object_unref (toplevel); ++ ++ /* After this point, self->widget will always be set */ ++ ++ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self->widget)); ++ if (!gtk_widget_is_toplevel (toplevel)) { ++ /* User did not add widget its own UI, let's popup a new GtkWindow to ++ * make gst-launch-1.0 work. */ ++ self->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); ++ gtk_window_set_default_size (GTK_WINDOW (self->window), 640, 480); ++ gtk_window_set_title (GTK_WINDOW (self->window), "Gst GTK Wayland Sink"); ++ gtk_container_add (GTK_CONTAINER (self->window), toplevel); ++ self->window_destroy_id = g_signal_connect (self->window, "destroy", ++ G_CALLBACK (window_destroy_cb), self); ++ } ++ ++ display = gtk_widget_get_display (self->widget); ++ if (!GDK_IS_WAYLAND_DISPLAY (display)) { ++ GST_ERROR_OBJECT (self, "GDK is not using its wayland backend."); ++ return FALSE; ++ } ++ display_handle = gdk_wayland_display_get_wl_display (display); ++ context = gst_wayland_display_handle_context_new (display_handle); ++ gst_element_set_context (self->waylandsink, context); ++ gst_context_unref (context); ++ ++ return TRUE; ++} ++ ++static gboolean ++gst_gtk_wayland_sink_stop_on_main (GstGtkWaylandSink * self) ++{ ++ if (self->window) { ++ if (self->window_destroy_id) ++ g_signal_handler_disconnect (self->window, self->window_destroy_id); ++ self->window_destroy_id = 0; ++ gtk_widget_destroy (self->window); ++ self->window = NULL; ++ } ++ ++ return TRUE; ++} ++ ++static void ++gst_gtk_widget_show_all_and_unref (GtkWidget * widget) ++{ ++ gtk_widget_show_all (widget); ++ g_object_unref (widget); ++} ++ ++static GstStateChangeReturn ++gst_gtk_wayland_sink_change_state (GstElement * element, ++ GstStateChange transition) ++{ ++ GstGtkWaylandSink *self = GST_GTK_WAYLAND_SINK (element); ++ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; ++ ++ switch (transition) { ++ case GST_STATE_CHANGE_NULL_TO_READY: ++ if (!self->waylandsink) { ++ GST_ERROR_OBJECT (self, "Failed to load waylandsink"); ++ return GST_STATE_CHANGE_FAILURE; ++ } ++ if (!gst_gtk_invoke_on_main ((GThreadFunc) ++ gst_gtk_wayland_sink_start_on_main, element)) ++ return GST_STATE_CHANGE_FAILURE; ++ break; ++ case GST_STATE_CHANGE_READY_TO_PAUSED: ++ { ++ GtkWindow *window = NULL; ++ ++ GST_OBJECT_LOCK (self); ++ if (self->window) ++ window = g_object_ref (GTK_WINDOW (self->window)); ++ GST_OBJECT_UNLOCK (self); ++ ++ if (window) ++ gst_gtk_invoke_on_main ((GThreadFunc) gst_gtk_widget_show_all_and_unref, ++ window); ++ ++ break; ++ } ++ default: ++ break; ++ } ++ ++ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); ++ if (ret != GST_STATE_CHANGE_SUCCESS) ++ return ret; ++ ++ switch (transition) { ++ case GST_STATE_CHANGE_READY_TO_NULL: ++ case GST_STATE_CHANGE_NULL_TO_NULL: ++ gst_gtk_invoke_on_main ((GThreadFunc) ++ gst_gtk_wayland_sink_stop_on_main, element); ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++static GstPadProbeReturn ++sink_pad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) ++{ ++ GstGtkWaylandSink *self = GST_GTK_WAYLAND_SINK (user_data); ++ if (GST_IS_EVENT (info->data) && ++ GST_EVENT_TYPE (info->data) == GST_EVENT_CAPS) { ++ GstVideoInfo v_info; ++ GstCaps *caps; ++ GtkWidget *widget; ++ ++ widget = gst_gtk_wayland_sink_acquire_widget (self); ++ if (widget) { ++ gst_event_parse_caps (GST_EVENT (info->data), &caps); ++ gst_video_info_from_caps (&v_info, caps); ++ gtk_gst_base_widget_set_format (GTK_GST_BASE_WIDGET (widget), &v_info); ++ g_object_unref (widget); ++ } ++ } ++ ++ return GST_PAD_PROBE_OK; ++} ++ ++static void ++gst_gtk_wayland_sink_set_window_handle_on_main (GstGtkWaylandSink * self) ++{ ++ GtkAllocation allocation; ++ GdkWindow *window; ++ struct wl_surface *window_handle; ++ ++ gtk_widget_get_allocation (self->widget, &allocation); ++ window = gtk_widget_get_window (self->widget); ++ window_handle = gdk_wayland_window_get_wl_surface (window); ++ ++ GST_INFO_OBJECT (self, "setting window handle and size (%d x %d)", ++ allocation.width, allocation.height); ++ ++ gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (self->waylandsink), ++ (guintptr) window_handle); ++ gst_video_overlay_set_render_rectangle (GST_VIDEO_OVERLAY (self->waylandsink), ++ allocation.x, allocation.y, allocation.width, allocation.height); ++} ++ ++static void ++gst_gtk_wayland_sink_handle_message (GstBin * bin, GstMessage * message) ++{ ++ GstGtkWaylandSink *self = GST_GTK_WAYLAND_SINK (bin); ++ ++ if (gst_is_video_overlay_prepare_window_handle_message (message)) { ++ gst_gtk_invoke_on_main ((GThreadFunc) ++ gst_gtk_wayland_sink_set_window_handle_on_main, self); ++ gst_message_unref (message); ++ return; ++ } ++ ++ GST_BIN_CLASS (parent_class)->handle_message (bin, message); ++} ++ ++static void ++gst_gtk_wayland_sink_class_init (GstGtkWaylandSinkClass * klass) ++{ ++ GObjectClass *gobject_class = (GObjectClass *) klass; ++ GstElementClass *gstelement_class = (GstElementClass *) klass; ++ GstBinClass *gstbin_class = (GstBinClass *) klass; ++ ++ gobject_class->finalize = gst_gtk_wayland_sink_finalize; ++ gobject_class->get_property = gst_gtk_wayland_sink_get_property; ++ gstelement_class->change_state = gst_gtk_wayland_sink_change_state; ++ gstbin_class->handle_message = gst_gtk_wayland_sink_handle_message; ++ ++ g_object_class_install_property (gobject_class, PROP_WIDGET, ++ g_param_spec_object ("widget", "Gtk Widget", ++ "The GtkWidget to place in the widget hierarchy " ++ "(must only be get from the GTK main thread)", ++ GTK_TYPE_WIDGET, ++ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); ++ ++ gst_element_class_set_metadata (gstelement_class, "Gtk Wayland Video Sink", ++ "Sink/Video", ++ "A video sink that renders to a GtkWidget using Wayland API", ++ "George Kiagiadakis "); ++ ++ gst_element_class_add_static_pad_template (gstelement_class, &sink_template); ++} ++ ++static void ++gst_gtk_wayland_sink_navigation_send_event (GstNavigation * navigation, ++ GstStructure * structure) ++{ ++ GstGtkWaylandSink *sink = GST_GTK_WAYLAND_SINK (navigation); ++ GstEvent *event; ++ GstPad *pad; ++ gdouble x, y; ++ ++ if (gst_structure_get_double (structure, "pointer_x", &x) && ++ gst_structure_get_double (structure, "pointer_y", &y)) { ++ GtkGstBaseWidget *widget = ++ (GtkGstBaseWidget *) gst_gtk_wayland_sink_acquire_widget (sink); ++ gdouble stream_x, stream_y; ++ ++ if (widget == NULL) { ++ GST_ERROR_OBJECT (sink, "Could not ensure GTK initialization."); ++ return; ++ } ++ ++ gtk_gst_base_widget_display_size_to_stream_size (widget, ++ x, y, &stream_x, &stream_y); ++ gst_structure_set (structure, ++ "pointer_x", G_TYPE_DOUBLE, (gdouble) stream_x, ++ "pointer_y", G_TYPE_DOUBLE, (gdouble) stream_y, NULL); ++ ++ g_object_unref (widget); ++ } ++ ++ event = gst_event_new_navigation (structure); ++ pad = gst_pad_get_peer (sink->ghostpad); ++ ++ GST_TRACE_OBJECT (sink, "navigation event %" GST_PTR_FORMAT, structure); ++ ++ if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) { ++ if (!gst_pad_send_event (pad, gst_event_ref (event))) { ++ /* If upstream didn't handle the event we'll post a message with it ++ * for the application in case it wants to do something with it */ ++ gst_element_post_message (GST_ELEMENT_CAST (sink), ++ gst_navigation_message_new_event (GST_OBJECT_CAST (sink), event)); ++ } ++ gst_event_unref (event); ++ gst_object_unref (pad); ++ } ++} ++ ++static void ++gst_gtk_wayland_sink_navigation_interface_init (GstNavigationInterface * iface) ++{ ++ iface->send_event = gst_gtk_wayland_sink_navigation_send_event; ++} +diff --git a/ext/gtk/gstgtkwaylandsink.h b/ext/gtk/gstgtkwaylandsink.h +new file mode 100644 +index 0000000..33fc96f +--- /dev/null ++++ b/ext/gtk/gstgtkwaylandsink.h +@@ -0,0 +1,51 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2021 Collabora Ltd. ++ * @author George Kiagiadakis ++ * ++ * 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. ++ */ ++ ++#ifndef __GST_GTK_WAYLAND_SINK_H__ ++#define __GST_GTK_WAYLAND_SINK_H__ ++ ++#include ++#include ++ ++G_BEGIN_DECLS ++ ++#define GST_TYPE_GTK_WAYLAND_SINK (gst_gtk_wayland_sink_get_type()) ++G_DECLARE_FINAL_TYPE (GstGtkWaylandSink, gst_gtk_wayland_sink, GST, GTK_WAYLAND_SINK, GstBin) ++ ++/** ++ * GstGtkWaylandSink: ++ * ++ * Opaque #GstGtkWaylandSink object ++ */ ++struct _GstGtkWaylandSink ++{ ++ /* */ ++ GstBin parent; ++ GstElement *waylandsink; ++ GstPad *ghostpad; ++ GtkWidget *widget; ++ GtkWidget *window; ++ gulong window_destroy_id; ++}; ++ ++G_END_DECLS ++ ++#endif /* __GST_GTK_WAYLAND_SINK_H__ */ +diff --git a/ext/gtk/gstplugin.c b/ext/gtk/gstplugin.c +new file mode 100644 +index 0000000..f154b08 +--- /dev/null ++++ b/ext/gtk/gstplugin.c +@@ -0,0 +1,43 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2015 Matthew Waters ++ * ++ * 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 "gstgtkwaylandsink.h" ++ ++static gboolean ++plugin_init (GstPlugin * plugin) ++{ ++ gboolean ret = FALSE; ++ ++ ret |= gst_element_register (plugin, "gtkwaylandsink", GST_RANK_NONE, ++ GST_TYPE_GTK_WAYLAND_SINK); ++ ++ return ret; ++} ++ ++GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, ++ GST_VERSION_MINOR, ++ gtkwayland, ++ "Gtk+ wayland sink", ++ plugin_init, PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, ++ GST_PACKAGE_ORIGIN) +diff --git a/ext/gtk/gtkgstbasewidget.c b/ext/gtk/gtkgstbasewidget.c +new file mode 100644 +index 0000000..053640b +--- /dev/null ++++ b/ext/gtk/gtkgstbasewidget.c +@@ -0,0 +1,542 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2015 Matthew Waters ++ * ++ * 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 "gtkgstbasewidget.h" ++ ++GST_DEBUG_CATEGORY (gst_debug_gtk_base_widget); ++#define GST_CAT_DEFAULT gst_debug_gtk_base_widget ++ ++#define DEFAULT_FORCE_ASPECT_RATIO TRUE ++#define DEFAULT_PAR_N 0 ++#define DEFAULT_PAR_D 1 ++#define DEFAULT_IGNORE_ALPHA TRUE ++ ++enum ++{ ++ PROP_0, ++ PROP_FORCE_ASPECT_RATIO, ++ PROP_PIXEL_ASPECT_RATIO, ++ PROP_IGNORE_ALPHA, ++}; ++ ++static void ++gtk_gst_base_widget_get_preferred_width (GtkWidget * widget, gint * min, ++ gint * natural) ++{ ++ GtkGstBaseWidget *gst_widget = (GtkGstBaseWidget *) widget; ++ gint video_width = gst_widget->display_width; ++ ++ if (!gst_widget->negotiated) ++ video_width = 10; ++ ++ if (min) ++ *min = 1; ++ if (natural) ++ *natural = video_width; ++} ++ ++static void ++gtk_gst_base_widget_get_preferred_height (GtkWidget * widget, gint * min, ++ gint * natural) ++{ ++ GtkGstBaseWidget *gst_widget = (GtkGstBaseWidget *) widget; ++ gint video_height = gst_widget->display_height; ++ ++ if (!gst_widget->negotiated) ++ video_height = 10; ++ ++ if (min) ++ *min = 1; ++ if (natural) ++ *natural = video_height; ++} ++ ++static void ++gtk_gst_base_widget_set_property (GObject * object, guint prop_id, ++ const GValue * value, GParamSpec * pspec) ++{ ++ GtkGstBaseWidget *gtk_widget = GTK_GST_BASE_WIDGET (object); ++ ++ switch (prop_id) { ++ case PROP_FORCE_ASPECT_RATIO: ++ gtk_widget->force_aspect_ratio = g_value_get_boolean (value); ++ break; ++ case PROP_PIXEL_ASPECT_RATIO: ++ gtk_widget->par_n = gst_value_get_fraction_numerator (value); ++ gtk_widget->par_d = gst_value_get_fraction_denominator (value); ++ break; ++ case PROP_IGNORE_ALPHA: ++ gtk_widget->ignore_alpha = g_value_get_boolean (value); ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static void ++gtk_gst_base_widget_get_property (GObject * object, guint prop_id, ++ GValue * value, GParamSpec * pspec) ++{ ++ GtkGstBaseWidget *gtk_widget = GTK_GST_BASE_WIDGET (object); ++ ++ switch (prop_id) { ++ case PROP_FORCE_ASPECT_RATIO: ++ g_value_set_boolean (value, gtk_widget->force_aspect_ratio); ++ break; ++ case PROP_PIXEL_ASPECT_RATIO: ++ gst_value_set_fraction (value, gtk_widget->par_n, gtk_widget->par_d); ++ break; ++ case PROP_IGNORE_ALPHA: ++ g_value_set_boolean (value, gtk_widget->ignore_alpha); ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static gboolean ++_calculate_par (GtkGstBaseWidget * widget, GstVideoInfo * info) ++{ ++ gboolean ok; ++ gint width, height; ++ gint par_n, par_d; ++ gint display_par_n, display_par_d; ++ ++ width = GST_VIDEO_INFO_WIDTH (info); ++ height = GST_VIDEO_INFO_HEIGHT (info); ++ ++ par_n = GST_VIDEO_INFO_PAR_N (info); ++ par_d = GST_VIDEO_INFO_PAR_D (info); ++ ++ if (!par_n) ++ par_n = 1; ++ ++ /* get display's PAR */ ++ if (widget->par_n != 0 && widget->par_d != 0) { ++ display_par_n = widget->par_n; ++ display_par_d = widget->par_d; ++ } else { ++ display_par_n = 1; ++ display_par_d = 1; ++ } ++ ++ ++ ok = gst_video_calculate_display_ratio (&widget->display_ratio_num, ++ &widget->display_ratio_den, width, height, par_n, par_d, display_par_n, ++ display_par_d); ++ ++ if (ok) { ++ GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, ++ display_par_d); ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static void ++_apply_par (GtkGstBaseWidget * widget) ++{ ++ guint display_ratio_num, display_ratio_den; ++ gint width, height; ++ ++ width = GST_VIDEO_INFO_WIDTH (&widget->v_info); ++ height = GST_VIDEO_INFO_HEIGHT (&widget->v_info); ++ ++ display_ratio_num = widget->display_ratio_num; ++ display_ratio_den = widget->display_ratio_den; ++ ++ if (height % display_ratio_den == 0) { ++ GST_DEBUG ("keeping video height"); ++ widget->display_width = (guint) ++ gst_util_uint64_scale_int (height, display_ratio_num, ++ display_ratio_den); ++ widget->display_height = height; ++ } else if (width % display_ratio_num == 0) { ++ GST_DEBUG ("keeping video width"); ++ widget->display_width = width; ++ widget->display_height = (guint) ++ gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num); ++ } else { ++ GST_DEBUG ("approximating while keeping video height"); ++ widget->display_width = (guint) ++ gst_util_uint64_scale_int (height, display_ratio_num, ++ display_ratio_den); ++ widget->display_height = height; ++ } ++ ++ GST_DEBUG ("scaling to %dx%d", widget->display_width, widget->display_height); ++} ++ ++static gboolean ++_queue_draw (GtkGstBaseWidget * widget) ++{ ++ GTK_GST_BASE_WIDGET_LOCK (widget); ++ widget->draw_id = 0; ++ ++ if (widget->pending_resize) { ++ widget->pending_resize = FALSE; ++ ++ widget->v_info = widget->pending_v_info; ++ widget->negotiated = TRUE; ++ ++ _apply_par (widget); ++ ++ gtk_widget_queue_resize (GTK_WIDGET (widget)); ++ } else { ++ gtk_widget_queue_draw (GTK_WIDGET (widget)); ++ } ++ ++ GTK_GST_BASE_WIDGET_UNLOCK (widget); ++ ++ return G_SOURCE_REMOVE; ++} ++ ++static const gchar * ++_gdk_key_to_navigation_string (guint keyval) ++{ ++ /* TODO: expand */ ++ switch (keyval) { ++#define KEY(key) case GDK_KEY_ ## key: return G_STRINGIFY(key) ++ KEY (Up); ++ KEY (Down); ++ KEY (Left); ++ KEY (Right); ++ KEY (Home); ++ KEY (End); ++#undef KEY ++ default: ++ return NULL; ++ } ++} ++ ++static gboolean ++gtk_gst_base_widget_key_event (GtkWidget * widget, GdkEventKey * event) ++{ ++ GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); ++ GstElement *element; ++ ++ if ((element = g_weak_ref_get (&base_widget->element))) { ++ if (GST_IS_NAVIGATION (element)) { ++ const gchar *str = _gdk_key_to_navigation_string (event->keyval); ++ const gchar *key_type = ++ event->type == GDK_KEY_PRESS ? "key-press" : "key-release"; ++ ++ if (!str) ++ str = event->string; ++ ++ gst_navigation_send_key_event (GST_NAVIGATION (element), key_type, str); ++ } ++ g_object_unref (element); ++ } ++ ++ return FALSE; ++} ++ ++static void ++_fit_stream_to_allocated_size (GtkGstBaseWidget * base_widget, ++ GtkAllocation * allocation, GstVideoRectangle * result) ++{ ++ if (base_widget->force_aspect_ratio) { ++ GstVideoRectangle src, dst; ++ ++ src.x = 0; ++ src.y = 0; ++ src.w = base_widget->display_width; ++ src.h = base_widget->display_height; ++ ++ dst.x = 0; ++ dst.y = 0; ++ dst.w = allocation->width; ++ dst.h = allocation->height; ++ ++ gst_video_sink_center_rect (src, dst, result, TRUE); ++ } else { ++ result->x = 0; ++ result->y = 0; ++ result->w = allocation->width; ++ result->h = allocation->height; ++ } ++} ++ ++void ++gtk_gst_base_widget_display_size_to_stream_size (GtkGstBaseWidget * base_widget, ++ gdouble x, gdouble y, gdouble * stream_x, gdouble * stream_y) ++{ ++ gdouble stream_width, stream_height; ++ GtkAllocation allocation; ++ GstVideoRectangle result; ++ ++ gtk_widget_get_allocation (GTK_WIDGET (base_widget), &allocation); ++ _fit_stream_to_allocated_size (base_widget, &allocation, &result); ++ ++ stream_width = (gdouble) GST_VIDEO_INFO_WIDTH (&base_widget->v_info); ++ stream_height = (gdouble) GST_VIDEO_INFO_HEIGHT (&base_widget->v_info); ++ ++ /* from display coordinates to stream coordinates */ ++ if (result.w > 0) ++ *stream_x = (x - result.x) / result.w * stream_width; ++ else ++ *stream_x = 0.; ++ ++ /* clip to stream size */ ++ if (*stream_x < 0.) ++ *stream_x = 0.; ++ if (*stream_x > GST_VIDEO_INFO_WIDTH (&base_widget->v_info)) ++ *stream_x = GST_VIDEO_INFO_WIDTH (&base_widget->v_info); ++ ++ /* same for y-axis */ ++ if (result.h > 0) ++ *stream_y = (y - result.y) / result.h * stream_height; ++ else ++ *stream_y = 0.; ++ ++ if (*stream_y < 0.) ++ *stream_y = 0.; ++ if (*stream_y > GST_VIDEO_INFO_HEIGHT (&base_widget->v_info)) ++ *stream_y = GST_VIDEO_INFO_HEIGHT (&base_widget->v_info); ++ ++ GST_TRACE ("transform %fx%f into %fx%f", x, y, *stream_x, *stream_y); ++} ++ ++static gboolean ++gtk_gst_base_widget_button_event (GtkWidget * widget, GdkEventButton * event) ++{ ++ GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); ++ GstElement *element; ++ ++ if ((element = g_weak_ref_get (&base_widget->element))) { ++ if (GST_IS_NAVIGATION (element)) { ++ const gchar *key_type = ++ event->type == ++ GDK_BUTTON_PRESS ? "mouse-button-press" : "mouse-button-release"; ++ gst_navigation_send_mouse_event (GST_NAVIGATION (element), key_type, ++ event->button, event->x, event->y); ++ } ++ g_object_unref (element); ++ } ++ ++ return FALSE; ++} ++ ++static gboolean ++gtk_gst_base_widget_motion_event (GtkWidget * widget, GdkEventMotion * event) ++{ ++ GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); ++ GstElement *element; ++ ++ if ((element = g_weak_ref_get (&base_widget->element))) { ++ if (GST_IS_NAVIGATION (element)) { ++ gst_navigation_send_mouse_event (GST_NAVIGATION (element), "mouse-move", ++ 0, event->x, event->y); ++ } ++ g_object_unref (element); ++ } ++ ++ return FALSE; ++} ++ ++static gboolean ++gtk_gst_base_widget_scroll_event (GtkWidget * widget, GdkEventScroll * event) ++{ ++#if GST_CHECK_VERSION(1, 18, 0) ++ GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); ++ GstElement *element; ++ ++ if ((element = g_weak_ref_get (&base_widget->element))) { ++ if (GST_IS_NAVIGATION (element)) { ++ gdouble x, y, delta_x, delta_y; ++ ++ gtk_gst_base_widget_display_size_to_stream_size (base_widget, event->x, ++ event->y, &x, &y); ++ ++ if (!gdk_event_get_scroll_deltas ((GdkEvent *) event, &delta_x, &delta_y)) { ++ gdouble offset = 20; ++ ++ delta_x = event->delta_x; ++ delta_y = event->delta_y; ++ ++ switch (event->direction) { ++ case GDK_SCROLL_UP: ++ delta_y = offset; ++ break; ++ case GDK_SCROLL_DOWN: ++ delta_y = -offset; ++ break; ++ case GDK_SCROLL_LEFT: ++ delta_x = -offset; ++ break; ++ case GDK_SCROLL_RIGHT: ++ delta_x = offset; ++ break; ++ default: ++ break; ++ } ++ } ++ gst_navigation_send_mouse_scroll_event (GST_NAVIGATION (element), ++ x, y, delta_x, delta_y); ++ } ++ g_object_unref (element); ++ } ++#endif ++ return FALSE; ++} ++ ++ ++void ++gtk_gst_base_widget_class_init (GtkGstBaseWidgetClass * klass) ++{ ++ GObjectClass *gobject_klass = (GObjectClass *) klass; ++ GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass; ++ ++ gobject_klass->set_property = gtk_gst_base_widget_set_property; ++ gobject_klass->get_property = gtk_gst_base_widget_get_property; ++ ++ g_object_class_install_property (gobject_klass, PROP_FORCE_ASPECT_RATIO, ++ g_param_spec_boolean ("force-aspect-ratio", ++ "Force aspect ratio", ++ "When enabled, scaling will respect original aspect ratio", ++ DEFAULT_FORCE_ASPECT_RATIO, ++ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); ++ ++ g_object_class_install_property (gobject_klass, PROP_PIXEL_ASPECT_RATIO, ++ gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio", ++ "The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D, ++ G_MAXINT, 1, 1, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); ++ ++ g_object_class_install_property (gobject_klass, PROP_IGNORE_ALPHA, ++ g_param_spec_boolean ("ignore-alpha", "Ignore Alpha", ++ "When enabled, alpha will be ignored and converted to black", ++ DEFAULT_IGNORE_ALPHA, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); ++ ++ widget_klass->get_preferred_width = gtk_gst_base_widget_get_preferred_width; ++ widget_klass->get_preferred_height = gtk_gst_base_widget_get_preferred_height; ++ widget_klass->key_press_event = gtk_gst_base_widget_key_event; ++ widget_klass->key_release_event = gtk_gst_base_widget_key_event; ++ widget_klass->button_press_event = gtk_gst_base_widget_button_event; ++ widget_klass->button_release_event = gtk_gst_base_widget_button_event; ++ widget_klass->motion_notify_event = gtk_gst_base_widget_motion_event; ++ widget_klass->scroll_event = gtk_gst_base_widget_scroll_event; ++ ++ GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_widget, "gtkbasewidget", 0, ++ "Gtk Video Base Widget"); ++} ++ ++void ++gtk_gst_base_widget_init (GtkGstBaseWidget * widget) ++{ ++ int event_mask; ++ ++ widget->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; ++ widget->par_n = DEFAULT_PAR_N; ++ widget->par_d = DEFAULT_PAR_D; ++ widget->ignore_alpha = DEFAULT_IGNORE_ALPHA; ++ ++ gst_video_info_init (&widget->v_info); ++ gst_video_info_init (&widget->pending_v_info); ++ ++ g_weak_ref_init (&widget->element, NULL); ++ g_mutex_init (&widget->lock); ++ ++ gtk_widget_set_can_focus (GTK_WIDGET (widget), TRUE); ++ event_mask = gtk_widget_get_events (GTK_WIDGET (widget)); ++ event_mask |= GDK_KEY_PRESS_MASK ++ | GDK_KEY_RELEASE_MASK ++ | GDK_BUTTON_PRESS_MASK ++ | GDK_BUTTON_RELEASE_MASK ++ | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_SCROLL_MASK; ++ gtk_widget_set_events (GTK_WIDGET (widget), event_mask); ++} ++ ++void ++gtk_gst_base_widget_finalize (GObject * object) ++{ ++ GtkGstBaseWidget *widget = GTK_GST_BASE_WIDGET (object); ++ ++ gst_buffer_replace (&widget->pending_buffer, NULL); ++ gst_buffer_replace (&widget->buffer, NULL); ++ g_mutex_clear (&widget->lock); ++ g_weak_ref_clear (&widget->element); ++ ++ if (widget->draw_id) ++ g_source_remove (widget->draw_id); ++} ++ ++void ++gtk_gst_base_widget_set_element (GtkGstBaseWidget * widget, ++ GstElement * element) ++{ ++ g_weak_ref_set (&widget->element, element); ++} ++ ++gboolean ++gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget, ++ GstVideoInfo * v_info) ++{ ++ GTK_GST_BASE_WIDGET_LOCK (widget); ++ ++ if (gst_video_info_is_equal (&widget->pending_v_info, v_info)) { ++ GTK_GST_BASE_WIDGET_UNLOCK (widget); ++ return TRUE; ++ } ++ ++ if (!_calculate_par (widget, v_info)) { ++ GTK_GST_BASE_WIDGET_UNLOCK (widget); ++ return FALSE; ++ } ++ ++ widget->pending_resize = TRUE; ++ widget->pending_v_info = *v_info; ++ ++ if (!widget->draw_id) { ++ widget->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT, ++ (GSourceFunc) _queue_draw, widget, NULL); ++ } ++ ++ GTK_GST_BASE_WIDGET_UNLOCK (widget); ++ ++ return TRUE; ++} ++ ++void ++gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer * buffer) ++{ ++ /* As we have no type, this is better then no check */ ++ g_return_if_fail (GTK_IS_WIDGET (widget)); ++ ++ GTK_GST_BASE_WIDGET_LOCK (widget); ++ ++ gst_buffer_replace (&widget->pending_buffer, buffer); ++ ++ if (!widget->draw_id) { ++ widget->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT, ++ (GSourceFunc) _queue_draw, widget, NULL); ++ } ++ ++ GTK_GST_BASE_WIDGET_UNLOCK (widget); ++} +diff --git a/ext/gtk/gtkgstbasewidget.h b/ext/gtk/gtkgstbasewidget.h +new file mode 100644 +index 0000000..c10ed38 +--- /dev/null ++++ b/ext/gtk/gtkgstbasewidget.h +@@ -0,0 +1,100 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2015 Matthew Waters ++ * ++ * 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. ++ */ ++ ++#ifndef __GTK_GST_BASE_WIDGET_H__ ++#define __GTK_GST_BASE_WIDGET_H__ ++ ++#include ++#include ++#include ++ ++#define GTK_GST_BASE_WIDGET(w) ((GtkGstBaseWidget *)(w)) ++#define GTK_GST_BASE_WIDGET_CLASS(k) ((GtkGstBaseWidgetClass *)(k)) ++#define GTK_GST_BASE_WIDGET_LOCK(w) g_mutex_lock(&((GtkGstBaseWidget*)(w))->lock) ++#define GTK_GST_BASE_WIDGET_UNLOCK(w) g_mutex_unlock(&((GtkGstBaseWidget*)(w))->lock) ++ ++G_BEGIN_DECLS ++ ++typedef struct _GtkGstBaseWidget GtkGstBaseWidget; ++typedef struct _GtkGstBaseWidgetClass GtkGstBaseWidgetClass; ++ ++struct _GtkGstBaseWidget ++{ ++ union { ++ GtkDrawingArea drawing_area; ++#if GTK_CHECK_VERSION(3, 15, 0) ++ GtkGLArea gl_area; ++#endif ++ } parent; ++ ++ /* properties */ ++ gboolean force_aspect_ratio; ++ gint par_n, par_d; ++ gboolean ignore_alpha; ++ ++ gint display_width; ++ gint display_height; ++ ++ gboolean negotiated; ++ GstBuffer *pending_buffer; ++ GstBuffer *buffer; ++ GstVideoInfo v_info; ++ ++ /* resize */ ++ gboolean pending_resize; ++ GstVideoInfo pending_v_info; ++ guint display_ratio_num; ++ guint display_ratio_den; ++ ++ /*< private >*/ ++ GMutex lock; ++ GWeakRef element; ++ ++ /* Pending draw idles callback */ ++ guint draw_id; ++}; ++ ++struct _GtkGstBaseWidgetClass ++{ ++ union { ++ GtkDrawingAreaClass drawing_area_class; ++#if GTK_CHECK_VERSION(3, 15, 0) ++ GtkGLAreaClass gl_area_class; ++#endif ++ } parent_class; ++}; ++ ++/* For implementer */ ++void gtk_gst_base_widget_class_init (GtkGstBaseWidgetClass * klass); ++void gtk_gst_base_widget_init (GtkGstBaseWidget * widget); ++ ++void gtk_gst_base_widget_finalize (GObject * object); ++ ++/* API */ ++gboolean gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget, GstVideoInfo * v_info); ++void gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer * buffer); ++void gtk_gst_base_widget_set_element (GtkGstBaseWidget * widget, GstElement * element); ++void gtk_gst_base_widget_display_size_to_stream_size (GtkGstBaseWidget * base_widget, ++ gdouble x, gdouble y, ++ gdouble * stream_x, gdouble * stream_y); ++ ++G_END_DECLS ++ ++#endif /* __GTK_GST_BASE_WIDGET_H__ */ +diff --git a/ext/gtk/gtkgstwaylandwidget.c b/ext/gtk/gtkgstwaylandwidget.c +new file mode 100644 +index 0000000..df3d1d5 +--- /dev/null ++++ b/ext/gtk/gtkgstwaylandwidget.c +@@ -0,0 +1,67 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2015 Matthew Waters ++ * ++ * 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 "gtkgstwaylandwidget.h" ++#include ++ ++/** ++ * SECTION:gtkgstwidget ++ * @title: GtkGstWaylandWidget ++ * @short_description: a #GtkWidget that renders GStreamer video #GstBuffers ++ * @see_also: #GtkDrawingArea, #GstBuffer ++ * ++ * #GtkGstWaylandWidget is an #GtkWidget that renders GStreamer video buffers. ++ */ ++ ++G_DEFINE_TYPE (GtkGstWaylandWidget, gtk_gst_wayland_widget, ++ GTK_TYPE_DRAWING_AREA); ++ ++static void ++gtk_gst_wayland_widget_finalize (GObject * object) ++{ ++ gtk_gst_base_widget_finalize (object); ++ ++ G_OBJECT_CLASS (gtk_gst_wayland_widget_parent_class)->finalize (object); ++} ++ ++static void ++gtk_gst_wayland_widget_class_init (GtkGstWaylandWidgetClass * klass) ++{ ++ GObjectClass *gobject_klass = (GObjectClass *) klass; ++ ++ gtk_gst_base_widget_class_init (GTK_GST_BASE_WIDGET_CLASS (klass)); ++ gobject_klass->finalize = gtk_gst_wayland_widget_finalize; ++} ++ ++static void ++gtk_gst_wayland_widget_init (GtkGstWaylandWidget * widget) ++{ ++ gtk_gst_base_widget_init (GTK_GST_BASE_WIDGET (widget)); ++} ++ ++GtkWidget * ++gtk_gst_wayland_widget_new (void) ++{ ++ return (GtkWidget *) g_object_new (GTK_TYPE_GST_WAYLAND_WIDGET, NULL); ++} +diff --git a/ext/gtk/gtkgstwaylandwidget.h b/ext/gtk/gtkgstwaylandwidget.h +new file mode 100644 +index 0000000..48cfe9e +--- /dev/null ++++ b/ext/gtk/gtkgstwaylandwidget.h +@@ -0,0 +1,68 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2015 Matthew Waters ++ * ++ * 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. ++ */ ++ ++#ifndef __GTK_GST_WAYLAND_WIDGET_H__ ++#define __GTK_GST_WAYLAND_WIDGET_H__ ++ ++#include ++#include ++ ++#include "gtkgstbasewidget.h" ++ ++G_BEGIN_DECLS ++ ++GType gtk_gst_wayland_widget_get_type (void); ++#define GTK_TYPE_GST_WAYLAND_WIDGET (gtk_gst_wayland_widget_get_type()) ++#define GTK_GST_WAYLAND_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GTK_TYPE_GST_WAYLAND_WIDGET,GtkGstWaylandWidget)) ++#define GTK_GST_WAYLAND_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GTK_TYPE_GST_WAYLAND_WIDGET,GtkGstWaylandWidgetClass)) ++#define GTK_IS_GST_WAYLAND_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GTK_TYPE_GST_WAYLAND_WIDGET)) ++#define GTK_IS_GST_WAYLAND_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GTK_TYPE_GST_WAYLAND_WIDGET)) ++#define GTK_GST_WAYLAND_WIDGET_CAST(obj) ((GtkGstWaylandWidget*)(obj)) ++ ++typedef struct _GtkGstWaylandWidget GtkGstWaylandWidget; ++typedef struct _GtkGstWaylandWidgetClass GtkGstWaylandWidgetClass; ++ ++/** ++ * GtkGstWaylandWidget: ++ * ++ * Opaque #GtkGstWaylandWidget object ++ */ ++struct _GtkGstWaylandWidget ++{ ++ /* */ ++ GtkGstBaseWidget base; ++}; ++ ++/** ++ * GtkGstWaylandWidgetClass: ++ * ++ * The #GtkGstWaylandWidgetClass struct only contains private data ++ */ ++struct _GtkGstWaylandWidgetClass ++{ ++ /* */ ++ GtkGstBaseWidgetClass base_class; ++}; ++ ++GtkWidget * gtk_gst_wayland_widget_new (void); ++ ++G_END_DECLS ++ ++#endif /* __GTK_GST_WAYLAND_WIDGET_H__ */ +diff --git a/ext/gtk/meson.build b/ext/gtk/meson.build +new file mode 100644 +index 0000000..199188d +--- /dev/null ++++ b/ext/gtk/meson.build +@@ -0,0 +1,22 @@ ++gtkwayland_sources = [ ++ 'gstplugin.c', ++ 'gstgtkutils.c', ++ 'gstgtkwaylandsink.c', ++ 'gtkgstbasewidget.c', ++ 'gtkgstwaylandwidget.c', ++] ++ ++gtk_dep = dependency('gtk+-3.0', required : get_option('gtk3')) ++gtk_wayland_dep = dependency('gtk+-wayland-3.0', required : get_option('gtk3')) ++ ++if gtk_dep.found() and gtk_wayland_dep.found() and use_wayland ++ gstgtkwayland = library('gstgtkwayland', ++ gtkwayland_sources, ++ c_args : gst_plugins_bad_args + ['-DGST_USE_UNSTABLE_API'], ++ include_directories : [configinc], ++ dependencies : [gtk_dep, gstvideo_dep, gstwayland_dep], ++ install : true, ++ install_dir : plugins_install_dir, ++ ) ++ pkgconfig.generate(gstgtkwayland, install_dir : plugins_pkgconfig_install_dir) ++endif +diff --git a/ext/meson.build b/ext/meson.build +index 1e40ace..17195f8 100644 +--- a/ext/meson.build ++++ b/ext/meson.build +@@ -21,6 +21,7 @@ subdir('fluidsynth') + subdir('gme') + subdir('gs') + subdir('gsm') ++subdir('gtk') + subdir('hls') + subdir('iqa') + subdir('isac') +diff --git a/meson_options.txt b/meson_options.txt +index b347dcb..c64f292 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -29,6 +29,7 @@ option('frei0r', type : 'feature', value : 'auto') + option('gaudieffects', type : 'feature', value : 'auto') + option('gdp', type : 'feature', value : 'auto') + option('geometrictransform', type : 'feature', value : 'auto') ++option('gtk3', type : 'feature', value : 'auto') + option('id3tag', type : 'feature', value : 'auto') + option('inter', type : 'feature', value : 'auto') + option('interlace', type : 'feature', value : 'auto') +-- +2.34.1 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad_1.20.2.bbappend b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad_1.20.2.bbappend new file mode 100644 index 000000000..a092505b3 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad_1.20.2.bbappend @@ -0,0 +1,39 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" + +SRC_URI:append = " \ + file://0001-waylandsink-add-dmabuf-bufferpool.patch \ + file://0002-waylandsink-fix-error-when-mmapping-dmabuf-buffers.patch \ + file://0003-waylandsink-fix-wrong-width-when-creating-dmabuf-dum.patch \ + file://0004-waylandsink-do-not-hardcode-dmabuf-bufferpool-info-s.patch \ + file://0005-waylandsink-increase-max-buffers-to-32-to-enable-dma.patch \ + file://0006-waylandsink-always-select-dmabuf-buffer-pool.patch \ + file://0007-waylandsink-do-not-destroy-pool-twice.patch \ + file://0008-waylandsink-HACK-disable-frame-dropping-while-redraw.patch \ + file://0009-waylandsink-Uprank-to-secondary.patch \ + file://0010-waylandsink-set-video-alignment-to-32-bytes.patch \ + file://0011-waylandsink-fallback-to-shm-if-display-does-not-supp.patch \ + file://0012-waylandsink-XDG-protocol-does-not-work-in-fullscreen.patch \ + file://0013-waylandsink-silently-drop-erroneous-frame.patch \ + file://0014-waylandsink-add-waylandpool-on-meson-build.patch \ + \ + file://0016-Add-new-gtkwaylandsink-element.patch \ +" + +PACKAGECONFIG_GL ?= "${@bb.utils.contains('DISTRO_FEATURES', 'opengl', 'gles2 egl', '', d)}" +PACKAGECONFIG[gtk3] = "-Dgtk3=enabled,-Dgtk3=disabled,gtk+3" + +PACKAGECONFIG ?= " \ + ${GSTREAMER_ORC} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'bluetooth', 'bluez', '', d)} \ + ${@bb.utils.filter('DISTRO_FEATURES', 'directfb vulkan', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'wayland', 'wayland gtk3', '', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'opengl', 'gl', '', d)} \ + bz2 closedcaption curl dash dtls hls rsvg sbc smoothstreaming sndfile \ + ttml uvch264 webp \ + kms \ +" + +do_install:append() { + install -d ${D}${includedir}/gstreamer-1.0/wayland + install -m 644 ${S}/gst-libs/gst/wayland/wayland.h ${D}${includedir}/gstreamer-1.0/wayland +} diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0001-playbin2-disable-any-default-video-processing.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0001-playbin2-disable-any-default-video-processing.patch new file mode 100644 index 000000000..9f4b0f523 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0001-playbin2-disable-any-default-video-processing.patch @@ -0,0 +1,32 @@ +From a698ef5806e50b614f49decb4eb2a2b4404f56e5 Mon Sep 17 00:00:00 2001 +From: Hugues Fruchet +Date: Wed, 23 Jan 2019 14:18:28 +0100 +Subject: [PATCH 1/2] playbin2: disable any default video processing + +Do not enable by default software video processing +to not degrade performances. + +Signed-off-by: Hugues Fruchet +--- + gst/playback/gstplaybin2.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c +index a2e9ed4..4c0163e 100644 +--- a/gst/playback/gstplaybin2.c ++++ b/gst/playback/gstplaybin2.c +@@ -499,9 +499,8 @@ struct _GstPlayBinClass + #define DEFAULT_URI NULL + #define DEFAULT_SUBURI NULL + #define DEFAULT_SOURCE NULL +-#define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \ +- GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_DEINTERLACE | \ +- GST_PLAY_FLAG_SOFT_COLORBALANCE ++#define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_SOFT_VOLUME ++ + #define DEFAULT_N_VIDEO 0 + #define DEFAULT_CURRENT_VIDEO -1 + #define DEFAULT_N_AUDIO 0 +-- +2.7.4 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0002-playbin3-disable-any-default-video-processing.patch b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0002-playbin3-disable-any-default-video-processing.patch new file mode 100644 index 000000000..b60f281b1 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0002-playbin3-disable-any-default-video-processing.patch @@ -0,0 +1,32 @@ +From 17a847850f31be11c0c98d31cdd4d62856bfa313 Mon Sep 17 00:00:00 2001 +From: Hugues Fruchet +Date: Wed, 23 Jan 2019 14:16:36 +0100 +Subject: [PATCH 2/2] playbin3: disable any default video processing + +Do not enable by default software video processing +to not degrade performances. + +Signed-off-by: Hugues Fruchet +--- + gst/playback/gstplaybin3.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/gst/playback/gstplaybin3.c b/gst/playback/gstplaybin3.c +index 027766b..9103cb1 100644 +--- a/gst/playback/gstplaybin3.c ++++ b/gst/playback/gstplaybin3.c +@@ -520,9 +520,8 @@ struct _GstPlayBin3Class + /* props */ + #define DEFAULT_URI NULL + #define DEFAULT_SUBURI NULL +-#define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \ +- GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_DEINTERLACE | \ +- GST_PLAY_FLAG_SOFT_COLORBALANCE | GST_PLAY_FLAG_BUFFERING ++#define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | \ ++ GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_BUFFERING + #define DEFAULT_CURRENT_VIDEO -1 + #define DEFAULT_CURRENT_AUDIO -1 + #define DEFAULT_CURRENT_TEXT -1 +-- +2.7.4 + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base_1.20.2.bbappend b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base_1.20.2.bbappend new file mode 100644 index 000000000..e557486c3 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base_1.20.2.bbappend @@ -0,0 +1,27 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}/:" + +SRC_URI:append = " file://0001-playbin2-disable-any-default-video-processing.patch " +SRC_URI:append = " file://0002-playbin3-disable-any-default-video-processing.patch " + +PACKAGECONFIG ?= " \ + ${GSTREAMER_ORC} \ + ${PACKAGECONFIG_GL} \ + ${@bb.utils.filter('DISTRO_FEATURES', 'alsa x11', d)} \ + jpeg ogg pango png theora vorbis \ + ${@bb.utils.contains('DISTRO_FEATURES', 'wayland', 'wayland egl', '', d)} \ + encoding \ +" + +PACKAGECONFIG[encoding] = "-Dencoding=enabled,-Dencoding=disabled," + +#enable hardware convert/scale in playbin (gstsubtitleoverlay.c, gstplaysinkvideoconvert.c, gstplaysink.c) & gstencodebin (gstencodebin.c) +#disable software convert/scale/rate in gstencodebin (gstencodebin.c) +#HW_TRANSFORM_CONFIG = 'CFLAGS="-DCOLORSPACE=\\\\\\"autovideoconvert\\\\\\" \ +# -DCOLORSPACE_SUBT=\\\\\\"videoconvert\\\\\\" \ +# -DGST_PLAYBIN_DEFAULT_FLAGS=0x00000017 \ +# -DCOLORSPACE2=\\\\\\"identity\\\\\\" \ +# -DVIDEOSCALE=\\\\\\"identity\\\\\\" \ +# -DVIDEORATE=\\\\\\"identity\\\\\\" "' + +#CACHED_CONFIGUREVARS += "${@bb.utils.contains('DISTRO_FEATURES', 'hwdecode', '${HW_TRANSFORM_CONFIG}', '', d)}" + diff --git a/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-good_1.20.2.bbappend b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-good_1.20.2.bbappend new file mode 100644 index 000000000..d6ce07961 --- /dev/null +++ b/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-good_1.20.2.bbappend @@ -0,0 +1,19 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}/:" + +PACKAGECONFIG ?= " \ + ${GSTREAMER_ORC} \ + ${@bb.utils.filter('DISTRO_FEATURES', 'pulseaudio x11', d)} \ + bz2 cairo flac gdk-pixbuf gudev jpeg lame libpng mpg123 soup speex taglib v4l2 \ + libv4l2 \ + ${@bb.utils.contains_any('DISTRO_FEATURES', '${GTK3DISTROFEATURES}', 'gtk', '', d)} \ +" + +EXTRA_OEMESON += " \ + -Dv4l2-probe=enabled \ + -Dv4l2-libv4l2=enabled \ + " + +# remove qt5 for the moment +PACKAGECONFIG:remove = " qt5" + +RDEPENDS:${PN}-soup += "libsoup-2.4"