caps: Don't assert in fixate() on EMPTY/ANY caps and document EMPTY/ANY behaviour...
authorSebastian Dröge <sebastian@centricular.com>
Sat, 7 Mar 2020 09:09:05 +0000 (11:09 +0200)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Mon, 9 Mar 2020 10:10:09 +0000 (10:10 +0000)
fixate() will return empty caps if it gets empty caps passed and assert
early if any caps are provided as there's no meaningful way of fixating
any caps.

truncate() and simplify() will return the input caps in case of
any/empty caps as before, but slightly optimized and as documented
behaviour.

Also add tests for this and a few other operations behaviour on
empty/any caps.

gst/gstcaps.c
tests/check/gst/gstcaps.c

index 51c9301..bfa6011 100644 (file)
@@ -1061,6 +1061,10 @@ gst_caps_copy_nth (const GstCaps * caps, guint nth)
  * on it if necessary, so you must not use @caps afterwards unless you keep an
  * additional reference to it with gst_caps_ref().
  *
+ * Note that it is not guaranteed that the returned caps have exactly one
+ * structure. If @caps is any or empty caps then then returned caps will be
+ * the same and contain no structure at all.
+ *
  * Returns: (transfer full): truncated caps
  */
 GstCaps *
@@ -1070,7 +1074,13 @@ gst_caps_truncate (GstCaps * caps)
 
   g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
 
+  /* Nothing to truncate here */
+  if (GST_CAPS_LEN (caps) == 0)
+    return caps;
+
   i = GST_CAPS_LEN (caps) - 1;
+
+  /* Already truncated */
   if (i == 0)
     return caps;
 
@@ -2183,6 +2193,10 @@ gst_caps_simplify (GstCaps * caps)
 
   g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
 
+  /* empty/any caps are as simple as can be */
+  if (GST_CAPS_LEN (caps) == 0)
+    return caps;
+
   start = GST_CAPS_LEN (caps) - 1;
   /* one caps, already as simple as can be */
   if (start == 0)
@@ -2244,6 +2258,12 @@ gst_caps_simplify (GstCaps * caps)
  * on it so you must not use @caps afterwards unless you keep an additional
  * reference to it with gst_caps_ref().
  *
+ * Note that it is not guaranteed that the returned caps have exactly one
+ * structure. If @caps are empty caps then then returned caps will be
+ * the empty too and contain no structure at all.
+ *
+ * Calling this function with any caps is not allowed.
+ *
  * Returns: (transfer full): the fixated caps
  */
 GstCaps *
@@ -2253,10 +2273,20 @@ gst_caps_fixate (GstCaps * caps)
   GstCapsFeatures *f;
 
   g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
+  g_return_val_if_fail (!CAPS_IS_ANY (caps), NULL);
 
   /* default fixation */
   caps = gst_caps_truncate (caps);
   caps = gst_caps_make_writable (caps);
+
+  /* need to return early here because empty caps have no structure
+   * but must return after make_writable() because the documentation
+   * specifies that it will call make_writable() on the return value
+   * and callers might assume writable caps.
+   */
+  if (CAPS_IS_EMPTY (caps))
+    return caps;
+
   s = gst_caps_get_structure (caps, 0);
   gst_structure_fixate (s);
 
index 68581a4..0335e8b 100644 (file)
@@ -270,6 +270,16 @@ GST_START_TEST (test_simplify)
   }
 
   gst_caps_unref (caps);
+
+  caps = gst_caps_new_empty ();
+  caps = gst_caps_simplify (caps);
+  fail_unless (gst_caps_is_empty (caps));
+  gst_caps_unref (caps);
+
+  caps = gst_caps_new_any ();
+  caps = gst_caps_simplify (caps);
+  fail_unless (gst_caps_is_any (caps));
+  gst_caps_unref (caps);
 }
 
 GST_END_TEST;
@@ -285,6 +295,45 @@ GST_START_TEST (test_truncate)
   caps = gst_caps_truncate (caps);
   fail_unless_equals_int (gst_caps_get_size (caps), 1);
   gst_caps_unref (caps);
