v4l2bufferpool: Don't stop streaming when pool is flushing
The purpose of being able to flush the buffer pool is only to
unlock any blocked operation. Doing streamoff/streamon had the
side effect of turning off and on the camera. As we do a flush_start
/ flush_stop sequence when shutting down, that would cause a really
quick sequence of streamoff/streamon/streamoff/close which was
causing some cameras to stop working.
https://bugzilla.gnome.org/show_bug.cgi?id=783945
diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c
index 56a8279..b5a9f47 100644
--- a/sys/v4l2/gstv4l2bufferpool.c
+++ b/sys/v4l2/gstv4l2bufferpool.c
@@ -610,67 +610,6 @@
}
}
-static gboolean
-gst_v4l2_buffer_pool_streamon (GstV4l2BufferPool * pool)
-{
- GstV4l2Object *obj = pool->obj;
-
- 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 (obj->ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
- goto streamon_failed;
-
- pool->streaming = TRUE;
-
- GST_DEBUG_OBJECT (pool, "Started streaming");
- }
- break;
- default:
- break;
- }
-
- return TRUE;
-
-streamon_failed:
- {
- GST_ERROR_OBJECT (pool, "error with STREAMON %d (%s)", errno,
- g_strerror (errno));
- return FALSE;
- }
-}
-
-static void
-gst_v4l2_buffer_pool_streamoff (GstV4l2BufferPool * pool)
-{
- GstV4l2Object *obj = pool->obj;
-
- 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 (obj->ioctl (pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
- GST_WARNING_OBJECT (pool, "STREAMOFF failed with errno %d (%s)",
- errno, g_strerror (errno));
-
- pool->streaming = FALSE;
-
- GST_DEBUG_OBJECT (pool, "Stopped streaming");
-
- if (pool->vallocator)
- gst_v4l2_allocator_flush (pool->vallocator);
- }
- break;
- default:
- break;
- }
-}
-
static GstFlowReturn
gst_v4l2_buffer_pool_resurect_buffer (GstV4l2BufferPool * pool)
{
@@ -698,6 +637,98 @@
}
static gboolean
+gst_v4l2_buffer_pool_streamon (GstV4l2BufferPool * pool)
+{
+ GstV4l2Object *obj = pool->obj;
+
+ if (pool->streaming)
+ return TRUE;
+
+ 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 (!V4L2_TYPE_IS_OUTPUT (pool->obj->type)) {
+ /* For captures, we need to enqueue buffers before we start streaming,
+ * so the driver don't underflow immediatly. As we have put then back
+ * into the base class queue, resurect them, then releasing will queue
+ * them back. */
+ while (gst_v4l2_buffer_pool_resurect_buffer (pool) == GST_FLOW_OK)
+ continue;
+ }
+
+ if (obj->ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
+ goto streamon_failed;
+
+ pool->streaming = TRUE;
+
+ GST_DEBUG_OBJECT (pool, "Started streaming");
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+
+streamon_failed:
+ {
+ GST_ERROR_OBJECT (pool, "error with STREAMON %d (%s)", errno,
+ g_strerror (errno));
+ return FALSE;
+ }
+}
+
+/* Call with streamlock held, or when streaming threads are down */
+static void
+gst_v4l2_buffer_pool_streamoff (GstV4l2BufferPool * pool)
+{
+ GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
+ GstV4l2Object *obj = pool->obj;
+ gint i;
+
+ if (!pool->streaming)
+ return;
+
+ 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 (obj->ioctl (pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
+ GST_WARNING_OBJECT (pool, "STREAMOFF failed with errno %d (%s)",
+ errno, g_strerror (errno));
+
+ pool->streaming = FALSE;
+
+ GST_DEBUG_OBJECT (pool, "Stopped streaming");
+
+ if (pool->vallocator)
+ gst_v4l2_allocator_flush (pool->vallocator);
+ break;
+ default:
+ break;
+ }
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (pool->buffers[i]) {
+ GstBuffer *buffer = pool->buffers[i];
+ GstBufferPool *bpool = GST_BUFFER_POOL (pool);
+
+ pool->buffers[i] = NULL;
+
+ if (V4L2_TYPE_IS_OUTPUT (pool->obj->type))
+ gst_v4l2_buffer_pool_release_buffer (bpool, buffer);
+ else /* Don't re-enqueue capture buffer on stop */
+ pclass->release_buffer (bpool, buffer);
+
+ g_atomic_int_add (&pool->num_queued, -1);
+ }
+ }
+}
+
+static gboolean
gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
{
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
@@ -707,7 +738,7 @@
GstCaps *caps;
guint size, min_buffers, max_buffers;
guint max_latency, min_latency, copy_threshold = 0;
- gboolean can_allocate = FALSE;
+ gboolean can_allocate = FALSE, ret = TRUE;
GST_DEBUG_OBJECT (pool, "activating pool");
@@ -838,12 +869,14 @@
if (!pclass->start (bpool))
goto start_failed;
- if (!V4L2_TYPE_IS_OUTPUT (obj->type))
+ 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_resurect_buffer), pool);
+ ret = gst_v4l2_buffer_pool_streamon (pool);
+ }
- return TRUE;
+ return ret;
/* ERRORS */
wrong_config:
@@ -877,9 +910,7 @@
gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
{
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
- GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
gboolean ret;
- gint i;
GST_DEBUG_OBJECT (pool, "stopping pool");
@@ -897,21 +928,6 @@
gst_v4l2_buffer_pool_streamoff (pool);
- 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_v4l2_buffer_pool_release_buffer (bpool, buffer);
- else /* Don't re-enqueue capture buffer on stop */
- pclass->release_buffer (bpool, buffer);
-
- g_atomic_int_add (&pool->num_queued, -1);
- }
- }
-
ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool);
if (ret && pool->vallocator) {
@@ -950,65 +966,12 @@
gst_v4l2_buffer_pool_flush_stop (GstBufferPool * bpool)
{
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
- GstV4l2Object *obj = pool->obj;
- GstBuffer *buffers[VIDEO_MAX_FRAME];
- 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);
- GST_OBJECT_LOCK (pool);
- gst_v4l2_buffer_pool_streamoff (pool);
- /* Remember buffers to re-enqueue */
- memcpy (buffers, pool->buffers, sizeof (buffers));
- memset (pool->buffers, 0, sizeof (pool->buffers));
- GST_OBJECT_UNLOCK (pool);
-
- /* Reset our state */
- 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 (i = 0; i < VIDEO_MAX_FRAME; i++) {
- /* Re-enqueue buffers */
- if (buffers[i]) {
- GstBufferPool *bpool = (GstBufferPool *) pool;
- GstBuffer *buffer = buffers[i];
-
- /* 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 (buffer->pool == NULL)
- gst_v4l2_buffer_pool_release_buffer (bpool, buffer);
-
- g_atomic_int_add (&pool->num_queued, -1);
- }
- }
-
- break;
- }
- default:
- g_assert_not_reached ();
- break;
- }
-
-streamon:
- /* Start streaming on capture device only */
- if (!V4L2_TYPE_IS_OUTPUT (obj->type))
- gst_v4l2_buffer_pool_streamon (pool);
-
gst_poll_set_flushing (pool->poll, FALSE);
}
@@ -2037,3 +2000,17 @@
pool->enable_copy_threshold = copy;
GST_OBJECT_UNLOCK (pool);
}
+
+gboolean
+gst_v4l2_buffer_pool_flush (GstBufferPool * bpool)
+{
+ GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+ gboolean ret = TRUE;
+
+ gst_v4l2_buffer_pool_streamoff (pool);
+
+ if (!V4L2_TYPE_IS_OUTPUT (pool->obj->type))
+ ret = gst_v4l2_buffer_pool_streamon (pool);
+
+ return ret;
+}
diff --git a/sys/v4l2/gstv4l2bufferpool.h b/sys/v4l2/gstv4l2bufferpool.h
index eff7737..0fffc71 100644
--- a/sys/v4l2/gstv4l2bufferpool.h
+++ b/sys/v4l2/gstv4l2bufferpool.h
@@ -107,6 +107,8 @@
void gst_v4l2_buffer_pool_copy_at_threshold (GstV4l2BufferPool * pool,
gboolean copy);
+gboolean gst_v4l2_buffer_pool_flush (GstBufferPool *pool);
+
G_END_DECLS
#endif /*__GST_V4L2_BUFFER_POOL_H__ */
diff --git a/sys/v4l2/gstv4l2transform.c b/sys/v4l2/gstv4l2transform.c
index feed7bf..0c29f91 100644
--- a/sys/v4l2/gstv4l2transform.c
+++ b/sys/v4l2/gstv4l2transform.c
@@ -989,6 +989,8 @@
GST_DEBUG_OBJECT (self, "flush stop");
gst_v4l2_object_unlock_stop (self->v4l2capture);
gst_v4l2_object_unlock_stop (self->v4l2output);
+ gst_v4l2_buffer_pool_flush (self->v4l2output->pool);
+ gst_v4l2_buffer_pool_flush (self->v4l2capture->pool);
break;
default:
break;
diff --git a/sys/v4l2/gstv4l2videodec.c b/sys/v4l2/gstv4l2videodec.c
index 8e369fa..0f19cc6 100644
--- a/sys/v4l2/gstv4l2videodec.c
+++ b/sys/v4l2/gstv4l2videodec.c
@@ -282,6 +282,9 @@
gst_v4l2_object_unlock_stop (self->v4l2output);
gst_v4l2_object_unlock_stop (self->v4l2capture);
+ gst_v4l2_buffer_pool_flush (self->v4l2output->pool);
+ gst_v4l2_buffer_pool_flush (self->v4l2capture->pool);
+
return TRUE;
}
diff --git a/sys/v4l2/gstv4l2videoenc.c b/sys/v4l2/gstv4l2videoenc.c
index ee89cec..c322f5d 100644
--- a/sys/v4l2/gstv4l2videoenc.c
+++ b/sys/v4l2/gstv4l2videoenc.c
@@ -218,6 +218,9 @@
gst_v4l2_object_stop (self->v4l2output);
gst_v4l2_object_stop (self->v4l2capture);
+ gst_v4l2_buffer_pool_flush (self->v4l2output->pool);
+ gst_v4l2_buffer_pool_flush (self->v4l2capture->pool);
+
if (self->input_state) {
gst_video_codec_state_unref (self->input_state);
self->input_state = NULL;