From e29ab42922706e0c4a1bb3fc8041c9a9dac6d4f1 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Tue, 19 Feb 2013 11:47:20 +0100 Subject: [PATCH] v4l2: Add support of dmabuf v4l has add a new IOCTL to export a buffer by using dmabuf. This patch allow to use this new IOTCL if it has been defined in videodev2.h I introduce a new IO mode (GST_V4L2_IO_DMABUF) to enable this way of working. https://bugzilla.gnome.org/show_bug.cgi?id=693826 --- configure.ac | 18 +++++++++++ sys/v4l2/Makefile.am | 6 ++-- sys/v4l2/gstv4l2bufferpool.c | 61 ++++++++++++++++++++++++++++-------- sys/v4l2/gstv4l2object.c | 1 + sys/v4l2/gstv4l2object.h | 3 +- sys/v4l2/gstv4l2src.c | 1 + 6 files changed, 72 insertions(+), 18 deletions(-) diff --git a/configure.ac b/configure.ac index 5b29cb9653..9817ab76bb 100644 --- a/configure.ac +++ b/configure.ac @@ -582,6 +582,24 @@ if test x$HAVE_GST_V4L2 = xyes; then fi fi +# Check if v4l2 support dmabuf +if test x$HAVE_GST_V4L2 = xyes; then + AC_CHECK_DECLS(V4L2_MEMORY_DMABUF,,,[ + #include + #ifdef __sun /* Solaris */ + #include + #include + #elif __FreeBSD__ + #include + #else /* Linux */ + #include + #define _LINUX_TIME_H + #define __user + #include + #endif + ]) +fi + dnl Check for X11 translit(dnm, m, l) AM_CONDITIONAL(USE_X, true) AG_GST_CHECK_FEATURE(X, [X libraries and plugins], diff --git a/sys/v4l2/Makefile.am b/sys/v4l2/Makefile.am index 4330da6e19..6b5134fca8 100644 --- a/sys/v4l2/Makefile.am +++ b/sys/v4l2/Makefile.am @@ -8,7 +8,6 @@ xv_source = xv_libs = endif - # variables used for enum/marshal generation glib_enum_headers = tuner.h tunernorm.h tunerchannel.h glib_enum_define = GST_INTERFACES @@ -56,11 +55,10 @@ libgstvideo4linux2_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \ libgstvideo4linux2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstvideo4linux2_la_LIBTOOLFLAGS = --tag=disable-static - libgstvideo4linux2_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ - $(GST_BASE_LIBS) \ - $(GST_PLUGINS_BASE_LIBS) \ + -lgstallocators-$(GST_API_VERSION) \ -lgstvideo-$(GST_API_VERSION) \ + $(GST_BASE_LIBS) \ $(GST_LIBS) \ $(xv_libs) \ $(LIBV4L2_LIBS) \ diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c index 0a9481862b..6208d13857 100644 --- a/sys/v4l2/gstv4l2bufferpool.c +++ b/sys/v4l2/gstv4l2bufferpool.c @@ -29,10 +29,14 @@ #include #include #include +#if HAVE_DECL_V4L2_MEMORY_DMABUF +#include +#endif #include "gst/video/video.h" #include "gst/video/gstvideometa.h" #include "gst/video/gstvideopool.h" +#include "gst/allocators/gstdmabuf.h" #include @@ -104,6 +108,7 @@ gst_v4l2_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer) switch (obj->mode) { case GST_V4L2_IO_RW: + case GST_V4L2_IO_DMABUF: break; case GST_V4L2_IO_MMAP: { @@ -152,6 +157,7 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer, break; } case GST_V4L2_IO_MMAP: + case GST_V4L2_IO_DMABUF: { newbuf = gst_buffer_new (); meta = GST_V4L2_META_ADD (newbuf); @@ -175,19 +181,35 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer, GST_LOG_OBJECT (pool, " memory: %d", meta->vbuffer.memory); if (meta->vbuffer.memory == V4L2_MEMORY_MMAP) GST_LOG_OBJECT (pool, " MMAP offset: %u", meta->vbuffer.m.offset); - GST_LOG_OBJECT (pool, " length: %u", meta->vbuffer.length); - meta->mem = v4l2_mmap (0, meta->vbuffer.length, - PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd, - meta->vbuffer.m.offset); - if (meta->mem == MAP_FAILED) - goto mmap_failed; + if (obj->mode == GST_V4L2_IO_MMAP) { + meta->mem = v4l2_mmap (0, meta->vbuffer.length, + PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd, + meta->vbuffer.m.offset); + if (meta->mem == MAP_FAILED) + goto mmap_failed; - gst_buffer_append_memory (newbuf, - gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, - meta->mem, meta->vbuffer.length, 0, meta->vbuffer.length, NULL, - NULL)); + gst_buffer_append_memory (newbuf, + gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, + meta->mem, meta->vbuffer.length, 0, meta->vbuffer.length, NULL, + NULL)); + } +#if HAVE_DECL_V4L2_MEMORY_DMABUF + if (obj->mode == GST_V4L2_IO_DMABUF) { + struct v4l2_exportbuffer expbuf; + expbuf.type = meta->vbuffer.type; + expbuf.index = meta->vbuffer.index; + expbuf.flags = O_CLOEXEC; + if (v4l2_ioctl (pool->video_fd, VIDIOC_EXPBUF, &expbuf) < 0) + goto mmap_failed; + + meta->vbuffer.memory = V4L2_MEMORY_DMABUF; + gst_buffer_append_memory (newbuf, + gst_dmabuf_allocator_alloc (pool->allocator, expbuf.fd, + meta->vbuffer.length)); + } +#endif /* add metadata to raw video buffers */ if (pool->add_videometa && info->finfo) { const GstVideoFormatInfo *finfo = info->finfo; @@ -298,6 +320,7 @@ gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config) num_buffers = 1; copy_threshold = 0; break; + case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: { /* request a reasonable number of buffers when no max specified. We will @@ -357,6 +380,10 @@ gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config) pool->size = size; pool->num_buffers = num_buffers; pool->copy_threshold = copy_threshold; + + if (obj->mode == GST_V4L2_IO_DMABUF) + allocator = gst_dmabuf_allocator_obtain (); + if (pool->allocator) gst_object_unref (pool->allocator); if ((pool->allocator = allocator)) @@ -406,6 +433,7 @@ start_streaming (GstV4l2BufferPool * pool) break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_USERPTR: + case GST_V4L2_IO_DMABUF: GST_DEBUG_OBJECT (pool, "STREAMON"); if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0) goto start_failed; @@ -478,6 +506,7 @@ gst_v4l2_buffer_pool_stop (GstBufferPool * bpool) break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_USERPTR: + case GST_V4L2_IO_DMABUF: /* we actually need to sync on all queued buffers but not * on the non-queued ones */ GST_DEBUG_OBJECT (pool, "STREAMOFF"); @@ -614,7 +643,12 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer) memset (&vbuffer, 0x00, sizeof (vbuffer)); vbuffer.type = obj->type; - vbuffer.memory = V4L2_MEMORY_MMAP; +#if HAVE_DECL_V4L2_MEMORY_DMABUF + if (obj->mode == GST_V4L2_IO_DMABUF) + vbuffer.memory = V4L2_MEMORY_DMABUF; + else +#endif + vbuffer.memory = V4L2_MEMORY_MMAP; GST_LOG_OBJECT (pool, "doing DQBUF"); if (v4l2_ioctl (pool->video_fd, VIDIOC_DQBUF, &vbuffer) < 0) @@ -743,7 +777,7 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer, ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool, buffer, params); break; - + case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: /* just dequeue a buffer, we basically use the queue of v4l2 as the * storage for our buffers. This function does poll first so we can @@ -831,6 +865,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer) GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer); break; + case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: /* queue back in the device */ gst_v4l2_buffer_pool_qbuf (pool, buffer); @@ -1083,7 +1118,7 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer * buf) /* FIXME, do write() */ GST_WARNING_OBJECT (pool, "implement write()"); break; - + case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: { GstBuffer *to_queue; diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index ec61b2c757..81654e20a1 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -389,6 +389,7 @@ gst_v4l2_io_mode_get_type (void) {GST_V4L2_IO_RW, "GST_V4L2_IO_RW", "rw"}, {GST_V4L2_IO_MMAP, "GST_V4L2_IO_MMAP", "mmap"}, {GST_V4L2_IO_USERPTR, "GST_V4L2_IO_USERPTR", "userptr"}, + {GST_V4L2_IO_DMABUF, "GST_V4L2_IO_DMABUF", "dmabuf"}, {0, NULL, NULL} }; diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h index 361181a48e..54703e95c6 100644 --- a/sys/v4l2/gstv4l2object.h +++ b/sys/v4l2/gstv4l2object.h @@ -75,7 +75,8 @@ typedef enum { GST_V4L2_IO_AUTO = 0, GST_V4L2_IO_RW = 1, GST_V4L2_IO_MMAP = 2, - GST_V4L2_IO_USERPTR = 3 + GST_V4L2_IO_USERPTR = 3, + GST_V4L2_IO_DMABUF = 4 } GstV4l2IOMode; typedef gboolean (*GstV4l2GetInOutFunction) (GstV4l2Object * v4l2object, gint * input); diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index 807ffea846..caa9f84bf4 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -571,6 +571,7 @@ gst_v4l2src_decide_allocation (GstBaseSrc * bsrc, GstQuery * query) break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_USERPTR: + case GST_V4L2_IO_DMABUF: /* in streaming mode, prefer our own pool */ pool = GST_BUFFER_POOL_CAST (obj->pool); size = obj->sizeimage;