deinterlace: Do passthrough in auto mode if downstream only supports interlaced
authorVivia Nikolaidou <vivia@toolsonair.com>
Tue, 26 Jan 2016 16:39:20 +0000 (17:39 +0100)
committerSebastian Dröge <sebastian@centricular.com>
Wed, 27 Jan 2016 15:45:29 +0000 (16:45 +0100)
If the following conditions are met:
1) upstream and downstream caps are compatible
2) upstream is interlaced
3) downstream doesn't support progressive mode
then deinterlace will just do passthrough instead of failing to link.

This is done with the following scenario in mind:

videotestsrc ! "video/x-raw,interlace-mode=interleaved" ! deinterlace
name=dein_src ! tee name=t ! queue ! deinterlace name=dein_file ! filesink t. !
queue ! deinterlace name=dein_desktop ! autovideosink
In this case, dein_src will do the deinterlacing. However,

videotestsrc ! "video/x-raw,interlace-mode=interleaved" ! deinterlace
name=dein_src ! tee name=t ! queue ! deinterlace name=dein_file ! filesink t. !
queue ! deinterlace name=dein_desktop ! autovideosink t. ! queue !
"video/x-raw,interlace-mode=interleaved" ! fakesink

In this case, caps auto-negotiation will make dein_file and dein_desktop do
the deinterlacing, while dein_src will be passthrough.

https://bugzilla.gnome.org/show_bug.cgi?id=760995

gst/deinterlace/gstdeinterlace.c

index 840b835..80c21d4 100644 (file)
@@ -2504,7 +2504,7 @@ gst_deinterlace_do_bufferpool (GstDeinterlace * self, GstCaps * outcaps)
 static gboolean
 gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps)
 {
-  GstCaps *srccaps;
+  GstCaps *srccaps = NULL;
   GstVideoInterlaceMode interlacing_mode;
   gint fps_n, fps_d;
 
@@ -2555,9 +2555,52 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps)
           "Passthrough because mode=auto and progressive caps");
       self->passthrough = TRUE;
     } else if (gst_caps_can_intersect (caps, tmp)) {
-      GST_DEBUG_OBJECT (self,
-          "Not passthrough because mode=auto and interlaced caps");
-      self->passthrough = FALSE;
+      GstCaps *peercaps;
+
+      peercaps = gst_pad_peer_query_caps (self->srcpad, NULL);
+      if (peercaps) {
+        GstCaps *templcaps = gst_pad_get_pad_template_caps (self->srcpad);
+        GstCaps *allowed_caps;
+        GstCaps *tmp2;
+        GstStructure *s;
+
+        allowed_caps = gst_caps_intersect (templcaps, peercaps);
+        gst_caps_unref (templcaps);
+        gst_caps_unref (peercaps);
+        peercaps = allowed_caps;
+        allowed_caps = gst_caps_intersect (peercaps, tmp);
+        gst_caps_unref (peercaps);
+
+        tmp2 = gst_caps_copy (caps);
+        s = gst_caps_get_structure (tmp2, 0);
+        gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive",
+            NULL);
+        gst_structure_remove_field (s, "framerate");
+
+        /* Downstream does not support progressive caps but supports
+         * the upstream caps, go passthrough.
+         * TODO: We might want to check the framerate compatibility
+         * of the caps too here
+         */
+        if (gst_caps_can_intersect (allowed_caps, caps)
+            && !gst_caps_can_intersect (allowed_caps, tmp2)) {
+          GST_DEBUG_OBJECT (self,
+              "Passthrough because mode=auto, "
+              "downstream does not support progressive caps and interlaced caps");
+          self->passthrough = TRUE;
+        } else {
+          GST_DEBUG_OBJECT (self, "Not passthrough because mode=auto, "
+              "downstream supports progressive caps and interlaced caps");
+          self->passthrough = FALSE;
+        }
+
+        gst_caps_unref (allowed_caps);
+        gst_caps_unref (tmp2);
+      } else {
+        GST_DEBUG_OBJECT (self,
+            "Not passthrough because mode=auto and interlaced caps");
+        self->passthrough = FALSE;
+      }
     } else {
       if (self->mode == GST_DEINTERLACE_MODE_AUTO) {
         GST_WARNING_OBJECT (self,
@@ -2647,18 +2690,22 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps)
 invalid_caps:
   {
     GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
+    if (srccaps)
+      gst_caps_unref (srccaps);
     return FALSE;
   }
 set_caps_failed:
   {
     GST_ERROR_OBJECT (pad, "Failed to set caps: %" GST_PTR_FORMAT, srccaps);
-    gst_caps_unref (srccaps);
+    if (srccaps)
+      gst_caps_unref (srccaps);
     return FALSE;
   }
 no_bufferpool:
   {
     GST_ERROR_OBJECT (pad, "could not negotiate bufferpool");
-    gst_caps_unref (srccaps);
+    if (srccaps)
+      gst_caps_unref (srccaps);
     return FALSE;
   }
 }