mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-05 07:56:35 +00:00
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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6792>
This commit is contained in:
parent
270e186311
commit
188b626ffc
5 changed files with 630 additions and 18 deletions
422
subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.c
Normal file
422
subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.c
Normal file
|
@ -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 <ext/gl/gstgldmabufbufferpool.h>
|
||||||
|
|
||||||
|
#include <gst/allocators/gstdmabuf.h>
|
||||||
|
#include <gst/gl/gstglcontext.h>
|
||||||
|
#include <gst/gl/gstglfuncs.h>
|
||||||
|
#include <gst/gl/gstglmemory.h>
|
||||||
|
#include <gst/gl/gstglsyncmeta.h>
|
||||||
|
#include <gst/gl/egl/gsteglimage.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
61
subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.h
Normal file
61
subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.h
Normal file
|
@ -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 <gst/gl/gstglbufferpool.h>
|
||||||
|
|
||||||
|
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_ */
|
|
@ -25,6 +25,7 @@
|
||||||
#include <gst/gl/gl.h>
|
#include <gst/gl/gl.h>
|
||||||
#include <gst/gl/gstglfuncs.h>
|
#include <gst/gl/gstglfuncs.h>
|
||||||
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
|
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
|
||||||
|
#include <gstgldmabufbufferpool.h>
|
||||||
#include <gst/gl/egl/gsteglimage.h>
|
#include <gst/gl/egl/gsteglimage.h>
|
||||||
#include <gst/allocators/gstdmabuf.h>
|
#include <gst/allocators/gstdmabuf.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -899,6 +900,8 @@ gst_gl_download_element_stop (GstBaseTransform * bt)
|
||||||
dl->dmabuf_allocator = NULL;
|
dl->dmabuf_allocator = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_clear_object (&dl->foreign_dmabuf_pool);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -939,16 +942,82 @@ gst_gl_download_element_set_caps (GstBaseTransform * bt, GstCaps * in_caps,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstCaps *
|
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
|
||||||
_set_caps_features (const GstCaps * caps, const gchar * feature_name)
|
static gboolean
|
||||||
|
_convert_dma_drm (GstGLContext * context, GstStructure * s)
|
||||||
{
|
{
|
||||||
GstCaps *tmp = gst_caps_copy (caps);
|
const GValue *fmtval = gst_structure_get_value (s, "format");
|
||||||
guint n = gst_caps_get_size (tmp);
|
|
||||||
guint i = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
if (!fmtval) {
|
||||||
gst_caps_set_features (tmp, i,
|
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));
|
gst_caps_features_new_single_static_str (feature_name));
|
||||||
|
}
|
||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
@ -969,32 +1038,43 @@ static GstCaps *
|
||||||
gst_gl_download_element_transform_caps (GstBaseTransform * bt,
|
gst_gl_download_element_transform_caps (GstBaseTransform * bt,
|
||||||
GstPadDirection direction, GstCaps * caps, GstCaps * filter)
|
GstPadDirection direction, GstCaps * caps, GstCaps * filter)
|
||||||
{
|
{
|
||||||
|
GstGLBaseFilter *base_filter = GST_GL_BASE_FILTER (bt);
|
||||||
|
|
||||||
|
GstGLContext *context;
|
||||||
GstCaps *result, *tmp;
|
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) {
|
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));
|
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);
|
tmp = gst_caps_merge (tmp, sys_caps);
|
||||||
} else {
|
} else {
|
||||||
GstCaps *newcaps;
|
GstCaps *newcaps;
|
||||||
tmp = gst_caps_ref (caps);
|
tmp = gst_caps_ref (caps);
|
||||||
|
|
||||||
#if GST_GL_HAVE_PLATFORM_EGL && defined(HAVE_NVMM)
|
#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");
|
_remove_field (newcaps, "texture-target");
|
||||||
// FIXME: RGBA-only?
|
// FIXME: RGBA-only?
|
||||||
tmp = gst_caps_merge (tmp, newcaps);
|
tmp = gst_caps_merge (tmp, newcaps);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
|
#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");
|
_remove_field (newcaps, "texture-target");
|
||||||
tmp = gst_caps_merge (tmp, newcaps);
|
tmp = gst_caps_merge (tmp, newcaps);
|
||||||
#endif
|
#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");
|
_remove_field (newcaps, "texture-target");
|
||||||
tmp = gst_caps_merge (tmp, newcaps);
|
tmp = gst_caps_merge (tmp, newcaps);
|
||||||
}
|
}
|
||||||
|
@ -1292,6 +1372,16 @@ gst_gl_download_element_prepare_output_buffer (GstBaseTransform * bt,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
|
#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) {
|
if (dl->mode == GST_GL_DOWNLOAD_MODE_DMABUF_EXPORTS) {
|
||||||
GstBuffer *buffer = _try_export_dmabuf (dl, inbuf);
|
GstBuffer *buffer = _try_export_dmabuf (dl, inbuf);
|
||||||
|
|
||||||
|
@ -1306,14 +1396,15 @@ gst_gl_download_element_prepare_output_buffer (GstBaseTransform * bt,
|
||||||
|
|
||||||
*outbuf = buffer;
|
*outbuf = buffer;
|
||||||
} else {
|
} else {
|
||||||
GstCaps *src_caps;
|
GstCaps *sink_caps, *src_caps;
|
||||||
GstCapsFeatures *features;
|
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
|
|
||||||
src_caps = gst_pad_get_current_caps (bt->srcpad);
|
sink_caps = gst_pad_get_current_caps (bt->sinkpad);
|
||||||
src_caps = gst_caps_make_writable (src_caps);
|
src_caps = _set_caps_features (context, sink_caps,
|
||||||
features = gst_caps_get_features (src_caps, 0);
|
GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
|
||||||
gst_caps_features_remove (features, GST_CAPS_FEATURE_MEMORY_DMABUF);
|
_remove_field (src_caps, "texture-target");
|
||||||
|
gst_caps_unref (sink_caps);
|
||||||
|
|
||||||
g_atomic_int_set (&dl->try_dmabuf_exports, FALSE);
|
g_atomic_int_set (&dl->try_dmabuf_exports, FALSE);
|
||||||
dl->mode = GST_GL_DOWNLOAD_MODE_PBO_TRANSFERS;
|
dl->mode = GST_GL_DOWNLOAD_MODE_PBO_TRANSFERS;
|
||||||
|
|
||||||
|
@ -1374,6 +1465,27 @@ gst_gl_download_element_decide_allocation (GstBaseTransform * trans,
|
||||||
download->add_videometa = FALSE;
|
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,
|
return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
|
||||||
query);
|
query);
|
||||||
}
|
}
|
||||||
|
@ -1446,6 +1558,16 @@ gst_gl_download_element_propose_allocation (GstBaseTransform * bt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
if (!pool) {
|
||||||
pool = gst_gl_buffer_pool_new (context);
|
pool = gst_gl_buffer_pool_new (context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ struct _GstGLDownloadElement
|
||||||
GstGlDownloadMode mode;
|
GstGlDownloadMode mode;
|
||||||
gboolean try_dmabuf_exports;
|
gboolean try_dmabuf_exports;
|
||||||
GstAllocator * dmabuf_allocator;
|
GstAllocator * dmabuf_allocator;
|
||||||
|
GstBufferPool * foreign_dmabuf_pool;
|
||||||
gboolean add_videometa;
|
gboolean add_videometa;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,12 @@ if png_dep.found()
|
||||||
endif
|
endif
|
||||||
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
|
if glconf.get('GST_GL_HAVE_WINDOW_COCOA', 0) == 1
|
||||||
corefoundation_dep = dependency('appleframeworks', modules : ['CoreFoundation'], required : false)
|
corefoundation_dep = dependency('appleframeworks', modules : ['CoreFoundation'], required : false)
|
||||||
foundation_dep = dependency('appleframeworks', modules : ['Foundation'], required : false)
|
foundation_dep = dependency('appleframeworks', modules : ['Foundation'], required : false)
|
||||||
|
|
Loading…
Reference in a new issue