From a9d5e44094fe1fe3eea6116ba0dff867f32699cb Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 26 Apr 2023 15:58:23 -0400 Subject: [PATCH] v4l2: pool: Flush events on capture queue Unfortunately streamoff does not flush the events, and this can cause all sort of issues. Flush events on capture queue. We also return GST_V4L2_FLOW_RESOLUTION_CHANGE in case a resolution change was seen. This allow skipping streamon(capture) on flush, which could lead to a configuration miss-match, or failure if the buffers aren't of the right size. Part-of: --- .../gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c | 57 ++++++++++++++++++++-- .../gst-plugins-good/sys/v4l2/gstv4l2bufferpool.h | 2 +- .../gst-plugins-good/sys/v4l2/gstv4l2videodec.c | 9 +++- 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c index 7d49c80..cb7b0d9 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c @@ -2215,22 +2215,69 @@ gst_v4l2_buffer_pool_copy_at_threshold (GstV4l2BufferPool * pool, gboolean copy) GST_OBJECT_UNLOCK (pool); } -gboolean +static GstFlowReturn +gst_v4l2_buffer_pool_flush_events (GstV4l2Object * v4l2object) +{ + GstFlowReturn ret = GST_FLOW_OK; + gboolean event_found; + + /* FIXME simplify this when we drop legacy support for driver without poll() + * support. When we do, we can switch the video_fd to non blocking, and just + * pop the events directly. */ + + do { + struct v4l2_event event = { 0, }; + gint poll_ret; + + event_found = FALSE; + + gst_poll_set_flushing (v4l2object->poll, FALSE); + + do { + /* GstPoll don't have 0ns timeout, but 1 will do */ + poll_ret = gst_poll_wait (v4l2object->poll, 1); + } while (poll_ret == EAGAIN || poll_ret == EINTR); + + if (gst_poll_fd_has_pri (v4l2object->poll, &v4l2object->pollfd)) { + if (!gst_v4l2_dequeue_event (v4l2object, &event)) + return GST_FLOW_ERROR; + + event_found = TRUE; + + if (event.type == V4L2_EVENT_SOURCE_CHANGE && + (event.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)) { + GST_DEBUG_OBJECT (v4l2object->dbg_obj, + "Can't streamon capture as the resolution have changed."); + ret = GST_V4L2_FLOW_RESOLUTION_CHANGE; + } + } + } while (event_found); + + return ret; +} + +GstFlowReturn gst_v4l2_buffer_pool_flush (GstV4l2Object * v4l2object) { GstBufferPool *bpool = gst_v4l2_object_get_buffer_pool (v4l2object); GstV4l2BufferPool *pool; - gboolean ret = TRUE; + GstFlowReturn ret = GST_FLOW_OK; if (!bpool) - return FALSE; + return GST_FLOW_ERROR; pool = GST_V4L2_BUFFER_POOL (bpool); gst_v4l2_buffer_pool_streamoff (pool); - if (!V4L2_TYPE_IS_OUTPUT (pool->obj->type)) - ret = gst_v4l2_buffer_pool_streamon (pool); + if (!V4L2_TYPE_IS_OUTPUT (pool->obj->type)) { + ret = gst_v4l2_buffer_pool_flush_events (v4l2object); + + /* If the format haven't change, avoid reallocation to go back to + * streaming */ + if (ret == GST_FLOW_OK) + ret = gst_v4l2_buffer_pool_streamon (pool); + } gst_object_unref (bpool); return ret; diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.h b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.h index 441dc22..db8c554 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.h +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.h @@ -115,7 +115,7 @@ void gst_v4l2_buffer_pool_set_other_pool (GstV4l2BufferPool * poo void gst_v4l2_buffer_pool_copy_at_threshold (GstV4l2BufferPool * pool, gboolean copy); -gboolean gst_v4l2_buffer_pool_flush (GstV4l2Object * v4l2object); +GstFlowReturn gst_v4l2_buffer_pool_flush (GstV4l2Object * v4l2object); gboolean gst_v4l2_buffer_pool_orphan (GstV4l2Object * v4l2object); diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2videodec.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2videodec.c index 1d95b19..1c1a3f4 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2videodec.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2videodec.c @@ -348,8 +348,12 @@ gst_v4l2_video_dec_flush (GstVideoDecoder * decoder) /* gst_v4l2_buffer_pool_flush() calls streamon the capture pool and must be * called after gst_v4l2_object_unlock_stop() stopped flushing the buffer - * pool. */ - gst_v4l2_buffer_pool_flush (self->v4l2capture); + * pool. If the resolution has changed before we stopped the driver we must + * reallocate the capture pool. We simply discard the pool, and let the + * capture thread handle re-allocation.*/ + if (gst_v4l2_buffer_pool_flush (self->v4l2capture) == + GST_V4L2_FLOW_RESOLUTION_CHANGE || self->draining) + gst_v4l2_object_stop (self->v4l2capture); return TRUE; } @@ -888,6 +892,7 @@ beach: GST_VIDEO_DECODER_STREAM_UNLOCK (decoder); return; } + GST_VIDEO_DECODER_STREAM_UNLOCK (decoder); } -- 2.7.4