+
+  caps = gst_caps_new_empty ();
+  caps = gst_caps_truncate (caps);
+  fail_if (caps == NULL);
+  fail_unless (gst_caps_is_empty (caps));
+  gst_caps_unref (caps);
+
+  caps = gst_caps_new_any ();
+  caps = gst_caps_truncate (caps);
+  fail_if (caps == NULL);
+  fail_unless (gst_caps_is_any (caps));
+  gst_caps_unref (caps);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_fixate)
+{
+  GstCaps *caps, *expected;
+
+  caps = gst_caps_from_string (non_simple_caps_string);
+  fail_unless (caps != NULL,
+      "gst_caps_from_string (non_simple_caps_string) failed");
+  fail_unless_equals_int (gst_caps_get_size (caps), 4);
+  caps = gst_caps_fixate (caps);
+  fail_unless_equals_int (gst_caps_get_size (caps), 1);
+  expected =
+      gst_caps_from_string
+      ("video/x-raw, format=(string)I420, framerate=(fraction)1/100, "
+      "width=(int)16, height=(int)16");
+  fail_unless (gst_caps_is_equal (caps, expected));
+  gst_caps_unref (caps);
+  gst_caps_unref (expected);
+
+  caps = gst_caps_new_empty ();
+  caps = gst_caps_fixate (caps);
+  fail_if (caps == NULL);
+  fail_unless (gst_caps_is_empty (caps));
+  gst_caps_unref (caps);
 }
 
 GST_END_TEST;
@@ -333,6 +382,22 @@ GST_START_TEST (test_subset)
   fail_if (gst_caps_is_equal (c1, c2));
   gst_caps_unref (c1);
   gst_caps_unref (c2);
+
+  c1 = gst_caps_from_string ("video/x-h264, parsed=(boolean)true");
+  c2 = gst_caps_new_empty ();
+  fail_unless (gst_caps_is_subset (c2, c1));
+  fail_if (gst_caps_is_subset (c1, c2));
+  fail_if (gst_caps_is_equal (c1, c2));
+  gst_caps_unref (c1);
+  gst_caps_unref (c2);
+
+  c1 = gst_caps_from_string ("video/x-h264, parsed=(boolean)true");
+  c2 = gst_caps_new_any ();
+  fail_if (gst_caps_is_subset (c2, c1));
+  fail_unless (gst_caps_is_subset (c1, c2));
+  fail_if (gst_caps_is_equal (c1, c2));
+  gst_caps_unref (c1);
+  gst_caps_unref (c2);
 }
 
 GST_END_TEST;
@@ -729,6 +794,55 @@ GST_START_TEST (test_intersect)
 
   gst_caps_unref (c1);
   gst_caps_unref (c2);
+
+  /* ========== */
+
+  c1 = gst_caps_from_string ("video/x-raw,format=(string)I420,width=20");
+  c2 = gst_caps_new_empty ();
+
+  ci1 = gst_caps_intersect (c1, c2);
+  GST_DEBUG ("intersected: %" GST_PTR_FORMAT, ci1);
+
+  fail_unless (gst_caps_is_empty (ci1));
+  fail_unless (gst_caps_get_size (ci1) == 0);
+
+  ci2 = gst_caps_intersect (c2, c1);
+  GST_DEBUG ("intersected: %" GST_PTR_FORMAT, ci2);
+
+  fail_unless (gst_caps_is_empty (ci2));
+  fail_unless (gst_caps_get_size (ci2) == 0);
+
+  fail_unless (gst_caps_is_equal (ci1, ci2));
+
+  gst_caps_unref (ci1);
+  gst_caps_unref (ci2);
+
+  gst_caps_unref (c1);
+  gst_caps_unref (c2);
+
+
+  /* ========== */
+
+  c1 = gst_caps_from_string ("video/x-raw,format=(string)I420,width=20");
+  c2 = gst_caps_new_any ();
+
+  ci1 = gst_caps_intersect (c1, c2);
+  GST_DEBUG ("intersected: %" GST_PTR_FORMAT, ci1);
+
+  fail_unless (gst_caps_is_equal (ci1, c1));
+
+  ci2 = gst_caps_intersect (c2, c1);
+  GST_DEBUG ("intersected: %" GST_PTR_FORMAT, ci2);
+
+  fail_unless (gst_caps_is_equal (ci2, c1));
+
+  fail_unless (gst_caps_is_equal (ci1, ci2));
+
+  gst_caps_unref (ci1);
+  gst_caps_unref (ci2);
+
+  gst_caps_unref (c1);
+  gst_caps_unref (c2);
 }
 
 GST_END_TEST;
@@ -1707,6 +1821,7 @@ gst_caps_suite (void)
   tcase_add_test (tc_chain, test_static_caps);
   tcase_add_test (tc_chain, test_simplify);
   tcase_add_test (tc_chain, test_truncate);
+  tcase_add_test (tc_chain, test_fixate);
   tcase_add_test (tc_chain, test_subset);
   tcase_add_test (tc_chain, test_subset_duplication);
   tcase_add_test (tc_chain, test_merge_fundamental);