mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-20 07:16:55 +00:00
output-selector: Add pad-negotiation-mode property
Adds getcaps/setcaps to output-selector and adds a property to select which type of negotiation should be done. The available modes are: * none: no negotiation (current behavior), getcaps return ANY and setcaps aren't set on any of the peers * all: use all pads (default), getcaps returns the intersection of peer pads and setcaps is set on all peers * active: getcaps and setcaps are proxied to the active pad https://bugzilla.gnome.org/show_bug.cgi?id=638381
This commit is contained in:
parent
c8ffd4e395
commit
757dc90faa
3 changed files with 276 additions and 10 deletions
|
@ -49,13 +49,43 @@ GST_STATIC_PAD_TEMPLATE ("src%d",
|
|||
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");
|
||||
|
@ -79,6 +109,8 @@ static GstStateChangeReturn gst_output_selector_change_state (GstElement *
|
|||
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)
|
||||
|
@ -113,6 +145,12 @@ gst_output_selector_class_init (GstOutputSelectorClass * klass)
|
|||
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);
|
||||
|
@ -135,12 +173,6 @@ gst_output_selector_init (GstOutputSelector * sel,
|
|||
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);
|
||||
|
||||
|
@ -152,6 +184,8 @@ gst_output_selector_init (GstOutputSelector * sel,
|
|||
|
||||
sel->resend_latest = FALSE;
|
||||
sel->latest_buffer = NULL;
|
||||
gst_output_selector_switch_pad_negotiation_mode (sel,
|
||||
DEFAULT_PAD_NEGOTIATION_MODE);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -218,6 +252,11 @@ gst_output_selector_set_property (GObject * object, guint prop_id,
|
|||
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;
|
||||
|
@ -243,12 +282,75 @@ gst_output_selector_get_property (GObject * object, guint prop_id,
|
|||
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)
|
||||
|
|
|
@ -47,6 +47,8 @@ struct _GstOutputSelector {
|
|||
GstPad *pending_srcpad;
|
||||
guint nb_srcpads;
|
||||
|
||||
gint pad_negotiation_mode;
|
||||
|
||||
GstSegment segment;
|
||||
|
||||
/* resend latest buffer after switch */
|
||||
|
|
|
@ -61,13 +61,16 @@ probe_cb (GstPad * pad, GstMiniObject * obj, gpointer user_data)
|
|||
|
||||
/* 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 */
|
||||
|
@ -244,7 +247,7 @@ run_output_selector_buffer_count (gint num_output_pads,
|
|||
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 */
|
||||
|
@ -369,6 +372,157 @@ GST_START_TEST (test_input_selector_buffer_count);
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -379,6 +533,14 @@ 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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue