v4l2: pool: Flush events on capture queue
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Wed, 26 Apr 2023 19:58:23 +0000 (15:58 -0400)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Tue, 2 May 2023 14:42:43 +0000 (14:42 +0000)
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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4525>

subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c
subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.h
subprojects/gst-plugins-good/sys/v4l2/gstv4l2videodec.c

index 7d49c80..cb7b0d9 100644 (file)
@@ -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;
index 441dc22..db8c554 100644 (file)
@@ -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);
 
index 1d95b19..1c1a3f4 100644 (file)
@@ -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);
   }