v4l2bufferpool: Port to bufferpool flush_start/stop method
authorNicolas Dufresne <nicolas.dufresne@collabora.co.uk>
Sun, 25 May 2014 00:20:07 +0000 (20:20 -0400)
committerNicolas Dufresne <nicolas.dufresne@collabora.com>
Mon, 26 May 2014 17:43:30 +0000 (13:43 -0400)
Port the buffer pool to use the new flush_start/flush_stop virtual
methods added to GstBufferPool.

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

sys/v4l2/gstv4l2allocator.c
sys/v4l2/gstv4l2bufferpool.c
sys/v4l2/gstv4l2bufferpool.h
sys/v4l2/gstv4l2object.c
sys/v4l2/gstv4l2object.h
sys/v4l2/gstv4l2transform.c
sys/v4l2/gstv4l2videodec.c
sys/v4l2/v4l2_calls.c

index 6f3dfb2..416770b 100644 (file)
@@ -1221,6 +1221,8 @@ gst_v4l2_allocator_qbuf (GstV4l2Allocator * allocator,
   gboolean ret = TRUE;
   gint i;
 
+  g_return_val_if_fail (g_atomic_int_get (&allocator->active), FALSE);
+
   /* update sizes */
   if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
     for (i = 0; i < group->n_mem; i++)
index e39ac72..a67887a 100644 (file)
@@ -520,80 +520,69 @@ wrong_config:
 }
 
 static gboolean
-start_streaming (GstV4l2BufferPool * pool)
+gst_v4l2_buffer_pool_streamon (GstV4l2BufferPool * pool)
 {
   GstV4l2Object *obj = pool->obj;
 
-  GST_DEBUG_OBJECT (pool, "start streaming");
-
-  if (pool->streaming)
-    return TRUE;
-
   switch (obj->mode) {
-    case GST_V4L2_IO_RW:
-      break;
     case GST_V4L2_IO_MMAP:
     case GST_V4L2_IO_USERPTR:
     case GST_V4L2_IO_DMABUF:
     case GST_V4L2_IO_DMABUF_IMPORT:
-    {
-      /* For capture device, we need to re-enqueue buffers before be can let
-       * the driver stream again */
-      if (!V4L2_TYPE_IS_OUTPUT (obj->type) && pool->vallocator) {
-        GstBufferPool *bpool = GST_BUFFER_POOL (pool);
-        GstBufferPoolAcquireParams params = { 0 };
-        gsize num_allocated, num_to_queue;
-        GstFlowReturn ret;
-
-        num_allocated = gst_v4l2_allocator_num_allocated (pool->vallocator);
-        num_to_queue = num_allocated - g_atomic_int_get (&pool->num_queued);
+      if (!pool->streaming) {
+        if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
+          goto streamon_failed;
 
-        while (num_to_queue > 0) {
-          GstBuffer *buf;
+        pool->streaming = TRUE;
 
-          params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
-          ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
-              &buf, &params);
+        GST_DEBUG_OBJECT (pool, "Started streaming");
+      }
+      break;
+    default:
+      break;
+  }
 
-          if (ret != GST_FLOW_OK)
-            goto requeue_failed;
+  return TRUE;
 
-          gst_v4l2_buffer_pool_release_buffer (bpool, buf);
-          num_to_queue--;
-        }
+streamon_failed:
+  {
+    GST_ERROR_OBJECT (pool, "error with STREAMON %d (%s)", errno,
+        g_strerror (errno));
+    return FALSE;
+  }
+}
 
-        if (num_allocated != g_atomic_int_get (&pool->num_queued))
-          goto requeue_failed;
-      }
+static gboolean
+gst_v4l2_buffer_pool_streamoff (GstV4l2BufferPool * pool)
+{
+  GstV4l2Object *obj = pool->obj;
 
-      if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
-        goto start_failed;
+  switch (obj->mode) {
+    case GST_V4L2_IO_MMAP:
+    case GST_V4L2_IO_USERPTR:
+    case GST_V4L2_IO_DMABUF:
+    case GST_V4L2_IO_DMABUF_IMPORT:
+      if (pool->streaming) {
+        if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
+          goto streamoff_failed;
 
-      GST_DEBUG_OBJECT (pool, "STREAMON");
+        pool->streaming = FALSE;
 
+        GST_DEBUG_OBJECT (pool, "Stopped streaming");
+      }
       break;
-    }
     default:
-      g_assert_not_reached ();
       break;
   }
 
-  pool->streaming = TRUE;
-
   return TRUE;
 
-  /* ERRORS */
-start_failed:
+streamoff_failed:
   {
-    GST_ERROR_OBJECT (pool, "error with STREAMON %d (%s)", errno,
+    GST_ERROR_OBJECT (pool, "error with STREAMOFF %d (%s)", errno,
         g_strerror (errno));
     return FALSE;
   }
-requeue_failed:
-  {
-    GST_ERROR_OBJECT (pool, "failed to re-enqueue buffers");
-    return FALSE;
-  }
 }
 
 static void
