#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
{
PROP_LAST_MESSAGE,
PROP_PULL_MODE,
PROP_ALLOC_PAD,
+ PROP_ALLOW_NOT_LINKED,
};
static GstStaticPadTemplate tee_src_template =
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",
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;
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;
gst_object_unref (pad);
+ if (ret == GST_FLOW_NOT_LINKED && tee->allow_not_linked) {
+ ret = GST_FLOW_OK;
+ }
+
return ret;
}
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;
/* 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;
GstPadMode sink_mode;
GstTeePullMode pull_mode;
GstPad *pull_pad;
+
+ gboolean allow_not_linked;
};
struct _GstTeeClass {
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)
{
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;
}