Revert "v4l2bufferpool: Port to bufferpool flush_start/stop method"

This reverts commit 2e0fb42e86.

Conflicts:
	sys/v4l2/gstv4l2allocator.c
	sys/v4l2/gstv4l2bufferpool.c
	sys/v4l2/gstv4l2videodec.c
This commit is contained in:
Nicolas Dufresne 2014-05-24 20:00:14 -04:00
parent ba10cb14ea
commit 2e89f4ecff
8 changed files with 328 additions and 249 deletions

View file

@ -1221,12 +1221,6 @@ gst_v4l2_allocator_qbuf (GstV4l2Allocator * allocator,
gboolean ret = TRUE;
gint i;
g_return_val_if_fail (g_atomic_int_get (&allocator->active), FALSE);
/* 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++)

View file

@ -520,67 +520,78 @@ wrong_config:
}
static gboolean
gst_v4l2_buffer_pool_streamon (GstV4l2BufferPool * pool)
start_streaming (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:
if (!pool->streaming) {
if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
goto streamon_failed;
{
/* 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;
pool->streaming = TRUE;
num_allocated = gst_v4l2_allocator_num_allocated (pool->vallocator);
num_to_queue = num_allocated - g_atomic_int_get (&pool->num_queued);
GST_DEBUG_OBJECT (pool, "Started streaming");
while (num_to_queue > 0) {
GstBuffer *buf;
params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
&buf, &params);
if (ret != GST_FLOW_OK)
goto requeue_failed;
gst_v4l2_buffer_pool_release_buffer (bpool, buf);
num_to_queue--;
}
if (num_allocated != g_atomic_int_get (&pool->num_queued))
goto requeue_failed;
}
if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
goto start_failed;
GST_DEBUG_OBJECT (pool, "STREAMON");
break;
}
default:
g_assert_not_reached ();
break;
}
pool->streaming = TRUE;
return TRUE;
streamon_failed:
/* ERRORS */
start_failed:
{
GST_ERROR_OBJECT (pool, "error with STREAMON %d (%s)", errno,
g_strerror (errno));
return FALSE;
}
}
static gboolean
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 (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
goto streamoff_failed;
pool->streaming = FALSE;
GST_DEBUG_OBJECT (pool, "Stopped streaming");
}
break;
default:
break;
}
return TRUE;
streamoff_failed:
requeue_failed:
{
GST_ERROR_OBJECT (pool, "error with STREAMOFF %d (%s)", errno,
g_strerror (errno));
GST_ERROR_OBJECT (pool, "failed to re-enqueue buffers");
return FALSE;
}
}
@ -607,7 +618,6 @@ 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;
@ -733,7 +743,7 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
max_buffers);
pclass->set_config (bpool, config);
GST_BUFFER_POOL_CLASS (parent_class)->set_config (bpool, config);
gst_structure_free (config);
if (pool->other_pool)
@ -741,14 +751,22 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
goto other_pool_failed;
/* now, allocate the buffers: */
if (!pclass->start (bpool))
if (!GST_BUFFER_POOL_CLASS (parent_class)->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 */
@ -779,103 +797,26 @@ other_pool_failed:
}
}
static gboolean
gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
stop_streaming (GstV4l2BufferPool * pool)
{
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");
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 (vret == GST_V4L2_BUSY)
GST_WARNING_OBJECT (pool, "some buffers are still outstanding");
ret = (vret == GST_V4L2_OK);
}
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");
GST_DEBUG_OBJECT (pool, "stopping stream");
/* If we haven't started streaming yet, simply call streamon */
if (!pool->streaming)
goto streamon;
gst_poll_set_flushing (obj->poll, TRUE);
if (pool->other_pool)
gst_buffer_pool_set_flushing (pool->other_pool, FALSE);
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 (!gst_v4l2_buffer_pool_streamoff (pool))
goto stop_failed;
pool->flushing = TRUE;
gst_v4l2_allocator_flush (pool->vallocator);
/* Reset our state */
switch (obj->mode) {
case GST_V4L2_IO_RW:
break;
@ -886,69 +827,118 @@ gst_v4l2_buffer_pool_flush_stop (GstBufferPool * bpool)
{
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/dmabuf-import */
/* Remove qdata, this will unmap any map data in userptr */
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
gst_v4l2_buffer_pool_release_buffer (bpool, buffer);
g_atomic_int_add (&pool->num_queued, -1);
/* Give back the outstanding buffer to the pool */
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
buffer);
}
}
g_return_val_if_fail (pool->num_queued == 0, FALSE);
break;
}
default:
g_assert_not_reached ();
g_return_val_if_reached (FALSE);
break;
}
streamon:
/* Start streaming on capture device only */
if (!V4L2_TYPE_IS_OUTPUT (obj->type))
gst_v4l2_buffer_pool_streamon (pool);
pool->flushing = FALSE;
pool->streaming = FALSE;
gst_poll_set_flushing (pool->poll, FALSE);
return;
return TRUE;
/* ERRORS */
stop_failed:
{
GST_ERROR_OBJECT (pool, "device refused to flush");
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);
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;
}
}
return ret;
/* ERRORS */
stop_failed:
{
GST_ERROR_OBJECT (pool, "error with STREAMOFF %d (%s)", errno,
g_strerror (errno));
return FALSE;
}
}
static GstFlowReturn
gst_v4l2_buffer_pool_poll (GstV4l2BufferPool * pool)
gst_v4l2_object_poll (GstV4l2Object * v4l2object)
{
gint ret;
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 (v4l2object->can_poll_device) {
GST_LOG_OBJECT (v4l2object->element, "polling device");
ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
if (G_UNLIKELY (ret < 0)) {
if (errno == EBUSY)
goto stopped;
if (errno == ENXIO) {
GST_WARNING_OBJECT (pool,
GST_WARNING_OBJECT (v4l2object->element,
"v4l2 device doesn't support polling. Disabling");
pool->can_poll_device = FALSE;
v4l2object->can_poll_device = FALSE;
} else {
if (errno != EAGAIN && errno != EINTR)
goto select_error;
@ -960,12 +950,12 @@ gst_v4l2_buffer_pool_poll (GstV4l2BufferPool * pool)
/* ERRORS */
stopped:
{
GST_DEBUG_OBJECT (pool, "stop called");
GST_DEBUG ("stop called");
return GST_FLOW_FLUSHING;
}
select_error:
{
GST_ELEMENT_ERROR (pool->obj->element, RESOURCE, READ, (NULL),
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
return GST_FLOW_ERROR;
}
@ -1024,7 +1014,7 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer)
GstV4l2MemoryGroup *group;
gint i;
if ((res = gst_v4l2_buffer_pool_poll (pool)) != GST_FLOW_OK)
if ((res = gst_v4l2_object_poll (obj)) != GST_FLOW_OK)
goto poll_failed;
GST_LOG_OBJECT (pool, "dequeueing a buffer");
@ -1106,14 +1096,17 @@ 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 = pclass->acquire_buffer (bpool, buffer, params);
ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool, buffer,
params);
goto done;
}
@ -1125,7 +1118,8 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
case GST_V4L2_IO_RW:
{
/* take empty buffer from the pool */
ret = pclass->acquire_buffer (bpool, buffer, params);
ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
buffer, params);
break;
}
case GST_V4L2_IO_DMABUF:
@ -1143,7 +1137,8 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
GstBuffer *copy;
if (GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP)) {
if (pclass->acquire_buffer (bpool, &copy, params) == GST_FLOW_OK) {
if (GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
&copy, params) == GST_FLOW_OK) {
gst_v4l2_buffer_pool_release_buffer (bpool, copy);
break;
}
@ -1181,7 +1176,8 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
switch (obj->mode) {
case GST_V4L2_IO_RW:
/* get an empty buffer */
ret = pclass->acquire_buffer (bpool, buffer, params);
ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
buffer, params);
break;
case GST_V4L2_IO_MMAP:
@ -1189,7 +1185,8 @@ 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 = pclass->acquire_buffer (bpool, buffer, params);
ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
buffer, params);
break;
default:
@ -1206,13 +1203,19 @@ 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);
@ -1225,7 +1228,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
switch (obj->mode) {
case GST_V4L2_IO_RW:
/* release back in the pool */
pclass->release_buffer (bpool, buffer);
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer);
break;
case GST_V4L2_IO_DMABUF:
@ -1233,17 +1236,23 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
case GST_V4L2_IO_USERPTR:
case GST_V4L2_IO_DMABUF_IMPORT:
{
if (gst_v4l2_is_buffer_valid (buffer, NULL)) {
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)) {
/* 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)
pclass->release_buffer (bpool, buffer);
GST_BUFFER_POOL_CLASS (parent_class)->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);
pclass->release_buffer (bpool, buffer);
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
buffer);
}
break;
}
@ -1258,7 +1267,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
switch (obj->mode) {
case GST_V4L2_IO_RW:
/* release back in the pool */
pclass->release_buffer (bpool, buffer);
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer);
break;
case GST_V4L2_IO_MMAP:
@ -1273,7 +1282,8 @@ 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);
pclass->release_buffer (bpool, buffer);
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
buffer);
break;
}
@ -1291,7 +1301,8 @@ 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. */
pclass->release_buffer (bpool, buffer);
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
buffer);
} else {
/* We keep a ref on queued buffer, so this should never happen */
g_assert_not_reached ();
@ -1325,8 +1336,6 @@ 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);
@ -1347,8 +1356,6 @@ 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
@ -1365,8 +1372,6 @@ 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;
}
/**
@ -1384,7 +1389,6 @@ 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,16 +1404,8 @@ 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);
@ -1448,7 +1444,7 @@ gst_v4l2_do_read (GstV4l2BufferPool * pool, GstBuffer * buf)
gst_buffer_map (buf, &map, GST_MAP_WRITE);
do {
if ((res = gst_v4l2_buffer_pool_poll (pool)) != GST_FLOW_OK)
if ((res = gst_v4l2_object_poll (obj)) != GST_FLOW_OK)
goto poll_error;
amount = v4l2_read (obj->video_fd, map.data, toread);
@ -1516,9 +1512,6 @@ 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:
@ -1637,9 +1630,11 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf)
/* if we are not streaming yet (this is the first buffer, start
* streaming now */
if (!gst_v4l2_buffer_pool_streamon (pool)) {
gst_buffer_unref (to_queue);
goto start_failed;
if (!pool->streaming) {
if (!start_streaming (pool)) {
gst_buffer_unref (to_queue);
goto start_failed;
}
}
if (g_atomic_int_get (&pool->num_queued) ==
@ -1704,6 +1699,53 @@ 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)

View file

@ -50,8 +50,6 @@ 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;
@ -86,6 +84,9 @@ 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);

