tee: Add allow-not-linked property
authorJose Antonio Santos Cadenas <santoscadenas@gmail.com>
Thu, 19 Mar 2015 09:36:11 +0000 (10:36 +0100)
committerSebastian Dröge <sebastian@centricular.com>
Thu, 26 Mar 2015 09:46:26 +0000 (10:46 +0100)
This property avoids not linked error when all the pads are unlinked
or when there are no source pads. This is useful in dynamic pipelines
where it can happen that for a short time there are no pads at all or
all downstream pads are not linked yet.

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

plugins/elements/gsttee.c
plugins/elements/gsttee.h
tests/check/elements/tee.c

index 81fcea775c3fbc3f787c38d2fd8d0eed88a418f3..ba717104d1dc795459574705286ae9b381674e6d 100644 (file)
@@ -84,6 +84,7 @@ gst_tee_pull_mode_get_type (void)
 #define DEFAULT_PROP_SILENT            TRUE
 #define DEFAULT_PROP_LAST_MESSAGE      NULL
 #define DEFAULT_PULL_MODE              GST_TEE_PULL_MODE_NEVER
+#define DEFAULT_PROP_ALLOW_NOT_LINKED  FALSE
 
 enum
 {
@@ -94,6 +95,7 @@ enum
   PROP_LAST_MESSAGE,
   PROP_PULL_MODE,
   PROP_ALLOC_PAD,
+  PROP_ALLOW_NOT_LINKED,
 };
 
 static GstStaticPadTemplate tee_src_template =
@@ -265,6 +267,23 @@ gst_tee_class_init (GstTeeClass * klass)
   g_object_class_install_property (gobject_class, PROP_ALLOC_PAD,
       pspec_alloc_pad);
 
