summaryrefslogtreecommitdiff
path: root/gst-libs/gst/gl/gstglupload.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst-libs/gst/gl/gstglupload.c')
-rw-r--r--gst-libs/gst/gl/gstglupload.c267
1 files changed, 266 insertions, 1 deletions
diff --git a/gst-libs/gst/gl/gstglupload.c b/gst-libs/gst/gl/gstglupload.c
index f70fae976..bcb378049 100644
--- a/gst-libs/gst/gl/gstglupload.c
+++ b/gst-libs/gst/gl/gstglupload.c
@@ -31,6 +31,10 @@
#include "egl/gsteglimagememory.h"
#endif
+#if GST_GL_HAVE_DMABUF
+#include <gst/allocators/gstdmabuf.h>
+#endif
+
/**
* SECTION:gstglupload
* @short_description: an object that uploads to GL textures
@@ -544,7 +548,265 @@ static const UploadMethod _egl_image_upload = {
&_egl_image_upload_perform,
&_egl_image_upload_free
};
-#endif
+#endif /* GST_GL_HAVE_PLATFORM_EGL */
+
+#if GST_GL_HAVE_DMABUF
+struct DmabufUpload
+{
+ GstGLUpload *upload;
+
+ GstMemory *eglimage[GST_VIDEO_MAX_PLANES];
+ GstBuffer *outbuf;
+ GstGLVideoAllocationParams *params;
+};
+
+static GstStaticCaps _dma_buf_upload_caps =
+GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_MEMORY_VIDEO_FORMATS_STR));
+
+static gpointer
+_dma_buf_upload_new (GstGLUpload * upload)
+{
+ struct DmabufUpload *dmabuf = g_new0 (struct DmabufUpload, 1);
+ dmabuf->upload = upload;
+ return dmabuf;
+}
+
+static GstCaps *
+_dma_buf_upload_transform_caps (GstGLContext * context,
+ GstPadDirection direction, GstCaps * caps)
+{
+ GstCaps *ret;
+
+ if (direction == GST_PAD_SINK) {
+ ret = _set_caps_features (caps, GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
+ } else {
+ gint i, n;
+
+ ret = _set_caps_features (caps, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
+
+ n = gst_caps_get_size (ret);
+ for (i = 0; i < n; i++) {
+ GstStructure *s = gst_caps_get_structure (ret, i);
+
+ gst_structure_remove_fields (s, "texture-target", NULL);
+ }
+ }
+
+ return ret;
+}
+
+static GQuark
+_eglimage_quark (gint plane)
+{
+ static GQuark quark[4] = { 0 };
+ static const gchar *quark_str[] = {
+ "GstGLDMABufEGLImage0",
+ "GstGLDMABufEGLImage1",
+ "GstGLDMABufEGLImage2",
+ "GstGLDMABufEGLImage3",
+ };
+
+ if (!quark[plane])
+ quark[plane] = g_quark_from_static_string (quark_str[plane]);
+
+ return quark[plane];
+}
+
+static GstMemory *
+_get_cached_eglimage (GstMemory * mem, gint plane)
+{
+ return gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
+ _eglimage_quark (plane));
+}
+
+static void
+_set_cached_eglimage (GstMemory * mem, GstMemory * eglimage, gint plane)
+{
+ return gst_mini_object_set_qdata (GST_MINI_OBJECT (mem),
+ _eglimage_quark (plane), eglimage, (GDestroyNotify) gst_memory_unref);
+}
+
+static gboolean
+_dma_buf_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
+ GstCaps * out_caps)
+{
+ struct DmabufUpload *dmabuf = impl;
+ GstVideoInfo *in_info = &dmabuf->upload->priv->in_info;
+ guint n_planes = GST_VIDEO_INFO_N_PLANES (in_info);
+ GstVideoMeta *meta;
+ guint n_mem;
+ guint mems_idx[GST_VIDEO_MAX_PLANES];
+ gsize mems_skip[GST_VIDEO_MAX_PLANES];
+ GstMemory *mems[GST_VIDEO_MAX_PLANES];
+ guint i;
+
+ n_mem = gst_buffer_n_memory (buffer);
+ meta = gst_buffer_get_video_meta (buffer);
+
+ /* dmabuf upload is only supported with EGL contexts. */
+ if (!GST_IS_GL_CONTEXT_EGL (dmabuf->upload->context))
+ return FALSE;
+
+ if (!gst_gl_context_check_feature (dmabuf->upload->context,
+ "EGL_KHR_image_base"))
+ return FALSE;
+
+ /* This will eliminate most non-dmabuf out there */
+ if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (buffer, 0)))
+ return FALSE;
+
+ /* We cannot have multiple dmabuf per plane */
+ if (n_mem > n_planes)
+ return FALSE;
+
+ /* Update video info based on video meta */
+ if (meta) {
+ in_info->width = meta->width;
+ in_info->height = meta->height;
+
+ for (i = 0; i < meta->n_planes; i++) {
+ in_info->offset[i] = meta->offset[i];
+ in_info->stride[i] = meta->stride[i];
+ }
+ }
+
+ if (dmabuf->params)
+ gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params);
+ if (!(dmabuf->params =
+ gst_gl_video_allocation_params_new (dmabuf->upload->context, NULL,
+ &dmabuf->upload->priv->in_info, -1, NULL,
+ GST_GL_TEXTURE_TARGET_2D)))
+ return FALSE;
+
+ /* Find and validate all memories */
+ for (i = 0; i < n_planes; i++) {
+ guint plane_size;
+ guint length;
+
+ plane_size = gst_gl_get_plane_data_size (in_info, NULL, i);
+
+ if (!gst_buffer_find_memory (buffer, in_info->offset[i], plane_size,
+ &mems_idx[i], &length, &mems_skip[i]))
+ return FALSE;
+
+ /* We can't have more then one dmabuf per plane */
+ if (length != 1)
+ return FALSE;
+
+ mems[i] = gst_buffer_peek_memory (buffer, mems_idx[i]);
+
+ /* And all memory found must be dmabuf */
+ if (!gst_is_dmabuf_memory (mems[i]))
+ return FALSE;
+ }
+
+ /* Now create an EGLImage for each dmabufs */
+ for (i = 0; i < n_planes; i++) {
+ /* check if one is cached */
+ dmabuf->eglimage[i] = _get_cached_eglimage (mems[i], i);
+ if (dmabuf->eglimage[i])
+ continue;
+
+ /* otherwise create one and cache it */
+ dmabuf->eglimage[i] =
+ gst_egl_image_memory_from_dmabuf (dmabuf->upload->context,
+ gst_dmabuf_memory_get_fd (mems[i]), in_info, i, mems_skip[i]);
+
+ if (!dmabuf->eglimage[i])
+ return FALSE;
+
+ _set_cached_eglimage (mems[i], dmabuf->eglimage[i], i);
+ }
+
+ return TRUE;
+}
+
+static void
+_dma_buf_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
+ GstQuery * query)
+{
+ /* nothing to do for now. */
+}
+
+static void
+_dma_buf_upload_perform_gl_thread (GstGLContext * context,
+ struct DmabufUpload *dmabuf)
+{
+ GstGLMemoryAllocator *allocator;
+ guint i, n;
+
+ allocator =
+ GST_GL_MEMORY_ALLOCATOR (gst_allocator_find
+ (GST_GL_MEMORY_PBO_ALLOCATOR_NAME));
+
+ /* FIXME: buffer pool */
+ dmabuf->outbuf = gst_buffer_new ();
+ gst_gl_memory_setup_buffer (allocator, dmabuf->outbuf, dmabuf->params);
+ gst_object_unref (allocator);
+
+ n = gst_buffer_n_memory (dmabuf->outbuf);
+ for (i = 0; i < n; i++) {
+ const GstGLFuncs *gl = NULL;
+ GstGLMemory *gl_mem =
+ (GstGLMemory *) gst_buffer_peek_memory (dmabuf->outbuf, i);
+
+ if (!dmabuf->eglimage[i]) {
+ g_clear_pointer (&dmabuf->outbuf, gst_buffer_unref);
+ return;
+ }
+
+ gl = GST_GL_CONTEXT (((GstEGLImageMemory *) gl_mem)->context)->gl_vtable;
+
+ gl->ActiveTexture (GL_TEXTURE0 + i);
+ gl->BindTexture (GL_TEXTURE_2D, gl_mem->tex_id);
+ gl->EGLImageTargetTexture2D (GL_TEXTURE_2D,
+ gst_egl_image_memory_get_image (dmabuf->eglimage[i]));
+ }
+}
+
+static GstGLUploadReturn
+_dma_buf_upload_perform (gpointer impl, GstBuffer * buffer, GstBuffer ** outbuf)
+{
+ struct DmabufUpload *dmabuf = impl;
+
+ gst_gl_context_thread_add (dmabuf->upload->context,
+ (GstGLContextThreadFunc) _dma_buf_upload_perform_gl_thread, dmabuf);
+
+ if (!dmabuf->outbuf)
+ return GST_GL_UPLOAD_ERROR;
+
+ gst_buffer_add_parent_buffer_meta (dmabuf->outbuf, buffer);
+
+ *outbuf = dmabuf->outbuf;
+ dmabuf->outbuf = NULL;
+
+ return GST_GL_UPLOAD_DONE;
+}
+
+static void
+_dma_buf_upload_free (gpointer impl)
+{
+ struct DmabufUpload *dmabuf = impl;
+
+ if (dmabuf->params)
+ gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params);
+
+ g_free (impl);
+}
+
+static const UploadMethod _dma_buf_upload = {
+ "Dmabuf",
+ 0,
+ &_dma_buf_upload_caps,
+ &_dma_buf_upload_new,
+ &_dma_buf_upload_transform_caps,
+ &_dma_buf_upload_accept,
+ &_dma_buf_upload_propose_allocation,
+ &_dma_buf_upload_perform,
+ &_dma_buf_upload_free
+};
+
+#endif /* GST_GL_HAVE_DMABUF */
struct GLUploadMeta
{
@@ -978,6 +1240,9 @@ static const UploadMethod *upload_methods[] = { &_gl_memory_upload,
#if GST_GL_HAVE_PLATFORM_EGL
&_egl_image_upload,
#endif
+#if GST_GL_HAVE_DMABUF
+ &_dma_buf_upload,
+#endif
&_upload_meta_upload, &_raw_data_upload
};