Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / gst-libs / gst / pbutils / gstdiscoverer.c
index c41acee..756b164 100644 (file)
 #endif
 
 #include <gst/video/video.h>
+
 #include "pbutils.h"
 #include "pbutils-marshal.h"
 #include "pbutils-private.h"
 
+#include "gst/glib-compat-private.h"
+
 GST_DEBUG_CATEGORY_STATIC (discoverer_debug);
 #define GST_CAT_DEFAULT discoverer_debug
 
@@ -99,7 +102,7 @@ struct _GstDiscovererPrivate
   GstElement *uridecodebin;
   GstBus *bus;
 
-  GType decodebin2_type;
+  GType decodebin_type;
 
   /* Custom main context variables */
   GMainContext *ctx;
@@ -232,7 +235,8 @@ gst_discoverer_class_init (GstDiscovererClass * klass)
       g_signal_new ("discovered", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
       G_STRUCT_OFFSET (GstDiscovererClass, discovered),
       NULL, NULL, pbutils_marshal_VOID__POINTER_BOXED,
-      G_TYPE_NONE, 2, GST_TYPE_DISCOVERER_INFO, GST_TYPE_G_ERROR);
+      G_TYPE_NONE, 2, GST_TYPE_DISCOVERER_INFO,
+      G_TYPE_ERROR | G_SIGNAL_TYPE_STATIC_SCOPE);
 }
 
 static void
@@ -242,7 +246,7 @@ uridecodebin_element_added_cb (GstElement * uridecodebin,
   GST_DEBUG ("New element added to uridecodebin : %s",
       GST_ELEMENT_NAME (child));
 
-  if (G_OBJECT_TYPE (child) == dc->priv->decodebin2_type) {
+  if (G_OBJECT_TYPE (child) == dc->priv->decodebin_type) {
     g_object_set (child, "post-stream-topology", TRUE, NULL);
   }
 }
@@ -289,14 +293,14 @@ gst_discoverer_init (GstDiscoverer * dc)
 
   GST_DEBUG_OBJECT (dc, "Done initializing Discoverer");
 
-  /* This is ugly. We get the GType of decodebin2 so we can quickly detect
-   * when a decodebin2 is added to uridecodebin so we can set the
+  /* This is ugly. We get the GType of decodebin so we can quickly detect
+   * when a decodebin is added to uridecodebin so we can set the
    * post-stream-topology setting to TRUE */
   dc->priv->element_added_id =
       g_signal_connect_object (dc->priv->uridecodebin, "element-added",
       G_CALLBACK (uridecodebin_element_added_cb), dc, 0);
-  tmp = gst_element_factory_make ("decodebin2", NULL);
-  dc->priv->decodebin2_type = G_OBJECT_TYPE (tmp);
+  tmp = gst_element_factory_make ("decodebin", NULL);
+  dc->priv->decodebin_type = G_OBJECT_TYPE (tmp);
   gst_object_unref (tmp);
 
   /* create queries */
@@ -409,9 +413,11 @@ gst_discoverer_set_timeout (GstDiscoverer * dc, GstClockTime timeout)
   DISCO_UNLOCK (dc);
 }
 
-static gboolean
-_event_probe (GstPad * pad, GstEvent * event, PrivateStream * ps)
+static GstPadProbeReturn
+_event_probe (GstPad * pad, GstPadProbeInfo * info, PrivateStream * ps)
 {
+  GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
+
   if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) {
     GstTagList *tl = NULL, *tmp;
 
@@ -434,7 +440,25 @@ _event_probe (GstPad * pad, GstEvent * event, PrivateStream * ps)
     DISCO_UNLOCK (ps->dc);
   }
 
