From 1ab90ababa6196066139a6f90a39b060e6acbb3c Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 10 Apr 2014 16:26:34 -0400 Subject: [PATCH] v4l2: Add dmabuf export support This can be enabled sing io-mode=dmabuf. This will enabled mmap base drivers to export the buffers as dmabuf. --- sys/v4l2/gstv4l2allocator.c | 108 +++++++++++++++++++++++++++++++++++++++---- sys/v4l2/gstv4l2allocator.h | 4 ++ sys/v4l2/gstv4l2bufferpool.c | 9 +++- 3 files changed, 112 insertions(+), 9 deletions(-) diff --git a/sys/v4l2/gstv4l2allocator.c b/sys/v4l2/gstv4l2allocator.c index 5450387..f2f92a1 100644 --- a/sys/v4l2/gstv4l2allocator.c +++ b/sys/v4l2/gstv4l2allocator.c @@ -23,7 +23,12 @@ #include "gstv4l2allocator.h" #include "v4l2_calls.h" +#include + +#include #include +#include +#include #define GST_V4L2_MEMORY_TYPE "V4l2Memory" @@ -121,7 +126,8 @@ _v4l2mem_dispose (GstV4l2Memory * mem) gboolean ret; if (group->mem[mem->plane]) { - gst_memory_ref ((GstMemory *) mem); + /* We may have a dmabuf, replace it with returned original memory */ + group->mem[mem->plane] = gst_memory_ref ((GstMemory *) mem); gst_v4l2_allocator_release (allocator, mem); ret = FALSE; } else { @@ -135,13 +141,15 @@ _v4l2mem_dispose (GstV4l2Memory * mem) static void _v4l2mem_free (GstV4l2Memory * mem) { + if (mem->dmafd > 0) + close (mem->dmafd); g_slice_free (GstV4l2Memory, mem); } static inline GstV4l2Memory * _v4l2mem_new (GstMemoryFlags flags, GstAllocator * allocator, GstMemory * parent, gsize maxsize, gsize align, gsize offset, gsize size, - gint plane, gpointer data, GstV4l2MemoryGroup * group) + gint plane, gpointer data, int dmafd, GstV4l2MemoryGroup * group) { GstV4l2Memory *mem; @@ -155,6 +163,7 @@ _v4l2mem_new (GstMemoryFlags flags, GstAllocator * allocator, mem->plane = plane; mem->data = data; + mem->dmafd = dmafd; mem->group = group; return mem; @@ -177,7 +186,7 @@ _v4l2mem_share (GstV4l2Memory * mem, gssize offset, gsize size) sub = _v4l2mem_new (GST_MINI_OBJECT_FLAGS (parent) | GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->mem.allocator, parent, mem->mem.maxsize, mem->mem.align, offset, size, mem->plane, mem->data, - mem->group); + -1, mem->group); return sub; } @@ -192,6 +201,13 @@ _v4l2mem_is_span (GstV4l2Memory * mem1, GstV4l2Memory * mem2, gsize * offset) return mem1->mem.offset + mem1->mem.size == mem2->mem.offset; } +static void +_v4l2mem_parent_to_dmabuf (GstV4l2Memory * mem, GstMemory * dma_mem) +{ + gst_memory_lock (&mem->mem, GST_LOCK_FLAG_EXCLUSIVE); + dma_mem->parent = gst_memory_ref (&mem->mem); +} + gboolean gst_is_v4l2_memory (GstMemory * mem) { @@ -721,7 +737,7 @@ gst_v4l2_allocator_alloc_mmap (GstV4l2Allocator * allocator) group->mem[i] = (GstMemory *) _v4l2mem_new (0, GST_ALLOCATOR (allocator), NULL, group->planes[i].length, 0, 0, group->planes[i].length, i, - data, group); + data, -1, group); } else { /* Take back the allocator reference */ gst_object_ref (allocator); @@ -757,14 +773,90 @@ mmap_failed: } } -#if 0 GstV4l2MemoryGroup * -gst_v4l2_allocator_alloc_dmabuf (GstV4l2Allocator * allocator) +gst_v4l2_allocator_alloc_dmabuf (GstV4l2Allocator * allocator, + GstAllocator * dmabuf_allocator) { - /* TODO */ - return NULL; + GstV4l2MemoryGroup *group; + gint i; + + g_return_val_if_fail (allocator->memory == V4L2_MEMORY_MMAP, NULL); + + group = gst_v4l2_allocator_alloc (allocator); + + if (group == NULL) + return NULL; + + for (i = 0; i < group->n_mem; i++) { + GstV4l2Memory *mem; + GstMemory *dma_mem; + gint dmafd; + + if (group->mem[i] == NULL) { + struct v4l2_exportbuffer expbuf = { 0 }; + + expbuf.type = allocator->type; + expbuf.index = group->buffer.index; + expbuf.plane = i; + expbuf.flags = O_CLOEXEC | O_RDWR; + + if (v4l2_ioctl (allocator->video_fd, VIDIOC_EXPBUF, &expbuf) < 0) + goto expbuf_failed; + + GST_LOG_OBJECT (allocator, "exported DMABUF as fd %i plane %d", + expbuf.fd, i); + + group->mem[i] = (GstMemory *) _v4l2mem_new (0, GST_ALLOCATOR (allocator), + NULL, group->planes[i].length, 0, 0, group->planes[i].length, i, + NULL, expbuf.fd, group); + } else { + /* Take back the allocator reference */ + gst_object_ref (allocator); + } + + g_assert (gst_is_v4l2_memory (group->mem[i])); + mem = (GstV4l2Memory *) group->mem[i]; + + if ((dmafd = dup (mem->dmafd)) < 0) + goto dup_failed; + + dma_mem = gst_dmabuf_allocator_alloc (dmabuf_allocator, dmafd, + mem->mem.maxsize); + _v4l2mem_parent_to_dmabuf (mem, dma_mem); + + group->mem[i] = dma_mem; + group->mems_allocated++; + } + + gst_v4l2_allocator_reset_size (allocator, group); + + return group; + +expbuf_failed: + { + GST_ERROR_OBJECT (allocator, "Failed to export DMABUF: %s", + g_strerror (errno)); + goto cleanup; + } +dup_failed: + { + GST_ERROR_OBJECT (allocator, "Failed to dup DMABUF descriptor: %s", + g_strerror (errno)); + goto cleanup; + } +cleanup: + { + if (group->mems_allocated > 0) { + for (i = 0; i < group->n_mem; i++) + gst_memory_unref (group->mem[i]); + } else { + gst_atomic_queue_push (allocator->free_queue, group); + } + return NULL; + } } +#if 0 GstV4l2MemoryGroup * gst_v4l2_allocator_import_dmabuf (GstV4l2Allocator * allocator, gint dmabuf_fd[VIDEO_MAX_PLANES]) diff --git a/sys/v4l2/gstv4l2allocator.h b/sys/v4l2/gstv4l2allocator.h index be1444c..7027745 100644 --- a/sys/v4l2/gstv4l2allocator.h +++ b/sys/v4l2/gstv4l2allocator.h @@ -72,6 +72,7 @@ struct _GstV4l2Memory gint plane; GstV4l2MemoryGroup *group; gpointer data; + gint dmafd; }; struct _GstV4l2MemoryGroup @@ -122,6 +123,9 @@ gboolean gst_v4l2_allocator_stop (GstV4l2Allocator * alloc GstV4l2MemoryGroup* gst_v4l2_allocator_alloc_mmap (GstV4l2Allocator * allocator); +GstV4l2MemoryGroup* gst_v4l2_allocator_alloc_dmabuf (GstV4l2Allocator * allocator, + GstAllocator * dmabuf_allocator); + void gst_v4l2_allocator_flush (GstV4l2Allocator * allocator); gboolean gst_v4l2_allocator_qbuf (GstV4l2Allocator * allocator, diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c index c63eb53..088e3d5 100644 --- a/sys/v4l2/gstv4l2bufferpool.c +++ b/sys/v4l2/gstv4l2bufferpool.c @@ -73,6 +73,9 @@ gst_v4l2_is_buffer_valid (GstBuffer * buffer, GstV4l2MemoryGroup ** group) if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY)) goto done; + if (gst_is_dmabuf_memory (mem)) + mem = mem->parent; + if (gst_is_v4l2_memory (mem)) { GstV4l2Memory *vmem = (GstV4l2Memory *) mem; valid = TRUE; @@ -108,7 +111,8 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer, group = gst_v4l2_allocator_alloc_mmap (pool->vallocator); break; case GST_V4L2_IO_DMABUF: - /* TODO group = gst_v4l2_allocator_alloc_dmabuf (pool->vallocator); */ + group = gst_v4l2_allocator_alloc_dmabuf (pool->vallocator, + pool->allocator); break; case GST_V4L2_IO_USERPTR: default: @@ -850,6 +854,7 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer, break; case GST_V4L2_IO_MMAP: + case GST_V4L2_IO_DMABUF: /* get a free unqueued buffer */ ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool, buffer, params); @@ -929,6 +934,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer) break; case GST_V4L2_IO_MMAP: + case GST_V4L2_IO_DMABUF: { GstV4l2MemoryGroup *group; guint index; @@ -1172,6 +1178,7 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer * buf) break; case GST_V4L2_IO_MMAP: + case GST_V4L2_IO_DMABUF: { GstBuffer *tmp; -- 2.7.4