v4l2: videodec: Move pool setup inside negotiate()
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Mon, 26 Jun 2023 21:08:57 +0000 (17:08 -0400)
committerTim-Philipp Müller <tim@centricular.com>
Sun, 9 Jul 2023 16:50:29 +0000 (17:50 +0100)
Move all the pool configuration inside the negotiate() virtual function.
This allow settting up a pool with default format whenever the base
class wants to start without input data, like gaps.

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

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

index 1d3b83b..61e0330 100644 (file)
@@ -359,22 +359,173 @@ gst_v4l2_video_dec_flush (GstVideoDecoder * decoder)
 }
 
 static gboolean
+gst_v4l2_video_remove_padding (GstCapsFeatures * features,
+    GstStructure * structure, gpointer user_data)
+{
+  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (user_data);
+  GstVideoAlignment *align = &self->v4l2capture->align;
+  GstVideoInfo *info = &self->v4l2capture->info;
+  int width, height;
+
+  if (!gst_structure_get_int (structure, "width", &width))
+    return TRUE;
+
+  if (!gst_structure_get_int (structure, "height", &height))
+    return TRUE;
+
+  if (align->padding_left != 0 || align->padding_top != 0 ||
+      height != info->height + align->padding_bottom)
+    return TRUE;
+
+  if (height == info->height + align->padding_bottom) {
+    /* Some drivers may round up width to the padded with */
+    if (width == info->width + align->padding_right)
+      gst_structure_set (structure,
+          "width", G_TYPE_INT, width - align->padding_right,
+          "height", G_TYPE_INT, height - align->padding_bottom, NULL);
+    /* Some drivers may keep visible width and only round up bytesperline */
+    else if (width == info->width)
+      gst_structure_set (structure,
+          "height", G_TYPE_INT, height - align->padding_bottom, NULL);
+  }
+
+  return TRUE;
+}
+
+static gboolean
 gst_v4l2_video_dec_negotiate (GstVideoDecoder * decoder)
 {
   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+  GstV4l2Error error = GST_V4L2_ERROR_INIT;
+  GstVideoInfo info;
+  GstVideoCodecState *output_state;
+  GstCaps *acquired_caps, *fixation_caps, *available_caps, *caps, *filter;
+  GstStructure *st;
+  gboolean active;
+  GstBufferPool *cpool;
+  gboolean ret;
 
   /* We don't allow renegotiation without careful disabling the pool */
-  {
-    GstBufferPool *cpool = gst_v4l2_object_get_buffer_pool (self->v4l2capture);
-    if (cpool) {
-      gboolean is_active = gst_buffer_pool_is_active (cpool);
-      gst_object_unref (cpool);
-      if (is_active)
-        return TRUE;
-    }
+  cpool = gst_v4l2_object_get_buffer_pool (self->v4l2capture);
+  if (cpool) {
+    gboolean is_active = gst_buffer_pool_is_active (cpool);
+    gst_object_unref (cpool);
+    if (is_active)
+      return TRUE;
   }
 
-  return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
+  /* init capture fps according to output */
+  self->v4l2capture->info.fps_d = self->v4l2output->info.fps_d;
+  self->v4l2capture->info.fps_n = self->v4l2output->info.fps_n;
+
+  /* For decoders G_FMT returns coded size, G_SELECTION returns visible size
+   * in the compose rectangle. gst_v4l2_object_acquire_format() checks both
+   * and returns the visible size as with/height and the coded size as
+   * padding. */
+  if (!gst_v4l2_object_acquire_format (self->v4l2capture, &info))
+    goto not_negotiated;
+
+  /* gst_v4l2_object_acquire_format() does not set fps, copy from sink */
+  info.fps_n = self->v4l2output->info.fps_n;
+  info.fps_d = self->v4l2output->info.fps_d;
+
+  gst_caps_replace (&self->probed_srccaps, NULL);
+  self->probed_srccaps = gst_v4l2_object_probe_caps (self->v4l2capture,
+      gst_v4l2_object_get_raw_caps ());
+  /* Create caps from the acquired format, remove the format field */
+  acquired_caps = gst_video_info_to_caps (&info);
+  GST_DEBUG_OBJECT (self, "Acquired caps: %" GST_PTR_FORMAT, acquired_caps);
+  fixation_caps = gst_caps_copy (acquired_caps);
+  st = gst_caps_get_structure (fixation_caps, 0);
+  gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site",
+      NULL);
+
+  /* Probe currently available pixel formats */
+  available_caps = gst_caps_copy (self->probed_srccaps);
+  GST_DEBUG_OBJECT (self, "Available caps: %" GST_PTR_FORMAT, available_caps);
+
+  /* Replace coded size with visible size, we want to negotiate visible size
+   * with downstream, not coded size. */
+  gst_caps_map_in_place (available_caps, gst_v4l2_video_remove_padding, self);
+
+  filter = gst_caps_intersect_full (available_caps, fixation_caps,
+      GST_CAPS_INTERSECT_FIRST);
+  GST_DEBUG_OBJECT (self, "Filtered caps: %" GST_PTR_FORMAT, filter);
+  gst_caps_unref (fixation_caps);
+  gst_caps_unref (available_caps);
+  caps = gst_pad_peer_query_caps (decoder->srcpad, filter);
+  gst_caps_unref (filter);
+
+  GST_DEBUG_OBJECT (self, "Possible decoded caps: %" GST_PTR_FORMAT, caps);
+  if (gst_caps_is_empty (caps)) {
+    gst_caps_unref (caps);
+    goto not_negotiated;
+  }
+
+  /* Prefer the acquired caps over anything suggested downstream, this ensure
+   * that we preserves the bit depth, as we don't have any fancy fixation
+   * process */
+  if (gst_caps_is_subset (acquired_caps, caps)) {
+    gst_caps_unref (acquired_caps);
+    goto use_acquired_caps;
+  }
+
+  /* Fixate pixel format */
+  caps = gst_caps_fixate (caps);
+
+  GST_DEBUG_OBJECT (self, "Chosen decoded caps: %" GST_PTR_FORMAT, caps);
+
+  /* Try to set negotiated format, on success replace acquired format */
+  if (gst_v4l2_object_set_format (self->v4l2capture, caps, &error))
+    gst_video_info_from_caps (&info, caps);
+  else
+    gst_v4l2_clear_error (&error);
+
+use_acquired_caps:
+  gst_caps_unref (caps);
+
+  /* catch possible bogus driver that don't enumerate the format it actually
+   * returned from G_FMT */
+  if (!self->v4l2capture->fmtdesc)
+    goto not_negotiated;
+
+  output_state = gst_video_decoder_set_output_state (decoder,
+      info.finfo->format, info.width, info.height, self->input_state);
+
+  /* Copy the rest of the information, there might be more in the future */
+  output_state->info.interlace_mode = info.interlace_mode;
+  output_state->info.colorimetry = info.colorimetry;
+  gst_video_codec_state_unref (output_state);
+
+  ret = GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
+  if (!ret)
+    goto not_negotiated;
+
+  /* The pool may be created through gst_video_decoder_negotiate(), so must
+   * be kept after */
+  cpool = gst_v4l2_object_get_buffer_pool (self->v4l2capture);
+  gst_v4l2_buffer_pool_enable_resolution_change (GST_V4L2_BUFFER_POOL (cpool));
+
+  /* Ensure our internal pool is activated */
+  active = gst_buffer_pool_set_active (cpool, TRUE);
+  if (cpool)
+    gst_object_unref (cpool);
+  if (!active)
+    goto activate_failed;
+
+  return TRUE;
+
+not_negotiated:
+  GST_ERROR_OBJECT (self, "not negotiated");
+  gst_v4l2_error (self, &error);
+  gst_v4l2_object_stop (self->v4l2capture);
+  return FALSE;
+activate_failed:
+  GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+      (_("Failed to allocate required memory.")),
+      ("Buffer pool activation failed"));
+  gst_v4l2_object_stop (self->v4l2capture);
+  return FALSE;
 }
 
 static gboolean
