v4l2: Fixup USERPTR/DMABUF capture support
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Fri, 18 Apr 2014 21:02:50 +0000 (17:02 -0400)
committerNicolas Dufresne <nicolas.dufresne@collabora.com>
Thu, 8 May 2014 19:56:37 +0000 (15:56 -0400)
sys/v4l2/gstv4l2allocator.c
sys/v4l2/gstv4l2allocator.h
sys/v4l2/gstv4l2bufferpool.c

index b0d7a47..fa884f6 100644 (file)
@@ -489,9 +489,110 @@ gst_v4l2_allocator_probe (GstV4l2Allocator * allocator, guint32 memory,
   return flags;
 }
 
+static GstV4l2MemoryGroup *
+gst_v4l2_allocator_create_buf (GstV4l2Allocator * allocator)
+{
+  struct v4l2_create_buffers bcreate = { 0 };
+  GstV4l2MemoryGroup *group = NULL;
+
+  GST_OBJECT_LOCK (allocator);
+
+  if (!allocator->active)
+    goto done;
+
+  bcreate.memory = allocator->memory;
+  bcreate.format = allocator->format;
+  bcreate.count = 1;
+
+  if (!allocator->can_allocate)
+    goto done;
+
+  if (v4l2_ioctl (allocator->video_fd, VIDIOC_CREATE_BUFS, &bcreate) < 0)
+    goto create_bufs_failed;
+
+  group = gst_v4l2_memory_group_new (allocator, bcreate.index);
+
+  if (group) {
+    allocator->groups[bcreate.index] = group;
+    allocator->count++;
+  }
+
+done:
+  GST_OBJECT_UNLOCK (allocator);
+  return group;
+
+create_bufs_failed:
+  {
+    GST_WARNING_OBJECT (allocator, "error creating a new buffer: %s",
+        g_strerror (errno));
+    goto done;
+  }
+}
+
+static GstV4l2MemoryGroup *
+gst_v4l2_allocator_alloc (GstV4l2Allocator * allocator)
+{
+  GstV4l2MemoryGroup *group;
+
+  if (!g_atomic_int_get (&allocator->active))
+    return NULL;
+
+  group = gst_atomic_queue_pop (allocator->free_queue);
+
+  if (group == NULL) {
+    if (allocator->can_allocate) {
+      group = gst_v4l2_allocator_create_buf (allocator);
+
+      /* Don't hammer on CREATE_BUFS */
+      if (group == NULL)
+        allocator->can_allocate = FALSE;
+    }
+  }
+
+  return group;
+}
+
+static void
+gst_v4l2_allocator_reset_size (GstV4l2Allocator * allocator,
+    GstV4l2MemoryGroup * group)
+{
+  gsize size;
+
+  if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
+    gint i;
+
+    for (i = 0; i < group->n_mem; i++) {
+      size = allocator->format.fmt.pix_mp.plane_fmt[i].sizeimage;
+      gst_memory_resize (group->mem[i], 0, size);
+    }
+
+  } else {
+    size = allocator->format.fmt.pix.sizeimage;
+    gst_memory_resize (group->mem[0], 0, size);
+  }
+}
+
+static void
+_cleanup_failed_alloc (GstV4l2Allocator * allocator, GstV4l2MemoryGroup * group)
+{
+  if (group->mems_allocated > 0) {
+    gint i;
+    /* If one or more mmap worked, we need to unref the memory, otherwise
+     * they will keep a ref on the allocator and leak it. This will put back
+     * the group into the free_queue */
+    for (i = 0; i < group->n_mem; i++)
+      gst_memory_unref (group->mem[i]);
+  } else {
+    /* Otherwise, group has to be on free queue for _stop() to work */
+    gst_atomic_queue_push (allocator->free_queue, group);
+  }
+}
+
+
+
 GstV4l2Allocator *
 gst_v4l2_allocator_new (GstObject * parent, gint video_fd,
-    struct v4l2_format * format)
+    struct v4l2_format *format)
 {
   GstV4l2Allocator *allocator;
   guint32 flags = 0;
@@ -658,85 +759,6 @@ reqbufs_failed:
   }
 }
 
