From 3e0a0e05555e49d0a7066d15738eb0f9aa440dd4 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Sun, 1 May 2022 17:04:35 +0200 Subject: [PATCH] plugin: Add GL memory importer Add "clapperglimporter" and a base class for creating GL importers. This module allows importing GL memory into GdkTexture. --- .../importers/gstclapperglbaseimporter.c | 549 ++++++++++++++++++ .../importers/gstclapperglbaseimporter.h | 75 +++ .../plugin/importers/gstclapperglimporter.c | 70 +++ .../plugin/importers/gstclapperglimporter.h | 36 ++ lib/gst/plugin/importers/meson.build | 72 +++ meson_options.txt | 5 + 6 files changed, 807 insertions(+) create mode 100644 lib/gst/plugin/importers/gstclapperglbaseimporter.c create mode 100644 lib/gst/plugin/importers/gstclapperglbaseimporter.h create mode 100644 lib/gst/plugin/importers/gstclapperglimporter.c create mode 100644 lib/gst/plugin/importers/gstclapperglimporter.h diff --git a/lib/gst/plugin/importers/gstclapperglbaseimporter.c b/lib/gst/plugin/importers/gstclapperglbaseimporter.c new file mode 100644 index 00000000..4c29fd0a --- /dev/null +++ b/lib/gst/plugin/importers/gstclapperglbaseimporter.c @@ -0,0 +1,549 @@ +/* + * Copyright (C) 2022 Rafał Dzięgiel + * + * 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 "gstclapperglbaseimporter.h" +#include "gst/plugin/gstgdkformats.h" +#include "gst/plugin/gstgtkutils.h" + +#include + +#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_WAYLAND +#include +#include +#endif + +#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11 +#include +#endif +#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_GLX +#include +#endif +#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_EGL +#include +#endif + +#define GST_CAT_DEFAULT gst_clapper_gl_base_importer_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +#define parent_class gst_clapper_gl_base_importer_parent_class +G_DEFINE_TYPE (GstClapperGLBaseImporter, gst_clapper_gl_base_importer, GST_TYPE_CLAPPER_IMPORTER); + +static GstGLContext * +wrap_current_gl (GstGLDisplay *display, GdkGLAPI gdk_gl_api, GstGLPlatform platform) +{ + GstGLAPI gst_gl_api = GST_GL_API_NONE; + + switch (gdk_gl_api) { + case GDK_GL_API_GL: + gst_gl_api = GST_GL_API_OPENGL | GST_GL_API_OPENGL3; + break; + case GDK_GL_API_GLES: + gst_gl_api = GST_GL_API_GLES2; + break; + default: + g_assert_not_reached (); + break; + } + + if (gst_gl_api != GST_GL_API_NONE) { + guintptr gl_handle; + + gst_gl_display_filter_gl_api (display, gst_gl_api); + + if ((gl_handle = gst_gl_context_get_current_gl_context (platform))) + return gst_gl_context_new_wrapped (display, gl_handle, platform, gst_gl_api); + } + + return NULL; +} + +static gboolean +retrieve_gl_context_on_main (GstClapperGLBaseImporter *self) +{ + GstClapperGLBaseImporterClass *gl_bi_class = GST_CLAPPER_GL_BASE_IMPORTER_GET_CLASS (self); + GdkDisplay *gdk_display; + GdkGLContext *gdk_context; + GError *error = NULL; + GdkGLAPI gdk_gl_api; + GstGLPlatform platform = GST_GL_PLATFORM_NONE; + gint gl_major = 0, gl_minor = 0; + + if (!gtk_init_check ()) { + GST_ERROR_OBJECT (self, "Could not ensure GTK initialization"); + return FALSE; + } + + /* Make sure we are clean here, otherwise data sharing + * between GL-based importers may lead to leaks */ + gst_clear_object (&self->wrapped_context); + g_clear_object (&self->gdk_context); + gst_clear_object (&self->gst_display); + + gdk_display = gdk_display_get_default (); + + if (!(gdk_context = gdk_display_create_gl_context (gdk_display, &error))) { + GST_ERROR_OBJECT (self, "Error creating Gdk GL context: %s", + error ? error->message : "No error set by Gdk"); + g_clear_error (&error); + + return FALSE; + } + + if (!gl_bi_class->gdk_context_realize (self, gdk_context)) { + GST_ERROR_OBJECT (self, "Could not realize Gdk context: %" GST_PTR_FORMAT, + gdk_context); + g_object_unref (gdk_context); + + return FALSE; + } + gdk_gl_api = gdk_gl_context_get_api (gdk_context); + + GST_OBJECT_LOCK (self); + + self->gdk_context = gdk_context; + +#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_WAYLAND + if (GDK_IS_WAYLAND_DISPLAY (gdk_display)) { + struct wl_display *wayland_display = + gdk_wayland_display_get_wl_display (gdk_display); + self->gst_display = (GstGLDisplay *) + gst_gl_display_wayland_new_with_display (wayland_display); + } +#endif + +#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11 + if (GDK_IS_X11_DISPLAY (gdk_display)) { + gpointer display_ptr; +#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_EGL + display_ptr = gdk_x11_display_get_egl_display (gdk_display); + if (display_ptr) { + self->gst_display = (GstGLDisplay *) + gst_gl_display_egl_new_with_egl_display (display_ptr); + } +#endif +#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_GLX + if (!self->gst_display) { + display_ptr = gdk_x11_display_get_xdisplay (gdk_display); + self->gst_display = (GstGLDisplay *) + gst_gl_display_x11_new_with_display (display_ptr); + } + } +#endif +#endif + + /* Fallback to generic display */ + if (G_UNLIKELY (!self->gst_display)) { + GST_WARNING_OBJECT (self, "Unknown Gdk display!"); + self->gst_display = gst_gl_display_new (); + } + +#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_WAYLAND + if (GST_IS_GL_DISPLAY_WAYLAND (self->gst_display)) { + platform = GST_GL_PLATFORM_EGL; + GST_INFO_OBJECT (self, "Using EGL on Wayland"); + goto have_display; + } +#endif +#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_EGL + if (GST_IS_GL_DISPLAY_EGL (self->gst_display)) { + platform = GST_GL_PLATFORM_EGL; + GST_INFO_OBJECT (self, "Using EGL on x11"); + goto have_display; + } +#endif +#if GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_GLX + if (GST_IS_GL_DISPLAY_X11 (self->gst_display)) { + platform = GST_GL_PLATFORM_GLX; + GST_INFO_OBJECT (self, "Using GLX on x11"); + goto have_display; + } +#endif + + g_clear_object (&self->gdk_context); + gst_clear_object (&self->gst_display); + + GST_OBJECT_UNLOCK (self); + + GST_ERROR_OBJECT (self, "Unsupported GL platform"); + return FALSE; + +have_display: + gdk_gl_context_make_current (self->gdk_context); + + self->wrapped_context = wrap_current_gl (self->gst_display, gdk_gl_api, platform); + if (!self->wrapped_context) { + GST_ERROR ("Could not retrieve Gdk OpenGL context"); + gdk_gl_context_clear_current (); + + g_clear_object (&self->gdk_context); + gst_clear_object (&self->gst_display); + + GST_OBJECT_UNLOCK (self); + + return FALSE; + } + + GST_INFO ("Retrieved Gdk OpenGL context %" GST_PTR_FORMAT, self->wrapped_context); + gst_gl_context_activate (self->wrapped_context, TRUE); + + if (!gst_gl_context_fill_info (self->wrapped_context, &error)) { + GST_ERROR ("Failed to fill Gdk context info: %s", error->message); + g_clear_error (&error); + + gst_gl_context_activate (self->wrapped_context, FALSE); + + gst_clear_object (&self->wrapped_context); + g_clear_object (&self->gdk_context); + gst_clear_object (&self->gst_display); + + GST_OBJECT_UNLOCK (self); + + return FALSE; + } + + gst_gl_context_get_gl_version (self->wrapped_context, &gl_major, &gl_minor); + GST_INFO ("Using OpenGL%s %i.%i", (gdk_gl_api == GDK_GL_API_GLES) ? " ES" : "", + gl_major, gl_minor); + + /* Deactivate in both places */ + gst_gl_context_activate (self->wrapped_context, FALSE); + gdk_gl_context_clear_current (); + + GST_OBJECT_UNLOCK (self); + + return TRUE; +} + +static gboolean +retrieve_gst_context (GstClapperGLBaseImporter *self) +{ + GstGLDisplay *gst_display = NULL; + GstGLContext *gst_context = NULL; + GError *error = NULL; + + GST_OBJECT_LOCK (self); + + gst_display = gst_object_ref (self->gst_display); + + /* GstGLDisplay operations require display object lock to be held */ + GST_OBJECT_LOCK (gst_display); + + if (!self->gst_context) { + GST_TRACE_OBJECT (self, "Creating new GstGLContext"); + + if (!gst_gl_display_create_context (gst_display, self->wrapped_context, + &self->gst_context, &error)) { + GST_WARNING ("Could not create OpenGL context: %s", + error ? error->message : "Unknown"); + g_clear_error (&error); + + GST_OBJECT_UNLOCK (gst_display); + GST_OBJECT_UNLOCK (self); + + return FALSE; + } + } + + gst_context = gst_object_ref (self->gst_context); + + GST_OBJECT_UNLOCK (self); + + gst_gl_display_add_context (gst_display, gst_context); + + GST_OBJECT_UNLOCK (gst_display); + + gst_object_unref (gst_display); + gst_object_unref (gst_context); + + return TRUE; +} + +static gboolean +gst_clapper_gl_base_importer_prepare (GstClapperImporter *importer) +{ + GstClapperGLBaseImporter *self = GST_CLAPPER_GL_BASE_IMPORTER_CAST (importer); + gboolean need_invoke; + + GST_OBJECT_LOCK (self); + need_invoke = (!self->gdk_context || !self->gst_display || !self->wrapped_context); + GST_OBJECT_UNLOCK (self); + + if (need_invoke) { + if (!(! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback) + retrieve_gl_context_on_main, self))) + return FALSE; + } + + if (!retrieve_gst_context (self)) + return FALSE; + + if (!GST_CLAPPER_IMPORTER_CLASS (parent_class)->prepare) + return TRUE; + + return GST_CLAPPER_IMPORTER_CLASS (parent_class)->prepare (importer); +} + +static void +gst_clapper_gl_base_importer_share_data (GstClapperImporter *importer, GstClapperImporter *dest_importer) +{ + GstClapperGLBaseImporter *self = GST_CLAPPER_GL_BASE_IMPORTER (importer); + + if (GST_IS_CLAPPER_GL_BASE_IMPORTER (dest_importer)) { + GstClapperGLBaseImporter *dest = GST_CLAPPER_GL_BASE_IMPORTER (dest_importer); + + GST_OBJECT_LOCK (self); + GST_OBJECT_LOCK (dest); + + /* Successfully prepared GL importer should have all three */ + if (self->gdk_context && self->gst_display && self->wrapped_context) { + g_clear_object (&dest->gdk_context); + dest->gdk_context = g_object_ref (self->gdk_context); + + gst_clear_object (&dest->gst_display); + dest->gst_display = gst_object_ref (self->gst_display); + + gst_clear_object (&dest->wrapped_context); + dest->wrapped_context = gst_object_ref (self->wrapped_context); + } + + /* This context is not required, we can create it ourselves + * using gst_display and wrapped_context */ + if (self->gst_context) { + gst_clear_object (&dest->gst_context); + dest->gst_context = gst_object_ref (self->gst_context); + } + + GST_OBJECT_UNLOCK (dest); + GST_OBJECT_UNLOCK (self); + } + + if (GST_CLAPPER_IMPORTER_CLASS (parent_class)->share_data) + GST_CLAPPER_IMPORTER_CLASS (parent_class)->share_data (importer, dest_importer); +} + +static gboolean +gst_clapper_gl_base_importer_handle_context_query (GstClapperImporter *importer, + GstBaseSink *bsink, GstQuery *query) +{ + GstClapperGLBaseImporter *self = GST_CLAPPER_GL_BASE_IMPORTER_CAST (importer); + gboolean res; + + GST_OBJECT_LOCK (self); + res = gst_gl_handle_context_query (GST_ELEMENT_CAST (bsink), query, + self->gst_display, self->gst_context, self->wrapped_context); + GST_OBJECT_UNLOCK (self); + + return res; +} + +static GstBufferPool * +gst_clapper_gl_base_importer_create_pool (GstClapperImporter *importer, GstStructure **config) +{ + GstClapperGLBaseImporter *self = GST_CLAPPER_GL_BASE_IMPORTER_CAST (importer); + GstBufferPool *pool; + + GST_DEBUG_OBJECT (self, "Creating new GL buffer pool"); + + GST_OBJECT_LOCK (self); + pool = gst_gl_buffer_pool_new (self->gst_context); + GST_OBJECT_UNLOCK (self); + + *config = gst_buffer_pool_get_config (pool); + + gst_buffer_pool_config_add_option (*config, GST_BUFFER_POOL_OPTION_VIDEO_META); + gst_buffer_pool_config_add_option (*config, GST_BUFFER_POOL_OPTION_GL_SYNC_META); + + return pool; +} + +static void +gst_clapper_gl_base_importer_add_allocation_metas (GstClapperImporter *importer, GstQuery *query) +{ + GstClapperGLBaseImporter *self = GST_CLAPPER_GL_BASE_IMPORTER_CAST (importer); + + gst_query_add_allocation_meta (query, GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL); + gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); + + GST_OBJECT_LOCK (self); + if (self->gst_context->gl_vtable->FenceSync) + gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, NULL); + GST_OBJECT_UNLOCK (self); +} + +static gboolean +gst_clapper_gl_base_importer_gdk_context_realize (GstClapperGLBaseImporter *self, GdkGLContext *gdk_context) +{ + GdkGLAPI allowed_apis; + GError *error = NULL; + const gchar *gl_env; + gboolean success; + + GST_DEBUG_OBJECT (self, "Realizing GdkGLContext with default implementation"); + + /* Use single "GST_GL_API" env to also influence Gdk GL selection */ + gl_env = g_getenv ("GST_GL_API"); + allowed_apis = (!gl_env || g_str_has_prefix (gl_env, "gles")) + ? GDK_GL_API_GLES + : (g_str_has_prefix (gl_env, "opengl")) + ? GDK_GL_API_GL + : GDK_GL_API_GL | GDK_GL_API_GLES; + + gdk_gl_context_set_allowed_apis (gdk_context, allowed_apis); + if (!(success = gdk_gl_context_realize (gdk_context, &error))) { + GST_WARNING_OBJECT (self, "Could not realize Gdk context with %s: %s", + (allowed_apis & GDK_GL_API_GL) ? "GL" : "GLES", error->message); + g_clear_error (&error); + } + if (!success && !gl_env) { + gdk_gl_context_set_allowed_apis (gdk_context, GDK_GL_API_GL); + if (!(success = gdk_gl_context_realize (gdk_context, &error))) { + GST_WARNING_OBJECT (self, "Could not realize Gdk context with GL: %s", error->message); + g_clear_error (&error); + } + } + + return success; +} + +static void +gst_clapper_gl_base_importer_init (GstClapperGLBaseImporter *self) +{ +} + +static void +gst_clapper_gl_base_importer_finalize (GObject *object) +{ + GstClapperGLBaseImporter *self = GST_CLAPPER_GL_BASE_IMPORTER_CAST (object); + + g_clear_object (&self->gdk_context); + + gst_clear_object (&self->gst_display); + gst_clear_object (&self->wrapped_context); + gst_clear_object (&self->gst_context); + + GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +static void +gst_clapper_gl_base_importer_class_init (GstClapperGLBaseImporterClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstClapperImporterClass *importer_class = (GstClapperImporterClass *) klass; + GstClapperGLBaseImporterClass *gl_bi_class = (GstClapperGLBaseImporterClass *) klass; + + GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperglbaseimporter", 0, + "Clapper GL Base Importer"); + + gobject_class->finalize = gst_clapper_gl_base_importer_finalize; + + importer_class->prepare = gst_clapper_gl_base_importer_prepare; + importer_class->share_data = gst_clapper_gl_base_importer_share_data; + importer_class->handle_context_query = gst_clapper_gl_base_importer_handle_context_query; + importer_class->create_pool = gst_clapper_gl_base_importer_create_pool; + importer_class->add_allocation_metas = gst_clapper_gl_base_importer_add_allocation_metas; + + gl_bi_class->gdk_context_realize = gst_clapper_gl_base_importer_gdk_context_realize; +} + +GstCaps * +gst_clapper_gl_base_importer_make_supported_gdk_gl_caps (void) +{ + GstCaps *caps, *tmp; + + tmp = gst_caps_from_string ( + GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, + "{ " GST_GDK_GL_TEXTURE_FORMATS " }") ", " + "texture-target = (string) { " GST_GL_TEXTURE_TARGET_2D_STR " }"); + + caps = gst_caps_copy (tmp); + gst_caps_set_features_simple (caps, gst_caps_features_new ( + GST_CAPS_FEATURE_MEMORY_GL_MEMORY, + GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, NULL)); + + gst_caps_append (caps, tmp); + + return caps; +} + +GStrv +gst_clapper_gl_base_importer_make_gl_context_types (void) +{ + GStrv context_types; + GStrvBuilder *builder = g_strv_builder_new (); + + g_strv_builder_add (builder, GST_GL_DISPLAY_CONTEXT_TYPE); + g_strv_builder_add (builder, "gst.gl.app_context"); + g_strv_builder_add (builder, "gst.gl.local_context"); + + context_types = g_strv_builder_end (builder); + g_strv_builder_unref (builder); + + return context_types; +} + +GdkTexture * +gst_clapper_gl_base_importer_make_gl_texture (GstClapperGLBaseImporter *self, + GstBuffer *buffer, GstVideoInfo *v_info) +{ + GdkTexture *texture; + GstGLSyncMeta *sync_meta; + GstVideoFrame frame; + + if (G_UNLIKELY (!gst_video_frame_map (&frame, v_info, buffer, GST_MAP_READ | GST_MAP_GL))) { + GST_ERROR_OBJECT (self, "Could not map input buffer for reading"); + return NULL; + } + + GST_OBJECT_LOCK (self); + + /* Must have context active here for both sync meta + * and Gdk texture format auto-detection to work */ + gdk_gl_context_make_current (self->gdk_context); + gst_gl_context_activate (self->wrapped_context, TRUE); + + sync_meta = gst_buffer_get_gl_sync_meta (buffer); + + /* Wait for all previous OpenGL commands to complete, + * before we start using the input texture */ + if (sync_meta) { + gst_gl_sync_meta_set_sync_point (sync_meta, self->gst_context); + gst_gl_sync_meta_wait (sync_meta, self->wrapped_context); + } + + texture = gdk_gl_texture_new ( + self->gdk_context, + *(guint *) GST_VIDEO_FRAME_PLANE_DATA (&frame, 0), + GST_VIDEO_FRAME_WIDTH (&frame), + GST_VIDEO_FRAME_HEIGHT (&frame), + (GDestroyNotify) gst_buffer_unref, + gst_buffer_ref (buffer)); + + gst_gl_context_activate (self->wrapped_context, FALSE); + gdk_gl_context_clear_current (); + + GST_OBJECT_UNLOCK (self); + + gst_video_frame_unmap (&frame); + + return texture; +} diff --git a/lib/gst/plugin/importers/gstclapperglbaseimporter.h b/lib/gst/plugin/importers/gstclapperglbaseimporter.h new file mode 100644 index 00000000..79fda32c --- /dev/null +++ b/lib/gst/plugin/importers/gstclapperglbaseimporter.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2022 Rafał Dzięgiel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include + +#include "gst/plugin/gstclapperimporter.h" + +G_BEGIN_DECLS + +#define GST_TYPE_CLAPPER_GL_BASE_IMPORTER (gst_clapper_gl_base_importer_get_type()) +#define GST_IS_CLAPPER_GL_BASE_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CLAPPER_GL_BASE_IMPORTER)) +#define GST_IS_CLAPPER_GL_BASE_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CLAPPER_GL_BASE_IMPORTER)) +#define GST_CLAPPER_GL_BASE_IMPORTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CLAPPER_GL_BASE_IMPORTER, GstClapperGLBaseImporterClass)) +#define GST_CLAPPER_GL_BASE_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CLAPPER_GL_BASE_IMPORTER, GstClapperGLBaseImporter)) +#define GST_CLAPPER_GL_BASE_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CLAPPER_GL_BASE_IMPORTER, GstClapperGLBaseImporterClass)) +#define GST_CLAPPER_GL_BASE_IMPORTER_CAST(obj) ((GstClapperGLBaseImporter *)(obj)) + +#define GST_CLAPPER_GL_BASE_IMPORTER_HAVE_WAYLAND (GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND)) +#define GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11 (GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11)) +#define GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_GLX (GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11 && GST_GL_HAVE_PLATFORM_GLX) +#define GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11_EGL (GST_CLAPPER_GL_BASE_IMPORTER_HAVE_X11 && GST_GL_HAVE_PLATFORM_EGL) + +typedef struct _GstClapperGLBaseImporter GstClapperGLBaseImporter; +typedef struct _GstClapperGLBaseImporterClass GstClapperGLBaseImporterClass; + +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstClapperGLBaseImporter, gst_object_unref) +#endif + +struct _GstClapperGLBaseImporter +{ + GstClapperImporter parent; + + GdkGLContext *gdk_context; + + GstGLDisplay *gst_display; + GstGLContext *wrapped_context; + GstGLContext *gst_context; +}; + +struct _GstClapperGLBaseImporterClass +{ + GstClapperImporterClass parent_class; + + gboolean (* gdk_context_realize) (GstClapperGLBaseImporter *gl_bi, + GdkGLContext *gdk_context); +}; + +GType gst_clapper_gl_base_importer_get_type (void); + +GstCaps * gst_clapper_gl_base_importer_make_supported_gdk_gl_caps (void); + +GStrv gst_clapper_gl_base_importer_make_gl_context_types (void); + +GdkTexture * gst_clapper_gl_base_importer_make_gl_texture (GstClapperGLBaseImporter *self, GstBuffer *buffer, GstVideoInfo *v_info); + +G_END_DECLS diff --git a/lib/gst/plugin/importers/gstclapperglimporter.c b/lib/gst/plugin/importers/gstclapperglimporter.c new file mode 100644 index 00000000..9cdfcbee --- /dev/null +++ b/lib/gst/plugin/importers/gstclapperglimporter.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2022 Rafał Dzięgiel + * + * 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 "gstclapperglimporter.h" + +#define GST_CAT_DEFAULT gst_clapper_gl_importer_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +#define parent_class gst_clapper_gl_importer_parent_class +GST_CLAPPER_IMPORTER_DEFINE (GstClapperGLImporter, gst_clapper_gl_importer, GST_TYPE_CLAPPER_GL_BASE_IMPORTER); + +static GdkTexture * +gst_clapper_gl_importer_generate_texture (GstClapperImporter *importer, + GstBuffer *buffer, GstVideoInfo *v_info) +{ + GstClapperGLBaseImporter *gl_bi = GST_CLAPPER_GL_BASE_IMPORTER_CAST (importer); + + return gst_clapper_gl_base_importer_make_gl_texture (gl_bi, buffer, v_info); +} + +static void +gst_clapper_gl_importer_init (GstClapperGLImporter *self) +{ +} + +static void +gst_clapper_gl_importer_class_init (GstClapperGLImporterClass *klass) +{ + GstClapperImporterClass *importer_class = (GstClapperImporterClass *) klass; + + GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperglimporter", 0, + "Clapper GL Importer"); + + importer_class->generate_texture = gst_clapper_gl_importer_generate_texture; +} + +GstClapperImporter * +make_importer (void) +{ + return g_object_new (GST_TYPE_CLAPPER_GL_IMPORTER, NULL); +} + +GstCaps * +make_caps (GstRank *rank, GStrv *context_types) +{ + *rank = GST_RANK_SECONDARY; + *context_types = gst_clapper_gl_base_importer_make_gl_context_types (); + + return gst_clapper_gl_base_importer_make_supported_gdk_gl_caps (); +} diff --git a/lib/gst/plugin/importers/gstclapperglimporter.h b/lib/gst/plugin/importers/gstclapperglimporter.h new file mode 100644 index 00000000..7c9cb3d3 --- /dev/null +++ b/lib/gst/plugin/importers/gstclapperglimporter.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 Rafał Dzięgiel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "gstclapperglbaseimporter.h" + +G_BEGIN_DECLS + +#define GST_TYPE_CLAPPER_GL_IMPORTER (gst_clapper_gl_importer_get_type()) +G_DECLARE_FINAL_TYPE (GstClapperGLImporter, gst_clapper_gl_importer, GST, CLAPPER_GL_IMPORTER, GstClapperGLBaseImporter) + +#define GST_CLAPPER_GL_IMPORTER_CAST(obj) ((GstClapperGLImporter *)(obj)) + +struct _GstClapperGLImporter +{ + GstClapperGLBaseImporter parent; +}; + +G_END_DECLS diff --git a/lib/gst/plugin/importers/meson.build b/lib/gst/plugin/importers/meson.build index 2796afce..a8daaaa8 100644 --- a/lib/gst/plugin/importers/meson.build +++ b/lib/gst/plugin/importers/meson.build @@ -1,3 +1,5 @@ +gst_clapper_gl_base_importer_dep = dependency('', required: false) + if not get_option('rawimporter').disabled() library( 'gstclapperrawimporter', @@ -9,3 +11,73 @@ if not get_option('rawimporter').disabled() install_dir: gst_clapper_importers_libdir, ) endif + +plugin_needs_gl_base = ( + not get_option('glimporter').disabled() +) + +gst_plugin_gl_deps = [gstgl_dep, gstglproto_dep] +have_gtk_gl_windowing = false + +if gst_gl_have_window_x11 and (gst_gl_have_platform_egl or gst_gl_have_platform_glx) + gtk_x11_dep = dependency('gtk4-x11', required: false) + if gtk_x11_dep.found() + gst_plugin_gl_deps += gtk_x11_dep + if gst_gl_have_platform_glx + gst_plugin_gl_deps += gstglx11_dep + endif + have_gtk_gl_windowing = true + endif +endif + +if gst_gl_have_window_wayland and gst_gl_have_platform_egl + gtk_wayland_dep = dependency('gtk4-wayland', required: false) + if gtk_wayland_dep.found() + gst_plugin_gl_deps += [gtk_wayland_dep, gstglwayland_dep] + have_gtk_gl_windowing = true + endif +endif + +if gst_gl_have_platform_egl + gst_plugin_gl_deps += gstglegl_dep +endif + +gst_clapper_gl_base_importer_deps = [ + gst_clapper_sink_dep +] + gst_plugin_gl_deps + +foreach dep : gst_clapper_gl_base_importer_deps + if not dep.found() or not have_gtk_gl_windowing + if get_option('glimporter').enabled() + error('GL importer was enabled, but required dependencies were not found') + endif + plugin_needs_gl_base = false + endif +endforeach + +if plugin_needs_gl_base + gst_clapper_gl_base_importer_dep = declare_dependency( + link_with: library('gstclapperglbaseimporter', + 'gstclapperglbaseimporter.c', + c_args: gst_clapper_plugin_args, + include_directories: configinc, + dependencies: gst_clapper_gl_base_importer_deps, + version: libversion, + install: true, + ), + include_directories: configinc, + dependencies: gst_clapper_gl_base_importer_deps, + ) +endif + +if not get_option('glimporter').disabled() and gst_clapper_gl_base_importer_dep.found() + library( + 'gstclapperglimporter', + 'gstclapperglimporter.c', + dependencies: gst_clapper_gl_base_importer_dep, + include_directories: configinc, + c_args: gst_clapper_plugin_args, + install: true, + install_dir: gst_clapper_importers_libdir, + ) +endif diff --git a/meson_options.txt b/meson_options.txt index 87c8eec1..a5fc377b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -19,6 +19,11 @@ option('rawimporter', value: 'auto', description: 'Build RAW system memory importer for clappersink' ) +option('glimporter', + type: 'feature', + value: 'auto', + description: 'Build GL memory importer for clappersink' +) option('devel-checks', type: 'boolean',