v4l2: call VIDIOC_REQBUFS with count = 0 in pool_finalize
authorMichael Olbrich <m.olbrich@pengutronix.de>
Mon, 3 Jun 2013 15:07:10 +0000 (17:07 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 4 Jun 2013 08:45:06 +0000 (10:45 +0200)
Without this the following sequence fails:

- set_caps()
  - object_stop() (does nothing)
  - set_format() -> VIDIOC_S_FMT
- set_config() -> VIDIOC_REQBUFS with count = N
- set_caps()
  - object_stop()
    - pool_finalize()
  - set_format() -> VIDIOC_S_FMT => EBUSY

Usually the pool is started after set_config(), in which case object_stop()
will result in a pool_stop and therefore VIDIOC_REQBUFS with count = 0 but
that is not guaranteed.
Also calling VIDIOC_REQBUFS with count = 0 in pool_finalize() if necessary
fixes this problem.

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

sys/v4l2/gstv4l2bufferpool.c

index d5fcd33..34a444b 100644 (file)
@@ -538,6 +538,23 @@ start_failed:
   }
 }
 
+static void
+gst_v4l2_buffer_pool_free_buffers (GstV4l2BufferPool * pool)
+{
+  if (pool->num_buffers > 0) {
+    struct v4l2_requestbuffers breq;
+    memset (&breq, 0, sizeof (struct v4l2_requestbuffers));
+    breq.type = pool->obj->type;
+    breq.count = 0;
+    breq.memory = V4L2_MEMORY_MMAP;
+    if (v4l2_ioctl (pool->video_fd, VIDIOC_REQBUFS, &breq) < 0) {
+      GST_ERROR_OBJECT (pool, "error releasing buffers: %s",
+          g_strerror (errno));
+    }
+    pool->num_buffers = 0;
+  }
+}
+
 static gboolean
 gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
 {
@@ -582,18 +599,7 @@ gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
   g_free (pool->buffers);
   pool->buffers = NULL;
 
-  if (pool->num_buffers > 0) {
-    struct v4l2_requestbuffers breq;
-    memset (&breq, 0, sizeof (struct v4l2_requestbuffers));
-    breq.type = obj->type;
-    breq.count = 0;
-    breq.memory = V4L2_MEMORY_MMAP;
-    if (v4l2_ioctl (pool->video_fd, VIDIOC_REQBUFS, &breq) < 0) {
-      GST_ERROR_OBJECT (pool, "error releasing buffers: %s",
-          g_strerror (errno));
-    }
-    pool->num_buffers = 0;
-  }
+  gst_v4l2_buffer_pool_free_buffers (pool);
 
   return ret;
 
@@ -1003,6 +1009,8 @@ gst_v4l2_buffer_pool_finalize (GObject * object)
 {
   GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (object);
 
+  gst_v4l2_buffer_pool_free_buffers (pool);
+
   if (pool->video_fd >= 0)
     v4l2_close (pool->video_fd);
   if (pool->allocator)