View file

@ -431,6 +431,7 @@ 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);
@ -460,6 +461,9 @@ 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);
@ -3039,27 +3043,19 @@ gst_v4l2_object_caps_equal (GstV4l2Object * v4l2object, GstCaps * caps)
gboolean
gst_v4l2_object_unlock (GstV4l2Object * v4l2object)
{
gboolean ret = TRUE;
GST_LOG_OBJECT (v4l2object->element, "flush poll");
gst_poll_set_flushing (v4l2object->poll, 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;
return TRUE;
}
gboolean
gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object)
{
gboolean ret = TRUE;
GST_LOG_OBJECT (v4l2object->element, "flush stop poll");
gst_poll_set_flushing (v4l2object->poll, FALSE);
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;
return TRUE;
}
gboolean

View file

@ -88,6 +88,8 @@ struct _GstV4l2Object {
/* the video-device's file descriptor */
gint video_fd;
GstV4l2IOMode mode;
GstPoll * poll;
gboolean can_poll_device;
gboolean active;
gboolean streaming;

View file

@ -533,6 +533,19 @@ 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;
}
@ -542,9 +555,12 @@ gst_v4l2_transform_sink_event (GstBaseTransform * trans, GstEvent * event)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP:
/* Buffer should be back now */
GST_DEBUG_OBJECT (self, "flush stop");
gst_v4l2_object_unlock_stop (self->v4l2capture);
gst_v4l2_object_unlock_stop (self->v4l2output);
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");
break;
default:
break;

