From 7b00d7ac4603c802b3e575644bd83bb93338b7d9 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 16 Apr 2014 15:51:03 -0400 Subject: [PATCH] v4l2allocator: Guaranty queued state integrety Because of the buf in videobuf2, dqbuf may leave the DONE flag being, which would implied that the buffer is queued. As this has been broken for 4 years, simply guaranty the state flags integrity when doing qbuf/dqbuf. See https://patchwork.linuxtv.org/patch/23641/ --- sys/v4l2/gstv4l2allocator.c | 46 +++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/sys/v4l2/gstv4l2allocator.c b/sys/v4l2/gstv4l2allocator.c index 6c6886f8f3..54503870df 100644 --- a/sys/v4l2/gstv4l2allocator.c +++ b/sys/v4l2/gstv4l2allocator.c @@ -33,6 +33,14 @@ G_DEFINE_TYPE (GstV4l2Allocator, gst_v4l2_allocator, GST_TYPE_ALLOCATOR); GST_DEBUG_CATEGORY_STATIC (v4l2allocator_debug); #define GST_CAT_DEFAULT v4l2allocator_debug +#define UNSET_QUEUED(buffer) \ + ((buffer).flags &= ~(V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)) + +#define SET_QUEUED(buffer) ((buffer).flags |= V4L2_BUF_FLAG_QUEUED) + +#define IS_QUEUED(buffer) \ + ((buffer).flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)) + enum { GROUP_RELEASED, @@ -787,11 +795,10 @@ gst_v4l2_allocator_flush (GstV4l2Allocator * allocator) for (i = 0; i < allocator->count; i++) { GstV4l2MemoryGroup *group = allocator->groups[i]; - guint32 queued = (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE); gint n; - if (group->buffer.flags & queued) { - group->buffer.flags &= ~queued; + if (IS_QUEUED (group->buffer)) { + UNSET_QUEUED (group->buffer); for (n = 0; n < group->n_mem; n++) gst_memory_unref (group->mem[n]); @@ -822,12 +829,28 @@ gst_v4l2_allocator_qbuf (GstV4l2Allocator * allocator, GST_ERROR_OBJECT (allocator, "failed queing buffer %i: %s", group->buffer.index, g_strerror (errno)); ret = FALSE; + if (IS_QUEUED (group->buffer)) { + GST_DEBUG_OBJECT (allocator, + "driver pretends buffer is queued even if queue failed"); + UNSET_QUEUED (group->buffer); + } + goto done; + } + + GST_LOG_OBJECT (allocator, "queued buffer %i (flags 0x%X)", + group->buffer.index, group->buffer.flags); + + if (!IS_QUEUED (group->buffer)) { + GST_DEBUG_OBJECT (allocator, + "driver pretends buffer is not queued even if queue succeeded"); + SET_QUEUED (group->buffer); } /* Ensure the memory will stay around and is RO */ for (i = 0; i < group->n_mem; i++) gst_memory_ref (group->mem[i]); +done: return ret; } @@ -854,6 +877,15 @@ gst_v4l2_allocator_dqbuf (GstV4l2Allocator * allocator) group = allocator->groups[buffer.index]; group->buffer = buffer; + GST_LOG_OBJECT (allocator, "dequeued buffer %i (flags 0x%X)", buffer.index, + buffer.flags); + + if (IS_QUEUED (group->buffer)) { + GST_DEBUG_OBJECT (allocator, + "driver pretends buffer is queued even if dequeue succeeded"); + UNSET_QUEUED (group->buffer); + } + if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { group->buffer.m.planes = group->planes; memcpy (group->planes, buffer.m.planes, sizeof (planes)); @@ -907,7 +939,7 @@ error: " Note the driver might dequeue an (empty) buffer despite" " returning an error, or even stop capturing."); /* have we de-queued a buffer ? */ - if (!(buffer.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) { + if (!IS_QUEUED (buffer)) { GST_DEBUG_OBJECT (allocator, "reenqueing buffer"); /* FIXME ... should we do something here? */ } @@ -921,6 +953,12 @@ error: g_strerror (errno)); break; } + + if (!IS_QUEUED (group->buffer)) { + GST_DEBUG_OBJECT (allocator, + "driver pretends buffer is dequeued even if dequeue failed"); + SET_QUEUED (group->buffer); + } return NULL; }