@@ -618,6 +607,7 @@ static gboolean
 gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
 {
   GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+  GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
   GstV4l2Object *obj = pool->obj;
   GstStructure *config;
   GstCaps *caps;
@@ -739,7 +729,7 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
 
   gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
       max_buffers);
-  GST_BUFFER_POOL_CLASS (parent_class)->set_config (bpool, config);
+  pclass->set_config (bpool, config);
   gst_structure_free (config);
 
   if (pool->other_pool)
@@ -747,22 +737,14 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
       goto other_pool_failed;
 
   /* now, allocate the buffers: */
-  if (!GST_BUFFER_POOL_CLASS (parent_class)->start (bpool))
+  if (!pclass->start (bpool))
     goto start_failed;
 
-  /* we can start capturing now, we wait for the playback case until we queued
-   * the first buffer */
-  if (!V4L2_TYPE_IS_OUTPUT (obj->type))
-    if (!start_streaming (pool))
-      goto start_failed;
-
   if (!V4L2_TYPE_IS_OUTPUT (obj->type))
     pool->group_released_handler =
         g_signal_connect_swapped (pool->vallocator, "group-released",
         G_CALLBACK (gst_v4l2_buffer_pool_group_released), pool);
 
-  gst_poll_set_flushing (obj->poll, FALSE);
-
   return TRUE;
 
   /* ERRORS */
@@ -793,26 +775,103 @@ other_pool_failed:
   }
 }
 
-
 static gboolean
-stop_streaming (GstV4l2BufferPool * pool)
+gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
 {
-  GstV4l2Object *obj = pool->obj;
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+  GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
+  gboolean ret;
   gint i;
 
-  GST_DEBUG_OBJECT (pool, "stopping stream");
+  GST_DEBUG_OBJECT (pool, "stopping pool");
+
+  if (pool->group_released_handler > 0) {
+    g_signal_handler_disconnect (pool->vallocator,
+        pool->group_released_handler);
+    pool->group_released_handler = 0;
+  }
+
+  if (pool->other_pool) {
+    gst_object_unref (pool->other_pool);
+    pool->other_pool = NULL;
+  }
+
+  if (!gst_v4l2_buffer_pool_streamoff (pool))
+    goto streamoff_failed;
+
+  gst_v4l2_allocator_flush (pool->vallocator);
+
+  for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+    if (pool->buffers[i]) {
+      GstBuffer *buffer = pool->buffers[i];
+
+      pool->buffers[i] = NULL;
+
+      if (V4L2_TYPE_IS_OUTPUT (pool->obj->type))
+        gst_buffer_unref (buffer);
+      else
+        pclass->release_buffer (bpool, buffer);
 
-  gst_poll_set_flushing (obj->poll, TRUE);
+      g_atomic_int_add (&pool->num_queued, -1);
+    }
+  }
+
+  ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool);
+
+  if (ret) {
+    GstV4l2Return vret;
 
-  if (!pool->streaming) {
-    /* it avoid error: STREAMOFF 22 (Invalid argument) when
-     * attempting to stop a stream not previously started */
-    GST_DEBUG_OBJECT (pool, "no need to stop, was not previously started");
-    return TRUE;
+    vret = gst_v4l2_allocator_stop (pool->vallocator);
+
+    if (vret == GST_V4L2_BUSY)
+      GST_WARNING_OBJECT (pool, "some buffers are still outstanding");
+
+    ret = (vret == GST_V4L2_OK);
   }
 
-  pool->flushing = TRUE;
+  return ret;
 
+  /* ERRORS */
+streamoff_failed:
+  GST_ERROR_OBJECT (pool, "device refused to stop streaming");
+  return FALSE;
+}
+
+static void
+gst_v4l2_buffer_pool_flush_start (GstBufferPool * bpool)
+{
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+
+  GST_DEBUG_OBJECT (pool, "start flushing");
+
+  gst_poll_set_flushing (pool->poll, TRUE);
+
+  if (pool->other_pool)
+    gst_buffer_pool_set_flushing (pool->other_pool, TRUE);
+}
+
+static void
+gst_v4l2_buffer_pool_flush_stop (GstBufferPool * bpool)
+{
+  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+  GstV4l2Object *obj = pool->obj;
+  gint i;
+
+  GST_DEBUG_OBJECT (pool, "stop flushing");
+
+  /* If we haven't started streaming yet, simply call streamon */
+  if (!pool->streaming)
+    goto streamon;
+
+  if (pool->other_pool)
+    gst_buffer_pool_set_flushing (pool->other_pool, FALSE);
+
+  if (!gst_v4l2_buffer_pool_streamoff (pool))
+    goto stop_failed;
+
+  gst_v4l2_allocator_flush (pool->vallocator);
+
+  /* Reset our state */
   switch (obj->mode) {
     case GST_V4L2_IO_RW:
       break;
@@ -823,118 +882,68 @@ stop_streaming (GstV4l2BufferPool * pool)
     {
       gsize num_allocated;
 
-      if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
-        goto stop_failed;
-
-      GST_DEBUG_OBJECT (pool, "STREAMOFF");
-
-      gst_v4l2_allocator_flush (pool->vallocator);
-
       num_allocated = gst_v4l2_allocator_num_allocated (pool->vallocator);
 
       for (i = 0; i < num_allocated; i++) {
+        /* Re-enqueue buffers */
         if (pool->buffers[i]) {
           GstBufferPool *bpool = (GstBufferPool *) pool;
           GstBuffer *buffer = pool->buffers[i];
 
           pool->buffers[i] = NULL;
-          g_atomic_int_add (&pool->num_queued, -1);
 
-          /* Remove qdata, this will unmap any map data in userptr */
+          /* Remove qdata, this will unmap any map data in
+           * userptr/dmabuf-import */
           gst_mini_object_set_qdata (GST_MINI_OBJECT (buffer),
               GST_V4L2_IMPORT_QUARK, NULL, NULL);
 
           if (V4L2_TYPE_IS_OUTPUT (obj->type))
             gst_buffer_unref (buffer);
           else
-            /* Give back the outstanding buffer to the pool */
-            GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
-                buffer);
+            gst_v4l2_buffer_pool_release_buffer (bpool, buffer);
+
+          g_atomic_int_add (&pool->num_queued, -1);
         }
       }
-      g_return_val_if_fail (pool->num_queued == 0, FALSE);
 
       break;
     }
     default:
-      g_return_val_if_reached (FALSE);
+      g_assert_not_reached ();
       break;
   }
 
-  pool->flushing = FALSE;
-  pool->streaming = FALSE;
-
-  return TRUE;
-
-  /* ERRORS */
-stop_failed:
-  {
-    GST_ERROR_OBJECT (pool, "error with STREAMOFF %d (%s)", errno,
-        g_strerror (errno));
-    return FALSE;
-  }
-}
-
-static gboolean
-gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
-{
-  gboolean ret;
-  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
-  GstV4l2Object *obj = pool->obj;
-
-  GST_DEBUG_OBJECT (pool, "stopping pool");
-
-  if (pool->group_released_handler > 0) {
-    g_signal_handler_disconnect (pool->vallocator,
-        pool->group_released_handler);
-    pool->group_released_handler = 0;
-  }
-
-  gst_poll_set_flushing (obj->poll, TRUE);
-  if (!stop_streaming (pool))
-    goto stop_failed;
-
-  ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool);
-
-  if (ret) {
-    GstV4l2Return vret;
-
-    vret = gst_v4l2_allocator_stop (pool->vallocator);
+streamon:
+  /* Start streaming on capture device only */
+  if (!V4L2_TYPE_IS_OUTPUT (obj->type))
+    gst_v4l2_buffer_pool_streamon (pool);
 
-    if (vret == GST_V4L2_BUSY) {
-      GST_WARNING_OBJECT (pool, "allocated buffer need to be reclaimed");
-      /* FIXME deal with reclaiming */
-    } else if (vret == GST_V4L2_ERROR) {
-      ret = FALSE;
-    }
-  }
+  gst_poll_set_flushing (pool->poll, FALSE);
 
-  return ret;
+  return;
 
   /* ERRORS */
 stop_failed:
   {
-    GST_ERROR_OBJECT (pool, "error with STREAMOFF %d (%s)", errno,
-        g_strerror (errno));
-    return FALSE;
+    GST_ERROR_OBJECT (pool, "device refused to flush");
   }
 }
 
 static GstFlowReturn
