Add -Wmissing-declarations -Wmissing-prototypes to warning flags
[platform/upstream/gstreamer.git] / gst / playback / gsturidecodebin.c
index a1691fb..b19459b 100644 (file)
 
 #include <gst/gst.h>
 #include <gst/gst-i18n-plugin.h>
+#include <gst/pbutils/missing-plugins.h>
 
 #include "gstfactorylists.h"
 #include "gstplay-marshal.h"
 #include "gstplay-enum.h"
+#include "gstrawcaps.h"
 
 #define GST_TYPE_URI_DECODE_BIN \
   (gst_uri_decode_bin_get_type())
@@ -67,6 +69,8 @@ struct _GstURIDecodeBin
 
   GMutex *lock;                 /* lock for constructing */
 
+  GMutex *factories_lock;
+  guint32 factories_cookie;
   GValueArray *factories;       /* factories we can use for selecting elements */
 
   gchar *uri;
@@ -83,6 +87,7 @@ struct _GstURIDecodeBin
   gboolean use_buffering;
 
   GstElement *source;
+  GstElement *queue;
   GstElement *typefind;
   guint have_type_id;           /* have-type signal id from typefind */
   GSList *decodebins;
@@ -124,6 +129,8 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src%d",
     GST_PAD_SOMETIMES,
     GST_STATIC_CAPS_ANY);
 
+static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
+
 GST_DEBUG_CATEGORY_STATIC (gst_uri_decode_bin_debug);
 #define GST_CAT_DEFAULT gst_uri_decode_bin_debug
 
@@ -148,7 +155,7 @@ enum
 #define DEFAULT_PROP_URI            NULL
 #define DEFAULT_PROP_SOURCE         NULL
 #define DEFAULT_CONNECTION_SPEED    0
-#define DEFAULT_CAPS                NULL
+#define DEFAULT_CAPS                (gst_static_caps_get (&default_raw_caps))
 #define DEFAULT_SUBTITLE_ENCODING   NULL
 #define DEFAULT_BUFFER_DURATION     -1
 #define DEFAULT_BUFFER_SIZE         -1
@@ -172,6 +179,7 @@ enum
 
 static guint gst_uri_decode_bin_signals[LAST_SIGNAL] = { 0 };
 
+GType gst_uri_decode_bin_get_type (void);
 GST_BOILERPLATE (GstURIDecodeBin, gst_uri_decode_bin, GstBin, GST_TYPE_BIN);
 
 static void remove_decoders (GstURIDecodeBin * bin, gboolean force);
@@ -246,18 +254,34 @@ gst_uri_decode_bin_autoplug_continue (GstElement * element, GstPad * pad,
   return TRUE;
 }
 
