Commit 652ed3bc authored by Nicolas Dufresne's avatar Nicolas Dufresne

v4l2bufferpool: Wait before polling if queue is empty

In kernel before 3.17, polling during queue underrun would unblock right
away and trigger POLLERR. As we are not handling POLLERR, we would endup
blocking in DQBUF call, which won't be unblocked correctly when going
to NULL state. A deadlock at start caused by locking error in libv4l2 was
also seen before this patch. Instead, we wait until the queue is no longer
empty before polling.

https://bugzilla.gnome.org/show_bug.cgi?id=731015
parent db1d9444
...@@ -846,6 +846,11 @@ gst_v4l2_buffer_pool_flush_start (GstBufferPool * bpool) ...@@ -846,6 +846,11 @@ gst_v4l2_buffer_pool_flush_start (GstBufferPool * bpool)
gst_poll_set_flushing (pool->poll, TRUE); gst_poll_set_flushing (pool->poll, TRUE);
GST_OBJECT_LOCK (pool);
pool->empty = FALSE;
g_cond_broadcast (&pool->empty_cond);
GST_OBJECT_UNLOCK (pool);
if (pool->other_pool) if (pool->other_pool)
gst_buffer_pool_set_flushing (pool->other_pool, TRUE); gst_buffer_pool_set_flushing (pool->other_pool, TRUE);
} }
...@@ -934,6 +939,11 @@ gst_v4l2_buffer_pool_poll (GstV4l2BufferPool * pool) ...@@ -934,6 +939,11 @@ gst_v4l2_buffer_pool_poll (GstV4l2BufferPool * pool)
{ {
gint ret; gint ret;
GST_OBJECT_LOCK (pool);
while (pool->empty)
g_cond_wait (&pool->empty_cond, GST_OBJECT_GET_LOCK (pool));
GST_OBJECT_UNLOCK (pool);
if (!pool->can_poll_device) if (!pool->can_poll_device)
goto done; goto done;
...@@ -1001,6 +1011,11 @@ gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf) ...@@ -1001,6 +1011,11 @@ gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf)
if (!gst_v4l2_allocator_qbuf (pool->vallocator, group)) if (!gst_v4l2_allocator_qbuf (pool->vallocator, group))
goto queue_failed; goto queue_failed;
GST_OBJECT_LOCK (pool);
pool->empty = FALSE;
g_cond_signal (&pool->empty_cond);
GST_OBJECT_UNLOCK (pool);
return GST_FLOW_OK; return GST_FLOW_OK;
already_queued: already_queued:
...@@ -1047,7 +1062,11 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer) ...@@ -1047,7 +1062,11 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer)
/* mark the buffer outstanding */ /* mark the buffer outstanding */
pool->buffers[group->buffer.index] = NULL; pool->buffers[group->buffer.index] = NULL;
g_atomic_int_add (&pool->num_queued, -1); if (g_atomic_int_dec_and_test (&pool->num_queued)) {
GST_OBJECT_LOCK (pool);
pool->empty = TRUE;
GST_OBJECT_UNLOCK (pool);
}
timestamp = GST_TIMEVAL_TO_TIME (group->buffer.timestamp); timestamp = GST_TIMEVAL_TO_TIME (group->buffer.timestamp);
...@@ -1354,6 +1373,8 @@ gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool) ...@@ -1354,6 +1373,8 @@ gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool)
{ {
pool->poll = gst_poll_new (TRUE); pool->poll = gst_poll_new (TRUE);
pool->can_poll_device = TRUE; pool->can_poll_device = TRUE;
g_cond_init (&pool->empty_cond);
pool->empty = TRUE;
} }
static void static void
......
...@@ -53,6 +53,9 @@ struct _GstV4l2BufferPool ...@@ -53,6 +53,9 @@ struct _GstV4l2BufferPool
GstPoll *poll; /* a poll for video_fd */ GstPoll *poll; /* a poll for video_fd */
gboolean can_poll_device; gboolean can_poll_device;
gboolean empty;
GCond empty_cond;
GstV4l2Allocator *vallocator; GstV4l2Allocator *vallocator;
GstAllocator *allocator; GstAllocator *allocator;
GstAllocationParams params; GstAllocationParams params;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment