v4l2: videodec: Prefer acquired caps over anything downstream
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Fri, 31 Mar 2023 14:32:54 +0000 (10:32 -0400)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 14 Apr 2023 15:16:06 +0000 (15:16 +0000)
As we don't have anything smart in the fixation process, we may endup with
a format that has a lower bitdepth, even if downstream can handle higher
depth. it is notably the case when negotiating with deinterlace, which places
is non-passthrough caps before its passthrough one. This makes the generic
fixation prefer the formats natively supported by deinterlace element over
the HW 10bit format. As some HW can downscale 10bit to 8bit, this can break
10bit decoding.

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

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

index 5f564e5..889447f 100644 (file)
@@ -2333,8 +2333,6 @@ gst_v4l2_buffer_pool_enable_resolution_change (GstV4l2BufferPool * pool)
 {
   guint32 input_id = 0;
 
-  g_return_if_fail (!gst_buffer_pool_is_active (GST_BUFFER_POOL (pool)));
-
   /* Make sure we subscribe for the current input */
   gst_v4l2_get_input (pool->obj, &input_id);
 
index 7a32783..8550910 100644 (file)
@@ -570,7 +570,7 @@ gst_v4l2_video_dec_setup_capture (GstVideoDecoder * decoder)
   GstV4l2Error error = GST_V4L2_ERROR_INIT;
   GstVideoInfo info;
   GstVideoCodecState *output_state;
-  GstCaps *acquired_caps, *available_caps, *caps, *filter;
+  GstCaps *acquired_caps, *fixation_caps, *available_caps, *caps, *filter;
   GstStructure *st;
   GstBufferPool *cpool;
   gboolean active;
@@ -598,7 +598,8 @@ gst_v4l2_video_dec_setup_capture (GstVideoDecoder * decoder)
     /* 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);
-    st = gst_caps_get_structure (acquired_caps, 0);
+    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);
 
@@ -610,10 +611,10 @@ gst_v4l2_video_dec_setup_capture (GstVideoDecoder * decoder)
      * 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, acquired_caps,
+    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 (acquired_caps);
+    gst_caps_unref (fixation_caps);
     gst_caps_unref (available_caps);
     caps = gst_pad_peer_query_caps (decoder->srcpad, filter);
     gst_caps_unref (filter);
@@ -624,6 +625,14 @@ gst_v4l2_video_dec_setup_capture (GstVideoDecoder * decoder)
       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);
 
@@ -634,6 +643,8 @@ gst_v4l2_video_dec_setup_capture (GstVideoDecoder * decoder)
       gst_video_info_from_caps (&info, caps);
     else
       gst_v4l2_clear_error (&error);
+
+  use_acquired_caps:
     gst_caps_unref (caps);
 
     output_state = gst_video_decoder_set_output_state (decoder,
@@ -644,19 +655,19 @@ gst_v4l2_video_dec_setup_capture (GstVideoDecoder * decoder)
     output_state->info.colorimetry = info.colorimetry;
     gst_video_codec_state_unref (output_state);
 
-    cpool = gst_v4l2_object_get_buffer_pool (self->v4l2capture);
-    gst_v4l2_buffer_pool_enable_resolution_change (GST_V4L2_BUFFER_POOL
-        (cpool));
-
     if (!gst_video_decoder_negotiate (decoder)) {
-      if (cpool)
-        gst_object_unref (cpool);
       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)