@@ -532,175 +683,6 @@ check_system_frame_number_too_old (guint32 current, guint32 old)
   return FALSE;
 }
 
-static gboolean
-gst_v4l2_video_remove_padding (GstCapsFeatures * features,
-    GstStructure * structure, gpointer user_data)
-{
-  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (user_data);
-  GstVideoAlignment *align = &self->v4l2capture->align;
-  GstVideoInfo *info = &self->v4l2capture->info;
-  int width, height;
-
-  if (!gst_structure_get_int (structure, "width", &width))
-    return TRUE;
-
-  if (!gst_structure_get_int (structure, "height", &height))
-    return TRUE;
-
-  if (align->padding_left != 0 || align->padding_top != 0 ||
-      height != info->height + align->padding_bottom)
-    return TRUE;
-
-  if (height == info->height + align->padding_bottom) {
-    /* Some drivers may round up width to the padded with */
-    if (width == info->width + align->padding_right)
-      gst_structure_set (structure,
-          "width", G_TYPE_INT, width - align->padding_right,
-          "height", G_TYPE_INT, height - align->padding_bottom, NULL);
-    /* Some drivers may keep visible width and only round up bytesperline */
-    else if (width == info->width)
-      gst_structure_set (structure,
-          "height", G_TYPE_INT, height - align->padding_bottom, NULL);
-  }
-
-  return TRUE;
-}
-
-static GstFlowReturn
-gst_v4l2_video_dec_setup_capture (GstVideoDecoder * decoder)
-{
-  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
-  GstV4l2Error error = GST_V4L2_ERROR_INIT;
-  GstVideoInfo info;
-  GstVideoCodecState *output_state;
-  GstCaps *acquired_caps, *fixation_caps, *available_caps, *caps, *filter;
-  GstStructure *st;
-  GstBufferPool *cpool;
-  gboolean active;
-
-  if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) {
-    /* init capture fps according to output */
-    self->v4l2capture->info.fps_d = self->v4l2output->info.fps_d;
-    self->v4l2capture->info.fps_n = self->v4l2output->info.fps_n;
-
-    /* For decoders G_FMT returns coded size, G_SELECTION returns visible size
-     * in the compose rectangle. gst_v4l2_object_acquire_format() checks both
-     * and returns the visible size as with/height and the coded size as
-     * padding. */
-    if (!gst_v4l2_object_acquire_format (self->v4l2capture, &info))
-      goto not_negotiated;
-
-    /* gst_v4l2_object_acquire_format() does not set fps, copy from sink */
-    info.fps_n = self->v4l2output->info.fps_n;
-    info.fps_d = self->v4l2output->info.fps_d;
-
-    gst_caps_replace (&self->probed_srccaps, NULL);
-    self->probed_srccaps = gst_v4l2_object_probe_caps (self->v4l2capture,
-        gst_v4l2_object_get_raw_caps ());
-    /* Create caps from the acquired format, remove the format field */
-    acquired_caps = gst_video_info_to_caps (&info);
-    GST_DEBUG_OBJECT (self, "Acquired caps: %" GST_PTR_FORMAT, acquired_caps);
-    fixation_caps = gst_caps_copy (acquired_caps);
-    st = gst_caps_get_structure (fixation_caps, 0);
-    gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site",
-        NULL);
-
-    /* Probe currently available pixel formats */
-    available_caps = gst_caps_copy (self->probed_srccaps);
-    GST_DEBUG_OBJECT (self, "Available caps: %" GST_PTR_FORMAT, available_caps);
-
-    /* Replace coded size with visible size, we want to negotiate visible size
-     * with downstream, not coded size. */
-    gst_caps_map_in_place (available_caps, gst_v4l2_video_remove_padding, self);
-
-    filter = gst_caps_intersect_full (available_caps, fixation_caps,
-        GST_CAPS_INTERSECT_FIRST);
-    GST_DEBUG_OBJECT (self, "Filtered caps: %" GST_PTR_FORMAT, filter);
-    gst_caps_unref (fixation_caps);
-    gst_caps_unref (available_caps);
-    caps = gst_pad_peer_query_caps (decoder->srcpad, filter);
-    gst_caps_unref (filter);
-
-    GST_DEBUG_OBJECT (self, "Possible decoded caps: %" GST_PTR_FORMAT, caps);
-    if (gst_caps_is_empty (caps)) {
-      gst_caps_unref (caps);
-      goto not_negotiated;
-    }
-
-    /* Prefer the acquired caps over anything suggested downstream, this ensure
-     * that we preserves the bit depth, as we don't have any fancy fixation
-     * process */
-    if (gst_caps_is_subset (acquired_caps, caps)) {
-      gst_caps_unref (acquired_caps);
-      goto use_acquired_caps;
-    }
-
-    /* Fixate pixel format */
-    caps = gst_caps_fixate (caps);
-
-    GST_DEBUG_OBJECT (self, "Chosen decoded caps: %" GST_PTR_FORMAT, caps);
-
-    /* Try to set negotiated format, on success replace acquired format */
-    if (gst_v4l2_object_set_format (self->v4l2capture, caps, &error))
-      gst_video_info_from_caps (&info, caps);
-    else
-      gst_v4l2_clear_error (&error);
-
-  use_acquired_caps:
-    gst_caps_unref (caps);
-
-    /* catch possible bogus driver that don't enumerate the format it actually
-     * returned from G_FMT */
-    if (!self->v4l2capture->fmtdesc)
-      goto not_negotiated;
-
-    output_state = gst_video_decoder_set_output_state (decoder,
-        info.finfo->format, info.width, info.height, self->input_state);
-
-    /* Copy the rest of the information, there might be more in the future */
-    output_state->info.interlace_mode = info.interlace_mode;
-    output_state->info.colorimetry = info.colorimetry;
-    gst_video_codec_state_unref (output_state);
-
-    if (!gst_video_decoder_negotiate (decoder)) {
-      if (GST_PAD_IS_FLUSHING (decoder->srcpad))
-        goto flushing;
-      else
-        goto not_negotiated;
-    }
-
-    /* The pool may be created through gst_video_decoder_negotiate(), so must
-     * be kept after */
-    cpool = gst_v4l2_object_get_buffer_pool (self->v4l2capture);
-    gst_v4l2_buffer_pool_enable_resolution_change (GST_V4L2_BUFFER_POOL
-        (cpool));
-
-    /* Ensure our internal pool is activated */
-    active = gst_buffer_pool_set_active (cpool, TRUE);
-    if (cpool)
-      gst_object_unref (cpool);
-    if (!active)
-      goto activate_failed;
-  }
-
-  return GST_FLOW_OK;
-
-not_negotiated:
-  GST_ERROR_OBJECT (self, "not negotiated");
-  gst_v4l2_error (self, &error);
-  gst_v4l2_object_stop (self->v4l2capture);
-  return GST_FLOW_NOT_NEGOTIATED;
-activate_failed:
-  GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
-      (_("Failed to allocate required memory.")),
-      ("Buffer pool activation failed"));
-  gst_v4l2_object_stop (self->v4l2capture);
-  return GST_FLOW_ERROR;
-flushing:
-  gst_v4l2_object_stop (self->v4l2capture);
-  return GST_FLOW_FLUSHING;
-}
-
 /* Only used initially to wait for a SRC_CH event
  * called with decoder stream lock */
 static GstFlowReturn
