uridecodebin: aggregate topology messages
authorMathieu Duponchelle <mathieu.duponchelle@collabora.com>
Tue, 27 Jun 2017 00:21:22 +0000 (02:21 +0200)
committerOlivier CrĂȘte <olivier.crete@collabora.com>
Tue, 4 Jul 2017 00:08:55 +0000 (20:08 -0400)
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

gst/playback/gsturidecodebin.c

index 45e9251..c523651 100644 (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