GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
+enum GstOutputSelectorPadNegotiationMode
+{
+ GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_NONE,
+ GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL,
+ GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ACTIVE
+};
+#define GST_TYPE_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE (gst_output_selector_pad_negotiation_mode_get_type())
+static GType
+gst_output_selector_pad_negotiation_mode_get_type (void)
+{
+ static GType pad_negotiation_mode_type = 0;
+ static GEnumValue pad_negotiation_modes[] = {
+ {GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_NONE, "None", "none"},
+ {GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL, "All", "all"},
+ {GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ACTIVE, "Active", "active"},
+ {0, NULL, NULL}
+ };
+
+ if (!pad_negotiation_mode_type) {
+ pad_negotiation_mode_type =
+ g_enum_register_static ("GstOutputSelectorPadNegotiationMode",
+ pad_negotiation_modes);
+ }
+ return pad_negotiation_mode_type;
+}
+
+
enum
{
PROP_0,
PROP_ACTIVE_PAD,
- PROP_RESEND_LATEST
+ PROP_RESEND_LATEST,
+ PROP_PAD_NEGOTIATION_MODE
};
+#define DEFAULT_PAD_NEGOTIATION_MODE GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL
+
#define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (output_selector_debug, \
"output-selector", 0, "Output stream selector");
element, GstStateChange transition);
static gboolean gst_output_selector_handle_sink_event (GstPad * pad,
GstEvent * event);
+static void gst_output_selector_switch_pad_negotiation_mode (GstOutputSelector *
+ sel, gint mode);
static void
gst_output_selector_base_init (gpointer g_class)
g_param_spec_boolean ("resend-latest", "Resend latest buffer",
"Resend latest buffer after a switch to a new pad", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_PAD_NEGOTIATION_MODE,
+ g_param_spec_enum ("pad-negotiation-mode", "Pad negotiation mode",
+ "The mode to be used for pad negotiation",
+ GST_TYPE_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE,
+ DEFAULT_PAD_NEGOTIATION_MODE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_output_selector_request_new_pad);
GST_DEBUG_FUNCPTR (gst_output_selector_handle_sink_event));
gst_pad_set_bufferalloc_function (sel->sinkpad,
GST_DEBUG_FUNCPTR (gst_output_selector_buffer_alloc));
- /*
- gst_pad_set_setcaps_function (sel->sinkpad,
- GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
- gst_pad_set_getcaps_function (sel->sinkpad,
- GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
- */
gst_element_add_pad (GST_ELEMENT (sel), sel->sinkpad);
sel->resend_latest = FALSE;
sel->latest_buffer = NULL;
+ gst_output_selector_switch_pad_negotiation_mode (sel,
+ DEFAULT_PAD_NEGOTIATION_MODE);
}
static void
sel->resend_latest = g_value_get_boolean (value);
break;
}
+ case PROP_PAD_NEGOTIATION_MODE:{
+ gst_output_selector_switch_pad_negotiation_mode (sel,
+ g_value_get_enum (value));
+ break;
+ }
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
GST_OBJECT_UNLOCK (object);
break;
}
+ case PROP_PAD_NEGOTIATION_MODE:
+ g_value_set_enum (value, sel->pad_negotiation_mode);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
+static GstCaps *
+gst_output_selector_sink_getcaps (GstPad * pad)
+{
+ GstOutputSelector *sel = GST_OUTPUT_SELECTOR (GST_PAD_PARENT (pad));
+ GstPad *active;
+ GstCaps *caps;
+
+ GST_OBJECT_LOCK (sel);
+ if (sel->pending_srcpad)
+ active = gst_object_ref (sel->pending_srcpad);
+ else
+ active = gst_object_ref (sel->active_srcpad);
+ GST_OBJECT_UNLOCK (sel);
+
+ caps = gst_pad_peer_get_caps_reffed (active);
+ gst_object_unref (active);
+ if (caps == NULL) {
+ caps = gst_caps_new_any ();
+ }
+ return caps;
+}
+
+static gboolean
+gst_output_selector_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstOutputSelector *sel = GST_OUTPUT_SELECTOR (GST_PAD_PARENT (pad));
+ GstPad *active;
+ gboolean ret;
+
+ GST_OBJECT_LOCK (sel);
+ if (sel->pending_srcpad)
+ active = gst_object_ref (sel->pending_srcpad);
+ else
+ active = gst_object_ref (sel->active_srcpad);
+ GST_OBJECT_UNLOCK (sel);
+
+ ret = gst_pad_set_caps (active, caps);
+ gst_object_unref (active);
+ return ret;
+}
+
+static void
+gst_output_selector_switch_pad_negotiation_mode (GstOutputSelector * sel,
+ gint mode)
+{
+ sel->pad_negotiation_mode = mode;
+ if (mode == GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL) {
+ gst_pad_set_getcaps_function (sel->sinkpad, gst_pad_proxy_getcaps);
+ gst_pad_set_setcaps_function (sel->sinkpad, gst_pad_proxy_setcaps);
+ } else if (mode == GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_NONE) {
+ gst_pad_set_getcaps_function (sel->sinkpad, NULL);
+ gst_pad_set_setcaps_function (sel->sinkpad, NULL);
+ } else { /* active */
+ gst_pad_set_getcaps_function (sel->sinkpad,
+ gst_output_selector_sink_getcaps);
+ gst_pad_set_setcaps_function (sel->sinkpad,
+ gst_output_selector_sink_setcaps);
+ }
+}
+
static GstFlowReturn
gst_output_selector_buffer_alloc (GstPad * pad, guint64 offset, guint size,
GstCaps * caps, GstBuffer ** buf)
/* Create and link output pad: selector:src%d ! output_pad */
static GstPad *
-setup_output_pad (GstElement * element)
+setup_output_pad (GstElement * element, GstStaticPadTemplate * tmpl)
{
GstPad *srcpad = NULL, *output_pad = NULL;
gulong probe_id = 0;
+ if (tmpl == NULL)
+ tmpl = &sinktemplate;
+
/* create output_pad */
- output_pad = gst_pad_new_from_static_template (&sinktemplate, "sink");
+ output_pad = gst_pad_new_from_static_template (tmpl, "sink");
fail_if (output_pad == NULL, "Could not create a output_pad");
/* add probe */
input_pads = g_list_append (input_pads, input_pad);
gst_pad_set_active (input_pad, TRUE);
for (i = 0; i < num_output_pads; i++) {
- output_pads = g_list_append (output_pads, setup_output_pad (sel));
+ output_pads = g_list_append (output_pads, setup_output_pad (sel, NULL));
}
/* run the test */
GST_END_TEST;
+GstElement *sel;
+GstPad *input_pad;
+GList *output_pads = NULL; /* list of sinkpads linked to output-selector */
+#define OUTPUT_SELECTOR_NUM_PADS 2
+
+static GstStaticPadTemplate sinktmpl_nego_a = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("format/abc; format/xyz"));
+static GstStaticPadTemplate sinktmpl_nego_b = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("format/abc"));
+
+static void
+setup_output_selector (void)
+{
+ sel = gst_check_setup_element ("output-selector");
+ input_pad = gst_check_setup_src_pad (sel, &srctemplate, NULL);
+ gst_pad_set_active (input_pad, TRUE);
+
+ output_pads = g_list_append (output_pads, setup_output_pad (sel,
+ &sinktmpl_nego_a));
+ output_pads = g_list_append (output_pads, setup_output_pad (sel,
+ &sinktmpl_nego_b));
+}
+
+static void
+teardown_output_selector (void)
+{
+ gst_pad_set_active (input_pad, FALSE);
+ gst_object_unref (input_pad);
+ gst_check_teardown_src_pad (sel);
+ g_list_foreach (output_pads, (GFunc) cleanup_pad, sel);
+ g_list_free (output_pads);
+ gst_check_teardown_element (sel);
+ output_pads = NULL;
+}
+
+GST_START_TEST (test_output_selector_getcaps_none);
+{
+ GList *walker;
+
+ /* set pad negotiation mode to none */
+ g_object_set (sel, "pad-negotiation-mode", 0, NULL);
+
+ fail_unless (gst_element_set_state (sel,
+ GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+ "could not set to playing");
+
+ for (walker = output_pads; walker; walker = g_list_next (walker)) {
+ GstCaps *caps;
+ GstPad *pad;
+
+ pad = gst_pad_get_peer ((GstPad *) walker->data);
+
+ g_object_set (sel, "active-pad", pad, NULL);
+
+ caps = gst_pad_peer_get_caps (input_pad);
+
+ /* in 'none' mode, the getcaps returns the template, which is ANY */
+ g_assert (gst_caps_is_any (caps));
+ gst_caps_unref (caps);
+ }
+
+ fail_unless (gst_element_set_state (sel,
+ GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_output_selector_getcaps_all);
+{
+ GList *walker;
+ GstCaps *expected;
+
+ /* set pad negotiation mode to 'all' */
+ g_object_set (sel, "pad-negotiation-mode", 1, NULL);
+
+ fail_unless (gst_element_set_state (sel,
+ GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+ "could not set to playing");
+
+ /* in 'all' mode, the intersection of the srcpad caps should be returned on
+ * the sinkpad's getcaps */
+ expected = gst_caps_new_simple ("format/abc", NULL);
+
+ for (walker = output_pads; walker; walker = g_list_next (walker)) {
+ GstCaps *caps;
+ GstPad *pad;
+
+ pad = gst_pad_get_peer ((GstPad *) walker->data);
+
+ g_object_set (sel, "active-pad", pad, NULL);
+
+ caps = gst_pad_peer_get_caps (input_pad);
+
+ g_assert (gst_caps_is_equal (caps, expected));
+ gst_caps_unref (caps);
+ }
+ gst_caps_unref (expected);
+
+ fail_unless (gst_element_set_state (sel,
+ GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_output_selector_getcaps_active);
+{
+ GList *walker;
+ GstCaps *expected;
+
+ /* set pad negotiation mode to 'active' */
+ g_object_set (sel, "pad-negotiation-mode", 2, NULL);
+
+ fail_unless (gst_element_set_state (sel,
+ GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+ "could not set to playing");
+
+ for (walker = output_pads; walker; walker = g_list_next (walker)) {
+ GstCaps *caps;
+ GstPad *pad;
+
+ pad = gst_pad_get_peer ((GstPad *) walker->data);
+
+ g_object_set (sel, "active-pad", pad, NULL);
+
+ /* in 'active' mode, the active srcpad peer's caps should be returned on
+ * the sinkpad's getcaps */
+
+ expected = gst_pad_template_get_caps (gst_pad_get_pad_template ((GstPad *)
+ walker->data));
+ caps = gst_pad_peer_get_caps (input_pad);
+
+ g_assert (gst_caps_is_equal (caps, expected));
+ gst_caps_unref (caps);
+ }
+
+ fail_unless (gst_element_set_state (sel,
+ GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+
+}
+
+GST_END_TEST;
+
+
static Suite *
selector_suite (void)
{
tcase_add_test (tc_chain, test_output_selector_buffer_count);
tcase_add_test (tc_chain, test_input_selector_buffer_count);
+ tc_chain = tcase_create ("output-selector-negotiation");
+ tcase_add_checked_fixture (tc_chain, setup_output_selector,
+ teardown_output_selector);
+ suite_add_tcase (s, tc_chain);
+ tcase_add_test (tc_chain, test_output_selector_getcaps_none);
+ tcase_add_test (tc_chain, test_output_selector_getcaps_all);
+ tcase_add_test (tc_chain, test_output_selector_getcaps_active);
+
return s;
}