-gst_v4l2_object_poll (GstV4l2Object * v4l2object)
+gst_v4l2_buffer_pool_poll (GstV4l2BufferPool * pool)
 {
   gint ret;
 
-  if (v4l2object->can_poll_device) {
-    GST_LOG_OBJECT (v4l2object->element, "polling device");
-    ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
+  if (pool->can_poll_device) {
+    GST_LOG_OBJECT (pool, "polling device");
+    ret = gst_poll_wait (pool->poll, GST_CLOCK_TIME_NONE);
     if (G_UNLIKELY (ret < 0)) {
       if (errno == EBUSY)
         goto stopped;
       if (errno == ENXIO) {
-        GST_WARNING_OBJECT (v4l2object->element,
+        GST_WARNING_OBJECT (pool,
             "v4l2 device doesn't support polling. Disabling");
-        v4l2object->can_poll_device = FALSE;
+        pool->can_poll_device = FALSE;
       } else {
         if (errno != EAGAIN && errno != EINTR)
           goto select_error;
@@ -946,12 +955,12 @@ gst_v4l2_object_poll (GstV4l2Object * v4l2object)
   /* ERRORS */
 stopped:
   {
-    GST_DEBUG ("stop called");
+    GST_DEBUG_OBJECT (pool, "stop called");
     return GST_FLOW_FLUSHING;
   }
 select_error:
   {
-    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
+    GST_ELEMENT_ERROR (pool->obj->element, RESOURCE, READ, (NULL),
         ("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
     return GST_FLOW_ERROR;
   }
@@ -960,6 +969,7 @@ select_error:
 static GstFlowReturn
 gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf)
 {
+  GstFlowReturn ret;
   GstV4l2MemoryGroup *group = NULL;
   gint index;
 
@@ -971,8 +981,22 @@ gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf)
 
   index = group->buffer.index;
 
-  if (pool->buffers[index] != NULL)
-    goto already_queued;
+  if (V4L2_TYPE_IS_OUTPUT (pool->obj->type)) {
+    /* If already queued, dequeue it, so we keep the render order */
+    while (pool->buffers[index]) {
+      GstBuffer *tmp;
+
+      ret = gst_v4l2_buffer_pool_dqbuf (pool, &tmp);
+
+      if (ret != GST_FLOW_OK)
+        goto already_queued;
+
+      gst_buffer_unref (tmp);
+    }
+  } else {
+    /* Should never happen, would mean a buffer got freed twice */
+    g_return_val_if_fail (pool->buffers[index] == NULL, GST_FLOW_ERROR);
+  }
 
   GST_LOG_OBJECT (pool, "queuing buffer %i", index);
 
@@ -986,8 +1010,10 @@ gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf)
 
 already_queued:
   {
-    GST_ERROR_OBJECT (pool, "the buffer %i was already queued", index);
-    return GST_FLOW_ERROR;
+    if (ret != GST_FLOW_FLUSHING)
+      GST_ERROR_OBJECT (pool,
+          "buffer %i was already queued and we could not dequeue it", index);
+    return ret;
   }
 queue_failed:
   {
@@ -1010,7 +1036,7 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer)
   GstV4l2MemoryGroup *group;
   gint i;
 
-  if ((res = gst_v4l2_object_poll (obj)) != GST_FLOW_OK)
+  if ((res = gst_v4l2_buffer_pool_poll (pool)) != GST_FLOW_OK)
     goto poll_failed;
 
   GST_LOG_OBJECT (pool, "dequeueing a buffer");
@@ -1092,17 +1118,14 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
 {
   GstFlowReturn ret;
   GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+  GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
   GstV4l2Object *obj = pool->obj;
 
   GST_DEBUG_OBJECT (pool, "acquire");
 
-  if (GST_BUFFER_POOL_IS_FLUSHING (bpool))
-    goto flushing;
-
   /* If this is being called to resurect a lost buffer */
   if (params && params->flags & GST_V4L2_POOL_ACQUIRE_FLAG_RESURECT) {
-    ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool, buffer,
-        params);
+    ret = pclass->acquire_buffer (bpool, buffer, params);
     goto done;
   }
 
@@ -1114,8 +1137,7 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
         case GST_V4L2_IO_RW:
         {
           /* take empty buffer from the pool */
-          ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
-              buffer, params);
+          ret = pclass->acquire_buffer (bpool, buffer, params);
           break;
         }
         case GST_V4L2_IO_DMABUF:
@@ -1133,8 +1155,7 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
             GstBuffer *copy;
 
             if (GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP)) {
-              if (GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
-                      &copy, params) == GST_FLOW_OK) {
+              if (pclass->acquire_buffer (bpool, &copy, params) == GST_FLOW_OK) {
                 gst_v4l2_buffer_pool_release_buffer (bpool, copy);
                 break;
               }
@@ -1172,8 +1193,7 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
       switch (obj->mode) {
         case GST_V4L2_IO_RW:
           /* get an empty buffer */
-          ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
-              buffer, params);
+          ret = pclass->acquire_buffer (bpool, buffer, params);
           break;
 
         case GST_V4L2_IO_MMAP:
@@ -1181,8 +1201,7 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
         case GST_V4L2_IO_USERPTR:
         case GST_V4L2_IO_DMABUF_IMPORT:
           /* get a free unqueued buffer */
-          ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
-              buffer, params);
+          ret = pclass->acquire_buffer (bpool, buffer, params);
           break;
 
         default:
@@ -1199,19 +1218,13 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
   }
 done:
   return ret;
-
-  /* ERRORS */
-flushing:
-  {
-    GST_DEBUG_OBJECT (pool, "We are flushing");
-    return GST_FLOW_FLUSHING;
-  }
 }
 
 static void
 gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
 {
   GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+  GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
   GstV4l2Object *obj = pool->obj;
 
   GST_DEBUG_OBJECT (pool, "release buffer %p", buffer);
@@ -1224,7 +1237,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
       switch (obj->mode) {
         case GST_V4L2_IO_RW:
           /* release back in the pool */
-          GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer);
+          pclass->release_buffer (bpool, buffer);
           break;
 
         case GST_V4L2_IO_DMABUF:
@@ -1232,23 +1245,17 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
         case GST_V4L2_IO_USERPTR:
         case GST_V4L2_IO_DMABUF_IMPORT:
         {
-          if (pool->flushing) {
-            /* put back on outstanding list */
-            GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
-                buffer);
-          } else if (gst_v4l2_is_buffer_valid (buffer, NULL)) {
+          if (gst_v4l2_is_buffer_valid (buffer, NULL)) {
             /* queue back in the device */
             if (pool->other_pool)
               gst_v4l2_buffer_pool_prepare_buffer (pool, buffer, NULL);
             if (gst_v4l2_buffer_pool_qbuf (pool, buffer) != GST_FLOW_OK)
-              GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
-                  buffer);
+              pclass->release_buffer (bpool, buffer);
           } else {
             /* Simply release invalide/modified buffer, the allocator will
              * give it back later */
             GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
-            GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
-                buffer);
+            pclass->release_buffer (bpool, buffer);
           }
           break;
         }
@@ -1263,7 +1270,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
       switch (obj->mode) {
         case GST_V4L2_IO_RW:
           /* release back in the pool */
-          GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer);
+          pclass->release_buffer (bpool, buffer);
           break;
 
         case GST_V4L2_IO_MMAP:
@@ -1278,8 +1285,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
             /* Simply release invalide/modified buffer, the allocator will
              * give it back later */
             GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
-            GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
-                buffer);
+            pclass->release_buffer (bpool, buffer);
             break;
           }
 