-  return TRUE;
+  return GST_PAD_PROBE_OK;
+}
+
+static GstStaticCaps subtitle_caps = GST_STATIC_CAPS ("text/plain; "
+    "text/x-pango-markup; subpicture/x-pgs; subpicture/x-dvb; "
+    "application/x-subtitle-unknown; application/x-ssa; application/x-ass; "
+    "subtitle/x-kate; application/x-kate; video/x-dvd-subpicture");
+
+static gboolean
+is_subtitle_caps (const GstCaps * caps)
+{
+  GstCaps *subs_caps;
+  gboolean ret;
+
+  subs_caps = gst_static_caps_get (&subtitle_caps);
+  ret = gst_caps_can_intersect (caps, subs_caps);
+  gst_caps_unref (subs_caps);
+
+  return ret;
 }
 
 static void
@@ -444,14 +468,6 @@ uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad,
   PrivateStream *ps;
   GstPad *sinkpad = NULL;
   GstCaps *caps;
-  static GstCaps *subs_caps = NULL;
-
-  if (!subs_caps) {
-    subs_caps = gst_caps_from_string ("text/plain; text/x-pango-markup; "
-        "subpicture/x-pgs; subpicture/x-dvb; application/x-subtitle-unknown; "
-        "application/x-ssa; application/x-ass; subtitle/x-kate; "
-        "video/x-dvd-subpicture; ");
-  }
 
   GST_DEBUG_OBJECT (dc, "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
 
@@ -468,10 +484,10 @@ uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad,
   g_object_set (ps->sink, "silent", TRUE, NULL);
   g_object_set (ps->queue, "max-size-buffers", 1, "silent", TRUE, NULL);
 
-  caps = gst_pad_get_caps_reffed (pad);
+  caps = gst_pad_query_caps (pad, NULL);
 
-  if (gst_caps_can_intersect (caps, subs_caps)) {
-    /* Subtitle streams are sparse and don't provide any information - don't
+  if (is_subtitle_caps (caps)) {
+    /* Subtitle streams are sparse and may not provide any information - don't
      * wait for data to preroll */
     g_object_set (ps->sink, "async", FALSE, NULL);
   }
@@ -497,7 +513,8 @@ uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad,
   gst_object_unref (sinkpad);
 
   /* Add an event probe */
-  gst_pad_add_event_probe (pad, G_CALLBACK (_event_probe), ps);
+  gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+      (GstPadProbeCallback) _event_probe, ps, NULL);
 
   DISCO_LOCK (dc);
   dc->priv->streams = g_list_append (dc->priv->streams, ps);
@@ -574,15 +591,15 @@ collect_stream_information (GstDiscoverer * dc, PrivateStream * ps, guint idx)
   gchar *stname;
 
   stname = g_strdup_printf ("stream-%02d", idx);
-  st = gst_structure_empty_new (stname);
+  st = gst_structure_new_empty (stname);
   g_free (stname);
 
   /* Get caps */
-  caps = gst_pad_get_negotiated_caps (ps->pad);
+  caps = gst_pad_get_current_caps (ps->pad);
   if (!caps) {
     GST_WARNING ("Couldn't get negotiated caps from %s:%s",
         GST_DEBUG_PAD_NAME (ps->pad));
-    caps = gst_pad_get_caps (ps->pad);
+    caps = gst_pad_query_caps (ps->pad, NULL);
   }
   if (caps) {
     GST_DEBUG ("Got caps %" GST_PTR_FORMAT, caps);
@@ -591,11 +608,28 @@ collect_stream_information (GstDiscoverer * dc, PrivateStream * ps, guint idx)
     gst_caps_unref (caps);
   }
   if (ps->tags)
-    gst_structure_id_set (st, _TAGS_QUARK, GST_TYPE_STRUCTURE, ps->tags, NULL);
+    gst_structure_id_set (st, _TAGS_QUARK, GST_TYPE_TAG_LIST, ps->tags, NULL);
 
   return st;
 }
 
+/* takes ownership of new_tags, may replace *taglist with a new one */
+static void
+gst_discoverer_merge_and_replace_tags (GstTagList ** taglist,
+    GstTagList * new_tags)
+{
+  if (new_tags == NULL)
+    return;
+
+  if (*taglist == NULL) {
+    *taglist = new_tags;
+    return;
+  }
+
+  gst_tag_list_insert (*taglist, new_tags, GST_TAG_MERGE_REPLACE);
+  gst_tag_list_free (new_tags);
+}
+
 /* Parses a set of caps and tags in st and populates a GstDiscovererStreamInfo
  * structure (parent, if !NULL, otherwise it allocates one)
  */
