Commit 7b00d7ac authored by Nicolas Dufresne's avatar Nicolas Dufresne

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/
parent 783417ee
......@@ -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;
}
......
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