@@ -1297,8 +1303,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
             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,
-                buffer);
+            pclass->release_buffer (bpool, buffer);
           } else {
             /* We keep a ref on queued buffer, so this should never happen */
             g_assert_not_reached ();
@@ -1332,6 +1337,8 @@ gst_v4l2_buffer_pool_finalize (GObject * object)
   if (pool->video_fd >= 0)
     v4l2_close (pool->video_fd);
 
+  gst_poll_free (pool->poll);
+
   if (pool->vallocator)
     gst_object_unref (pool->vallocator);
 
@@ -1352,6 +1359,8 @@ gst_v4l2_buffer_pool_finalize (GObject * object)
 static void
 gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool)
 {
+  pool->poll = gst_poll_new (TRUE);
+  pool->can_poll_device = TRUE;
 }
 
 static void
@@ -1368,6 +1377,8 @@ gst_v4l2_buffer_pool_class_init (GstV4l2BufferPoolClass * klass)
   bufferpool_class->alloc_buffer = gst_v4l2_buffer_pool_alloc_buffer;
   bufferpool_class->acquire_buffer = gst_v4l2_buffer_pool_acquire_buffer;
   bufferpool_class->release_buffer = gst_v4l2_buffer_pool_release_buffer;
+  bufferpool_class->flush_start = gst_v4l2_buffer_pool_flush_start;
+  bufferpool_class->flush_stop = gst_v4l2_buffer_pool_flush_stop;
 }
 
 /**
@@ -1385,6 +1396,7 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
   GstStructure *config;
   gchar *name, *parent_name;
   gint fd;
+  GstPollFD pollfd = GST_POLL_FD_INIT;
 
   fd = v4l2_dup (obj->video_fd);
   if (fd < 0)
@@ -1400,8 +1412,16 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
       "name", name, NULL);
   g_free (name);
 
+  pollfd.fd = fd;
+  gst_poll_add_fd (pool->poll, &pollfd);
+  if (V4L2_TYPE_IS_OUTPUT (obj->type))
+    gst_poll_fd_ctl_write (pool->poll, &pollfd, TRUE);
+  else
+    gst_poll_fd_ctl_read (pool->poll, &pollfd, TRUE);
+
   pool->video_fd = fd;
   pool->obj = obj;
+  pool->can_poll_device = TRUE;
 
   pool->vallocator =
       gst_v4l2_allocator_new (GST_OBJECT (pool), obj->video_fd, &obj->format);
@@ -1440,7 +1460,7 @@ gst_v4l2_do_read (GstV4l2BufferPool * pool, GstBuffer * buf)
   gst_buffer_map (buf, &map, GST_MAP_WRITE);
 
   do {
-    if ((res = gst_v4l2_object_poll (obj)) != GST_FLOW_OK)
+    if ((res = gst_v4l2_buffer_pool_poll (pool)) != GST_FLOW_OK)
       goto poll_error;
 
     amount = v4l2_read (obj->video_fd, map.data, toread);
@@ -1508,6 +1528,9 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf)
 
   g_return_val_if_fail (gst_buffer_pool_is_active (bpool), GST_FLOW_ERROR);
 
+  if (GST_BUFFER_POOL_IS_FLUSHING (pool))
+    return GST_FLOW_FLUSHING;
+
   switch (obj->type) {
     case V4L2_BUF_TYPE_VIDEO_CAPTURE:
     case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
@@ -1626,11 +1649,9 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf)
 
           /* if we are not streaming yet (this is the first buffer, start
            * streaming now */
-          if (!pool->streaming) {
-            if (!start_streaming (pool)) {
-              gst_buffer_unref (to_queue);
-              goto start_failed;
-            }
+          if (!gst_v4l2_buffer_pool_streamon (pool)) {
+            gst_buffer_unref (to_queue);
+            goto start_failed;
           }
 
           if (g_atomic_int_get (&pool->num_queued) >= pool->min_latency) {
@@ -1694,53 +1715,6 @@ start_failed:
   }
 }
 
