uridecodebin: aggregate topology messages

This makes it possible for GstDiscoverer to work with sources that
have multiple source pads and hence will trigger the creation of multiple
decodebin instances such as rtspsrc.

Based on the work of Vineeth TM <vineeth.tm@samsung.com>

https://bugzilla.gnome.org/show_bug.cgi?id=754178
This commit is contained in:
Mathieu Duponchelle 2017-06-27 02:21:22 +02:00 committed by Olivier Crête
parent 20705f01fc
commit bfba213437

View file

@ -1640,6 +1640,11 @@ remove_decoders (GstURIDecodeBin * bin, gboolean force)
GstElement *decoder = GST_ELEMENT_CAST (walk->data);
GST_DEBUG_OBJECT (bin, "removing old decoder element");
/* Even if we reuse this decodebin, the previous topology will
* be irrelevant */
g_object_set_data (G_OBJECT (decoder), "uridecodebin-topology", NULL);
if (force) {
gst_element_set_state (decoder, GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (bin), decoder);
@ -2392,6 +2397,54 @@ handle_redirect_message (GstURIDecodeBin * dec, GstMessage * msg)
return new_msg;
}
static GstMessage *
make_topology_message (GstURIDecodeBin * dec)
{
GSList *tmp;
GstStructure *aggregated_topology = NULL;
GValue list = G_VALUE_INIT;
GstCaps *caps = NULL;
gchar *name, *proto;
aggregated_topology = gst_structure_new_empty ("stream-topology");
g_value_init (&list, GST_TYPE_LIST);
for (tmp = dec->decodebins; tmp; tmp = tmp->next) {
GValue item = G_VALUE_INIT;
GstStructure *dec_topology =
g_object_get_data (G_OBJECT (tmp->data), "uridecodebin-topology");
g_value_init (&item, GST_TYPE_STRUCTURE);
gst_value_set_structure (&item, dec_topology);
gst_value_list_append_and_take_value (&list, &item);
}
gst_structure_take_value (aggregated_topology, "next", &list);
/* This is a bit wacky, but that's the best way I can find to express
* uridecodebin 'caps' as subsequently shown by gst-discoverer */
proto = gst_uri_get_protocol (dec->uri);
name = g_strdup_printf ("application/%s", proto);
g_free (proto);
caps = gst_caps_new_empty_simple (name);
g_free (name);
gst_structure_set (aggregated_topology, "caps", GST_TYPE_CAPS, caps, NULL);
gst_caps_unref (caps);
return gst_message_new_element (GST_OBJECT (dec), aggregated_topology);
}
static void
check_topology (gpointer data, gpointer user_data)
{
gboolean *has_topo = user_data;
if (g_object_get_data (data, "uridecodebin-topology") == NULL)
*has_topo = FALSE;
}
static void
handle_message (GstBin * bin, GstMessage * msg)
{
@ -2399,7 +2452,32 @@ handle_message (GstBin * bin, GstMessage * msg)
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_ELEMENT:{
if (gst_message_has_name (msg, "redirect")) {
if (gst_message_has_name (msg, "stream-topology")) {
GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (msg));
gboolean has_all_topo = TRUE;
if (dec->pending || (dec->decodebins && dec->decodebins->next != NULL)) {
const GstStructure *structure;
/* If there is only one, just let it through, so this case is if
* there is more than one.
*/
structure = gst_message_get_structure (msg);
g_object_set_data_full (G_OBJECT (element), "uridecodebin-topology",
gst_structure_copy (structure),
(GDestroyNotify) gst_structure_free);
gst_message_unref (msg);
msg = NULL;
g_slist_foreach (dec->decodebins, check_topology, &has_all_topo);
if (has_all_topo)
msg = make_topology_message (dec);
}
} else if (gst_message_has_name (msg, "redirect")) {
/* sort redirect messages based on the connection speed. This simplifies
* the user of this element as it can in most cases just pick the first item
* of the sorted list as a good redirection candidate. It can of course