v4l2: videodec: Don't forcibly drain on resolution changes
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Wed, 19 Apr 2023 18:19:13 +0000 (14:19 -0400)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Tue, 2 May 2023 14:42:43 +0000 (14:42 +0000)
Let the driver detects the change and reconfigure the capture side
transparently from there. This avoid reallocation of the output buffers,
and eliminates the need to stop and restart the capture task. This is
only happening if the driver have support for this, otherwise the old
behaviour is maintained.

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 a35750666c8025cca2ecdefcb9ee8d9edf93520f..b780d23e129d52e9306a44b6959602f663a8e801 100644 (file)
@@ -259,13 +259,15 @@ static gboolean
 gst_v4l2_video_dec_set_format (GstVideoDecoder * decoder,
     GstVideoCodecState * state)
 {
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
   GstV4l2Error error = GST_V4L2_ERROR_INIT;
   gboolean ret = TRUE;
-  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+  gboolean dyn_resolution = self->v4l2output->fmtdesc &&
+      (self->v4l2output->fmtdesc->flags & V4L2_FMT_FLAG_DYN_RESOLUTION);
 
   GST_DEBUG_OBJECT (self, "Setting format: %" GST_PTR_FORMAT, state->caps);
 
-  if (self->input_state) {
+  if (self->input_state && !dyn_resolution) {
     if (compatible_caps (self, state->caps)) {
       GST_DEBUG_OBJECT (self, "Compatible caps");
       goto done;
@@ -303,7 +305,10 @@ gst_v4l2_video_dec_set_format (GstVideoDecoder * decoder,
     self->output_flow = GST_FLOW_OK;
   }
 
-  ret = gst_v4l2_object_set_format (self->v4l2output, state->caps, &error);
+  /* No V4L2_FMT_FLAG_DYN_RESOLUTION or no fmtdesc set yet */
+  if (!dyn_resolution)
+    ret = gst_v4l2_object_set_format (self->v4l2output, state->caps, &error);
+
   if (ret)
     self->input_state = gst_video_codec_state_ref (state);
   else
@@ -414,6 +419,9 @@ gst_v4l2_video_dec_finish (GstVideoDecoder * decoder)
 
   GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
 
+  /* If we are in the middle of a source change, cancel it */
+  self->draining = FALSE;
+
   if (gst_v4l2_decoder_cmd (self->v4l2output, V4L2_DEC_CMD_STOP, 0)) {
     GstTask *task;
 
@@ -771,11 +779,6 @@ gst_v4l2_video_dec_loop (GstVideoDecoder * decoder)
     ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
     g_object_unref (pool);
 
-    if (ret == GST_V4L2_FLOW_RESOLUTION_CHANGE) {
-      GST_INFO_OBJECT (decoder, "Received resolution change");
-      goto resolution_changed;
-    }
-
     if (ret != GST_FLOW_OK)
       goto beach;
 
@@ -788,11 +791,6 @@ gst_v4l2_video_dec_loop (GstVideoDecoder * decoder)
       if (cpool)
         gst_object_unref (cpool);
     }
-
-    if (ret == GST_V4L2_FLOW_RESOLUTION_CHANGE) {
-      GST_INFO_OBJECT (decoder, "Received resolution change");
-      goto resolution_changed;
-    }
   } while (ret == GST_V4L2_FLOW_CORRUPTED_BUFFER);
 
   if (ret != GST_FLOW_OK)
@@ -865,15 +863,26 @@ gst_v4l2_video_dec_loop (GstVideoDecoder * decoder)
 
   return;
 
-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;
-
 beach:
+  if (ret == GST_V4L2_FLOW_RESOLUTION_CHANGE) {
+    GST_VIDEO_DECODER_STREAM_LOCK (decoder);
+    self->draining = TRUE;
+    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+    GST_INFO_OBJECT (decoder, "Received resolution change");
+    return;
+  }
+
+  if (ret == GST_FLOW_EOS) {
+    GST_VIDEO_DECODER_STREAM_LOCK (decoder);
+    if (self->draining) {
+      self->draining = FALSE;
+      gst_v4l2_object_stop (self->v4l2capture);
+      GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+      return;
+    }
+    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+  }
+
   GST_DEBUG_OBJECT (decoder, "Leaving output thread: %s",
       gst_flow_get_name (ret));
 
@@ -990,6 +999,7 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
     /* Start the processing task, when it quits, the task will disable input
      * processing to unlock input if draining, or prevent potential block */
     self->output_flow = GST_FLOW_FLUSHING;
+    self->draining = FALSE;
     if (!gst_pad_start_task (decoder->srcpad,
             (GstTaskFunction) gst_v4l2_video_dec_loop, self, NULL))
       goto start_task_failed;
index c4814d2417a63488e0887e78acc04ee107f89712..fbbfb60b01d86e4825d4854d63932ca74e20541f 100644 (file)
@@ -65,6 +65,7 @@ struct _GstV4l2VideoDec
 
   /* Source Change Events */
   gboolean wait_for_source_change;
+  gboolean draining;
 
   /* Capabilities */
   gboolean supports_source_change;