-static GstV4l2MemoryGroup *
-gst_v4l2_allocator_create_buf (GstV4l2Allocator * allocator)
-{
-  struct v4l2_create_buffers bcreate = { 0 };
-  GstV4l2MemoryGroup *group = NULL;
-
-  GST_OBJECT_LOCK (allocator);
-
-  if (!allocator->active)
-    goto done;
-
-  bcreate.memory = allocator->memory;
-  bcreate.format = allocator->format;
-  bcreate.count = 1;
-
-  if (!allocator->can_allocate)
-    goto done;
-
-  if (v4l2_ioctl (allocator->video_fd, VIDIOC_CREATE_BUFS, &bcreate) < 0)
-    goto create_bufs_failed;
-
-  group = gst_v4l2_memory_group_new (allocator, bcreate.index);
-
-  if (group) {
-    allocator->groups[bcreate.index] = group;
-    allocator->count++;
-  }
-
-done:
-  GST_OBJECT_UNLOCK (allocator);
-  return group;
-
-create_bufs_failed:
-  {
-    GST_WARNING_OBJECT (allocator, "error creating a new buffer: %s",
-        g_strerror (errno));
-    goto done;
-  }
-}
-
-static GstV4l2MemoryGroup *
-gst_v4l2_allocator_alloc (GstV4l2Allocator * allocator)
-{
-  GstV4l2MemoryGroup *group;
-
-  if (!g_atomic_int_get (&allocator->active))
-    return NULL;
-
-  group = gst_atomic_queue_pop (allocator->free_queue);
-
-  if (group == NULL) {
-    if (allocator->can_allocate) {
-      group = gst_v4l2_allocator_create_buf (allocator);
-
-      /* Don't hammer on CREATE_BUFS */
-      if (group == NULL)
-        allocator->can_allocate = FALSE;
-    }
-  }
-
-  return group;
-}
-
-static void
-_cleanup_failed_alloc (GstV4l2Allocator * allocator, GstV4l2MemoryGroup * group)
-{
-  if (group->mems_allocated > 0) {
-    gint i;
-    /* If one or more mmap worked, we need to unref the memory, otherwise
-     * they will keep a ref on the allocator and leak it. This will put back
-     * the group into the free_queue */
-    for (i = 0; i < group->n_mem; i++)
-      gst_memory_unref (group->mem[i]);
-  } else {
-    /* Otherwise, group has to be on free queue for _stop() to work */
-    gst_atomic_queue_push (allocator->free_queue, group);
-  }
-}
-
 GstV4l2MemoryGroup *
 gst_v4l2_allocator_alloc_mmap (GstV4l2Allocator * allocator)
 {
@@ -869,6 +891,45 @@ cleanup:
   }
 }
 
+static void
+gst_v4l2_allocator_clear_dmabufin (GstV4l2Allocator * allocator,
+    GstV4l2MemoryGroup * group)
+{
+  GstV4l2Memory *mem;
+  gint i;
+
+  g_return_if_fail (allocator->memory == V4L2_MEMORY_DMABUF);
+
+  for (i = 0; i < group->n_mem; i++) {
+
+    mem = (GstV4l2Memory *) group->mem[i];
+
+    GST_LOG_OBJECT (allocator, "clearing DMABUF import, fd %i plane %d",
+        mem->dmafd, i);
+
+    if (mem->dmafd >= 0)
+      close (mem->dmafd);
+
+    /* Update memory */
+    mem->mem.maxsize = 0;
+    mem->mem.offset = 0;
+    mem->mem.size = 0;
+    mem->dmafd = -1;
+
+    /* Update v4l2 structure */
+    group->planes[i].length = 0;
+    group->planes[i].bytesused = 0;
+    group->planes[i].m.fd = -1;
+    group->planes[i].data_offset = 0;
+  }
+
+  if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
+    group->buffer.bytesused = 0;
+    group->buffer.length = 0;
+    group->buffer.m.fd = -1;
+  }
+}
+
 GstV4l2MemoryGroup *
 gst_v4l2_allocator_alloc_dmabufin (GstV4l2Allocator * allocator)
 {
@@ -901,6 +962,37 @@ gst_v4l2_allocator_alloc_dmabufin (GstV4l2Allocator * allocator)
   return group;
 }
 