@@ -604,19 +638,19 @@ collect_information (GstDiscoverer * dc, const GstStructure * st,
     GstDiscovererStreamInfo * parent)
 {
   GstCaps *caps;
-  GstStructure *caps_st, *tags_st;
+  GstStructure *caps_st;
+  GstTagList *tags_st;
   const gchar *name;
-  int tmp, tmp2;
+  int tmp;
   guint utmp;
-  gboolean btmp;
 
   if (!st || !gst_structure_id_has_field (st, _CAPS_QUARK)) {
     GST_WARNING ("Couldn't find caps !");
     if (parent)
-      return parent;
+      return gst_discoverer_stream_info_ref (parent);
     else
       return (GstDiscovererStreamInfo *)
-          gst_mini_object_new (GST_TYPE_DISCOVERER_STREAM_INFO);
+          g_object_new (GST_TYPE_DISCOVERER_STREAM_INFO, NULL);
   }
 
   gst_structure_id_get (st, _CAPS_QUARK, GST_TYPE_CAPS, &caps, NULL);
@@ -627,11 +661,11 @@ collect_information (GstDiscoverer * dc, const GstStructure * st,
     GstDiscovererAudioInfo *info;
 
     if (parent)
-      info = (GstDiscovererAudioInfo *) parent;
+      info = (GstDiscovererAudioInfo *) gst_discoverer_stream_info_ref (parent);
     else {
       info = (GstDiscovererAudioInfo *)
-          gst_mini_object_new (GST_TYPE_DISCOVERER_AUDIO_INFO);
-      info->parent.caps = caps;
+          g_object_new (GST_TYPE_DISCOVERER_AUDIO_INFO, NULL);
+      info->parent.caps = gst_caps_ref (caps);
     }
 
     if (gst_structure_get_int (caps_st, "rate", &tmp))
@@ -644,74 +678,112 @@ collect_information (GstDiscoverer * dc, const GstStructure * st,
       info->depth = (guint) tmp;
 
     if (gst_structure_id_has_field (st, _TAGS_QUARK)) {
-      gst_structure_id_get (st, _TAGS_QUARK,
-          GST_TYPE_STRUCTURE, &tags_st, NULL);
-      if (gst_structure_get_uint (tags_st, GST_TAG_BITRATE, &utmp) ||
-          gst_structure_get_uint (tags_st, GST_TAG_NOMINAL_BITRATE, &utmp))
+      gst_structure_id_get (st, _TAGS_QUARK, GST_TYPE_TAG_LIST, &tags_st, NULL);
+      if (gst_tag_list_get_uint (tags_st, GST_TAG_BITRATE, &utmp) ||
+          gst_tag_list_get_uint (tags_st, GST_TAG_NOMINAL_BITRATE, &utmp))
         info->bitrate = utmp;
 
-      if (gst_structure_get_uint (tags_st, GST_TAG_MAXIMUM_BITRATE, &utmp))
+      if (gst_tag_list_get_uint (tags_st, GST_TAG_MAXIMUM_BITRATE, &utmp))
         info->max_bitrate = utmp;
 
       /* FIXME: Is it worth it to remove the tags we've parsed? */
-      info->parent.tags = gst_tag_list_merge (info->parent.tags,
-          (GstTagList *) tags_st, GST_TAG_MERGE_REPLACE);
+      gst_discoverer_merge_and_replace_tags (&info->parent.tags, tags_st);
+    }
 
-      gst_structure_free (tags_st);
+    if (!info->language && ((GstDiscovererStreamInfo *) info)->tags) {
+      gchar *language;
+      if (gst_tag_list_get_string (((GstDiscovererStreamInfo *) info)->tags,
+              GST_TAG_LANGUAGE_CODE, &language)) {
+        info->language = language;
+      }
     }
 
+    gst_caps_unref (caps);
     return (GstDiscovererStreamInfo *) info;
 
   } else if (g_str_has_prefix (name, "video/") ||
       g_str_has_prefix (name, "image/")) {
     GstDiscovererVideoInfo *info;
-    GstVideoFormat format;
+    GstVideoInfo vinfo;
 
     if (parent)
-      info = (GstDiscovererVideoInfo *) parent;
+      info = (GstDiscovererVideoInfo *) gst_discoverer_stream_info_ref (parent);
     else {
       info = (GstDiscovererVideoInfo *)
-          gst_mini_object_new (GST_TYPE_DISCOVERER_VIDEO_INFO);
-      info->parent.caps = caps;
+          g_object_new (GST_TYPE_DISCOVERER_VIDEO_INFO, NULL);
+      info->parent.caps = gst_caps_ref (caps);
     }
 
-    if (gst_video_format_parse_caps (caps, &format, &tmp, &tmp2)) {
-      info->width = (guint) tmp;
-      info->height = (guint) tmp2;
-    }
+    /* FIXME : gst_video_info_from_caps only works with raw caps,
+     * wouldn't we want to get all the info below for non-raw caps ? 
+     */
+    if (g_str_has_prefix (name, "video/x-raw") &&
+        gst_video_info_from_caps (&vinfo, caps)) {
+      info->width = (guint) vinfo.width;
+      info->height = (guint) vinfo.height;
 
-    if (gst_structure_get_int (caps_st, "depth", &tmp))
-      info->depth = (guint) tmp;
+      info->depth = (guint) 0;
 
-    if (gst_video_parse_caps_pixel_aspect_ratio (caps, &tmp, &tmp2)) {
-      info->par_num = tmp;
-      info->par_denom = tmp2;
-    }
+      info->par_num = vinfo.par_n;
+      info->par_denom = vinfo.par_d;
 
-    if (gst_video_parse_caps_framerate (caps, &tmp, &tmp2)) {
-      info->framerate_num = tmp;
-      info->framerate_denom = tmp2;
-    }
+      info->framerate_num = vinfo.fps_n;
+      info->framerate_denom = vinfo.fps_d;
 
-    if (gst_video_format_parse_caps_interlaced (caps, &btmp))
-      info->interlaced = btmp;
+      info->interlaced = (vinfo.flags & GST_VIDEO_FLAG_INTERLACED) != 0;
+    }
 
     if (gst_structure_id_has_field (st, _TAGS_QUARK)) {
-      gst_structure_id_get (st, _TAGS_QUARK,
-          GST_TYPE_STRUCTURE, &tags_st, NULL);
-      if (gst_structure_get_uint (tags_st, GST_TAG_BITRATE, &utmp) ||
-          gst_structure_get_uint (tags_st, GST_TAG_NOMINAL_BITRATE, &utmp))
+      gst_structure_id_get (st, _TAGS_QUARK, GST_TYPE_TAG_LIST, &tags_st, NULL);
+      if (gst_tag_list_get_uint (tags_st, GST_TAG_BITRATE, &utmp) ||
+          gst_tag_list_get_uint (tags_st, GST_TAG_NOMINAL_BITRATE, &utmp))
         info->bitrate = utmp;
 
-      if (gst_structure_get_uint (tags_st, GST_TAG_MAXIMUM_BITRATE, &utmp))
+      if (gst_tag_list_get_uint (tags_st, GST_TAG_MAXIMUM_BITRATE, &utmp))
         info->max_bitrate = utmp;
 
       /* FIXME: Is it worth it to remove the tags we've parsed? */
-      info->parent.tags = gst_tag_list_merge (info->parent.tags,
-          (GstTagList *) tags_st, GST_TAG_MERGE_REPLACE);
-      gst_structure_free (tags_st);
+      gst_discoverer_merge_and_replace_tags (&info->parent.tags,
+          (GstTagList *) tags_st);
     }
 
+    gst_caps_unref (caps);
+    return (GstDiscovererStreamInfo *) info;
+
+  } else if (is_subtitle_caps (caps)) {
+    GstDiscovererSubtitleInfo *info;
+
+    if (parent)
+      info =
+          (GstDiscovererSubtitleInfo *) gst_discoverer_stream_info_ref (parent);
+    else {
+      info = (GstDiscovererSubtitleInfo *)
+          g_object_new (GST_TYPE_DISCOVERER_SUBTITLE_INFO, NULL);
+      info->parent.caps = gst_caps_ref (caps);
+    }
+
+    if (gst_structure_id_has_field (st, _TAGS_QUARK)) {
+      const gchar *language;
+
+      gst_structure_id_get (st, _TAGS_QUARK, GST_TYPE_TAG_LIST, &tags_st, NULL);
+
+      language = gst_structure_get_string (caps_st, GST_TAG_LANGUAGE_CODE);
+      if (language)
+        info->language = g_strdup (language);
+
+      /* FIXME: Is it worth it to remove the tags we've parsed? */
+      gst_discoverer_merge_and_replace_tags (&info->parent.tags, tags_st);
+    }
+
+    if (!info->language && ((GstDiscovererStreamInfo *) info)->tags) {
+      gchar *language;
+      if (gst_tag_list_get_string (((GstDiscovererStreamInfo *) info)->tags,
+              GST_TAG_LANGUAGE_CODE, &language)) {
+        info->language = language;
+      }
+    }
+
+    gst_caps_unref (caps);
     return (GstDiscovererStreamInfo *) info;
 
   } else {
@@ -719,20 +791,19 @@ collect_information (GstDiscoverer * dc, const GstStructure * st,
     GstDiscovererStreamInfo *info;
 
     if (parent)
-      info = parent;
+      info = gst_discoverer_stream_info_ref (parent);
     else {
       info = (GstDiscovererStreamInfo *)
-          gst_mini_object_new (GST_TYPE_DISCOVERER_STREAM_INFO);
-      info->caps = caps;
+          g_object_new (GST_TYPE_DISCOVERER_STREAM_INFO, NULL);
+      info->caps = gst_caps_ref (caps);
     }
 
     if (gst_structure_id_get (st, _TAGS_QUARK,
-            GST_TYPE_STRUCTURE, &tags_st, NULL)) {
-      info->tags = gst_tag_list_merge (info->tags, (GstTagList *) tags_st,
-          GST_TAG_MERGE_REPLACE);
-      gst_structure_free (tags_st);
+            GST_TYPE_TAG_LIST, &tags_st, NULL)) {
+      gst_discoverer_merge_and_replace_tags (&info->tags, tags_st);
     }
 
+    gst_caps_unref (caps);
     return info;
   }
 
@@ -756,8 +827,10 @@ find_stream_for_node (GstDiscoverer * dc, const GstStructure * topology)
   gst_structure_id_get (topology, _TOPOLOGY_PAD_QUARK,
       GST_TYPE_PAD, &pad, NULL);
 
-  if (!dc->priv->streams)
+  if (!dc->priv->streams) {
+    gst_object_unref (pad);
     return NULL;
+  }
 
   for (i = 0, tmp = dc->priv->streams; tmp; tmp = tmp->next, i++) {
     ps = (PrivateStream *) tmp->data;
@@ -778,9 +851,9 @@ find_stream_for_node (GstDiscoverer * dc, const GstStructure * topology)
 }
 
 static gboolean
-child_is_raw_stream (GstCaps * parent, GstCaps * child)
+child_is_raw_stream (const GstCaps * parent, const GstCaps * child)
 {
-  GstStructure *st1, *st2;
+  const GstStructure *st1, *st2;
   const gchar *name1, *name2;
 
   st1 = gst_caps_get_structure (parent, 0);
@@ -797,6 +870,9 @@ child_is_raw_stream (GstCaps * parent, GstCaps * child)
     return TRUE;
   }
 
+  if (is_subtitle_caps (parent))
+    return TRUE;
+
   return FALSE;
 }
 
@@ -846,30 +922,29 @@ parse_stream_topology (GstDiscoverer * dc, const GstStructure * topology,
           /* We sometimes get an extra sub-stream from the parser. If this is
            * the case, we just replace the parent caps with this stream's caps
            * since they might contain more information */
-          gst_caps_unref (parent->caps);
-          parent->caps = caps;
+          gst_caps_replace (&parent->caps, caps);
 
           parse_stream_topology (dc, st, parent);
           add_to_list = FALSE;
-
         } else if (child_is_raw_stream (parent->caps, caps)) {
           /* This is the "raw" stream corresponding to the parent. This
            * contains more information than the parent, tags etc. */
           parse_stream_topology (dc, st, parent);
           add_to_list = FALSE;
-          gst_caps_unref (caps);
-
         } else {
           GstDiscovererStreamInfo *next = parse_stream_topology (dc, st, NULL);
           res->next = next;
           next->previous = res;
         }
+        gst_caps_unref (caps);
       }
     }
 
     if (add_to_list) {
       dc->priv->current_info->stream_list =
           g_list_append (dc->priv->current_info->stream_list, res);
+    } else {
+      gst_discoverer_stream_info_unref (res);
     }
 
   } else if (GST_VALUE_HOLDS_LIST (nval)) {
@@ -885,7 +960,7 @@ parse_stream_topology (GstDiscoverer * dc, const GstStructure * topology,
     GST_DEBUG ("next is a list of %d entries", len);
 
     cont = (GstDiscovererContainerInfo *)
-        gst_mini_object_new (GST_TYPE_DISCOVERER_CONTAINER_INFO);
+        g_object_new (GST_TYPE_DISCOVERER_CONTAINER_INFO, NULL);
     cont->parent.caps = caps;
     res = (GstDiscovererStreamInfo *) cont;
 
@@ -893,7 +968,7 @@ parse_stream_topology (GstDiscoverer * dc, const GstStructure * topology,
       GstTagList *tmp;
 
       gst_structure_id_get (topology, _TAGS_QUARK,
-          GST_TYPE_STRUCTURE, &tags, NULL);
+          GST_TYPE_TAG_LIST, &tags, NULL);
 
       GST_DEBUG ("Merge tags %" GST_PTR_FORMAT, tags);
 
@@ -942,20 +1017,43 @@ discoverer_collect (GstDiscoverer * dc)
     /* FIXME : Make this querying optional */
     if (TRUE) {
       GstElement *pipeline = (GstElement *) dc->priv->pipeline;
-      GstFormat format = GST_FORMAT_TIME;
       gint64 dur;
 
       GST_DEBUG ("Attempting to query duration");
 
-      if (gst_element_query_duration (pipeline, &format, &dur)) {
-        if (format == GST_FORMAT_TIME) {
-          GST_DEBUG ("Got duration %" GST_TIME_FORMAT, GST_TIME_ARGS (dur));
-          dc->priv->current_info->duration = (guint64) dur;
+      if (gst_element_query_duration (pipeline, GST_FORMAT_TIME, &dur)) {
+        GST_DEBUG ("Got duration %" GST_TIME_FORMAT, GST_TIME_ARGS (dur));
+        dc->priv->current_info->duration = (guint64) dur;
+      } else {
+        GstStateChangeReturn sret;
+
+        /* Some parsers may not even return a rough estimate right away, e.g.
+         * because they've only processed a single frame so far, so if we
+         * didn't get a duration the first time, spin a bit and try again.
+         * Ugly, but still better than making parsers or other elements return
+         * completely bogus values. We need some API extensions to solve this
+         * better. */
+        GST_INFO ("No duration yet, try a bit harder..");
+        sret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
+        if (sret != GST_STATE_CHANGE_FAILURE) {
+          int i;
+
+          for (i = 0; i < 2; ++i) {
+            g_usleep (G_USEC_PER_SEC / 20);
+            if (gst_element_query_duration (pipeline, GST_FORMAT_TIME, &dur)
+                && dur > 0) {
+              GST_DEBUG ("Got duration %" GST_TIME_FORMAT, GST_TIME_ARGS (dur));
+              dc->priv->current_info->duration = (guint64) dur;
+              break;
+            }
+          }
+          gst_element_set_state (pipeline, GST_STATE_PAUSED);
         }
       }
 
       if (dc->priv->seeking_query) {
         if (gst_element_query (pipeline, dc->priv->seeking_query)) {
+          GstFormat format;
           gboolean seekable;
 
           gst_query_parse_seeking (dc->priv->seeking_query, &format,
@@ -977,7 +1075,7 @@ discoverer_collect (GstDiscoverer * dc)
      * caps named image/<foo> (th exception being MJPEG video which is also
      * type image/jpeg), and should consist of precisely one stream (actually
      * initially there are 2, the image and raw stream, but we squash these
-     * while parsing the stream topology). At some ponit, if we find that these
+     * while parsing the stream topology). At some point, if we find that these
      * conditions are not sufficient, we can count the number of decoders and
      * parsers in the chain, and if there's more than one decoder, or any
      * parser at all, we should not mark this as an image.
@@ -1079,16 +1177,24 @@ handle_message (GstDiscoverer * dc, GstMessage * msg)
 
     case GST_MESSAGE_ELEMENT:
     {
-      GQuark sttype = gst_structure_get_name_id (msg->structure);
+      GQuark sttype;
+      const GstStructure *structure;
+
+      structure = gst_message_get_structure (msg);
+      sttype = gst_structure_get_name_id (structure);
       GST_DEBUG_OBJECT (GST_MESSAGE_SRC (msg),
-          "structure %" GST_PTR_FORMAT, msg->structure);
+          "structure %" GST_PTR_FORMAT, structure);
       if (sttype == _MISSING_PLUGIN_QUARK) {
         GST_DEBUG_OBJECT (GST_MESSAGE_SRC (msg),
             "Setting result to MISSING_PLUGINS");
         dc->priv->current_info->result = GST_DISCOVERER_MISSING_PLUGINS;
-        dc->priv->current_info->misc = gst_structure_copy (msg->structure);
+        if (dc->priv->current_info->misc)
+          gst_structure_free (dc->priv->current_info->misc);
+        dc->priv->current_info->misc = gst_structure_copy (structure);
       } else if (sttype == _STREAM_TOPOLOGY_QUARK) {
-        dc->priv->current_topology = gst_structure_copy (msg->structure);
+        if (dc->priv->current_topology)
+          gst_structure_free (dc->priv->current_topology);
+        dc->priv->current_topology = gst_structure_copy (structure);
       }
     }
       break;
@@ -1138,7 +1244,6 @@ handle_current_sync (GstDiscoverer * dc)
       done = handle_message (dc, msg);
       gst_message_unref (msg);
     }
-
   } while (!done && (g_timer_elapsed (timer, NULL) < deadline));
 
   /* return result */
@@ -1162,7 +1267,7 @@ _setup_locked (GstDiscoverer * dc)
 
   /* Pop URI off the pending URI list */
   dc->priv->current_info =
-      (GstDiscovererInfo *) gst_mini_object_new (GST_TYPE_DISCOVERER_INFO);
+      (GstDiscovererInfo *) g_object_new (GST_TYPE_DISCOVERER_INFO, NULL);
   dc->priv->current_info->uri = (gchar *) dc->priv->pending_uris->data;
   dc->priv->pending_uris =
       g_list_delete_link (dc->priv->pending_uris, dc->priv->pending_uris);
@@ -1410,7 +1515,7 @@ gst_discoverer_stop (GstDiscoverer * discoverer)
  * A copy of @uri will be made internally, so the caller can safely g_free()
  * afterwards.
  *
- * Returns: %TRUE if the @uri was succesfully appended to the list of pending
+ * Returns: %TRUE if the @uri was successfully appended to the list of pending
  * uris, else %FALSE
  *
  * Since: 0.10.31