+  /**
+   * GstTee:allow-not-linked
+   *
+   * This property makes sink pad return GST_FLOW_OK even if there are no
+   * source pads or any of them is linked.
+   *
+   * This is useful to avoid errors when you have a dynamic pipeline and during
+   * a reconnection you can have all the pads unlinked or removed.
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_ALLOW_NOT_LINKED,
+      g_param_spec_boolean ("allow-not-linked", "Allow not linked",
+          "Return GTS_FLOW_OK even if there are not source pads or all are "
+          "unlinked", DEFAULT_PROP_ALLOW_NOT_LINKED,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gst_element_class_set_static_metadata (gstelement_class,
       "Tee pipe fitting",
       "Generic",
@@ -487,6 +506,9 @@ gst_tee_set_property (GObject * object, guint prop_id, const GValue * value,
       GST_OBJECT_UNLOCK (pad);
       break;
     }
+    case PROP_ALLOW_NOT_LINKED:
+      tee->allow_not_linked = g_value_get_boolean (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -520,6 +542,9 @@ gst_tee_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_ALLOC_PAD:
       g_value_set_object (value, tee->allocpad);
       break;
+    case PROP_ALLOW_NOT_LINKED:
+      g_value_set_boolean (value, tee->allow_not_linked);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -636,6 +661,10 @@ gst_tee_handle_data (GstTee * tee, gpointer data, gboolean is_list)
 
     gst_object_unref (pad);
 
+    if (ret == GST_FLOW_NOT_LINKED && tee->allow_not_linked) {
+      ret = GST_FLOW_OK;
+    }
+
     return ret;
   }
 
@@ -643,7 +672,11 @@ gst_tee_handle_data (GstTee * tee, gpointer data, gboolean is_list)
   g_list_foreach (pads, (GFunc) clear_pads, tee);
 
 restart:
-  cret = GST_FLOW_NOT_LINKED;
+  if (tee->allow_not_linked) {
+    cret = GST_FLOW_OK;
+  } else {
+    cret = GST_FLOW_NOT_LINKED;
+  }
   pads = GST_ELEMENT_CAST (tee)->srcpads;
   cookie = GST_ELEMENT_CAST (tee)->pads_cookie;
 
@@ -709,13 +742,23 @@ restart:
   /* ERRORS */
 no_pads:
   {
-    GST_DEBUG_OBJECT (tee, "there are no pads, return not-linked");
-    ret = GST_FLOW_NOT_LINKED;
-    goto error;
+    if (tee->allow_not_linked) {
+      GST_DEBUG_OBJECT (tee, "there are no pads, dropping %s",
+          is_list ? "buffer-list" : "buffer");
+      ret = GST_FLOW_OK;
+    } else {
+      GST_DEBUG_OBJECT (tee, "there are no pads, return not-linked");
+      ret = GST_FLOW_NOT_LINKED;
+    }
+    goto end;
   }
 error:
   {
     GST_DEBUG_OBJECT (tee, "received error %s", gst_flow_get_name (ret));
+    goto end;
+  }
+end:
+  {
     GST_OBJECT_UNLOCK (tee);
     gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
     return ret;
index ed488aea30c28c9e3512a4129b0e0ecf42e1500a..e4ce310caa81b4ef93d3b88cb9f6a59f835d7944 100644 (file)
@@ -79,6 +79,8 @@ struct _GstTee {
   GstPadMode      sink_mode;
   GstTeePullMode  pull_mode;
   GstPad         *pull_pad;
+
+  gboolean        allow_not_linked;
 };
 
 struct _GstTeeClass {
index 7491215119eed1fa89fb821de938a49c7de0bad2..3cdd0f6301748d7120cf7768040f816902637167 100644 (file)
@@ -625,6 +625,79 @@ GST_START_TEST (test_request_pads)
 
 GST_END_TEST;
 
+GST_START_TEST (test_allow_not_linked)
+{
+  GstElement *tee;
+  GstPad *src1, *src2;
+  GstBuffer *buffer;
+  GstPad *srcpad;
+  GstCaps *caps;
+  GstSegment segment;
+
+  static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+      GST_PAD_SRC,
+      GST_PAD_ALWAYS,
+      GST_STATIC_CAPS_ANY);
+
+  caps = gst_caps_new_empty_simple ("test/test");
+
+  tee = gst_check_setup_element ("tee");
+  fail_unless (tee);
+  g_object_set (tee, "allow-not-linked", TRUE, NULL);
+
+  srcpad = gst_check_setup_src_pad (tee, &srctemplate);
+  gst_pad_set_active (srcpad, TRUE);
+
+  gst_pad_push_event (srcpad, gst_event_new_stream_start ("test"));
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  gst_pad_push_event (srcpad, gst_event_new_stream_start ("test"));
+  gst_pad_set_caps (srcpad, caps);
+  gst_caps_unref (caps);
+  gst_pad_push_event (srcpad, gst_event_new_segment (&segment));
+
+  fail_unless (gst_element_set_state (tee,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+
+  buffer = gst_buffer_new ();
+  fail_unless (buffer);
+
+  fail_unless (gst_pad_push (srcpad, gst_buffer_ref (buffer)) == GST_FLOW_OK);
+
+  src1 = gst_element_get_request_pad (tee, "src_%u");
+
+  fail_unless (gst_pad_push (srcpad, gst_buffer_ref (buffer)) == GST_FLOW_OK);
+
+  src2 = gst_element_get_request_pad (tee, "src_%u");
+
+  fail_unless (gst_pad_push (srcpad, gst_buffer_ref (buffer)) == GST_FLOW_OK);
+
+  g_object_set (tee, "allow-not-linked", FALSE, NULL);
+
+  fail_unless (gst_pad_push (srcpad,
+          gst_buffer_ref (buffer)) == GST_FLOW_NOT_LINKED);
+
+  gst_element_release_request_pad (tee, src1);
+
+  fail_unless (gst_pad_push (srcpad,
+          gst_buffer_ref (buffer)) == GST_FLOW_NOT_LINKED);
+
+  gst_element_release_request_pad (tee, src2);
+  g_object_unref (src1);
+  g_object_unref (src2);
+
+  fail_unless (gst_pad_push (srcpad,
+          gst_buffer_ref (buffer)) == GST_FLOW_NOT_LINKED);
+
+  gst_pad_set_active (srcpad, FALSE);
+  gst_check_teardown_src_pad (tee);
+  gst_check_teardown_element (tee);
+
+  fail_if (buffer->mini_object.refcount != 1);
+  gst_buffer_unref (buffer);
+}
+
+GST_END_TEST;
+
 static Suite *
 tee_suite (void)
 {
@@ -642,6 +715,7 @@ tee_suite (void)
   tcase_add_test (tc_chain, test_internal_links);
   tcase_add_test (tc_chain, test_flow_aggregation);
   tcase_add_test (tc_chain, test_request_pads);
+  tcase_add_test (tc_chain, test_allow_not_linked);
 
   return s;
 }