@@ -751,21 +733,22 @@ gst_v4l2_video_dec_loop (GstVideoDecoder * decoder)
     }
 
     GST_DEBUG_OBJECT (decoder, "Setup the capture queue");
-    ret = gst_v4l2_video_dec_setup_capture (decoder);
-    /* FIXME not super nice ? */
-    if (ret == GST_FLOW_FLUSHING || GST_PAD_IS_FLUSHING (decoder->sinkpad)
-        || GST_PAD_IS_FLUSHING (decoder->srcpad)) {
-      ret = GST_FLOW_FLUSHING;
-      GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
-      goto beach;
-    }
-    if (ret != GST_FLOW_OK) {
-      GST_ERROR_OBJECT (decoder, "Failed to setup capture queue");
-      GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
-      goto beach;
+    if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) {
+      if (!gst_video_decoder_negotiate (decoder)) {
+        /* FIXME not super nice ? */
+        if (GST_PAD_IS_FLUSHING (decoder->sinkpad)
+            || GST_PAD_IS_FLUSHING (decoder->srcpad)) {
+          ret = GST_FLOW_FLUSHING;
+        } else {
+          ret = GST_FLOW_NOT_NEGOTIATED;
+          GST_ERROR_OBJECT (decoder, "Failed to setup capture queue");
+        }
+        GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+        goto beach;
+      }
     }
 
-    /* just a safety, as introducing mistakes in setup_capture seems rather
+    /* just a safety, as introducing mistakes in negotiation seems rather
      * easy.*/
     g_return_if_fail (GST_V4L2_IS_ACTIVE (self->v4l2capture));
   }