From 2e0fb42e868fc9f6d98b028def80a3e953527307 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 23 May 2014 14:12:10 -0400 Subject: [PATCH] v4l2bufferpool: Port to bufferpool flush_start/stop method --- sys/v4l2/gstv4l2allocator.c | 4 + sys/v4l2/gstv4l2bufferpool.c | 424 +++++++++++++++++++------------------------ sys/v4l2/gstv4l2bufferpool.h | 5 +- sys/v4l2/gstv4l2object.c | 24 ++- sys/v4l2/gstv4l2object.h | 2 - sys/v4l2/gstv4l2transform.c | 22 +-- sys/v4l2/gstv4l2videodec.c | 72 ++++---- sys/v4l2/v4l2_calls.c | 25 --- 8 files changed, 248 insertions(+), 330 deletions(-) diff --git a/sys/v4l2/gstv4l2allocator.c b/sys/v4l2/gstv4l2allocator.c index dc93b2b..12777c5 100644 --- a/sys/v4l2/gstv4l2allocator.c +++ b/sys/v4l2/gstv4l2allocator.c @@ -1219,6 +1219,10 @@ gst_v4l2_allocator_qbuf (GstV4l2Allocator * allocator, gboolean ret = TRUE; gint i; + /* Buffer already queued */ + if (IS_QUEUED (group->buffer)) + return TRUE; + /* update sizes */ if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { for (i = 0; i < group->n_mem; i++) diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c index f213769..a37ff7f 100644 --- a/sys/v4l2/gstv4l2bufferpool.c +++ b/sys/v4l2/gstv4l2bufferpool.c @@ -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 - 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, ¶ms); + 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 != 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; @@ -741,7 +731,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) @@ -749,22 +739,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 */ @@ -795,26 +777,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"); - gst_poll_set_flushing (obj->poll, TRUE); + 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); + + g_atomic_int_add (&pool->num_queued, -1); + } + } + + ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool); + + if (ret) { + GstV4l2Return vret; + + vret = gst_v4l2_allocator_stop (pool->vallocator); - 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; + 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; @@ -825,118 +884,69 @@ 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; - pool->num_queued--; - /* 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); + GST_LOG_OBJECT (pool, "device polled %i %s", ret, g_strerror (errno)); 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; @@ -948,12 +958,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; } @@ -982,7 +992,7 @@ gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf) goto queue_failed; pool->buffers[index] = buf; - pool->num_queued++; + g_atomic_int_inc (&pool->num_queued); return GST_FLOW_OK; @@ -1010,7 +1020,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"); @@ -1028,7 +1038,7 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer) /* mark the buffer outstanding */ pool->buffers[group->buffer.index] = NULL; - pool->num_queued--; + g_atomic_int_add (&pool->num_queued, -1); timestamp = GST_TIMEVAL_TO_TIME (group->buffer.timestamp); @@ -1092,17 +1102,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 +1121,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: @@ -1129,12 +1135,11 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer, goto done; /* start copying buffers when we are running low on buffers */ - if (pool->num_queued < pool->copy_threshold) { + if (g_atomic_int_get (&pool->num_queued) < pool->copy_threshold) { GstBuffer *copy; if (GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP)) { - if (GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool, - ©, params) == GST_FLOW_OK) { + if (pclass->acquire_buffer (bpool, ©, params) == GST_FLOW_OK) { gst_v4l2_buffer_pool_release_buffer (bpool, copy); break; } @@ -1172,8 +1177,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 +1185,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 +1202,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 +1221,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 +1229,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 +1254,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 +1269,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 +1287,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 +1321,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 +1343,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 +1361,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 +1380,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 +1396,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 +1444,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 +1512,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,14 +1633,12 @@ 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 (pool->num_queued == + if (g_atomic_int_get (&pool->num_queued) == gst_v4l2_allocator_num_allocated (pool->vallocator)) { GstBuffer *out; /* all buffers are queued, try to dequeue one and release it back @@ -1692,53 +1697,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) diff --git a/sys/v4l2/gstv4l2bufferpool.h b/sys/v4l2/gstv4l2bufferpool.h index 3459637..8fd0f61 100644 --- a/sys/v4l2/gstv4l2bufferpool.h +++ b/sys/v4l2/gstv4l2bufferpool.h @@ -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; @@ -84,9 +86,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); diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index f868d56..ea61aec 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -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 diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h index dbab527..c13cd64 100644 --- a/sys/v4l2/gstv4l2object.h +++ b/sys/v4l2/gstv4l2object.h @@ -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; diff --git a/sys/v4l2/gstv4l2transform.c b/sys/v4l2/gstv4l2transform.c index a314bd0..4ccddbb 100644 --- a/sys/v4l2/gstv4l2transform.c +++ b/sys/v4l2/gstv4l2transform.c @@ -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; diff --git a/sys/v4l2/gstv4l2videodec.c b/sys/v4l2/gstv4l2videodec.c index 1b4a051..b62e318 100644 --- a/sys/v4l2/gstv4l2videodec.c +++ b/sys/v4l2/gstv4l2videodec.c @@ -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; @@ -475,11 +473,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); @@ -517,14 +513,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); @@ -558,13 +546,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, @@ -686,16 +667,29 @@ 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_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); + break; + default: + break; + } + + return ret; } static GstStateChangeReturn @@ -703,11 +697,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); diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c index 7936853..d1cc284 100644 --- a/sys/v4l2/v4l2_calls.c +++ b/sys/v4l2/v4l2_calls.c @@ -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 */ -- 2.7.4