-
-/**
- * gst_v4l2_buffer_pool_stop_streaming:
- * @bpool: a #GstBufferPool
- *
- * First, set obj->poll to be flushing
- * Call STREAMOFF to clear QUEUED flag on every driver buffers.
- * Then release all buffers that are in pool->buffers array.
- *
- * Returns: TRUE on success.
- */
-gboolean
-gst_v4l2_buffer_pool_stop_streaming (GstV4l2BufferPool * pool)
-{
-  GST_DEBUG_OBJECT (pool, "stop streaming");
-
-  if (!stop_streaming (pool))
-    goto stop_failed;
-
-  return TRUE;
-
-  /* ERRORS */
-stop_failed:
-  {
-    GST_ERROR_OBJECT (pool, "failed to stop streaming");
-    return FALSE;
-  }
-}
-
-gboolean
-gst_v4l2_buffer_pool_start_streaming (GstV4l2BufferPool * pool)
-{
-  GST_DEBUG_OBJECT (pool, "start straming");
-
-  if (!start_streaming (pool))
-    goto start_failed;
-
-  return TRUE;
-
-  /* ERRORS */
-start_failed:
-  {
-    GST_ERROR_OBJECT (pool, "failed to start streaming");
-    return FALSE;
-  }
-}
-
 void
 gst_v4l2_buffer_pool_set_other_pool (GstV4l2BufferPool * pool,
     GstBufferPool * other_pool)
index eb9e814..65486bf 100644 (file)
@@ -50,6 +50,8 @@ struct _GstV4l2BufferPool
 
   GstV4l2Object *obj;        /* the v4l2 object */
   gint video_fd;             /* a dup(2) of the v4l2object's video_fd */
+  GstPoll *poll;             /* a poll for video_fd */
+  gboolean can_poll_device;
 
   GstV4l2Allocator *vallocator;
   GstAllocator *allocator;