+static void
+gst_v4l2_allocator_clear_userptr (GstV4l2Allocator * allocator,
+    GstV4l2MemoryGroup * group)
+{
+  GstV4l2Memory *mem;
+  gint i;
+
+  g_return_if_fail (allocator->memory == V4L2_MEMORY_USERPTR);
+
+  for (i = 0; i < group->n_mem; i++) {
+    mem = (GstV4l2Memory *) group->mem[i];
+
+    GST_LOG_OBJECT (allocator, "clearing USERPTR %p plane %d size %"
+        G_GSIZE_FORMAT, mem->data, i, mem->mem.size);
+
+    mem->mem.maxsize = 0;
+    mem->mem.size = 0;
+    mem->data = NULL;
+
+    group->planes[i].length = 0;
+    group->planes[i].bytesused = 0;
+    group->planes[i].m.userptr = 0;
+  }
+
+  if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
+    group->buffer.bytesused = 0;
+    group->buffer.length = 0;
+    group->buffer.m.userptr = 0;
+  }
+}
+
 GstV4l2MemoryGroup *
 gst_v4l2_allocator_alloc_userptr (GstV4l2Allocator * allocator)
 {
@@ -1005,46 +1097,6 @@ dup_failed:
   }
 }
 
-void
-gst_v4l2_allocator_clear_dmabufin (GstV4l2Allocator * allocator,
-    GstV4l2MemoryGroup * group)
-{
-  GstV4l2Memory *mem;
-  gint i;
-
-  g_return_if_fail (allocator->memory == V4L2_MEMORY_DMABUF);
-
-  for (i = 0; i < group->n_mem; i++) {
-
-    mem = (GstV4l2Memory *) group->mem[i];
-
-    GST_LOG_OBJECT (allocator, "clearing DMABUF import, fd %i plane %d",
-        mem->dmafd, i);
-
-    if (mem->dmafd >= 0)
-      close (mem->dmafd);
-
-    /* Update memory */
-    mem->mem.maxsize = 0;
-    mem->mem.offset = 0;
-    mem->mem.size = 0;
-    mem->dmafd = -1;
-
-    /* Update v4l2 structure */
-    group->planes[i].length = 0;
-    group->planes[i].bytesused = 0;
-    group->planes[i].m.fd = -1;
-    group->planes[i].data_offset = 0;
-  }
-
-  if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
-    group->buffer.bytesused = 0;
-    group->buffer.length = 0;
-    group->buffer.m.fd = -1;
-  }
-}
-
-
 gboolean
 gst_v4l2_allocator_import_userptr (GstV4l2Allocator * allocator,
     GstV4l2MemoryGroup * group, gsize img_size, int n_planes,
@@ -1112,37 +1164,6 @@ n_mem_missmatch:
 }
 
 void
-gst_v4l2_allocator_clear_userptr (GstV4l2Allocator * allocator,
-    GstV4l2MemoryGroup * group)
-{
-  GstV4l2Memory *mem;
-  gint i;
-
-  g_return_if_fail (allocator->memory == V4L2_MEMORY_USERPTR);
-
-  for (i = 0; i < group->n_mem; i++) {
-    mem = (GstV4l2Memory *) group->mem[i];
-
-    GST_LOG_OBJECT (allocator, "clearing USERPTR %p plane %d size %"
-        G_GSIZE_FORMAT, mem->data, i, mem->mem.size);
-
-    mem->mem.maxsize = 0;
-    mem->mem.size = 0;
-    mem->data = NULL;
-
-    group->planes[i].length = 0;
-    group->planes[i].bytesused = 0;
-    group->planes[i].m.userptr = 0;
-  }
-
-  if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
-    group->buffer.bytesused = 0;
-    group->buffer.length = 0;
-    group->buffer.m.userptr = 0;
-  }
-}
-
-void
 gst_v4l2_allocator_flush (GstV4l2Allocator * allocator)
 {
   gint i;
@@ -1322,21 +1343,21 @@ error:
 }
 
 void
