v4l2: videodec: Wait for source change event
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Fri, 14 Apr 2023 22:54:22 +0000 (18:54 -0400)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Tue, 2 May 2023 14:42:43 +0000 (14:42 +0000)
Stop doing capture buffer allocation based on guesses
and wait for the source change event when available.
Unlike stateless decoder, the stateful decoder is not aware of
the coded resolution, and this may lead to the wrong result
even when using TRY_FMT.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4525>

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

index a701ef5..da5ac2d 100644 (file)
@@ -138,6 +138,10 @@ gst_v4l2_video_dec_open (GstVideoDecoder * decoder)
   if (gst_caps_is_empty (self->probed_sinkcaps))
     goto no_encoded_format;
 
+  self->supports_source_change =
+      gst_v4l2_object_subscribe_event (self->v4l2capture,
+      V4L2_EVENT_SOURCE_CHANGE);
+
   return TRUE;
 
 no_encoded_format:
@@ -697,6 +701,33 @@ flushing:
   return GST_FLOW_FLUSHING;
 }
 
+/* Only used initially to wait for a SRC_CH event
+ * called with decoder stream lock */
+static GstFlowReturn
+gst_v4l2_video_dec_wait_for_src_ch (GstV4l2VideoDec * self)
+{
+  GstFlowReturn flowret;
+
+  if (!self->wait_for_source_change)
+    return GST_FLOW_OK;
+
+  GST_VIDEO_DECODER_STREAM_UNLOCK (GST_VIDEO_DECODER (self));
+  flowret = gst_v4l2_object_poll (self->v4l2capture, GST_CLOCK_TIME_NONE);
+  GST_VIDEO_DECODER_STREAM_LOCK (GST_VIDEO_DECODER (self));
+
+  /* Fix the flow return value, as the poll is watching for buffer, but we are
+   * looking for the source change event */
+  if (flowret == GST_V4L2_FLOW_RESOLUTION_CHANGE) {
+    self->wait_for_source_change = FALSE;
+    flowret = GST_FLOW_OK;
+  } else if (flowret == GST_FLOW_OK) {
+    /* A buffer would be unexpected, in this case just terminate */
+    flowret = GST_V4L2_FLOW_LAST_BUFFER;
+  }
+
+  return flowret;
+}
+
 static void
 gst_v4l2_video_dec_loop (GstVideoDecoder * decoder)
 {
@@ -707,12 +738,17 @@ gst_v4l2_video_dec_loop (GstVideoDecoder * decoder)
   GstFlowReturn ret;
 
   GST_VIDEO_DECODER_STREAM_LOCK (decoder);
-  /* FIXME at the moment we need a capture pool to poll for SRC_CH, they may
-   * cause suprious reallocation. */
   if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) {
+    ret = gst_v4l2_video_dec_wait_for_src_ch (self);
+    if (ret != GST_FLOW_OK) {
+      GST_INFO_OBJECT (decoder, "Polling for source change was interrupted");
+      GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+      goto beach;
+    }
+
     ret = gst_v4l2_video_dec_setup_capture (decoder);
     if (ret != GST_FLOW_OK) {
-      GST_ERROR_OBJECT (decoder, "Failed setup capture queue.\n");
+      GST_ERROR_OBJECT (decoder, "Failed setup capture queue");
       GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
       goto beach;
     }
@@ -841,6 +877,7 @@ resolution_changed:
   GST_VIDEO_DECODER_STREAM_LOCK (decoder);
   /* FIXME, should be draining here */
   gst_v4l2_object_stop (self->v4l2capture);
+  gst_v4l2_object_unlock_stop (self->v4l2capture);
   GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
   return;
 
@@ -921,6 +958,11 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
         goto activate_failed;
     }
 
+    /* Ensure to unlock capture, as it may be flushing due to previous
+     * unlock/stop calls */
+    gst_v4l2_object_unlock_stop (self->v4l2output);
+    gst_v4l2_object_unlock_stop (self->v4l2capture);
+
     if (!gst_buffer_pool_set_active (pool, TRUE))
       goto activate_failed;
 
@@ -933,6 +975,12 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
     GST_VIDEO_DECODER_STREAM_LOCK (decoder);
 
     gst_buffer_unref (codec_data);
+
+    /* Only wait for source change if the formats supports it */
+    if (self->v4l2output->fmtdesc->flags & V4L2_FMT_FLAG_DYN_RESOLUTION) {
+      gst_v4l2_object_unlock_stop (self->v4l2capture);
+      self->wait_for_source_change = TRUE;
+    }
   }
 
   task_state = gst_pad_get_task_state (GST_VIDEO_DECODER_SRC_PAD (self));
index 6696fcb..c4814d2 100644 (file)
@@ -62,6 +62,12 @@ struct _GstV4l2VideoDec
   GstVideoCodecState *input_state;
   gboolean active;
   GstFlowReturn output_flow;
+
+  /* Source Change Events */
+  gboolean wait_for_source_change;
+
+  /* Capabilities */
+  gboolean supports_source_change;
 };
 
 struct _GstV4l2VideoDecClass