@@ -85,9 +87,6 @@ GstBufferPool *     gst_v4l2_buffer_pool_new     (GstV4l2Object *obj, GstCaps *c
 
 GstFlowReturn       gst_v4l2_buffer_pool_process (GstV4l2BufferPool * bpool, GstBuffer ** buf);
 
-gboolean            gst_v4l2_buffer_pool_stop_streaming   (GstV4l2BufferPool * pool);
-gboolean            gst_v4l2_buffer_pool_start_streaming  (GstV4l2BufferPool * pool);
-
 void                gst_v4l2_buffer_pool_set_other_pool (GstV4l2BufferPool * pool,
                                                          GstBufferPool * other_pool);
 
index 7ab1dc1..69990ff 100644 (file)
@@ -431,7 +431,6 @@ gst_v4l2_object_new (GstElement * element,
   v4l2object->update_fps_func = update_fps_func;
 
   v4l2object->video_fd = -1;
-  v4l2object->poll = gst_poll_new (TRUE);
   v4l2object->active = FALSE;
   v4l2object->videodev = g_strdup (default_device);
 
@@ -461,9 +460,6 @@ gst_v4l2_object_destroy (GstV4l2Object * v4l2object)
   if (v4l2object->videodev)
     g_free (v4l2object->videodev);
 
-  if (v4l2object->poll)
-    gst_poll_free (v4l2object->poll);
-
   if (v4l2object->channel)
     g_free (v4l2object->channel);
 
@@ -3043,19 +3039,27 @@ gst_v4l2_object_caps_equal (GstV4l2Object * v4l2object, GstCaps * caps)
 gboolean
 gst_v4l2_object_unlock (GstV4l2Object * v4l2object)
 {
-  GST_LOG_OBJECT (v4l2object->element, "flush poll");
-  gst_poll_set_flushing (v4l2object->poll, TRUE);
+  gboolean ret = TRUE;
 
-  return TRUE;
+  GST_LOG_OBJECT (v4l2object->element, "start flushing");
+
+  if (v4l2object->pool && gst_buffer_pool_is_active (v4l2object->pool))
+    gst_buffer_pool_set_flushing (v4l2object->pool, TRUE);
+
+  return ret;
 }
 
 gboolean
 gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object)
 {
-  GST_LOG_OBJECT (v4l2object->element, "flush stop poll");
-  gst_poll_set_flushing (v4l2object->poll, FALSE);
+  gboolean ret = TRUE;
 
-  return TRUE;
+  GST_LOG_OBJECT (v4l2object->element, "stop flushing");
+
+  if (v4l2object->pool && gst_buffer_pool_is_active (v4l2object->pool))
+    gst_buffer_pool_set_flushing (v4l2object->pool, FALSE);
+
+  return ret;
 }
 
 gboolean
index dbab527..c13cd64 100644 (file)
@@ -88,8 +88,6 @@ struct _GstV4l2Object {
   /* the video-device's file descriptor */
   gint video_fd;
   GstV4l2IOMode mode;
-  GstPoll * poll;
-  gboolean can_poll_device;
 
   gboolean active;
   gboolean streaming;
index a314bd0..4ccddbb 100644 (file)
@@ -533,19 +533,6 @@ gst_v4l2_transform_sink_event (GstBaseTransform * trans, GstEvent * event)
       gst_v4l2_object_unlock (self->v4l2output);
       gst_v4l2_object_unlock (self->v4l2capture);
       break;
-    case GST_EVENT_FLUSH_STOP:
-      GST_DEBUG_OBJECT (self, "flush stop");
-
-      if (self->v4l2output->pool) {
-        gst_v4l2_buffer_pool_stop_streaming (GST_V4L2_BUFFER_POOL
-            (self->v4l2output->pool));
-        gst_v4l2_buffer_pool_start_streaming (GST_V4L2_BUFFER_POOL
-            (self->v4l2capture->pool));
-        gst_v4l2_object_unlock_stop (self->v4l2output);
-      }
-      if (self->v4l2capture->pool)
-        gst_v4l2_buffer_pool_stop_streaming (GST_V4L2_BUFFER_POOL
-            (self->v4l2capture->pool));
     default:
       break;
   }
@@ -555,12 +542,9 @@ gst_v4l2_transform_sink_event (GstBaseTransform * trans, GstEvent * event)
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_FLUSH_STOP:
       /* Buffer should be back now */
-      if (self->v4l2capture->pool) {
-        gst_v4l2_buffer_pool_start_streaming (GST_V4L2_BUFFER_POOL
-            (self->v4l2capture->pool));
-        gst_v4l2_object_unlock_stop (self->v4l2capture);
-      }
-      GST_DEBUG_OBJECT (self, "flush stop done");
+      GST_DEBUG_OBJECT (self, "flush stop");
+      gst_v4l2_object_unlock_stop (self->v4l2capture);
+      gst_v4l2_object_unlock_stop (self->v4l2output);
       break;
     default:
       break;
index a63db03..f3e03c7 100644 (file)
@@ -259,23 +259,23 @@ gst_v4l2_video_dec_flush (GstVideoDecoder * decoder)
 {
   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
 
-  GST_DEBUG_OBJECT (self, "Flushing");
+  GST_DEBUG_OBJECT (self, "Flushed");
 
-  /* Wait for capture thread to stop */
-  GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
-  gst_v4l2_object_unlock (self->v4l2capture);
-  gst_pad_stop_task (decoder->srcpad);
-  GST_VIDEO_DECODER_STREAM_LOCK (decoder);
+  /* Ensure the processing thread has stopped for the reverse playback
+   * discount case */
+  if (g_atomic_int_get (&self->processing)) {
+    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
 
-  self->output_flow = GST_FLOW_OK;
+    gst_v4l2_object_unlock (self->v4l2output);
+    gst_v4l2_object_unlock (self->v4l2capture);
+    gst_pad_stop_task (decoder->srcpad);
+    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+  }
 
-  if (self->v4l2output->pool)
-    gst_v4l2_buffer_pool_stop_streaming (GST_V4L2_BUFFER_POOL
-        (self->v4l2output->pool));
+  self->output_flow = GST_FLOW_OK;
 
-  if (self->v4l2capture->pool)
-    gst_v4l2_buffer_pool_stop_streaming (GST_V4L2_BUFFER_POOL
-        (self->v4l2capture->pool));
+  gst_v4l2_object_unlock_stop (self->v4l2output);
+  gst_v4l2_object_unlock_stop (self->v4l2capture);
 
   return TRUE;
 }
@@ -308,14 +308,12 @@ gst_v4l2_video_dec_finish (GstVideoDecoder * decoder)
             v4l2output->pool), &buffer);
     gst_buffer_unref (buffer);
   }
-  GST_VIDEO_DECODER_STREAM_LOCK (decoder);
 
-  /* Ensure the processing thread has stopped */
-  if (g_atomic_int_get (&self->processing)) {
-    gst_v4l2_object_unlock (self->v4l2capture);
-    gst_pad_stop_task (decoder->srcpad);
-    g_assert (g_atomic_int_get (&self->processing) == FALSE);
-  }
+  /* and ensure the processing thread has stopped in case another error
+   * occured. */
+  gst_v4l2_object_unlock (self->v4l2capture);
+  gst_pad_stop_task (decoder->srcpad);
+  GST_VIDEO_DECODER_STREAM_LOCK (decoder);
 
   if (ret == GST_FLOW_FLUSHING)
     ret = self->output_flow;
@@ -489,11 +487,9 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
     }
 
     GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
-    gst_v4l2_object_unlock_stop (self->v4l2output);
     ret =
         gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
             v4l2output->pool), &codec_data);
-    gst_v4l2_object_unlock (self->v4l2output);
     GST_VIDEO_DECODER_STREAM_LOCK (decoder);
 
     gst_buffer_unref (codec_data);
@@ -532,14 +528,6 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
 
     GST_DEBUG_OBJECT (self, "Starting decoding thread");
 