View file

@ -259,23 +259,23 @@ gst_v4l2_video_dec_flush (GstVideoDecoder * decoder)
{
GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
GST_DEBUG_OBJECT (self, "Flushed");
GST_DEBUG_OBJECT (self, "Flushing");
/* 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);
gst_v4l2_object_unlock (self->v4l2output);
gst_v4l2_object_unlock (self->v4l2capture);
gst_pad_stop_task (decoder->srcpad);
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
}
/* 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);
self->output_flow = GST_FLOW_OK;
gst_v4l2_object_unlock_stop (self->v4l2output);
gst_v4l2_object_unlock_stop (self->v4l2capture);
if (self->v4l2output->pool)
gst_v4l2_buffer_pool_stop_streaming (GST_V4L2_BUFFER_POOL
(self->v4l2output->pool));
if (self->v4l2capture->pool)
gst_v4l2_buffer_pool_stop_streaming (GST_V4L2_BUFFER_POOL
(self->v4l2capture->pool));
return TRUE;
}
@ -308,13 +308,15 @@ gst_v4l2_video_dec_finish (GstVideoDecoder * decoder)
v4l2output->pool), &buffer);
gst_buffer_unref (buffer);
}
/* 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);
/* 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);
}
if (ret == GST_FLOW_FLUSHING)
ret = self->output_flow;
@ -487,9 +489,11 @@ 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);
@ -528,6 +532,14 @@ 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);
@ -566,6 +578,13 @@ 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,
@ -705,31 +724,17 @@ 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;
}
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;
return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (decoder, event);
}
static GstStateChangeReturn
@ -737,13 +742,11 @@ 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);

View file

@ -514,6 +514,7 @@ 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);
@ -550,6 +551,8 @@ 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;
@ -586,6 +589,14 @@ 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);
@ -661,6 +672,8 @@ 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);
@ -683,7 +696,16 @@ 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;
@ -706,6 +728,7 @@ 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);
@ -714,6 +737,8 @@ 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 */