-gst_v4l2_allocator_reset_size (GstV4l2Allocator * allocator,
+gst_v4l2_allocator_reset_group (GstV4l2Allocator * allocator,
     GstV4l2MemoryGroup * group)
 {
-  gsize size;
-
-  if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
-    gint i;
-
-    for (i = 0; i < group->n_mem; i++) {
-      size = allocator->format.fmt.pix_mp.plane_fmt[i].sizeimage;
-      gst_memory_resize (group->mem[i], 0, size);
-    }
-
-  } else {
-    size = allocator->format.fmt.pix.sizeimage;
-    gst_memory_resize (group->mem[0], 0, size);
+  switch (allocator->memory) {
+    case V4L2_MEMORY_USERPTR:
+      gst_v4l2_allocator_clear_userptr (allocator, group);
+      break;
+    case V4L2_MEMORY_DMABUF:
+      gst_v4l2_allocator_clear_dmabufin (allocator, group);
+      break;
+    case V4L2_MEMORY_MMAP:
+      gst_v4l2_allocator_reset_size (allocator, group);
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
   }
 }
index 15b4dd6..282f855 100644 (file)
@@ -134,18 +134,11 @@ gboolean             gst_v4l2_allocator_import_dmabuf  (GstV4l2Allocator * alloc
                                                         GstV4l2MemoryGroup *group,
                                                         gint n_mem, GstMemory ** dma_mem);
 
-void                 gst_v4l2_allocator_clear_dmabufin (GstV4l2Allocator * allocator,
-                                                        GstV4l2MemoryGroup *group);
-
-
 gboolean             gst_v4l2_allocator_import_userptr (GstV4l2Allocator * allocator,
                                                         GstV4l2MemoryGroup *group,
                                                         gsize img_size, int n_planes,
                                                         gpointer * data, gsize * offset);
 
-void                 gst_v4l2_allocator_clear_userptr  (GstV4l2Allocator * allocator,
-                                                        GstV4l2MemoryGroup *group);
-
 void                 gst_v4l2_allocator_flush          (GstV4l2Allocator * allocator);
 
 gboolean             gst_v4l2_allocator_qbuf           (GstV4l2Allocator * allocator,
@@ -153,7 +146,7 @@ gboolean             gst_v4l2_allocator_qbuf           (GstV4l2Allocator * alloc
 
 GstV4l2MemoryGroup*  gst_v4l2_allocator_dqbuf          (GstV4l2Allocator * allocator);
 
-void                 gst_v4l2_allocator_reset_size     (GstV4l2Allocator * allocator,
+void                 gst_v4l2_allocator_reset_group    (GstV4l2Allocator * allocator,
                                                         GstV4l2MemoryGroup * group);
 
 G_END_DECLS
index 95e30cd..4bc3713 100644 (file)
@@ -1334,8 +1334,12 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
             GST_LOG_OBJECT (pool, "buffer %u not queued, putting on free list",
                 index);
 
+            /* Remove qdata, this will unmap any map data in userptr */
+            gst_mini_object_set_qdata (GST_MINI_OBJECT (buffer),
+                GST_V4L2_IMPORT_QUARK, NULL, NULL);
+
             /* reset to default size */
-            gst_v4l2_allocator_reset_size (pool->vallocator, group);
+            gst_v4l2_allocator_reset_group (pool->vallocator, group);
 
             /* playback, put the buffer back in the queue to refill later. */
             GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,