diff --git a/gst/playback/gsturidecodebin.c b/gst/playback/gsturidecodebin.c index 45e92511b0..c523651f9b 100644 --- a/gst/playback/gsturidecodebin.c +++ b/gst/playback/gsturidecodebin.c @@ -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