+/* Must be called with factories lock! */
+static void
+gst_uri_decode_bin_update_factories_list (GstURIDecodeBin * dec)
+{
+  if (!dec->factories ||
+      dec->factories_cookie !=
+      gst_default_registry_get_feature_list_cookie ()) {
+    if (dec->factories)
+      g_value_array_free (dec->factories);
+    dec->factories = gst_factory_list_get_elements (GST_FACTORY_LIST_DECODER);
+    dec->factories_cookie = gst_default_registry_get_feature_list_cookie ();
+  }
+}
+
 static GValueArray *
 gst_uri_decode_bin_autoplug_factories (GstElement * element, GstPad * pad,
     GstCaps * caps)
 {
   GValueArray *result;
+  GstURIDecodeBin *dec = GST_URI_DECODE_BIN_CAST (element);
 
   GST_DEBUG_OBJECT (element, "finding factories");
 
   /* return all compatible factories for caps */
-  result =
-      gst_factory_list_filter (GST_URI_DECODE_BIN_CAST (element)->factories,
-      caps);
+  g_mutex_lock (dec->factories_lock);
+  gst_uri_decode_bin_update_factories_list (dec);
+  result = gst_factory_list_filter (dec->factories, caps);
+  g_mutex_unlock (dec->factories_lock);
 
   GST_DEBUG_OBJECT (element, "autoplug-factories returns %p", result);
 
@@ -467,7 +491,8 @@ static void
 gst_uri_decode_bin_init (GstURIDecodeBin * dec, GstURIDecodeBinClass * klass)
 {
   /* first filter out the interesting element factories */
-  dec->factories = gst_factory_list_get_elements (GST_FACTORY_LIST_DECODER);
+  dec->factories_lock = g_mutex_new ();
+  gst_uri_decode_bin_update_factories_list (dec);
 
   dec->lock = g_mutex_new ();
 
@@ -489,6 +514,7 @@ gst_uri_decode_bin_finalize (GObject * obj)
 
   remove_decoders (dec, TRUE);
   g_mutex_free (dec->lock);
+  g_mutex_free (dec->factories_lock);
   g_free (dec->uri);
   g_free (dec->encoding);
   if (dec->factories)
@@ -657,7 +683,7 @@ unknown_type_cb (GstElement * element, GstPad * pad, GstCaps * caps,
   gchar *capsstr;
 
   capsstr = gst_caps_to_string (caps);
-  GST_ELEMENT_WARNING (decoder, CORE, MISSING_PLUGIN,
+  GST_ELEMENT_WARNING (decoder, STREAM, CODEC_NOT_FOUND,
       (_("No decoder available for type \'%s\'."), capsstr), (NULL));
   g_free (capsstr);
 }
@@ -721,9 +747,9 @@ source_no_more_pads (GstElement * element, GstURIDecodeBin * bin)
   GST_DEBUG_OBJECT (bin, "No more pads in source element %s.",
       GST_ELEMENT_NAME (element));
 
-  g_signal_handler_disconnect (G_OBJECT (element), bin->src_np_sig_id);
+  g_signal_handler_disconnect (element, bin->src_np_sig_id);
   bin->src_np_sig_id = 0;
-  g_signal_handler_disconnect (G_OBJECT (element), bin->src_nmp_sig_id);
+  g_signal_handler_disconnect (element, bin->src_nmp_sig_id);
   bin->src_nmp_sig_id = 0;
 
   no_more_pads_full (element, FALSE, bin);
@@ -757,6 +783,34 @@ new_decoded_pad_cb (GstElement * element, GstPad * pad, gboolean last,
   gst_element_add_pad (GST_ELEMENT_CAST (decoder), newpad);
 }
 
+
+static gboolean
+source_pad_event_probe (GstPad * pad, GstEvent * event,
+    GstURIDecodeBin * decoder)
+{
+  GST_LOG_OBJECT (pad, "%s, decoder %p", GST_EVENT_TYPE_NAME (event), decoder);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
+    GST_DEBUG_OBJECT (pad, "we received EOS");
+
+    g_signal_emit (decoder,
+        gst_uri_decode_bin_signals[SIGNAL_DRAINED], 0, NULL);
+  }
+  /* never drop events */
+  return TRUE;
+}
+
+/* called when we found a raw pad on the source element. We need to set up a
+ * padprobe to detect EOS before exposing the pad. */
+static void
+expose_decoded_pad (GstElement * element, GstPad * pad,
+    GstURIDecodeBin * decoder)
+{
+  gst_pad_add_event_probe (pad, G_CALLBACK (source_pad_event_probe), decoder);
+
+  new_decoded_pad_cb (element, pad, FALSE, decoder);
+}
+
 static void
 pad_removed_cb (GstElement * element, GstPad * pad, GstURIDecodeBin * decoder)
 {
@@ -835,12 +889,6 @@ static const gchar *no_media_mimes[] = {
 };
 #endif
 
-/* media types we consider raw media */
-static const gchar *raw_media[] = {
-  "audio/x-raw", "video/x-raw", "text/plain", "text/x-pango-markup",
-  "video/x-dvd-subpicture", "subpicture/x-", NULL
-};
-
 /* media types we can download */
 static const gchar *download_media[] = {
   "video/quicktime", "video/x-flv", NULL
@@ -850,7 +898,6 @@ static const gchar *download_media[] = {
 #define IS_QUEUE_URI(uri)           (array_has_uri_value (queue_uris, uri))
 #define IS_BLACKLISTED_URI(uri)     (array_has_uri_value (blacklisted_uris, uri))
 #define IS_NO_MEDIA_MIME(mime)      (array_has_value (no_media_mimes, mime))
-#define IS_RAW_MEDIA(media)         (array_has_value (raw_media, media))
 #define IS_DOWNLOAD_MEDIA(media)    (array_has_value (download_media, media))
 
 /*
@@ -905,8 +952,7 @@ gen_source_element (GstURIDecodeBin * decoder)
           "subtitle-encoding")) {
     GST_DEBUG_OBJECT (decoder,
         "setting subtitle-encoding=%s to source element", decoder->encoding);
-    g_object_set (G_OBJECT (source), "subtitle-encoding", decoder->encoding,
-        NULL);
+    g_object_set (source, "subtitle-encoding", decoder->encoding, NULL);
   }
   return source;
 
@@ -936,7 +982,13 @@ no_source:
     /* whoops, could not create the source element, dig a little deeper to
      * figure out what might be wrong. */
     if (prot) {
-      GST_ELEMENT_ERROR (decoder, RESOURCE, FAILED,
+      GstMessage *msg;
+
+      msg =
+          gst_missing_uri_source_message_new (GST_ELEMENT_CAST (decoder), prot);
+      gst_element_post_message (GST_ELEMENT_CAST (decoder), msg);
+
+      GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN,
           (_("No URI handler implemented for \"%s\"."), prot), (NULL));
       g_free (prot);
     } else
@@ -957,14 +1009,13 @@ no_source:
  * Returns: %FALSE @pad has no caps. Else TRUE and @all_raw set t the result.
  */
 static gboolean
-has_all_raw_caps (GstPad * pad, gboolean * all_raw)
+has_all_raw_caps (GstPad * pad, GstCaps * rawcaps, gboolean * all_raw)
 {
-  GstCaps *caps;
+  GstCaps *caps, *intersection;
   gint capssize;
-  guint i, num_raw = 0;
   gboolean res = FALSE;
 
-  caps = gst_pad_get_caps (pad);
+  caps = gst_pad_get_caps_reffed (pad);
   if (caps == NULL)
     return FALSE;
 
@@ -975,21 +1026,11 @@ has_all_raw_caps (GstPad * pad, gboolean * all_raw)
   if (capssize == 0 || gst_caps_is_empty (caps) || gst_caps_is_any (caps))
     goto done;
 
-  /* count the number of raw formats in the caps */
-  for (i = 0; i < capssize; ++i) {
-    GstStructure *s;
-    const gchar *media_type;
+  intersection = gst_caps_intersect (caps, rawcaps);
+  *all_raw = !gst_caps_is_empty (intersection)
+      && (gst_caps_get_size (intersection) == capssize);
+  gst_caps_unref (intersection);
 
-    s = gst_caps_get_structure (caps, i);
-    media_type = gst_structure_get_name (s);
-
-    GST_DEBUG_OBJECT (pad, "check media-type %s", media_type);
-
-    if (IS_RAW_MEDIA (media_type))
-      ++num_raw;
-  }
-
-  *all_raw = (num_raw == capssize);
   res = TRUE;
 
 done:
@@ -997,6 +1038,19 @@ done:
   return res;
 }
 
+static void
+post_missing_plugin_error (GstElement * dec, const gchar * element_name)
+{
+  GstMessage *msg;
+
+  msg = gst_missing_element_message_new (dec, element_name);
+  gst_element_post_message (dec, msg);
+
+  GST_ELEMENT_ERROR (dec, CORE, MISSING_PLUGIN,
+      (_("Missing element '%s' - check your GStreamer installation."),
+          element_name), (NULL));
+}
+
 /**
  * analyse_source:
  * @decoder: a #GstURIDecodeBin
@@ -1025,15 +1079,19 @@ analyse_source (GstURIDecodeBin * decoder, gboolean * is_raw,
   GstIterator *pads_iter;
   gboolean done = FALSE;
   gboolean res = TRUE;
+  GstCaps *rawcaps;
+  GstPad *pad;
 
   *have_out = FALSE;
   *is_raw = FALSE;
   *is_dynamic = FALSE;
 
+  g_object_get (decoder, "caps", &rawcaps, NULL);
+  if (!rawcaps)
+    rawcaps = DEFAULT_CAPS;
+
   pads_iter = gst_element_iterate_src_pads (decoder->source);
   while (!done) {
-    GstPad *pad;
-
     switch (gst_iterator_next (pads_iter, (gpointer) & pad)) {
       case GST_ITERATOR_ERROR:
         res = FALSE;
@@ -1053,7 +1111,7 @@ analyse_source (GstURIDecodeBin * decoder, gboolean * is_raw,
         *have_out = TRUE;
 
         /* if FALSE, this pad has no caps and we continue with the next pad. */
-        if (!has_all_raw_caps (pad, is_raw)) {
+        if (!has_all_raw_caps (pad, rawcaps, is_raw)) {
           gst_object_unref (pad);
           break;
         }
@@ -1066,7 +1124,10 @@ analyse_source (GstURIDecodeBin * decoder, gboolean * is_raw,
             GstPad *sinkpad;
 
             /* insert a queue element right before the raw pad */
-            outelem = gst_element_factory_make ("queue2", "queue");
+            outelem = gst_element_factory_make ("queue2", NULL);
+            if (!outelem)
+              goto no_queue2;
+
             gst_bin_add (GST_BIN_CAST (decoder), outelem);
 
             sinkpad = gst_element_get_static_pad (outelem, "sink");
@@ -1074,18 +1135,22 @@ analyse_source (GstURIDecodeBin * decoder, gboolean * is_raw,
             gst_object_unref (sinkpad);
             gst_object_unref (pad);
 
+            /* save queue pointer so we can remove it later */
+            decoder->queue = outelem;
+
             /* get the new raw srcpad */
             pad = gst_element_get_static_pad (outelem, "src");
           } else {
             outelem = decoder->source;
           }
-          new_decoded_pad_cb (outelem, pad, FALSE, decoder);
+          expose_decoded_pad (outelem, pad, decoder);
         }
         gst_object_unref (pad);
         break;
     }
   }
   gst_iterator_free (pads_iter);
+  gst_caps_unref (rawcaps);
 
   if (!*have_out) {
     GstElementClass *elemclass;
@@ -1110,6 +1175,16 @@ analyse_source (GstURIDecodeBin * decoder, gboolean * is_raw,
   }
 
   return res;
+no_queue2:
+  {
+    post_missing_plugin_error (GST_ELEMENT_CAST (decoder), "queue2");
+
+    gst_object_unref (pad);
+    gst_iterator_free (pads_iter);
+    gst_caps_unref (rawcaps);
+
+    return FALSE;
+  }
 }
 
 /* Remove all decodebin2 from ourself 
@@ -1130,10 +1205,18 @@ remove_decoders (GstURIDecodeBin * bin, gboolean force)
       gst_element_set_state (decoder, GST_STATE_NULL);
       gst_bin_remove (GST_BIN_CAST (bin), decoder);
     } else {
+      GstCaps *caps;
+
       gst_element_set_state (decoder, GST_STATE_READY);
       /* add it to our list of pending decodebins */
       g_object_ref (decoder);
       gst_bin_remove (GST_BIN_CAST (bin), decoder);
+      /* restore some properties we might have changed */
+      g_object_set (decoder, "sink-caps", NULL, NULL);
+      caps = DEFAULT_CAPS;
+      g_object_set (decoder, "caps", caps, NULL);
+      gst_caps_unref (caps);
+
       bin->pending_decodebins =
           g_slist_prepend (bin->pending_decodebins, decoder);
     }
@@ -1175,7 +1258,7 @@ proxy_unknown_type_signal (GstElement * element, GstPad * pad, GstCaps * caps,
 {
   GST_DEBUG_OBJECT (dec, "unknown-type signaled");
 
-  g_signal_emit (G_OBJECT (dec),
+  g_signal_emit (dec,
       gst_uri_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
 }
 
@@ -1185,7 +1268,7 @@ proxy_autoplug_continue_signal (GstElement * element, GstPad * pad,
 {
   gboolean result;
 
-  g_signal_emit (G_OBJECT (dec),
+  g_signal_emit (dec,
       gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE], 0, pad, caps,
       &result);
 
@@ -1200,7 +1283,7 @@ proxy_autoplug_factories_signal (GstElement * element, GstPad * pad,
 {
   GValueArray *result;
 
-  g_signal_emit (G_OBJECT (dec),
+  g_signal_emit (dec,
       gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_FACTORIES], 0, pad, caps,
       &result);
 
@@ -1215,7 +1298,7 @@ proxy_autoplug_select_signal (GstElement * element, GstPad * pad,
 {
   GstAutoplugSelectResult result;
 
-  g_signal_emit (G_OBJECT (dec),
+  g_signal_emit (dec,
       gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_SELECT], 0, pad, caps, factory,
       &result);
 
@@ -1229,8 +1312,7 @@ proxy_drained_signal (GstElement * element, GstURIDecodeBin * dec)
 {
   GST_DEBUG_OBJECT (dec, "drained signaled");
 
-  g_signal_emit (G_OBJECT (dec),
-      gst_uri_decode_bin_signals[SIGNAL_DRAINED], 0, NULL);
+  g_signal_emit (dec, gst_uri_decode_bin_signals[SIGNAL_DRAINED], 0, NULL);
 }
 
 /* make a decodebin and connect to all the signals */
@@ -1255,26 +1337,26 @@ make_decoder (GstURIDecodeBin * decoder)
     if (!decodebin)
       goto no_decodebin;
     /* connect signals to proxy */
-    g_signal_connect (G_OBJECT (decodebin), "unknown-type",
+    g_signal_connect (decodebin, "unknown-type",
         G_CALLBACK (proxy_unknown_type_signal), decoder);
-    g_signal_connect (G_OBJECT (decodebin), "autoplug-continue",
+    g_signal_connect (decodebin, "autoplug-continue",
         G_CALLBACK (proxy_autoplug_continue_signal), decoder);
-    g_signal_connect (G_OBJECT (decodebin), "autoplug-factories",
+    g_signal_connect (decodebin, "autoplug-factories",
         G_CALLBACK (proxy_autoplug_factories_signal), decoder);
-    g_signal_connect (G_OBJECT (decodebin), "autoplug-select",
+    g_signal_connect (decodebin, "autoplug-select",
         G_CALLBACK (proxy_autoplug_select_signal), decoder);
-    g_signal_connect (G_OBJECT (decodebin), "drained",
+    g_signal_connect (decodebin, "drained",
         G_CALLBACK (proxy_drained_signal), decoder);
 
     /* set up callbacks to create the links between decoded data
      * and video/audio/subtitle rendering/output. */
-    g_signal_connect (G_OBJECT (decodebin),
+    g_signal_connect (decodebin,
         "new-decoded-pad", G_CALLBACK (new_decoded_pad_cb), decoder);
-    g_signal_connect (G_OBJECT (decodebin),
+    g_signal_connect (decodebin,
         "pad-removed", G_CALLBACK (pad_removed_cb), decoder);
-    g_signal_connect (G_OBJECT (decodebin), "no-more-pads",
+    g_signal_connect (decodebin, "no-more-pads",
         G_CALLBACK (no_more_pads), decoder);
-    g_signal_connect (G_OBJECT (decodebin),
+    g_signal_connect (decodebin,
         "unknown-type", G_CALLBACK (unknown_type_cb), decoder);
   }
 
@@ -1282,9 +1364,10 @@ make_decoder (GstURIDecodeBin * decoder)
   if (decoder->caps)
     g_object_set (decodebin, "caps", decoder->caps, NULL);
 
-  if (!decoder->is_download) {
+  if (!decoder->is_stream) {
     /* propagate the use-buffering property but only when we are not already
-     * doing download buffering. */
+     * doing stream buffering with queue2. FIXME, we might want to do stream
+     * buffering with the multiqueue buffering instead of queue2. */
     g_object_set (decodebin, "use-buffering", decoder->use_buffering, NULL);
 
     if (decoder->use_buffering) {
@@ -1303,8 +1386,7 @@ make_decoder (GstURIDecodeBin * decoder)
   }
 
   g_object_set_data (G_OBJECT (decodebin), "pending", "1");
-  g_object_set (G_OBJECT (decodebin), "subtitle-encoding", decoder->encoding,
-      NULL);
+  g_object_set (decodebin, "subtitle-encoding", decoder->encoding, NULL);
   decoder->pending++;
   GST_LOG_OBJECT (decoder, "have %d pending dynamic objects", decoder->pending);
 
@@ -1317,12 +1399,13 @@ make_decoder (GstURIDecodeBin * decoder)
   /* ERRORS */
 no_decodebin:
   {
-    GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN,
-        (_("Could not create \"decodebin2\" element.")), (NULL));
+    post_missing_plugin_error (GST_ELEMENT_CAST (decoder), "decodebin2");
     return NULL;
   }
 }
 
+/* signaled when we have a stream and we need to configure the download
+ * buffering or regular buffering */
 static void
 type_found (GstElement * typefind, guint probability,
     GstCaps * caps, GstURIDecodeBin * decoder)
@@ -1347,7 +1430,7 @@ type_found (GstElement * typefind, guint probability,
   if (!queue)
     goto no_queue2;
 
-  g_object_set (G_OBJECT (queue), "use-buffering", TRUE, NULL);
+  g_object_set (queue, "use-buffering", TRUE, NULL);
 
   GST_DEBUG_OBJECT (decoder, "check media-type %s, %d", media_type,
       decoder->download);
@@ -1370,22 +1453,20 @@ type_found (GstElement * typefind, guint probability,
         temp_template, tmp_dir, prgname, filename);
 
     /* configure progressive download for selected media types */
-    g_object_set (G_OBJECT (queue), "temp-template", temp_template, NULL);
+    g_object_set (queue, "temp-template", temp_template, NULL);
 
     g_free (filename);
     g_free (temp_template);
   }
 
   /* Disable max-size-buffers */
-  g_object_set (G_OBJECT (queue), "max-size-buffers", 0, NULL);
+  g_object_set (queue, "max-size-buffers", 0, NULL);
 
   /* If buffer size or duration are set, set them on the queue2 element */
   if (decoder->buffer_size != -1)
-    g_object_set (G_OBJECT (queue), "max-size-bytes",
-        decoder->buffer_size, NULL);
+    g_object_set (queue, "max-size-bytes", decoder->buffer_size, NULL);
   if (decoder->buffer_duration != -1)
-    g_object_set (G_OBJECT (queue), "max-size-time",
-        decoder->buffer_duration, NULL);
+    g_object_set (queue, "max-size-time", decoder->buffer_duration, NULL);
 
   gst_bin_add (GST_BIN_CAST (decoder), queue);
 
@@ -1395,7 +1476,7 @@ type_found (GstElement * typefind, guint probability,
   /* to force caps on the decodebin element and avoid reparsing stuff by
    * typefind. It also avoids a deadlock in the way typefind activates pads in
    * the state change */
-  g_object_set (G_OBJECT (dec_elem), "sink-caps", caps, NULL);
+  g_object_set (dec_elem, "sink-caps", caps, NULL);
 
   if (!gst_element_link_pads (queue, "src", dec_elem, "sink"))
     goto could_not_link;
@@ -1421,8 +1502,7 @@ could_not_link:
   }
 no_queue2:
   {
-    GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN,
-        (_("Could not create \"queue2\" element.")), (NULL));
+    post_missing_plugin_error (GST_ELEMENT_CAST (decoder), "queue2");
     return;
   }
 }
@@ -1442,7 +1522,7 @@ setup_streaming (GstURIDecodeBin * decoder)
 
   gst_bin_add (GST_BIN_CAST (decoder), typefind);
 
-  if (!gst_element_link (decoder->source, typefind))
+  if (!gst_element_link_pads (decoder->source, NULL, typefind, "sink"))
     goto could_not_link;
 
   decoder->typefind = typefind;
@@ -1450,7 +1530,7 @@ setup_streaming (GstURIDecodeBin * decoder)
   /* connect a signal to find out when the typefind element found
    * a type */
   decoder->have_type_id =
-      g_signal_connect (G_OBJECT (decoder->typefind), "have-type",
+      g_signal_connect (decoder->typefind, "have-type",
       G_CALLBACK (type_found), decoder);
 
   do_async_start (decoder);
@@ -1460,18 +1540,19 @@ setup_streaming (GstURIDecodeBin * decoder)
   /* ERRORS */
 no_typefind:
   {
-    GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN,
-        (_("Could not create \"typefind\" element.")), (NULL));
+    post_missing_plugin_error (GST_ELEMENT_CAST (decoder), "typefind");
     return FALSE;
   }
 could_not_link:
   {
     GST_ELEMENT_ERROR (decoder, CORE, NEGOTIATION,
         (NULL), ("Can't link source to typefind element"));
+    gst_bin_remove (GST_BIN_CAST (decoder), typefind);
     return FALSE;
   }
 }
 
+/* remove source and all related elements */
 static void
 remove_source (GstURIDecodeBin * bin)
 {
@@ -1483,15 +1564,27 @@ remove_source (GstURIDecodeBin * bin)
     gst_bin_remove (GST_BIN_CAST (bin), source);
 
     if (bin->src_np_sig_id) {
-      g_signal_handler_disconnect (G_OBJECT (source), bin->src_np_sig_id);
+      g_signal_handler_disconnect (source, bin->src_np_sig_id);
       bin->src_np_sig_id = 0;
     }
     if (bin->src_nmp_sig_id) {
-      g_signal_handler_disconnect (G_OBJECT (source), bin->src_nmp_sig_id);
+      g_signal_handler_disconnect (source, bin->src_nmp_sig_id);
       bin->src_nmp_sig_id = 0;
     }
     bin->source = NULL;
   }
+  if (bin->queue) {
+    GST_DEBUG_OBJECT (bin, "removing old queue element");
+    gst_element_set_state (bin->queue, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN_CAST (bin), bin->queue);
+    bin->queue = NULL;
+  }
+  if (bin->typefind) {
+    GST_DEBUG_OBJECT (bin, "removing old typefind element");
+    gst_element_set_state (bin->typefind, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN_CAST (bin), bin->typefind);
+    bin->typefind = NULL;
+  }
 }
 
 /* is called when a dynamic source element created a new pad. */
@@ -1500,18 +1593,25 @@ source_new_pad (GstElement * element, GstPad * pad, GstURIDecodeBin * bin)
 {
   GstElement *decoder;
   gboolean is_raw;
+  GstCaps *rawcaps;
 
   GST_URI_DECODE_BIN_LOCK (bin);
   GST_DEBUG_OBJECT (bin, "Found new pad %s.%s in source element %s",
       GST_DEBUG_PAD_NAME (pad), GST_ELEMENT_NAME (element));
 
+  g_object_get (bin, "caps", &rawcaps, NULL);
+  if (!rawcaps)
+    rawcaps = DEFAULT_CAPS;
+
   /* if this is a pad with all raw caps, we can expose it */
-  if (has_all_raw_caps (pad, &is_raw) && is_raw) {
+  if (has_all_raw_caps (pad, rawcaps, &is_raw) && is_raw) {
     /* it's all raw, create output pads. */
     GST_URI_DECODE_BIN_UNLOCK (bin);
-    new_decoded_pad_cb (element, pad, FALSE, bin);
+    gst_caps_unref (rawcaps);
+    expose_decoded_pad (element, pad, bin);
     return;
   }
+  gst_caps_unref (rawcaps);
 
   /* not raw, create decoder */
   decoder = make_decoder (bin);
@@ -1519,7 +1619,7 @@ source_new_pad (GstElement * element, GstPad * pad, GstURIDecodeBin * bin)
     goto no_decodebin;
 
   /* and link to decoder */
-  if (!gst_element_link (bin->source, decoder))
+  if (!gst_element_link_pads (bin->source, NULL, decoder, "sink"))
     goto could_not_link;
 
   GST_DEBUG_OBJECT (bin, "linked decoder to new pad");
@@ -1600,10 +1700,10 @@ setup_source (GstURIDecodeBin * decoder)
     GST_DEBUG_OBJECT (decoder, "Source has dynamic output pads");
     /* connect a handler for the new-pad signal */
     decoder->src_np_sig_id =
-        g_signal_connect (G_OBJECT (decoder->source), "pad-added",
+        g_signal_connect (decoder->source, "pad-added",
         G_CALLBACK (source_new_pad), decoder);
     decoder->src_nmp_sig_id =
-        g_signal_connect (G_OBJECT (decoder->source), "no-more-pads",
+        g_signal_connect (decoder->source, "no-more-pads",
         G_CALLBACK (source_no_more_pads), decoder);
     g_object_set_data (G_OBJECT (decoder->source), "pending", "1");
     decoder->pending++;
@@ -1623,7 +1723,7 @@ setup_source (GstURIDecodeBin * decoder)
       if (!dec_elem)
         goto no_decoder;
 
-      if (!gst_element_link (decoder->source, dec_elem))
+      if (!gst_element_link_pads (decoder->source, NULL, dec_elem, "sink"))
         goto could_not_link;
     }
   }
@@ -2039,6 +2139,11 @@ gst_uri_decode_bin_change_state (GstElement * element,
   decoder = GST_URI_DECODE_BIN (element);
 
   switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      g_mutex_lock (decoder->factories_lock);
+      gst_uri_decode_bin_update_factories_list (decoder);
+      g_mutex_unlock (decoder->factories_lock);
+      break;
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       if (!setup_source (decoder))
         goto source_failed;