-    /* Enable processing input */
-    if (!gst_v4l2_buffer_pool_start_streaming (GST_V4L2_BUFFER_POOL
-            (self->v4l2capture->pool)))
-      goto start_streaming_failed;
-
-    gst_v4l2_object_unlock_stop (self->v4l2output);
-    gst_v4l2_object_unlock_stop (self->v4l2capture);
-
     /* Start the processing task, when it quits, the task will disable input
      * processing to unlock input if draining, or prevent potential block */
     g_atomic_int_set (&self->processing, TRUE);
@@ -578,13 +566,6 @@ not_negotiated:
     ret = GST_FLOW_NOT_NEGOTIATED;
     goto drop;
   }
-start_streaming_failed:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
-        (_("Failed to re-enabled decoder.")),
-        ("Could not re-enqueue and start streaming on decide."));
-    return GST_FLOW_ERROR;
-  }
 activate_failed:
   {
     GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
@@ -724,17 +705,31 @@ static gboolean
 gst_v4l2_video_dec_sink_event (GstVideoDecoder * decoder, GstEvent * event)
 {
   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+  gboolean ret;
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_FLUSH_START:
       GST_DEBUG_OBJECT (self, "flush start");
       gst_v4l2_object_unlock (self->v4l2output);
       gst_v4l2_object_unlock (self->v4l2capture);
+      break;
     default:
       break;
   }
 
-  return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (decoder, event);
+  ret = GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (decoder, event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      /* The processing thread should stop now, wait for it */
+      gst_pad_stop_task (decoder->srcpad);
+      GST_DEBUG_OBJECT (self, "flush start done");
+      break;
+    default:
+      break;
+  }
+
+  return ret;
 }
 
 static GstStateChangeReturn
@@ -742,11 +737,13 @@ gst_v4l2_video_dec_change_state (GstElement * element,
     GstStateChange transition)
 {
   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (element);
+  GstVideoDecoder *decoder = GST_VIDEO_DECODER (element);
 
   if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) {
     g_atomic_int_set (&self->active, FALSE);
     gst_v4l2_object_unlock (self->v4l2output);
     gst_v4l2_object_unlock (self->v4l2capture);
+    gst_pad_stop_task (decoder->srcpad);
   }
 
   return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
index 7936853..d1cc284 100644 (file)
@@ -514,7 +514,6 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
 {
   struct stat st;
   int libv4l2_fd;
-  GstPollFD pollfd = GST_POLL_FD_INIT;
 
   GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
       v4l2object->videodev);
@@ -551,8 +550,6 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
   if (libv4l2_fd != -1)
     v4l2object->video_fd = libv4l2_fd;
 
-  v4l2object->can_poll_device = TRUE;
-
   /* get capabilities, error will be posted */
   if (!gst_v4l2_get_capabilities (v4l2object))
     goto error;
@@ -589,14 +586,6 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
       "Opened device '%s' (%s) successfully",
       v4l2object->vcap.card, v4l2object->videodev);
 
-  pollfd.fd = v4l2object->video_fd;
-  gst_poll_add_fd (v4l2object->poll, &pollfd);
-  if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
-      || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-    gst_poll_fd_ctl_read (v4l2object->poll, &pollfd, TRUE);
-  else
-    gst_poll_fd_ctl_write (v4l2object->poll, &pollfd, TRUE);
-
   if (v4l2object->extra_controls)
     gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
 
@@ -672,8 +661,6 @@ error:
 gboolean
 gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other)
 {
-  GstPollFD pollfd = GST_POLL_FD_INIT;
-
   GST_DEBUG_OBJECT (v4l2object->element, "Trying to dup device %s",
       other->videodev);
 
@@ -696,16 +683,7 @@ gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other)
       "Cloned device '%s' (%s) successfully",
       v4l2object->vcap.card, v4l2object->videodev);
 
-  pollfd.fd = v4l2object->video_fd;
-  gst_poll_add_fd (v4l2object->poll, &pollfd);
-  if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
-      || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-    gst_poll_fd_ctl_read (v4l2object->poll, &pollfd, TRUE);
-  else
-    gst_poll_fd_ctl_write (v4l2object->poll, &pollfd, TRUE);
-
   v4l2object->never_interlaced = other->never_interlaced;
-  v4l2object->can_poll_device = TRUE;
 
   return TRUE;
 
@@ -728,7 +706,6 @@ not_open:
 gboolean
 gst_v4l2_close (GstV4l2Object * v4l2object)
 {
-  GstPollFD pollfd = GST_POLL_FD_INIT;
   GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s",
       v4l2object->videodev);
 
@@ -737,8 +714,6 @@ gst_v4l2_close (GstV4l2Object * v4l2object)
 
   /* close device */
   v4l2_close (v4l2object->video_fd);
-  pollfd.fd = v4l2object->video_fd;
-  gst_poll_remove_fd (v4l2object->poll, &pollfd);
   v4l2object->video_fd = -1;
 
   /* empty lists */