diff options
author | Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> | 2014-05-24 20:20:07 -0400 |
---|---|---|
committer | Nicolas Dufresne <nicolas.dufresne@collabora.com> | 2014-05-26 13:43:30 -0400 |
commit | e2fd7e274eb5bdb3fa03c4e8254086f42cf80b0c (patch) | |
tree | 8b054cc82962c072267153660d8dabdb8c5737d0 /sys | |
parent | f4d9e126140578f2a79b3b4f93323064b52d8b6d (diff) | |
download | gstreamer-plugins-good-e2fd7e274eb5bdb3fa03c4e8254086f42cf80b0c.tar.gz |
v4l2bufferpool: Port to bufferpool flush_start/stop method
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
Diffstat (limited to 'sys')
-rw-r--r-- | sys/v4l2/gstv4l2allocator.c | 2 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2bufferpool.c | 440 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2bufferpool.h | 5 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2object.c | 24 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2object.h | 2 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2transform.c | 22 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2videodec.c | 73 | ||||
-rw-r--r-- | sys/v4l2/v4l2_calls.c | 25 |
8 files changed, 263 insertions, 330 deletions
diff --git a/sys/v4l2/gstv4l2allocator.c b/sys/v4l2/gstv4l2allocator.c index 6f3dfb2eb..416770b5b 100644 --- a/sys/v4l2/gstv4l2allocator.c +++ b/sys/v4l2/gstv4l2allocator.c @@ -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++) diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c index e39ac72ba..a67887af1 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 - 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, ¶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 != 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, - ©, params) == GST_FLOW_OK) { + if (pclass->acquire_buffer (bpool, ©, 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) diff --git a/sys/v4l2/gstv4l2bufferpool.h b/sys/v4l2/gstv4l2bufferpool.h index eb9e81405..65486bff8 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; @@ -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); diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index 7ab1dc17d..69990ff02 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 dbab52744..c13cd6456 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 a314bd0ef..4ccddbba7 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 a63db037d..f3e03c78d 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; @@ -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); diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c index 793685380..d1cc2842d 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 */ |