From 188b626ffcd784d3dcf01214ad861ee6f4531252 Mon Sep 17 00:00:00 2001 From: Jakub Adam Date: Fri, 27 Sep 2024 14:17:34 +0200 Subject: [PATCH] gldownload: import DMABufs from downstream pool * if downstream provides us with a pool that can allocate DMA buffers, gldownload wraps it into a GL buffer pool that uses glEGLImageTargetTexture2DOES() to import dmabuf into textures * upstream GL elements can allocate from that pool * gldownload unwraps DMA buffers from incoming GL buffers and passes them downstream Part-of: --- .../ext/gl/gstgldmabufbufferpool.c | 422 ++++++++++++++++++ .../ext/gl/gstgldmabufbufferpool.h | 61 +++ .../ext/gl/gstgldownloadelement.c | 158 ++++++- .../ext/gl/gstgldownloadelement.h | 1 + .../gst-plugins-base/ext/gl/meson.build | 6 + 5 files changed, 630 insertions(+), 18 deletions(-) create mode 100644 subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.c create mode 100644 subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.h diff --git a/subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.c b/subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.c new file mode 100644 index 0000000000..7eb6f94726 --- /dev/null +++ b/subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.c @@ -0,0 +1,422 @@ +/* + * GStreamer + * Copyright © 2024 Advanced Micro Devices, Inc. + * + * 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 +#include +#include +#include +#include +#include + +#define GST_GL_DMABUF_EGLIMAGE "gst.gl.dmabuf.eglimage" + +typedef struct _GstGLDMABufBufferPoolPrivate +{ + GstBufferPool *dmabuf_pool; + GstGLMemoryAllocator *allocator; + GstGLVideoAllocationParams *glparams; + + gboolean add_glsyncmeta; +} GstGLDMABufBufferPoolPrivate; + +GST_DEBUG_CATEGORY_STATIC (GST_CAT_GL_DMABUF_BUFFER_POOL); +#define GST_CAT_DEFAULT GST_CAT_GL_DMABUF_BUFFER_POOL + +#define gst_gl_dmabuf_buffer_pool_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstGLDMABufBufferPool, gst_gl_dmabuf_buffer_pool, + GST_TYPE_GL_BUFFER_POOL, G_ADD_PRIVATE (GstGLDMABufBufferPool) + GST_DEBUG_CATEGORY_INIT (GST_CAT_GL_DMABUF_BUFFER_POOL, + "gldmabufbufferpool", 0, "GL-DMABuf Buffer Pool")); + +static gboolean +gst_gl_dmabuf_buffer_pool_set_config (GstBufferPool * pool, + GstStructure * config) +{ + GstGLDMABufBufferPool *self = GST_GL_DMABUF_BUFFER_POOL (pool); + + GstAllocator *allocator = NULL; + GstAllocationParams alloc_params; + GstGLAllocationParams *glparams; + GstVideoAlignment video_align = { 0 }; + GstCaps *caps; + guint size; + guint min; + guint max; + guint i; + + if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min, &max)) { + goto wrong_config; + } + + if (!gst_buffer_pool_config_get_allocator (config, &allocator, &alloc_params)) { + goto wrong_config; + } + + gst_clear_object (&self->priv->allocator); + + if (allocator) { + if (!GST_IS_GL_MEMORY_ALLOCATOR (allocator)) { + gst_clear_object (&allocator); + goto wrong_allocator; + } else { + self->priv->allocator = gst_object_ref (allocator); + } + } else { + self->priv->allocator = + gst_gl_memory_allocator_get_default (GST_GL_BUFFER_POOL + (pool)->context); + } + + /* + * This alignment is needed by nearly all AMD GPUs and should work fine on + * Mali as well. To my knowledge there is no API to query it at runtime, so + * it has to be hardcoded here. Users of the pool can still override the + * values with GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT added to the config. + */ + for (i = 0; i != GST_VIDEO_MAX_PLANES; ++i) { + video_align.stride_align[i] = 256 - 1; + } + + if (!gst_buffer_pool_config_has_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) { + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); + gst_buffer_pool_config_set_video_alignment (config, &video_align); + } + + gst_buffer_pool_config_get_video_alignment (config, &video_align); + alloc_params.align = MAX (alloc_params.align, video_align.stride_align[0]); + + gst_buffer_pool_config_set_allocator (config, allocator, &alloc_params); + + glparams = gst_buffer_pool_config_get_gl_allocation_params (config); + if (glparams) { + g_clear_pointer (&glparams->alloc_params, gst_allocation_params_free); + glparams->alloc_params = gst_allocation_params_copy (&alloc_params); + gst_buffer_pool_config_set_gl_allocation_params (config, glparams); + g_clear_pointer (&glparams, gst_gl_allocation_params_free); + } + + self->priv->add_glsyncmeta = gst_buffer_pool_config_has_option (config, + GST_BUFFER_POOL_OPTION_GL_SYNC_META); + + if (!GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config)) { + return FALSE; + } + + g_clear_pointer ((GstGLAllocationParams **) & self->priv->glparams, + gst_gl_allocation_params_free); + self->priv->glparams = (GstGLVideoAllocationParams *) + gst_gl_buffer_pool_get_gl_allocation_params (GST_GL_BUFFER_POOL (pool)); + + self->priv->glparams->parent.alloc_flags |= + GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE; + + /* Now configure the dma-buf pool. */ + + config = gst_buffer_pool_get_config (self->priv->dmabuf_pool); + gst_buffer_pool_config_set_params (config, caps, size, min, max); + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); + gst_buffer_pool_config_set_video_alignment (config, &video_align); + + return gst_buffer_pool_set_config (self->priv->dmabuf_pool, config); + +wrong_config: + { + GST_WARNING_OBJECT (pool, "Incorrect config for this pool"); + return FALSE; + } +wrong_allocator: + { + GST_WARNING_OBJECT (pool, "Incorrect allocator type for this pool"); + return FALSE; + } +} + +static gboolean +gst_gl_dmabuf_buffer_pool_start (GstBufferPool * pool) +{ + GstGLDMABufBufferPool *self = GST_GL_DMABUF_BUFFER_POOL (pool); + + if (!gst_buffer_pool_set_active (self->priv->dmabuf_pool, TRUE)) { + return FALSE; + } + + return GST_BUFFER_POOL_CLASS (parent_class)->start (pool); +} + +static gboolean +gst_gl_dmabuf_buffer_pool_stop (GstBufferPool * pool) +{ + GstGLDMABufBufferPool *self = GST_GL_DMABUF_BUFFER_POOL (pool); + + if (!gst_buffer_pool_set_active (self->priv->dmabuf_pool, FALSE)) { + return FALSE; + } + + return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool); +} + +typedef struct +{ + GstEGLImage *eglimage[GST_VIDEO_MAX_PLANES]; + gpointer gpuhandle[GST_VIDEO_MAX_PLANES]; + guint n_planes; +} WrapDMABufData; + +static void +_wrap_dmabuf_eglimage (GstGLContext * context, gpointer data) +{ + WrapDMABufData *d = data; + const GstGLFuncs *gl = context->gl_vtable; + GLuint tex_ids[GST_VIDEO_MAX_PLANES]; + guint i; + + gl->GenTextures (d->n_planes, tex_ids); + + for (i = 0; i < d->n_planes; ++i) { + gl->BindTexture (GL_TEXTURE_2D, tex_ids[i]); + gl->EGLImageTargetTexture2D (GL_TEXTURE_2D, + gst_egl_image_get_image (d->eglimage[i])); + + d->gpuhandle[i] = GUINT_TO_POINTER (tex_ids[i]); + } +} + +static GstFlowReturn +gst_gl_dmabuf_buffer_pool_alloc_buffer (GstBufferPool * pool, + GstBuffer ** buffer, GstBufferPoolAcquireParams * params) +{ + GstGLDMABufBufferPool *self = GST_GL_DMABUF_BUFFER_POOL (pool); + GstGLBufferPool *glpool = GST_GL_BUFFER_POOL (pool); + + GstBuffer *buf; + + if (!(buf = gst_buffer_new ())) { + goto no_buffer; + } + + if (self->priv->add_glsyncmeta) { + gst_buffer_add_gl_sync_meta (glpool->context, buf); + } + + *buffer = buf; + + return GST_FLOW_OK; + + /* ERROR */ +no_buffer: + { + GST_WARNING_OBJECT (self, "Could not create DMABuf buffer"); + return GST_FLOW_ERROR; + } +} + +static GstFlowReturn +gst_gl_dmabuf_buffer_pool_acquire_buffer (GstBufferPool * pool, + GstBuffer ** buffer, GstBufferPoolAcquireParams * params) +{ + GstGLDMABufBufferPool *self = GST_GL_DMABUF_BUFFER_POOL (pool); + GstGLBufferPool *glpool = GST_GL_BUFFER_POOL (pool); + + GstVideoInfo *v_info = self->priv->glparams->v_info; + GstFlowReturn ret; + GstBuffer *dmabuf; + GstBuffer *buf; + WrapDMABufData data; + guint i; + + ret = gst_buffer_pool_acquire_buffer (self->priv->dmabuf_pool, &dmabuf, NULL); + if (ret != GST_FLOW_OK) { + goto no_buffer; + } + + data.n_planes = GST_VIDEO_INFO_N_PLANES (v_info); + + for (i = 0; i < data.n_planes; ++i) { + guint mem_idx, length; + gsize skip; + GstMemory *dmabufmem; + + if (!gst_buffer_find_memory (dmabuf, GST_VIDEO_INFO_PLANE_OFFSET (v_info, + i), 1, &mem_idx, &length, &skip)) { + GST_WARNING_OBJECT (self, "Could not find memory for plane %d", i); + return GST_FLOW_ERROR; + } + + dmabufmem = gst_buffer_peek_memory (dmabuf, mem_idx); + + g_assert (gst_is_dmabuf_memory (dmabufmem)); + + data.eglimage[i] = gst_egl_image_from_dmabuf (glpool->context, + gst_dmabuf_memory_get_fd (dmabufmem), v_info, i, skip); + } + + gst_gl_context_thread_add (glpool->context, _wrap_dmabuf_eglimage, &data); + + ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (pool, &buf, + params); + if (ret != GST_FLOW_OK) { + return GST_FLOW_ERROR; + } + + if (!gst_gl_memory_setup_buffer (self->priv->allocator, buf, + self->priv->glparams, NULL, data.gpuhandle, data.n_planes)) { + goto mem_create_failed; + } + + for (i = 0; i < data.n_planes; ++i) { + GstMemory *mem = gst_buffer_peek_memory (buf, i); + + /* Unset wrapped flag, we want the texture be freed with the memory. */ + GST_GL_MEMORY_CAST (mem)->texture_wrapped = FALSE; + + gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), + g_quark_from_static_string (GST_GL_DMABUF_EGLIMAGE), + data.eglimage[i], (GDestroyNotify) gst_egl_image_unref); + } + + gst_buffer_add_parent_buffer_meta (buf, dmabuf); + gst_clear_buffer (&dmabuf); + + *buffer = buf; + + return GST_FLOW_OK; + + /* ERROR */ +no_buffer: + { + GST_WARNING_OBJECT (self, "Could not create DMABuf buffer"); + return GST_FLOW_ERROR; + } +mem_create_failed: + { + GST_WARNING_OBJECT (self, "Could not create GL Memory"); + return GST_FLOW_ERROR; + } +} + +static void +gst_gl_dmabuf_buffer_pool_reset_buffer (GstBufferPool * pool, + GstBuffer * buffer) +{ + gst_buffer_remove_all_memory (buffer); + + GST_BUFFER_POOL_CLASS (parent_class)->reset_buffer (pool, buffer); +} + +gboolean +gst_is_gl_dmabuf_buffer (GstBuffer * buffer) +{ + return GST_IS_GL_DMABUF_BUFFER_POOL (buffer->pool); +} + +GstBuffer * +gst_gl_dmabuf_buffer_unwrap (GstBuffer * buffer) +{ + GstGLDMABufBufferPool *pool; + GstParentBufferMeta *meta; + GstBuffer *wrapped_dmabuf = NULL; + + g_return_val_if_fail (gst_is_gl_dmabuf_buffer (buffer), NULL); + + pool = GST_GL_DMABUF_BUFFER_POOL (buffer->pool); + + if (gst_buffer_peek_memory (buffer, 0)->allocator != + GST_ALLOCATOR (pool->priv->allocator)) { + return NULL; + } + + meta = gst_buffer_get_parent_buffer_meta (buffer); + + if (meta && meta->buffer) { + wrapped_dmabuf = gst_buffer_ref (meta->buffer); + + gst_buffer_remove_meta (buffer, (GstMeta *) meta); + + gst_buffer_copy_into (wrapped_dmabuf, buffer, GST_BUFFER_COPY_FLAGS | + GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META, 0, -1); + } + + return wrapped_dmabuf; +} + +GstBufferPool * +gst_gl_dmabuf_buffer_pool_new (GstGLContext * context, + GstBufferPool * dmabuf_pool) +{ + GstGLDMABufBufferPool *pool; + + pool = g_object_new (GST_TYPE_GL_DMABUF_BUFFER_POOL, NULL); + gst_object_ref_sink (pool); + + GST_GL_BUFFER_POOL (pool)->context = gst_object_ref (context); + + pool->priv->dmabuf_pool = gst_object_ref (dmabuf_pool); + + GST_LOG_OBJECT (pool, "new GL-DMABuf buffer pool for pool %" GST_PTR_FORMAT + " and context %" GST_PTR_FORMAT, dmabuf_pool, context); + + return GST_BUFFER_POOL_CAST (pool); +} + +static void +gst_gl_dmabuf_buffer_pool_init (GstGLDMABufBufferPool * pool) +{ + pool->priv = gst_gl_dmabuf_buffer_pool_get_instance_private (pool); +} + +static void +gst_gl_dmabuf_buffer_pool_finalize (GObject * object) +{ + GstGLDMABufBufferPool *self = GST_GL_DMABUF_BUFFER_POOL (object); + + GST_LOG_OBJECT (self, "finalize GL-DMABuf buffer pool"); + + gst_clear_object (&self->priv->dmabuf_pool); + g_clear_pointer ((GstGLAllocationParams **) & self->priv->glparams, + gst_gl_allocation_params_free); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_gl_dmabuf_buffer_pool_class_init (GstGLDMABufBufferPoolClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass; + + gobject_class->finalize = gst_gl_dmabuf_buffer_pool_finalize; + + gstbufferpool_class->set_config = gst_gl_dmabuf_buffer_pool_set_config; + gstbufferpool_class->alloc_buffer = gst_gl_dmabuf_buffer_pool_alloc_buffer; + gstbufferpool_class->acquire_buffer = + gst_gl_dmabuf_buffer_pool_acquire_buffer; + gstbufferpool_class->reset_buffer = gst_gl_dmabuf_buffer_pool_reset_buffer; + gstbufferpool_class->start = gst_gl_dmabuf_buffer_pool_start; + gstbufferpool_class->stop = gst_gl_dmabuf_buffer_pool_stop; +} diff --git a/subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.h b/subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.h new file mode 100644 index 0000000000..7c75872eea --- /dev/null +++ b/subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.h @@ -0,0 +1,61 @@ +/* + * GStreamer + * Copyright © 2024 Advanced Micro Devices, Inc. + * + * 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_GL_DMABUF_BUFFER_POOL_H_ +#define _GST_GL_DMABUF_BUFFER_POOL_H_ + +#include + +G_BEGIN_DECLS + +typedef struct _GstGLDMABufBufferPoolPrivate GstGLDMABufBufferPoolPrivate; + +/** + * GST_TYPE_GL_DMABUF_BUFFER_POOL: + * + * Since: 1.26 + */ +#define GST_TYPE_GL_DMABUF_BUFFER_POOL (gst_gl_dmabuf_buffer_pool_get_type()) +G_DECLARE_FINAL_TYPE (GstGLDMABufBufferPool, gst_gl_dmabuf_buffer_pool, GST, GL_DMABUF_BUFFER_POOL, GstGLBufferPool) + +/** + * GstGLDMABufBufferPool: + * + * Opaque GstGLDMABufBufferPool struct + * + * Since: 1.26 + */ +struct _GstGLDMABufBufferPool +{ + GstGLBufferPool parent; + + /*< private >*/ + GstGLDMABufBufferPoolPrivate *priv; +}; + +GstBufferPool *gst_gl_dmabuf_buffer_pool_new (GstGLContext * context, GstBufferPool * dmabuf_pool); + +gboolean gst_is_gl_dmabuf_buffer (GstBuffer * buffer); + +GstBuffer *gst_gl_dmabuf_buffer_unwrap (GstBuffer * buffer); + +G_END_DECLS + +#endif /* _GST_GL_DMABUF_BUFFER_POOL_H_ */ diff --git a/subprojects/gst-plugins-base/ext/gl/gstgldownloadelement.c b/subprojects/gst-plugins-base/ext/gl/gstgldownloadelement.c index 1174f2ff64..c14dbae2ed 100644 --- a/subprojects/gst-plugins-base/ext/gl/gstgldownloadelement.c +++ b/subprojects/gst-plugins-base/ext/gl/gstgldownloadelement.c @@ -25,6 +25,7 @@ #include #include #if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF +#include #include #include #endif @@ -899,6 +900,8 @@ gst_gl_download_element_stop (GstBaseTransform * bt) dl->dmabuf_allocator = NULL; } + gst_clear_object (&dl->foreign_dmabuf_pool); + return TRUE; } @@ -939,16 +942,82 @@ gst_gl_download_element_set_caps (GstBaseTransform * bt, GstCaps * in_caps, return TRUE; } -static GstCaps * -_set_caps_features (const GstCaps * caps, const gchar * feature_name) +#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF +static gboolean +_convert_dma_drm (GstGLContext * context, GstStructure * s) { - GstCaps *tmp = gst_caps_copy (caps); - guint n = gst_caps_get_size (tmp); - guint i = 0; + const GValue *fmtval = gst_structure_get_value (s, "format"); - for (i = 0; i < n; i++) - gst_caps_set_features (tmp, i, + if (!fmtval) { + return FALSE; + } + + if (G_VALUE_HOLDS_STRING (fmtval) && + g_str_equal (g_value_get_string (fmtval), "DMA_DRM")) { + const GValue *drmval = gst_structure_get_value (s, "drm-format"); + GValue newfmtval = G_VALUE_INIT; + + if (context && gst_gl_dma_buf_transform_drm_formats_to_gst_formats (context, + drmval, 0, &newfmtval)) { + gst_structure_set_value (s, "format", &newfmtval); + gst_structure_remove_field (s, "drm-format"); + g_value_unset (&newfmtval); + } else { + return FALSE; + } + } else { + GValue drmfmtval = G_VALUE_INIT; + + if (!context) { + gst_structure_remove_field (s, "drm-format"); + } else if (gst_gl_dma_buf_transform_gst_formats_to_drm_formats (context, + fmtval, 0, &drmfmtval)) { + gst_structure_set_value (s, "drm-format", &drmfmtval); + g_value_unset (&drmfmtval); + } else { + return FALSE; + } + + gst_structure_set (s, "format", G_TYPE_STRING, + gst_video_format_to_string (GST_VIDEO_FORMAT_DMA_DRM), NULL); + } + + return TRUE; +} +#endif + +static GstCaps * +_set_caps_features (GstGLContext * context, const GstCaps * caps, + const gchar * feature_name) +{ + GstCaps *tmp = gst_caps_new_empty (); + guint n = gst_caps_get_size (caps); + guint i = 0; +#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF + const gboolean new_feature_is_dmabuf = + g_str_equal (feature_name, GST_CAPS_FEATURE_MEMORY_DMABUF); +#endif + + + for (i = 0; i < n; i++) { + GstStructure *s = gst_structure_copy (gst_caps_get_structure (caps, i)); + +#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF + gboolean old_feature_is_dmabuf = + gst_caps_features_contains (gst_caps_get_features (caps, i), + GST_CAPS_FEATURE_MEMORY_DMABUF); + + if (new_feature_is_dmabuf != old_feature_is_dmabuf) { + if (!_convert_dma_drm (context, s)) { + gst_clear_structure (&s); + continue; + } + } +#endif + + gst_caps_append_structure_full (tmp, s, gst_caps_features_new_single_static_str (feature_name)); + } return tmp; } @@ -969,32 +1038,43 @@ static GstCaps * gst_gl_download_element_transform_caps (GstBaseTransform * bt, GstPadDirection direction, GstCaps * caps, GstCaps * filter) { + GstGLBaseFilter *base_filter = GST_GL_BASE_FILTER (bt); + + GstGLContext *context; GstCaps *result, *tmp; + if (base_filter->display && !gst_gl_base_filter_find_gl_context (base_filter)) + return NULL; + + context = gst_gl_base_filter_get_gl_context (base_filter); + if (direction == GST_PAD_SRC) { - GstCaps *sys_caps = gst_caps_simplify (_set_caps_features (caps, + GstCaps *sys_caps = gst_caps_simplify (_set_caps_features (context, caps, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY)); - tmp = _set_caps_features (sys_caps, GST_CAPS_FEATURE_MEMORY_GL_MEMORY); + tmp = _set_caps_features (context, sys_caps, + GST_CAPS_FEATURE_MEMORY_GL_MEMORY); tmp = gst_caps_merge (tmp, sys_caps); } else { GstCaps *newcaps; tmp = gst_caps_ref (caps); #if GST_GL_HAVE_PLATFORM_EGL && defined(HAVE_NVMM) - newcaps = _set_caps_features (caps, GST_CAPS_FEATURE_MEMORY_NVMM); + newcaps = _set_caps_features (context, caps, GST_CAPS_FEATURE_MEMORY_NVMM); _remove_field (newcaps, "texture-target"); // FIXME: RGBA-only? tmp = gst_caps_merge (tmp, newcaps); #endif #if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF - newcaps = _set_caps_features (caps, GST_CAPS_FEATURE_MEMORY_DMABUF); + newcaps = + _set_caps_features (context, caps, GST_CAPS_FEATURE_MEMORY_DMABUF); _remove_field (newcaps, "texture-target"); tmp = gst_caps_merge (tmp, newcaps); #endif - newcaps = _set_caps_features (caps, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY); + newcaps = _set_caps_features (context, caps, + GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY); _remove_field (newcaps, "texture-target"); tmp = gst_caps_merge (tmp, newcaps); } @@ -1292,6 +1372,16 @@ gst_gl_download_element_prepare_output_buffer (GstBaseTransform * bt, } #endif #if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF + if (gst_is_gl_dmabuf_buffer (inbuf)) { + GstBuffer *wrapped_dmabuf = gst_gl_dmabuf_buffer_unwrap (inbuf); + + if (wrapped_dmabuf) { + *outbuf = wrapped_dmabuf; + + return GST_FLOW_OK; + } + } + if (dl->mode == GST_GL_DOWNLOAD_MODE_DMABUF_EXPORTS) { GstBuffer *buffer = _try_export_dmabuf (dl, inbuf); @@ -1306,14 +1396,15 @@ gst_gl_download_element_prepare_output_buffer (GstBaseTransform * bt, *outbuf = buffer; } else { - GstCaps *src_caps; - GstCapsFeatures *features; + GstCaps *sink_caps, *src_caps; gboolean ret; - src_caps = gst_pad_get_current_caps (bt->srcpad); - src_caps = gst_caps_make_writable (src_caps); - features = gst_caps_get_features (src_caps, 0); - gst_caps_features_remove (features, GST_CAPS_FEATURE_MEMORY_DMABUF); + sink_caps = gst_pad_get_current_caps (bt->sinkpad); + src_caps = _set_caps_features (context, sink_caps, + GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY); + _remove_field (src_caps, "texture-target"); + gst_caps_unref (sink_caps); + g_atomic_int_set (&dl->try_dmabuf_exports, FALSE); dl->mode = GST_GL_DOWNLOAD_MODE_PBO_TRANSFERS; @@ -1374,6 +1465,27 @@ gst_gl_download_element_decide_allocation (GstBaseTransform * trans, download->add_videometa = FALSE; } +#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF + { + GstCaps *caps; + const GstCapsFeatures *features; + + gst_clear_object (&download->foreign_dmabuf_pool); + + gst_query_parse_allocation (query, &caps, NULL); + features = gst_caps_get_features (caps, 0); + + if (gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_DMABUF) && + gst_query_get_n_allocation_pools (query) > 0) { + + gst_query_parse_nth_allocation_pool (query, 0, + &download->foreign_dmabuf_pool, NULL, NULL, NULL); + + gst_query_remove_nth_allocation_pool (query, 0); + } + } +#endif + return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans, query); } @@ -1446,6 +1558,16 @@ gst_gl_download_element_propose_allocation (GstBaseTransform * bt, } } #endif + +#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF + if (!pool && GST_GL_DOWNLOAD_ELEMENT (bt)->foreign_dmabuf_pool) { + pool = gst_gl_dmabuf_buffer_pool_new (context, + GST_GL_DOWNLOAD_ELEMENT (bt)->foreign_dmabuf_pool); + + GST_LOG_OBJECT (bt, "offering dma-buf-backed GL buffer pool"); + } +#endif + if (!pool) { pool = gst_gl_buffer_pool_new (context); } diff --git a/subprojects/gst-plugins-base/ext/gl/gstgldownloadelement.h b/subprojects/gst-plugins-base/ext/gl/gstgldownloadelement.h index 7ae7c44ecd..64017c94d4 100644 --- a/subprojects/gst-plugins-base/ext/gl/gstgldownloadelement.h +++ b/subprojects/gst-plugins-base/ext/gl/gstgldownloadelement.h @@ -54,6 +54,7 @@ struct _GstGLDownloadElement GstGlDownloadMode mode; gboolean try_dmabuf_exports; GstAllocator * dmabuf_allocator; + GstBufferPool * foreign_dmabuf_pool; gboolean add_videometa; }; diff --git a/subprojects/gst-plugins-base/ext/gl/meson.build b/subprojects/gst-plugins-base/ext/gl/meson.build index 743760d837..e38ad88db4 100644 --- a/subprojects/gst-plugins-base/ext/gl/meson.build +++ b/subprojects/gst-plugins-base/ext/gl/meson.build @@ -93,6 +93,12 @@ if png_dep.found() endif endif +if glconf.get('GST_GL_HAVE_DMABUF', 0) == 1 + opengl_sources += [ + 'gstgldmabufbufferpool.c', + ] +endif + if glconf.get('GST_GL_HAVE_WINDOW_COCOA', 0) == 1 corefoundation_dep = dependency('appleframeworks', modules : ['CoreFoundation'], required : false) foundation_dep = dependency('appleframeworks', modules : ['Foundation'], required : false)