v4l2: try to allocate new buffers with VIDIOC_CREATE_BUFS if needed
authorMichael Olbrich <m.olbrich@pengutronix.de>
Thu, 2 May 2013 07:41:01 +0000 (09:41 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 3 May 2013 09:18:04 +0000 (11:18 +0200)
If max_buffers is 0 then an arbitrary number of buffers (currently 4) is
allocated. If this is not enough v4l2src starts copying buffers.
With this patch VIDIOC_CREATE_BUFS is used to allocate a new buffer. If
this fails v4l2src falls back to copying buffers.

https://bugzilla.gnome.org/show_bug.cgi?id=699447

sys/v4l2/gstv4l2bufferpool.c
sys/v4l2/gstv4l2bufferpool.h

index 917cc64..3bf6d11 100644 (file)
@@ -157,6 +157,28 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
     case GST_V4L2_IO_MMAP:
     case GST_V4L2_IO_DMABUF:
     {
+#ifdef VIDIOC_CREATE_BUFS
+      if (pool->num_allocated == pool->num_buffers) {
+        struct v4l2_create_buffers create_bufs;
+
+        memset (&create_bufs, 0, sizeof (struct v4l2_create_buffers));
+        create_bufs.count = 1;
+        create_bufs.memory = V4L2_MEMORY_MMAP;
+        create_bufs.format.type = obj->type;
+
+        if (v4l2_ioctl (pool->video_fd, VIDIOC_G_FMT, &create_bufs.format) < 0)
+          goto g_fmt_failed;
+
+        if (v4l2_ioctl (pool->video_fd, VIDIOC_CREATE_BUFS, &create_bufs) < 0)
+          goto create_bufs_failed;
+
+        GST_LOG_OBJECT (pool, "created buffer with index: %u",
+            create_bufs.index);
+        pool->num_buffers++;
+        pool->buffers = g_renew (GstBuffer *, pool->buffers, pool->num_buffers);
+        pool->buffers[pool->num_buffers - 1] = NULL;
+      }
+#endif
       newbuf = gst_buffer_new ();
       meta = GST_V4L2_META_ADD (newbuf);
 
@@ -250,6 +272,24 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
   return GST_FLOW_OK;
 
   /* ERRORS */
+#ifdef VIDIOC_CREATE_BUFS
+g_fmt_failed:
+  {
+    gint errnosave = errno;
+
+    GST_WARNING ("Failed G_FMT: %s", g_strerror (errnosave));
+    errno = errnosave;
+    return GST_FLOW_ERROR;
+  }
+create_bufs_failed:
+  {
+    gint errnosave = errno;
+
+    GST_WARNING ("Failed CREATE_BUFS: %s", g_strerror (errnosave));
+    errno = errnosave;
+    return GST_FLOW_ERROR;
+  }
+#endif
 querybuf_failed:
   {
     gint errnosave = errno;
@@ -793,6 +833,17 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
           /* start copying buffers when we are running low on buffers */
           if (pool->num_queued < pool->copy_threshold) {
             GstBuffer *copy;
+#ifdef VIDIOC_CREATE_BUFS
+            if (pool->can_alloc) {
+              if (GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
+                      &copy, params) == GST_FLOW_OK) {
+                gst_v4l2_buffer_pool_release_buffer (bpool, copy);
+                break;
+              } else {
+                pool->can_alloc = FALSE;
+              }
+            }
+#endif
 
             /* copy the memory */
             copy = gst_buffer_copy (*buffer);
@@ -989,6 +1040,7 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
   pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, NULL);
   pool->video_fd = fd;
   pool->obj = obj;
+  pool->can_alloc = TRUE;
 
   s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
   gst_buffer_pool_config_set_params (s, caps, obj->sizeimage, 2, 0);
index 9c919af..90ccad4 100644 (file)
@@ -55,6 +55,7 @@ struct _GstV4l2BufferPool
   GstAllocationParams params;
   guint size;
   gboolean add_videometa;
+  gboolean can_alloc;        /* if extra buffers can be allocated */
 
   guint num_buffers;         /* number of buffers we use */
   guint num_allocated;       /* number of buffers allocated by the driver */