playback: remove old playbin and decodebin elements
authorTim-Philipp Müller <tim.muller@collabora.co.uk>
Tue, 14 Jun 2011 22:42:27 +0000 (23:42 +0100)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Tue, 14 Jun 2011 22:42:27 +0000 (23:42 +0100)
gst/playback/Makefile.am
gst/playback/README [deleted file]
gst/playback/gstdecodebin.c [deleted file]
gst/playback/gstplayback.c
gst/playback/gstplaybasebin.c [deleted file]
gst/playback/gstplaybasebin.h [deleted file]
gst/playback/gstplaybin.c [deleted file]
gst/playback/gststreaminfo.c [deleted file]
gst/playback/gststreaminfo.h [deleted file]

index 2fe90e6..dd6ac2c 100644 (file)
@@ -6,16 +6,13 @@ glib_gen_basename = gstplay
 built_sources = gstplay-marshal.c
 built_headers = gstplay-marshal.h
 
-plugin_LTLIBRARIES = libgstplaybin.la libgstdecodebin.la libgstdecodebin2.la
+plugin_LTLIBRARIES = libgstplaybin.la libgstdecodebin2.la
 
 libgstplaybin_la_SOURCES = \
        gstplayback.c \
-       gstplaybin.c \
        gstplaybin2.c \
        gstplaysink.c \
-       gstplaybasebin.c \
        gstplay-enum.c \
-       gststreaminfo.c \
        gststreamselector.c \
        gstsubtitleoverlay.c \
        gstplaysinkvideoconvert.c \
@@ -32,15 +29,6 @@ libgstplaybin_la_LIBADD = \
        $(GST_LIBS)
 libgstplaybin_la_LIBTOOLFLAGS = --tag=disable-static
 
-libgstdecodebin_la_SOURCES = gstdecodebin.c
-nodist_libgstdecodebin_la_SOURCES = $(built_sources)
-libgstdecodebin_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
-libgstdecodebin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstdecodebin_la_LIBADD = \
-       $(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la \
-       $(GST_LIBS)
-libgstdecodebin_la_LIBTOOLFLAGS = --tag=disable-static
-
 libgstdecodebin2_la_SOURCES = gstdecodebin2.c gsturidecodebin.c gstplay-enum.c
 nodist_libgstdecodebin2_la_SOURCES = $(built_sources)
 libgstdecodebin2_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
@@ -52,9 +40,7 @@ libgstdecodebin2_la_LIBTOOLFLAGS = --tag=disable-static
 
 noinst_HEADERS = \
        gstplayback.h \
-       gstplaybasebin.h \
        gstplaysink.h \
-       gststreaminfo.h \
        gstplay-enum.h \
        gststreamselector.h \
        gstrawcaps.h \
@@ -73,18 +59,6 @@ include $(top_srcdir)/common/gst-glib-gen.mak
 
 Android.mk: Makefile.am $(BUILT_SOURCES)
        androgenizer \
-       -:PROJECT libgstdecodebin -:SHARED libgstdecodebin \
-        -:TAGS eng debug \
-         -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
-        -:SOURCES $(libgstdecodebin_la_SOURCES) \
-                  $(nodist_libgstdecodebin_la_SOURCES) \
-        -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstdecodebin_la_CFLAGS) \
-        -:LDFLAGS $(libgstdecodebin_la_LDFLAGS) \
-                  $(libgstdecodebin_la_LIBADD) \
-                  -ldl \
-        -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
-                      LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
-        \
        -:PROJECT libgstdecodebin2 -:SHARED libgstdecodebin2 \
         -:TAGS eng debug \
          -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
diff --git a/gst/playback/README b/gst/playback/README
deleted file mode 100644 (file)
index 286e49f..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-decodebin:
-
-  A bin with a sinkpad that decodes the data into raw formats. It works by sending
-  the input data through a typefind element and then recursively autoplugs elements 
-  from the registry until a raw format is obtained. It will then create a new ghostpad
-  on itself to signal the app of the new pad. 
-
-  Decodebin will also remove pads when they are removed from the stream.
-
-  TODO
-   - reuse of decoderbin, cleanup in READY state
-   - threading after demuxing?
-   - new_media events should be handled.
-   - caching of elements.
-   - abstract more elements, pads (typefind, ...);
-
-   The autoplugging happens as follows:
-
-   1) typefind is added internally to the bin.
-   2) the have_type signal is connected to typefind.
-   3) in the have_type callback the close_pad_link function is called
-   4) close_pad_link checks the type on the pad, if it is raw, a ghostpad
-      is created and autoplugging for that pad stops.
-   5) if the type of the pad is not raw, a list of possible elements that
-      can connect to this type is generated in find_compatibles.
-   6) try_to_link_1 with the element list is called. The function will loop
-      over the element list and will try to connect one of the elements to
-      the pad. If the link works, a call is made to close_link.
-   7) close_link loops over all the source pads of the element and 
-      recursively calls 4) for any ALWAYS pad. For elements with
-      a SOMETIMES pad, a structure is set up and is passed to the callback
-      of the new_pad signal.
-   8) in the new_pad callback, 4) is called to try to autoplug the
-      new pad.
-
-
-playbasebin:
-
-  A bin with an uri property. It will find the right source element from the registry
-  and connect a decoderbin to it. When going to the PAUSED state, it will iterate the
-  decoderbin and listen for new pad signals from it. It will connect a queue to each
-  new pad and will iterate the decoderbin until one of the queues is filled. It is
-  assumed that by that time all the streams will be found so that when leaving the
-  PAUSED state, one can query the number of streams in the media file with the given
-  uri.
-
-  Playbasebin internally groups related streams together in a GstPlayBaseGroup. This
-  is particulary important for chained oggs. Initially, a new group is created in 
-  the 'building' state. All new streams will be added to the building group until
-  no-more-pads is signaled or one of the preroll queues overflows. When this happens,
-  the group is commited to a list of groups ready for playback. PlaybaseBin will then
-  attach a padprobe to each stream to figure out when it finished. It will remove
-  the current group and install the next playable group, then.
-
-  Before going to the PLAYING state, it is possible to connect a custom element to
-  each of the streams. To do that, you have to add the element to the bin and then
-  connect the pad(s) from the stream(s). You do not have to add the elements in
-  a thread, the bin will take care of then when it's needed. You are allowed to use
-  threads inside the elements, of course.
-  The bin tries to be smart and doesn't add a queue when there is only one possible 
-  stream.
-
-  
-  TODO
-  - reuse, cleanup in ready state
-  - when the first pad is closed, it's possible that another dynamic element is
-    added somewhere so that we need a queue for the first pad as well.
-
-
-playbin:
-  
-   Extends playbasebin, sets up default audiosink and videosink for first audio/video
-   stream detected. implements seeking and querying on the configured sinks.
-
-   It also waits for new notifications from playbasebin about any new groups that are
-   becomming active. It then disconnects the sinks and reconnects them to the new
-   pads in the group.
-
-   TODO
-   - reuse, refcounting, cleanup in READY state
-   - be smarter about replugging the sinks instead of removing them and readding them.
-   - Do not crap out when the audio device is in use.
-
-
-general
-
-   TODO
-   - playlist support. maybe use a playlist bin that streams the contents of the
-     playlist on a pad, interleaved with new_media events. Also add a tuner 
-     interface while we're at it.
-   
diff --git a/gst/playback/gstdecodebin.c b/gst/playback/gstdecodebin.c
deleted file mode 100644 (file)
index ef0571c..0000000
+++ /dev/null
@@ -1,2072 +0,0 @@
-/* GStreamer
- * Copyright (C) <2004> Wim Taymans <wim.taymans@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-decodebin
- *
- * #GstBin that auto-magically constructs a decoding pipeline using available
- * decoders and demuxers via auto-plugging.
- *
- * When using decodebin in your application, connect a signal handler to
- * #GstDecodeBin::new-decoded-pad and connect your sinks from within the
- * callback function.
- *
- * <note>
- * This element is deprecated and no longer supported. You should use the
- * #uridecodebin or #decodebin2 element instead (or, even better: #playbin2).
- * </note>
- *
- * Deprecated: use uridecodebin or decodebin2 instead.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gst/gst-i18n-plugin.h>
-
-#include <string.h>
-#include <gst/gst.h>
-#include <gst/pbutils/pbutils.h>
-
-#include "gstplay-marshal.h"
-
-/* generic templates */
-static GstStaticPadTemplate decoder_bin_sink_template =
-GST_STATIC_PAD_TEMPLATE ("sink",
-    GST_PAD_SINK,
-    GST_PAD_ALWAYS,
-    GST_STATIC_CAPS_ANY);
-
-static GstStaticPadTemplate decoder_bin_src_template =
-GST_STATIC_PAD_TEMPLATE ("src%d",
-    GST_PAD_SRC,
-    GST_PAD_SOMETIMES,
-    GST_STATIC_CAPS_ANY);
-
-GST_DEBUG_CATEGORY_STATIC (gst_decode_bin_debug);
-#define GST_CAT_DEFAULT gst_decode_bin_debug
-
-#define GST_TYPE_DECODE_BIN             (gst_decode_bin_get_type())
-#define GST_DECODE_BIN(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DECODE_BIN,GstDecodeBin))
-#define GST_DECODE_BIN_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DECODE_BIN,GstDecodeBinClass))
-#define GST_IS_DECODE_BIN(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DECODE_BIN))
-#define GST_IS_DECODE_BIN_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DECODE_BIN))
-
-typedef struct _GstDecodeBin GstDecodeBin;
-typedef struct _GstDecodeBinClass GstDecodeBinClass;
-
-/**
- * GstDecodeBin:
- *
- * Auto-plugging decoder element structure
- */
-struct _GstDecodeBin
-{
-  GstBin bin;                   /* we extend GstBin */
-
-  GstElement *typefind;         /* this holds the typefind object */
-  GstElement *fakesink;
-
-  GList *dynamics;              /* list of dynamic connections */
-
-  GList *queues;                /* list of demuxer-decoder queues */
-
-  GList *probes;                /* list of PadProbeData */
-
-  GList *factories;             /* factories we can use for selecting elements */
-  gint numpads;
-  gint numwaiting;
-
-  gboolean have_type;
-  guint have_type_id;           /* signal id for the typefind element */
-
-  gboolean shutting_down;       /* stop pluggin if we're shutting down */
-
-  GType queue_type;             /* store the GType of queues, to aid in recognising them */
-
-  GMutex *cb_mutex;             /* Mutex for multi-threaded callbacks, such as removing the fakesink */
-};
-
-struct _GstDecodeBinClass
-{
-  GstBinClass parent_class;
-
-  /* signal we fire when a new pad has been decoded into raw audio/video */
-  void (*new_decoded_pad) (GstElement * element, GstPad * pad, gboolean last);
-  /* signal we fire when a pad has been removed */
-  void (*removed_decoded_pad) (GstElement * element, GstPad * pad);
-  /* signal fired when we found a pad that we cannot decode */
-  void (*unknown_type) (GstElement * element, GstPad * pad, GstCaps * caps);
-};
-
-/* signals */
-enum
-{
-  SIGNAL_NEW_DECODED_PAD,
-  SIGNAL_REMOVED_DECODED_PAD,
-  SIGNAL_UNKNOWN_TYPE,
-  SIGNAL_REDIRECT,
-  LAST_SIGNAL
-};
-
-/* Properties */
-enum
-{
-  PROP_0,
-  PROP_SINK_CAPS,
-};
-
-
-typedef struct
-{
-  GstPad *pad;
-  gulong sigid;
-  gboolean done;
-} PadProbeData;
-
-/* this structure is created for all dynamic pads that could get created
- * at runtime */
-typedef struct
-{
-  GstDecodeBin *decode_bin;     /* pointer to ourself */
-
-  GstElement *element;          /* the element sending the signal */
-  gint np_sig_id;               /* signal id of new_pad */
-  gint nmp_sig_id;              /* signal id of no_more_pads */
-
-  GstPad *pad;                  /* the pad sending the signal */
-  gint caps_sig_id;             /* signal id of caps */
-}
-GstDynamic;
-
-static void gst_decode_bin_class_init (GstDecodeBinClass * klass);
-static void gst_decode_bin_init (GstDecodeBin * decode_bin);
-static void gst_decode_bin_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec);
-static void gst_decode_bin_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * pspec);
-static void gst_decode_bin_dispose (GObject * object);
-static void gst_decode_bin_finalize (GObject * object);
-
-static GstStateChangeReturn gst_decode_bin_change_state (GstElement * element,
-    GstStateChange transition);
-
-static gboolean add_fakesink (GstDecodeBin * decode_bin);
-static void remove_fakesink (GstDecodeBin * decode_bin);
-
-static void dynamic_free (GstDynamic * dyn);
-static void free_dynamics (GstDecodeBin * decode_bin);
-static void type_found (GstElement * typefind, guint probability,
-    GstCaps * caps, GstDecodeBin * decode_bin);
-static GstElement *try_to_link_1 (GstDecodeBin * decode_bin,
-    GstElement * origelement, GstPad * pad, GList * factories);
-static void close_link (GstElement * element, GstDecodeBin * decode_bin);
-static void close_pad_link (GstElement * element, GstPad * pad,
-    GstCaps * caps, GstDecodeBin * decode_bin, gboolean more);
-static void unlinked (GstPad * pad, GstPad * peerpad,
-    GstDecodeBin * decode_bin);
-static void new_pad (GstElement * element, GstPad * pad, GstDynamic * dynamic);
-static void no_more_pads (GstElement * element, GstDynamic * dynamic);
-static void new_caps (GstPad * pad, GParamSpec * unused, GstDynamic * dynamic);
-
-static void queue_filled_cb (GstElement * queue, GstDecodeBin * decode_bin);
-static void queue_underrun_cb (GstElement * queue, GstDecodeBin * decode_bin);
-
-static gboolean is_demuxer_element (GstElement * srcelement);
-
-static GstElementClass *parent_class;
-static guint gst_decode_bin_signals[LAST_SIGNAL] = { 0 };
-
-
-static GType
-gst_decode_bin_get_type (void)
-{
-  static GType gst_decode_bin_type = 0;
-
-  if (!gst_decode_bin_type) {
-    static const GTypeInfo gst_decode_bin_info = {
-      sizeof (GstDecodeBinClass),
-      NULL,
-      NULL,
-      (GClassInitFunc) gst_decode_bin_class_init,
-      NULL,
-      NULL,
-      sizeof (GstDecodeBin),
-      0,
-      (GInstanceInitFunc) gst_decode_bin_init,
-      NULL
-    };
-
-    gst_decode_bin_type =
-        g_type_register_static (GST_TYPE_BIN, "GstDecodeBin",
-        &gst_decode_bin_info, 0);
-  }
-
-  return gst_decode_bin_type;
-}
-
-static void
-gst_decode_bin_class_init (GstDecodeBinClass * klass)
-{
-  GObjectClass *gobject_klass;
-  GstElementClass *gstelement_klass;
-
-  gobject_klass = (GObjectClass *) klass;
-  gstelement_klass = (GstElementClass *) klass;
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  gobject_klass->set_property = gst_decode_bin_set_property;
-  gobject_klass->get_property = gst_decode_bin_get_property;
-  gobject_klass->dispose = gst_decode_bin_dispose;
-  gobject_klass->finalize = gst_decode_bin_finalize;
-
-  /**
-   * GstDecodeBin::new-decoded-pad:
-   * @bin: The decodebin
-   * @pad: The newly created pad
-   * @islast: #TRUE if this is the last pad to be added. Deprecated.
-   *
-   * This signal gets emitted as soon as a new pad of the same type as one of
-   * the valid 'raw' types is added.
-   */
-  gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD] =
-      g_signal_new ("new-decoded-pad", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST,
-      G_STRUCT_OFFSET (GstDecodeBinClass, new_decoded_pad), NULL, NULL,
-      gst_play_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, GST_TYPE_PAD,
-      G_TYPE_BOOLEAN);
-  /**
-   * GstDecodeBin::removed-decoded-pad:
-   * @bin: The decodebin
-   * @pad: The pad that was removed
-   *
-   * This signal is emitted when a 'final' caps pad has been removed.
-   */
-  gst_decode_bin_signals[SIGNAL_REMOVED_DECODED_PAD] =
-      g_signal_new ("removed-decoded-pad", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST,
-      G_STRUCT_OFFSET (GstDecodeBinClass, removed_decoded_pad), NULL, NULL,
-      gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD);
-  /**
-   * GstDecodeBin::unknown-type:
-   * @bin: The decodebin
-   * @pad: The new pad containing caps that cannot be resolved to a 'final'
-   *       stream type.
-   * @caps: The #GstCaps of the pad that cannot be resolved.
-   *
-   * This signal is emitted when a pad for which there is no further possible
-   * decoding is added to the decodebin.
-   */
-  gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE] =
-      g_signal_new ("unknown-type", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, unknown_type),
-      NULL, NULL, gst_marshal_VOID__OBJECT_BOXED, G_TYPE_NONE, 2,
-      GST_TYPE_PAD, GST_TYPE_CAPS);
-
-  g_object_class_install_property (gobject_klass, PROP_SINK_CAPS,
-      g_param_spec_boxed ("sink-caps", "Sink Caps",
-          "The caps of the input data. (NULL = use typefind element)",
-          GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-  gst_element_class_add_pad_template (gstelement_klass,
-      gst_static_pad_template_get (&decoder_bin_sink_template));
-  gst_element_class_add_pad_template (gstelement_klass,
-      gst_static_pad_template_get (&decoder_bin_src_template));
-
-  gst_element_class_set_details_simple (gstelement_klass,
-      "Decoder Bin", "Generic/Bin/Decoder",
-      "Autoplug and decode to raw media",
-      "Wim Taymans <wim.taymans@gmail.com>");
-
-  gstelement_klass->change_state =
-      GST_DEBUG_FUNCPTR (gst_decode_bin_change_state);
-}
-
-/* check if the bin is dynamic.
- *
- * If there are no outstanding dynamic connections, the bin is
- * considered to be non-dynamic.
- */
-static gboolean
-gst_decode_bin_is_dynamic (GstDecodeBin * decode_bin)
-{
-  return decode_bin->dynamics != NULL;
-}
-
-/* the filter function for selecting the elements we can use in
- * autoplugging */
-static gboolean
-gst_decode_bin_factory_filter (GstPluginFeature * feature,
-    GstDecodeBin * decode_bin)
-{
-  guint rank;
-  const gchar *klass;
-
-  /* we only care about element factories */
-  if (!GST_IS_ELEMENT_FACTORY (feature))
-    return FALSE;
-
-  klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
-  /* only demuxers, decoders and parsers can play */
-  if (strstr (klass, "Demux") == NULL &&
-      strstr (klass, "Decoder") == NULL && strstr (klass, "Parse") == NULL &&
-      strstr (klass, "Depayloader") == NULL) {
-    return FALSE;
-  }
-
-  /* only select elements with autoplugging rank */
-  rank = gst_plugin_feature_get_rank (feature);
-  if (rank < GST_RANK_MARGINAL)
-    return FALSE;
-
-  return TRUE;
-}
-
-/* function used to sort element features */
-static gint
-compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
-{
-  gint diff;
-  const gchar *rname1, *rname2;
-
-  diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
-  if (diff != 0)
-    return diff;
-
-  rname1 = gst_plugin_feature_get_name (f1);
-  rname2 = gst_plugin_feature_get_name (f2);
-
-  diff = strcmp (rname2, rname1);
-
-  return diff;
-}
-
-static void
-print_feature (GstPluginFeature * feature)
-{
-  const gchar *rname;
-
-  rname = gst_plugin_feature_get_name (feature);
-
-  GST_DEBUG ("%s", rname);
-}
-
-static void
-gst_decode_bin_init (GstDecodeBin * decode_bin)
-{
-  GList *factories;
-
-  decode_bin->cb_mutex = g_mutex_new ();
-
-  /* first filter out the interesting element factories */
-  factories = gst_default_registry_feature_filter (
-      (GstPluginFeatureFilter) gst_decode_bin_factory_filter,
-      FALSE, decode_bin);
-
-  /* sort them according to their ranks */
-  decode_bin->factories = g_list_sort (factories, (GCompareFunc) compare_ranks);
-  /* do some debugging */
-  g_list_foreach (decode_bin->factories, (GFunc) print_feature, NULL);
-
-  /* we create the typefind element only once */
-  decode_bin->typefind = gst_element_factory_make ("typefind", "typefind");
-  if (!decode_bin->typefind) {
-    g_warning ("can't find typefind element, decodebin will not work");
-  } else {
-    GstPad *pad, *gpad;
-    GstPadTemplate *pad_tmpl;
-
-    /* add the typefind element */
-    if (!gst_bin_add (GST_BIN (decode_bin), decode_bin->typefind)) {
-      g_warning ("Could not add typefind element, decodebin will not work");
-      gst_object_unref (decode_bin->typefind);
-      decode_bin->typefind = NULL;
-    }
-
-    /* get the sinkpad */
-    pad = gst_element_get_static_pad (decode_bin->typefind, "sink");
-
-    /* get the pad template */
-    pad_tmpl = gst_static_pad_template_get (&decoder_bin_sink_template);
-
-    /* ghost the sink pad to ourself */
-    gpad = gst_ghost_pad_new_from_template ("sink", pad, pad_tmpl);
-    gst_pad_set_active (gpad, TRUE);
-    gst_element_add_pad (GST_ELEMENT (decode_bin), gpad);
-
-    gst_object_unref (pad_tmpl);
-    gst_object_unref (pad);
-
-    /* connect a signal to find out when the typefind element found
-     * a type */
-    decode_bin->have_type_id =
-        g_signal_connect (G_OBJECT (decode_bin->typefind), "have_type",
-        G_CALLBACK (type_found), decode_bin);
-  }
-  add_fakesink (decode_bin);
-
-  decode_bin->dynamics = NULL;
-  decode_bin->queues = NULL;
-  decode_bin->probes = NULL;
-}
-
-static void
-gst_decode_bin_dispose (GObject * object)
-{
-  GstDecodeBin *decode_bin;
-
-  decode_bin = GST_DECODE_BIN (object);
-
-  if (decode_bin->factories)
-    gst_plugin_feature_list_free (decode_bin->factories);
-  decode_bin->factories = NULL;
-
-  G_OBJECT_CLASS (parent_class)->dispose (object);
-
-  /* our parent dispose might trigger new signals when pads are unlinked
-   * etc. clean up the mess here. */
-  /* FIXME do proper cleanup when going to NULL */
-  free_dynamics (decode_bin);
-}
-
-static void
-gst_decode_bin_set_sink_caps (GstDecodeBin * dbin, GstCaps * caps)
-{
-  GST_DEBUG_OBJECT (dbin, "Setting new caps: %" GST_PTR_FORMAT, caps);
-
-  g_object_set (dbin->typefind, "force-caps", caps, NULL);
-}
-
-static GstCaps *
-gst_decode_bin_get_sink_caps (GstDecodeBin * dbin)
-{
-  GstCaps *caps;
-
-  GST_DEBUG_OBJECT (dbin, "Getting currently set caps");
-
-  g_object_get (dbin->typefind, "force-caps", &caps, NULL);
-
-  return caps;
-}
-
-static void
-gst_decode_bin_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec)
-{
-  GstDecodeBin *dbin;
-
-  dbin = GST_DECODE_BIN (object);
-
-  switch (prop_id) {
-    case PROP_SINK_CAPS:
-      gst_decode_bin_set_sink_caps (dbin, g_value_get_boxed (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static void
-gst_decode_bin_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * pspec)
-{
-  GstDecodeBin *dbin;
-
-  dbin = GST_DECODE_BIN (object);
-  switch (prop_id) {
-    case PROP_SINK_CAPS:
-      g_value_take_boxed (value, gst_decode_bin_get_sink_caps (dbin));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static void
-gst_decode_bin_finalize (GObject * object)
-{
-  GstDecodeBin *decode_bin = GST_DECODE_BIN (object);
-
-  g_mutex_free (decode_bin->cb_mutex);
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-struct DynFind
-{
-  GstElement *elem;
-  GstPad *pad;
-};
-
-static gint
-find_dynamic (GstDynamic * dyn, struct DynFind *info)
-{
-  if (dyn->element == info->elem && dyn->pad == info->pad)
-    return 0;
-  return 1;
-}
-
-/* Add either an element (for dynamic pads/pad-added watching) or a
- * pad (for delayed caps/notify::caps watching) to the dynamic list,
- * taking care to ignore repeat entries so we don't end up handling a
- * pad twice, for example */
-static void
-dynamic_add (GstElement * element, GstPad * pad, GstDecodeBin * decode_bin)
-{
-  GstDynamic *dyn;
-  struct DynFind find_info;
-  GList *found;
-
-  g_return_if_fail (element != NULL);
-
-  /* do a search that this entry doesn't already exist */
-  find_info.elem = element;
-  find_info.pad = pad;
-  found = g_list_find_custom (decode_bin->dynamics, &find_info,
-      (GCompareFunc) find_dynamic);
-  if (found != NULL)
-    goto exit;
-
-  /* take refs */
-  dyn = g_new0 (GstDynamic, 1);
-  dyn->element = gst_object_ref (element);
-  dyn->decode_bin = gst_object_ref (decode_bin);
-  if (pad) {
-    dyn->pad = gst_object_ref (pad);
-    GST_DEBUG_OBJECT (decode_bin, "dynamic create for pad %" GST_PTR_FORMAT,
-        pad);
-    dyn->caps_sig_id = g_signal_connect (G_OBJECT (pad), "notify::caps",
-        G_CALLBACK (new_caps), dyn);
-  } else {
-    GST_DEBUG_OBJECT (decode_bin, "dynamic create for element %"
-        GST_PTR_FORMAT, element);
-    dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "pad-added",
-        G_CALLBACK (new_pad), dyn);
-    dyn->nmp_sig_id = g_signal_connect (G_OBJECT (element), "no-more-pads",
-        G_CALLBACK (no_more_pads), dyn);
-  }
-
-  /* and add this element to the dynamic elements */
-  decode_bin->dynamics = g_list_prepend (decode_bin->dynamics, dyn);
-
-  return;
-exit:
-  if (element) {
-    GST_DEBUG_OBJECT (decode_bin, "Dynamic element already added: %"
-        GST_PTR_FORMAT, element);
-  } else {
-    GST_DEBUG_OBJECT (decode_bin, "Dynamic pad already added: %"
-        GST_PTR_FORMAT, pad);
-  }
-}
-
-static void
-dynamic_free (GstDynamic * dyn)
-{
-  GST_DEBUG_OBJECT (dyn->decode_bin, "dynamic free");
-
-  /* disconnect signals */
-  if (dyn->np_sig_id)
-    g_signal_handler_disconnect (G_OBJECT (dyn->element), dyn->np_sig_id);
-  if (dyn->nmp_sig_id)
-    g_signal_handler_disconnect (G_OBJECT (dyn->element), dyn->nmp_sig_id);
-  if (dyn->caps_sig_id)
-    g_signal_handler_disconnect (G_OBJECT (dyn->pad), dyn->caps_sig_id);
-
-  if (dyn->pad)
-    gst_object_unref (dyn->pad);
-  dyn->pad = NULL;
-  if (dyn->element)
-    gst_object_unref (dyn->element);
-  dyn->element = NULL;
-
-  gst_object_unref (dyn->decode_bin);
-  dyn->decode_bin = NULL;
-
-  g_free (dyn);
-}
-
-static void
-free_dynamics (GstDecodeBin * decode_bin)
-{
-  GList *dyns;
-
-  for (dyns = decode_bin->dynamics; dyns; dyns = g_list_next (dyns)) {
-    GstDynamic *dynamic = (GstDynamic *) dyns->data;
-
-    dynamic_free (dynamic);
-  }
-  g_list_free (decode_bin->dynamics);
-  decode_bin->dynamics = NULL;
-}
-
-/* this function runs through the element factories and returns a list
- * of all elements that are able to sink the given caps
- */
-static GList *
-find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps)
-{
-  GList *factories;
-  GList *to_try = NULL;
-
-  /* loop over all the factories */
-  for (factories = decode_bin->factories; factories;
-      factories = g_list_next (factories)) {
-    GstElementFactory *factory = GST_ELEMENT_FACTORY (factories->data);
-    const GList *templates;
-    GList *walk;
-
-    /* get the templates from the element factory */
-    templates = gst_element_factory_get_static_pad_templates (factory);
-    for (walk = (GList *) templates; walk; walk = g_list_next (walk)) {
-      GstStaticPadTemplate *templ = walk->data;
-
-      /* we only care about the sink templates */
-      if (templ->direction == GST_PAD_SINK) {
-        gboolean can_intersect;
-        GstCaps *tmpl_caps;
-
-        /* try to intersect the caps with the caps of the template */
-        tmpl_caps = gst_static_caps_get (&templ->static_caps);
-
-        can_intersect = gst_caps_can_intersect (caps, tmpl_caps);
-        gst_caps_unref (tmpl_caps);
-
-        /* check if the intersection is empty */
-        if (can_intersect) {
-          /* non empty intersection, we can use this element */
-          to_try = g_list_prepend (to_try, factory);
-          break;
-        }
-      }
-    }
-  }
-  to_try = g_list_reverse (to_try);
-
-  return to_try;
-}
-
-static gboolean
-mimetype_is_raw (const gchar * mimetype)
-{
-  return g_str_has_prefix (mimetype, "video/x-raw") ||
-      g_str_has_prefix (mimetype, "audio/x-raw") ||
-      g_str_has_prefix (mimetype, "text/plain") ||
-      g_str_has_prefix (mimetype, "text/x-pango-markup");
-}
-
-static void
-free_pad_probes (GstDecodeBin * decode_bin)
-{
-  GList *tmp;
-
-  /* Remove pad probes */
-  for (tmp = decode_bin->probes; tmp; tmp = g_list_next (tmp)) {
-    PadProbeData *data = (PadProbeData *) tmp->data;
-
-    gst_pad_remove_probe (data->pad, data->sigid);
-    g_free (data);
-  }
-  g_list_free (decode_bin->probes);
-  decode_bin->probes = NULL;
-}
-
-/* used when we need to remove a probe because the decoder we plugged failed
- * to activate */
-static void
-free_pad_probe_for_element (GstDecodeBin * decode_bin, GstElement * element)
-{
-  GList *l;
-
-  for (l = decode_bin->probes; l != NULL; l = g_list_next (l)) {
-    PadProbeData *data = (PadProbeData *) l->data;
-
-    if (GST_ELEMENT_CAST (GST_PAD_PARENT (data->pad)) == element) {
-      gst_pad_remove_probe (data->pad, data->sigid);
-      decode_bin->probes = g_list_delete_link (decode_bin->probes, l);
-      g_free (data);
-      return;
-    }
-  }
-}
-
-static gboolean
-add_fakesink (GstDecodeBin * decode_bin)
-{
-  if (decode_bin->fakesink != NULL)
-    return TRUE;
-
-  g_mutex_lock (decode_bin->cb_mutex);
-
-  decode_bin->fakesink = gst_element_factory_make ("fakesink", "fakesink");
-  if (!decode_bin->fakesink)
-    goto no_fakesink;
-
-  /* hacky, remove sink flag, we don't want our decodebin to become a sink
-   * just because we add a fakesink element to make us ASYNC */
-  GST_OBJECT_FLAG_UNSET (decode_bin->fakesink, GST_ELEMENT_IS_SINK);
-
-  /* takes ownership */
-  if (!gst_bin_add (GST_BIN (decode_bin), decode_bin->fakesink)) {
-    g_warning ("Could not add fakesink element, decodebin will not work");
-    gst_object_unref (decode_bin->fakesink);
-    decode_bin->fakesink = NULL;
-  }
-  g_mutex_unlock (decode_bin->cb_mutex);
-  return TRUE;
-
-  /* ERRORS */
-no_fakesink:
-  {
-    g_warning ("can't find fakesink element, decodebin will not work");
-    g_mutex_unlock (decode_bin->cb_mutex);
-    return FALSE;
-  }
-}
-
-static void
-remove_fakesink (GstDecodeBin * decode_bin)
-{
-  gboolean removed_fakesink = FALSE;
-
-  if (decode_bin->fakesink == NULL)
-    return;
-
-  g_mutex_lock (decode_bin->cb_mutex);
-  if (decode_bin->fakesink) {
-    GST_DEBUG_OBJECT (decode_bin, "Removing fakesink and marking state dirty");
-
-    /* Lock the state to prevent it from changing state to non-NULL
-     * before it's removed */
-    gst_element_set_locked_state (decode_bin->fakesink, TRUE);
-    /* setting the state to NULL is never async */
-    gst_element_set_state (decode_bin->fakesink, GST_STATE_NULL);
-    gst_bin_remove (GST_BIN (decode_bin), decode_bin->fakesink);
-    decode_bin->fakesink = NULL;
-
-    removed_fakesink = TRUE;
-  }
-  g_mutex_unlock (decode_bin->cb_mutex);
-
-  if (removed_fakesink) {
-    free_pad_probes (decode_bin);
-  }
-}
-
-/* this should be implemented with _pad_block() */
-static GstProbeReturn
-pad_probe (GstPad * pad, GstProbeType type, gpointer type_data,
-    gpointer user_data)
-{
-  GstMiniObject *data = type_data;
-  GstDecodeBin *decode_bin = user_data;
-  GList *tmp;
-  gboolean alldone = TRUE;
-
-  for (tmp = decode_bin->probes; tmp; tmp = g_list_next (tmp)) {
-    PadProbeData *pdata = (PadProbeData *) tmp->data;
-
-    if (pdata->pad == pad) {
-      if (GST_IS_BUFFER (data)) {
-        if (!pdata->done)
-          decode_bin->numwaiting--;
-        pdata->done = TRUE;
-      } else if (GST_IS_EVENT (data) &&
-          ((GST_EVENT_TYPE (data) == GST_EVENT_EOS) ||
-              (GST_EVENT_TYPE (data) == GST_EVENT_TAG) ||
-              (GST_EVENT_TYPE (data) == GST_EVENT_FLUSH_START))) {
-        /* FIXME, what about NEWSEGMENT? really, use _pad_block()... */
-        if (!pdata->done)
-          decode_bin->numwaiting--;
-        pdata->done = TRUE;
-      }
-    }
-
-    if (!(pdata->done)) {
-      GST_LOG_OBJECT (decode_bin, "Pad probe on pad %" GST_PTR_FORMAT
-          " but pad %" GST_PTR_FORMAT " still needs data.", pad, pdata->pad);
-      alldone = FALSE;
-    }
-  }
-  if (alldone)
-    remove_fakesink (decode_bin);
-  return TRUE;
-}
-
-/* FIXME: this should be somehow merged with the queue code in
- * try_to_link_1() to reduce code duplication */
-static GstPad *
-add_raw_queue (GstDecodeBin * decode_bin, GstPad * pad)
-{
-  GstElement *queue = NULL;
-  GstPad *queuesinkpad = NULL, *queuesrcpad = NULL;
-
-  queue = gst_element_factory_make ("queue", NULL);
-  decode_bin->queue_type = G_OBJECT_TYPE (queue);
-
-  g_object_set (G_OBJECT (queue), "max-size-buffers", 0, NULL);
-  g_object_set (G_OBJECT (queue), "max-size-time", G_GINT64_CONSTANT (0), NULL);
-  g_object_set (G_OBJECT (queue), "max-size-bytes", 8192, NULL);
-  gst_bin_add (GST_BIN (decode_bin), queue);
-  gst_element_set_state (queue, GST_STATE_READY);
-  queuesinkpad = gst_element_get_static_pad (queue, "sink");
-  queuesrcpad = gst_element_get_static_pad (queue, "src");
-
-  if (gst_pad_link (pad, queuesinkpad) != GST_PAD_LINK_OK) {
-    GST_WARNING_OBJECT (decode_bin,
-        "Linking queue failed, trying without queue");
-    gst_element_set_state (queue, GST_STATE_NULL);
-    gst_object_unref (queuesrcpad);
-    gst_object_unref (queuesinkpad);
-    gst_bin_remove (GST_BIN (decode_bin), queue);
-    return gst_object_ref (pad);
-  }
-
-  decode_bin->queues = g_list_append (decode_bin->queues, queue);
-  g_signal_connect (G_OBJECT (queue),
-      "overrun", G_CALLBACK (queue_filled_cb), decode_bin);
-  g_signal_connect (G_OBJECT (queue),
-      "underrun", G_CALLBACK (queue_underrun_cb), decode_bin);
-
-  gst_element_set_state (queue, GST_STATE_PAUSED);
-  gst_object_unref (queuesinkpad);
-
-  return queuesrcpad;
-}
-
-/* given a pad and a caps from an element, find the list of elements
- * that could connect to the pad
- *
- * If the pad has a raw format, this function will create a ghostpad
- * for the pad onto the decodebin.
- *
- * If no compatible elements could be found, this function will signal
- * the unknown_type signal.
- */
-static void
-close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
-    GstDecodeBin * decode_bin, gboolean more)
-{
-  GstStructure *structure;
-  const gchar *mimetype;
-  gchar *padname;
-  gint diff;
-
-  padname = gst_pad_get_name (pad);
-  diff = strncmp (padname, "current_", 8);
-  g_free (padname);
-
-  /* hack.. ignore current pads */
-  if (!diff)
-    return;
-
-  /* the caps is empty, this means the pad has no type, we can only
-   * decide to fire the unknown_type signal. */
-  if (caps == NULL || gst_caps_is_empty (caps))
-    goto unknown_type;
-
-  /* the caps is any, this means the pad can be anything and
-   * we don't know yet */
-  if (gst_caps_is_any (caps))
-    goto dont_know_yet;
-
-  GST_LOG_OBJECT (element, "trying to close %" GST_PTR_FORMAT, caps);
-
-  /* FIXME, iterate over more structures? I guess it is possible that
-   * this pad has some encoded and some raw pads. This code will fail
-   * then if the first structure is not the raw type... */
-  structure = gst_caps_get_structure (caps, 0);
-  mimetype = gst_structure_get_name (structure);
-
-  /* first see if this is raw. If the type is raw, we can
-   * create a ghostpad for this pad. It's possible that the caps are not
-   * fixed. */
-  if (mimetype_is_raw (mimetype)) {
-    GstPadTemplate *tmpl;
-    gchar *padname;
-    GstPad *ghost;
-    PadProbeData *data;
-
-    /* If we're at a demuxer element but have raw data already
-     * we have to add a queue here. For non-raw data this is done
-     * in try_to_link_1() */
-    if (is_demuxer_element (element)) {
-      GST_DEBUG_OBJECT (decode_bin,
-          "Element %s is a demuxer, inserting a queue",
-          GST_OBJECT_NAME (element));
-
-      pad = add_raw_queue (decode_bin, pad);
-    }
-
-    /* make a unique name for this new pad */
-    padname = g_strdup_printf ("src%d", decode_bin->numpads);
-    decode_bin->numpads++;
-
-    /* make it a ghostpad */
-    tmpl = gst_static_pad_template_get (&decoder_bin_src_template);
-    ghost = gst_ghost_pad_new_from_template (padname, pad, tmpl);
-    gst_object_unref (tmpl);
-
-    gst_pad_set_active (ghost, TRUE);
-    gst_element_add_pad (GST_ELEMENT (decode_bin), ghost);
-
-    data = g_new0 (PadProbeData, 1);
-    data->pad = pad;
-    data->done = FALSE;
-
-    /* FIXME, use pad blocking */
-    data->sigid = gst_pad_add_probe (pad, GST_PROBE_TYPE_DATA, pad_probe,
-        decode_bin, NULL);
-    decode_bin->numwaiting++;
-
-    decode_bin->probes = g_list_append (decode_bin->probes, data);
-
-    GST_LOG_OBJECT (element, "closed pad %s", padname);
-
-    /* our own signal with an extra flag that this is the only pad */
-    GST_DEBUG_OBJECT (decode_bin, "emitting new-decoded-pad");
-    g_signal_emit (G_OBJECT (decode_bin),
-        gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD], 0, ghost, !more);
-    GST_DEBUG_OBJECT (decode_bin, "emitted new-decoded-pad");
-
-    g_free (padname);
-
-    /* If we're at a demuxer element pad was set to a queue's
-     * srcpad and must be unref'd here */
-    if (is_demuxer_element (element))
-      gst_object_unref (pad);
-  } else {
-    GList *to_try;
-
-    /* if the caps has many types, we need to delay */
-    if (!gst_caps_is_fixed (caps))
-      goto many_types;
-
-    /* continue plugging, first find all compatible elements */
-    to_try = find_compatibles (decode_bin, caps);
-    if (to_try == NULL)
-      /* no compatible elements, we cannot go on */
-      goto unknown_type;
-
-    if (try_to_link_1 (decode_bin, element, pad, to_try) == NULL) {
-      g_list_free (to_try);
-      GST_LOG_OBJECT (pad, "none of the allegedly available elements usable");
-      goto unknown_type;
-    }
-
-    /* can free the list again now */
-    g_list_free (to_try);
-  }
-  return;
-
-  /* ERRORS */
-unknown_type:
-  {
-    GST_LOG_OBJECT (pad, "unknown type found, fire signal");
-    g_signal_emit (G_OBJECT (decode_bin),
-        gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
-
-    gst_element_post_message (GST_ELEMENT_CAST (decode_bin),
-        gst_missing_decoder_message_new (GST_ELEMENT_CAST (decode_bin), caps));
-
-    if (element == decode_bin->typefind) {
-      gchar *desc;
-
-      desc = gst_pb_utils_get_decoder_description (caps);
-      GST_ELEMENT_ERROR (decode_bin, STREAM, CODEC_NOT_FOUND,
-          (_("A %s plugin is required to play this stream, but not installed."),
-              desc),
-          ("No decoder to handle media type '%s'",
-              gst_structure_get_name (gst_caps_get_structure (caps, 0))));
-      g_free (desc);
-    }
-
-    return;
-  }
-dont_know_yet:
-  {
-    GST_LOG_OBJECT (pad, "type is not known yet");
-    goto setup_caps_delay;
-  }
-many_types:
-  {
-    GST_LOG_OBJECT (pad, "many possible types");
-    goto setup_caps_delay;
-  }
-setup_caps_delay:
-  {
-    GST_LOG_OBJECT (pad, "setting up a delayed link");
-    dynamic_add (element, pad, decode_bin);
-    return;
-  }
-}
-
-/* Decide whether an element is a demuxer based on the
- * klass and number/type of src pad templates it has */
-static gboolean
-is_demuxer_element (GstElement * srcelement)
-{
-  GstElementFactory *srcfactory;
-  GstElementClass *elemclass;
-  GList *walk;
-  const gchar *klass;
-  gint potential_src_pads = 0;
-
-  srcfactory = gst_element_get_factory (srcelement);
-  klass = gst_element_factory_get_klass (srcfactory);
-
-  /* Can't be a demuxer unless it has Demux in the klass name */
-  if (klass == NULL || !strstr (klass, "Demux"))
-    return FALSE;
-
-  /* Walk the src pad templates and count how many the element
-   * might produce */
-  elemclass = GST_ELEMENT_GET_CLASS (srcelement);
-
-  walk = gst_element_class_get_pad_template_list (elemclass);
-  while (walk != NULL) {
-    GstPadTemplate *templ;
-
-    templ = (GstPadTemplate *) walk->data;
-    if (GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC) {
-      switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
-        case GST_PAD_ALWAYS:
-        case GST_PAD_SOMETIMES:
-          if (strstr (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ), "%"))
-            potential_src_pads += 2;    /* Might make multiple pads */
-          else
-            potential_src_pads += 1;
-          break;
-        case GST_PAD_REQUEST:
-          potential_src_pads += 2;
-          break;
-      }
-    }
-    walk = g_list_next (walk);
-  }
-
-  if (potential_src_pads < 2)
-    return FALSE;
-
-  return TRUE;
-}
-
-/*
- * given a list of element factories, try to link one of the factories
- * to the given pad.
- *
- * The function returns the element that was successfully linked to the
- * pad.
- */
-static GstElement *
-try_to_link_1 (GstDecodeBin * decode_bin, GstElement * srcelement, GstPad * pad,
-    GList * factories)
-{
-  GList *walk;
-  GstElement *result = NULL;
-  gboolean isdemux = FALSE;
-  GstPad *queuesinkpad = NULL, *queuesrcpad = NULL;
-  GstElement *queue = NULL;
-  GstPad *usedsrcpad = pad;
-
-  /* Check if the parent of the src pad is a demuxer */
-  isdemux = is_demuxer_element (srcelement);
-
-  if (isdemux && factories != NULL) {
-    GstPadLinkReturn dqlink;
-
-    /* Insert a queue between demuxer and decoder */
-    GST_DEBUG_OBJECT (decode_bin,
-        "Element %s is a demuxer, inserting a queue",
-        GST_OBJECT_NAME (srcelement));
-    queue = gst_element_factory_make ("queue", NULL);
-    decode_bin->queue_type = G_OBJECT_TYPE (queue);
-
-    g_object_set (G_OBJECT (queue), "max-size-buffers", 0, NULL);
-    g_object_set (G_OBJECT (queue), "max-size-time", G_GINT64_CONSTANT (0),
-        NULL);
-    g_object_set (G_OBJECT (queue), "max-size-bytes", 8192, NULL);
-    gst_bin_add (GST_BIN (decode_bin), queue);
-    gst_element_set_state (queue, GST_STATE_READY);
-    queuesinkpad = gst_element_get_static_pad (queue, "sink");
-    usedsrcpad = queuesrcpad = gst_element_get_static_pad (queue, "src");
-
-    dqlink = gst_pad_link (pad, queuesinkpad);
-    g_return_val_if_fail (dqlink == GST_PAD_LINK_OK, NULL);
-  }
-
-  /* loop over the factories */
-  for (walk = factories; walk; walk = g_list_next (walk)) {
-    GstElementFactory *factory = GST_ELEMENT_FACTORY (walk->data);
-    GstElement *element;
-    GstPadLinkReturn ret;
-    GstPad *sinkpad;
-
-    GST_DEBUG_OBJECT (decode_bin, "trying to link %s",
-        gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
-
-    /* make an element from the factory first */
-    if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
-      /* hmm, strange. Like with all things in life, let's move on.. */
-      GST_WARNING_OBJECT (decode_bin, "could not create an element from %s",
-          gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
-      continue;
-    }
-
-    /* try to link the given pad to a sinkpad */
-    /* FIXME, find the sinkpad by looping over the pads instead of
-     * looking it up by name */
-    if ((sinkpad = gst_element_get_static_pad (element, "sink")) == NULL) {
-      /* if no pad is found we can't do anything */
-      GST_WARNING_OBJECT (decode_bin, "could not find sinkpad in element");
-      continue;
-    }
-
-    /* now add the element to the bin first */
-    GST_DEBUG_OBJECT (decode_bin, "adding %s", GST_OBJECT_NAME (element));
-    gst_bin_add (GST_BIN (decode_bin), element);
-
-    /* set to READY first so it is ready, duh. */
-    if (gst_element_set_state (element,
-            GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
-      GST_WARNING_OBJECT (decode_bin, "Couldn't set %s to READY",
-          GST_ELEMENT_NAME (element));
-      /* get rid of the sinkpad */
-      gst_object_unref (sinkpad);
-      /* this element did not work, remove it again and continue trying
-       * other elements, the element will be disposed. */
-      /* FIXME: shouldn't we do this before adding it to the bin so that no
-       * error messages get through to the app? (tpm) */
-      gst_bin_remove (GST_BIN (decode_bin), element);
-      continue;
-    }
-
-    if ((ret = gst_pad_link (usedsrcpad, sinkpad)) != GST_PAD_LINK_OK) {
-      GST_DEBUG_OBJECT (decode_bin, "link failed on pad %s:%s, reason %d",
-          GST_DEBUG_PAD_NAME (pad), ret);
-      /* get rid of the sinkpad */
-      gst_object_unref (sinkpad);
-      /* this element did not work, remove it again and continue trying
-       * other elements, the element will be disposed. */
-      gst_element_set_state (element, GST_STATE_NULL);
-      gst_bin_remove (GST_BIN (decode_bin), element);
-    } else {
-      GST_DEBUG_OBJECT (decode_bin, "linked on pad %s:%s",
-          GST_DEBUG_PAD_NAME (usedsrcpad));
-
-      /* configure the queue some more */
-      if (queue != NULL) {
-        decode_bin->queues = g_list_append (decode_bin->queues, queue);
-        g_signal_connect (G_OBJECT (queue),
-            "overrun", G_CALLBACK (queue_filled_cb), decode_bin);
-        g_signal_connect (G_OBJECT (queue),
-            "underrun", G_CALLBACK (queue_underrun_cb), decode_bin);
-      }
-
-      /* The link worked, now figure out what it was that we connected */
-
-      /* make sure we catch unlink signals */
-      g_signal_connect (G_OBJECT (pad), "unlinked",
-          G_CALLBACK (unlinked), decode_bin);
-
-      /* now that we added the element we can try to continue autoplugging
-       * on it until we have a raw type */
-      close_link (element, decode_bin);
-
-      /* change the state of the element to that of the parent */
-      if ((gst_element_set_state (element,
-                  GST_STATE_PAUSED)) == GST_STATE_CHANGE_FAILURE) {
-        GST_WARNING_OBJECT (decode_bin, "Couldn't set %s to PAUSED",
-            GST_ELEMENT_NAME (element));
-        /* close_link -> close_pad_link -> might have set up a pad probe */
-        free_pad_probe_for_element (decode_bin, element);
-        gst_element_set_state (element, GST_STATE_NULL);
-        gst_bin_remove (GST_BIN (decode_bin), element);
-        continue;
-      }
-
-      result = element;
-
-      /* get rid of the sinkpad now */
-      gst_object_unref (sinkpad);
-
-      /* Set the queue to paused and set the pointer to NULL so we don't
-       * remove it below */
-      if (queue != NULL) {
-        gst_element_set_state (queue, GST_STATE_PAUSED);
-        queue = NULL;
-        gst_object_unref (queuesrcpad);
-        gst_object_unref (queuesinkpad);
-      }
-
-      /* and exit */
-      goto done;
-    }
-  }
-done:
-  if (queue != NULL) {
-    /* We didn't successfully connect to the queue */
-    gst_pad_unlink (pad, queuesinkpad);
-    gst_element_set_state (queue, GST_STATE_NULL);
-    gst_object_unref (queuesrcpad);
-    gst_object_unref (queuesinkpad);
-    gst_bin_remove (GST_BIN (decode_bin), queue);
-  }
-  return result;
-}
-
-static GstPad *
-get_our_ghost_pad (GstDecodeBin * decode_bin, GstPad * pad)
-{
-  GstIterator *pad_it = NULL;
-  GValue item = { 0, };
-  GstPad *db_pad = NULL;
-  gboolean done = FALSE;
-
-  if (pad == NULL || !GST_PAD_IS_SRC (pad)) {
-    GST_DEBUG_OBJECT (decode_bin, "pad NULL or not SRC pad");
-    return NULL;
-  }
-
-  /* our ghostpads are the sourcepads */
-  pad_it = gst_element_iterate_src_pads (GST_ELEMENT (decode_bin));
-  while (!done) {
-    db_pad = NULL;
-    switch (gst_iterator_next (pad_it, &item)) {
-      case GST_ITERATOR_OK:{
-        db_pad = g_value_get_object (&item);
-        GST_DEBUG_OBJECT (decode_bin, "looking at pad %s:%s",
-            GST_DEBUG_PAD_NAME (db_pad));
-        if (GST_IS_GHOST_PAD (db_pad)) {
-          GstPad *target_pad = NULL;
-
-          target_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (db_pad));
-          done = (target_pad == pad);
-          if (target_pad)
-            gst_object_unref (target_pad);
-
-          if (done) {
-            /* Found our ghost pad */
-            GST_DEBUG_OBJECT (decode_bin, "found ghostpad %s:%s for pad %s:%s",
-                GST_DEBUG_PAD_NAME (db_pad), GST_DEBUG_PAD_NAME (pad));
-            break;
-          }
-        }
-        /* Not the right one */
-        g_value_reset (&item);
-        break;
-      }
-      case GST_ITERATOR_RESYNC:
-        gst_iterator_resync (pad_it);
-        break;
-      case GST_ITERATOR_ERROR:
-        done = TRUE;
-        break;
-      case GST_ITERATOR_DONE:
-        done = TRUE;
-        break;
-    }
-  }
-  g_value_unset (&item);
-  gst_iterator_free (pad_it);
-
-  return db_pad;
-}
-
-/* remove all downstream elements starting from the given pad.
- * Also make sure to remove the ghostpad we created for the raw
- * decoded stream.
- */
-static void
-remove_element_chain (GstDecodeBin * decode_bin, GstPad * pad)
-{
-  GstIterator *iter;
-  gboolean done = FALSE;
-  GValue item = { 0, };
-  GstElement *elem = GST_ELEMENT (GST_OBJECT_PARENT (pad));
-
-  while (GST_OBJECT_PARENT (elem) &&
-      GST_OBJECT_PARENT (elem) != GST_OBJECT (decode_bin))
-    elem = GST_ELEMENT (GST_OBJECT_PARENT (elem));
-
-  if (G_OBJECT_TYPE (elem) == decode_bin->queue_type) {
-    GST_DEBUG_OBJECT (decode_bin,
-        "Encountered demuxer output queue while removing element chain");
-    decode_bin->queues = g_list_remove (decode_bin->queues, elem);
-  }
-
-  GST_DEBUG_OBJECT (decode_bin, "%s:%s", GST_DEBUG_PAD_NAME (pad));
-  iter = gst_pad_iterate_internal_links (pad);
-  if (!iter)
-    goto no_iter;
-
-  /* remove all elements linked to this pad up to the ghostpad
-   * that we created for this stream */
-  while (!done) {
-    switch (gst_iterator_next (iter, &item)) {
-      case GST_ITERATOR_OK:{
-        GstPad *pad;
-        GstPad *ghostpad;
-        GstPad *peer;
-
-        pad = g_value_get_object (&item);
-        GST_DEBUG_OBJECT (decode_bin, "inspecting internal pad %s:%s",
-            GST_DEBUG_PAD_NAME (pad));
-
-        ghostpad = get_our_ghost_pad (decode_bin, pad);
-        if (ghostpad) {
-          GST_DEBUG_OBJECT (decode_bin, "found our ghost pad %s:%s for %s:%s",
-              GST_DEBUG_PAD_NAME (ghostpad), GST_DEBUG_PAD_NAME (pad));
-
-          g_signal_emit (G_OBJECT (decode_bin),
-              gst_decode_bin_signals[SIGNAL_REMOVED_DECODED_PAD], 0, ghostpad);
-
-          gst_element_remove_pad (GST_ELEMENT (decode_bin), ghostpad);
-          gst_object_unref (ghostpad);
-          g_value_reset (&item);
-          continue;
-        } else {
-          GST_DEBUG_OBJECT (decode_bin, "not one of our ghostpads");
-        }
-
-        peer = gst_pad_get_peer (pad);
-        if (peer) {
-          GstObject *parent = gst_pad_get_parent (peer);
-
-          GST_DEBUG_OBJECT (decode_bin,
-              "internal pad %s:%s linked to pad %s:%s",
-              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer));
-
-          if (parent) {
-            GstObject *grandparent = gst_object_get_parent (parent);
-
-            if (grandparent != NULL) {
-              if (GST_ELEMENT (grandparent) != GST_ELEMENT (decode_bin)) {
-                GST_DEBUG_OBJECT (decode_bin, "dead end pad %s:%s parent %s",
-                    GST_DEBUG_PAD_NAME (peer), GST_OBJECT_NAME (grandparent));
-              } else {
-                GST_DEBUG_OBJECT (decode_bin,
-                    "recursing element %s on pad %s:%s",
-                    GST_ELEMENT_NAME (elem), GST_DEBUG_PAD_NAME (pad));
-                remove_element_chain (decode_bin, peer);
-              }
-              gst_object_unref (grandparent);
-            }
-            gst_object_unref (parent);
-          }
-          gst_object_unref (peer);
-        }
-        g_value_reset (&item);
-      }
-        break;
-      case GST_ITERATOR_RESYNC:
-        gst_iterator_resync (iter);
-        break;
-      case GST_ITERATOR_ERROR:
-        GST_ERROR_OBJECT (pad, "Could not iterate over internally linked pads");
-        done = TRUE;
-        break;
-      case GST_ITERATOR_DONE:
-        done = TRUE;
-        break;
-    }
-  }
-  GST_DEBUG_OBJECT (decode_bin, "removing %s", GST_ELEMENT_NAME (elem));
-  g_value_unset (&item);
-  gst_iterator_free (iter);
-
-no_iter:
-  gst_element_set_state (elem, GST_STATE_NULL);
-  gst_bin_remove (GST_BIN (decode_bin), elem);
-}
-
-/* there are @bytes bytes in @queue, enlarge it
- *
- * Returns: new max number of bytes in @queue
- */
-static guint
-queue_enlarge (GstElement * queue, guint bytes, GstDecodeBin * decode_bin)
-{
-  /* Increase the queue size by 1Mbyte if it is over 1Mb, else double its current limit
-   */
-  if (bytes > 1024 * 1024)
-    bytes += 1024 * 1024;
-  else
-    bytes *= 2;
-
-  GST_DEBUG_OBJECT (decode_bin,
-      "increasing queue %s max-size-bytes to %d", GST_ELEMENT_NAME (queue),
-      bytes);
-  g_object_set (G_OBJECT (queue), "max-size-bytes", bytes, NULL);
-
-  return bytes;
-}
-
-/* this callback is called when our queues fills up or are empty
- * We then check the status of all other queues to make sure we
- * never have an empty and full queue at the same time since that
- * would block dataflow. In the case of a filled queue, we make
- * it larger.
- */
-static void
-queue_underrun_cb (GstElement * queue, GstDecodeBin * decode_bin)
-{
-  /* FIXME: we don't really do anything here for now. Ideally we should
-   * see if some of the queues are filled and increase their values
-   * in that case.
-   * Note: be very carefull with thread safety here as this underrun
-   * signal is done from the streaming thread of queue srcpad which
-   * is different from the pad_added (where we add the queue to the
-   * list) and the overrun signals that are signalled from the
-   * demuxer thread.
-   */
-  GST_DEBUG_OBJECT (decode_bin, "got underrun");
-}
-
-/* Make sure we don't have a full queue and empty queue situation */
-static void
-queue_filled_cb (GstElement * queue, GstDecodeBin * decode_bin)
-{
-  GList *tmp;
-  gboolean increase = FALSE;
-  guint bytes;
-
-  /* get current byte level from the queue that is filled */
-  g_object_get (G_OBJECT (queue), "current-level-bytes", &bytes, NULL);
-  GST_DEBUG_OBJECT (decode_bin, "One of the queues is full at %d bytes", bytes);
-
-  /* we do not buffer more than 20Mb */
-  if (bytes > (20 * 1024 * 1024))
-    goto too_large;
-
-  /* check all other queue to see if one is empty, in that case
-   * we need to enlarge @queue */
-  for (tmp = decode_bin->queues; tmp; tmp = g_list_next (tmp)) {
-    GstElement *aqueue = GST_ELEMENT (tmp->data);
-    guint levelbytes = 0;
-
-    if (aqueue != queue) {
-      g_object_get (G_OBJECT (aqueue), "current-level-bytes", &levelbytes,
-          NULL);
-      if (levelbytes == 0) {
-        /* yup, found an empty queue, we can stop the search and
-         * need to enlarge the queue */
-        increase = TRUE;
-        break;
-      }
-    }
-  }
-
-  if (increase) {
-    /* enlarge @queue */
-    queue_enlarge (queue, bytes, decode_bin);
-  } else {
-    GST_DEBUG_OBJECT (decode_bin,
-        "Queue is full but other queues are not empty, not doing anything");
-  }
-  return;
-
-  /* errors */
-too_large:
-  {
-    GST_WARNING_OBJECT (decode_bin,
-        "Queue is bigger than 20Mbytes, something else is going wrong");
-    return;
-  }
-}
-
-/* This function will be called when a dynamic pad is created on an element.
- * We try to continue autoplugging on this new pad. */
-static void
-new_pad (GstElement * element, GstPad * pad, GstDynamic * dynamic)
-{
-  GstDecodeBin *decode_bin = dynamic->decode_bin;
-  GstCaps *caps;
-  gboolean more;
-
-  GST_OBJECT_LOCK (decode_bin);
-  if (decode_bin->shutting_down)
-    goto shutting_down1;
-  GST_OBJECT_UNLOCK (decode_bin);
-
-  GST_STATE_LOCK (decode_bin);
-  if (decode_bin->shutting_down)
-    goto shutting_down2;
-
-  /* see if any more pending dynamic connections exist */
-  more = gst_decode_bin_is_dynamic (decode_bin);
-
-  caps = gst_pad_get_caps (pad, NULL);
-  close_pad_link (element, pad, caps, decode_bin, more);
-  if (caps)
-    gst_caps_unref (caps);
-  GST_STATE_UNLOCK (decode_bin);
-
-  return;
-
-shutting_down1:
-  {
-    GST_DEBUG_OBJECT (decode_bin, "we are shutting down");
-    GST_OBJECT_UNLOCK (decode_bin);
-    return;
-  }
-shutting_down2:
-  {
-    GST_DEBUG_OBJECT (decode_bin, "we are shutting down");
-    GST_STATE_UNLOCK (decode_bin);
-    return;
-  }
-}
-
-static void
-dynamic_remove (GstDynamic * dynamic)
-{
-  GstDecodeBin *decode_bin = dynamic->decode_bin;
-
-  /* remove the dynamic from the list of dynamics */
-  decode_bin->dynamics = g_list_remove (decode_bin->dynamics, dynamic);
-  dynamic_free (dynamic);
-
-  /* if we have no more dynamic elements, we have no chance of creating
-   * more pads, so we fire the no_more_pads signal */
-  if (decode_bin->dynamics == NULL) {
-    if (decode_bin->numwaiting == 0) {
-      GST_DEBUG_OBJECT (decode_bin,
-          "no more dynamic elements, removing fakesink");
-      remove_fakesink (decode_bin);
-    }
-    GST_DEBUG_OBJECT (decode_bin,
-        "no more dynamic elements, signaling no_more_pads");
-    gst_element_no_more_pads (GST_ELEMENT (decode_bin));
-  } else {
-    GST_DEBUG_OBJECT (decode_bin, "we have more dynamic elements");
-  }
-}
-
-/* this signal is fired when an element signals the no_more_pads signal.
- * This means that the element will not generate more dynamic pads and
- * we can remove the element from the list of dynamic elements. When we
- * have no more dynamic elements in the pipeline, we can fire a no_more_pads
- * signal ourselves. */
-static void
-no_more_pads (GstElement * element, GstDynamic * dynamic)
-{
-  GST_DEBUG_OBJECT (dynamic->decode_bin, "no more pads on element %s",
-      GST_ELEMENT_NAME (element));
-
-  dynamic_remove (dynamic);
-}
-
-static void
-new_caps (GstPad * pad, GParamSpec * unused, GstDynamic * dynamic)
-{
-  GST_DEBUG_OBJECT (dynamic->decode_bin, "delayed link triggered");
-
-  new_pad (dynamic->element, pad, dynamic);
-
-  /* assume it worked and remove the dynamic */
-  dynamic_remove (dynamic);
-
-  return;
-}
-
-static gboolean
-is_our_kid (GstElement * e, GstDecodeBin * decode_bin)
-{
-  gboolean ret;
-  GstElement *parent;
-
-  parent = (GstElement *) gst_object_get_parent ((GstObject *) e);
-  ret = (parent == (GstElement *) decode_bin);
-
-  if (parent)
-    gst_object_unref ((GstObject *) parent);
-
-  return ret;
-}
-
-static gboolean
-elem_is_dynamic (GstElement * element, GstDecodeBin * decode_bin)
-{
-  GList *pads;
-
-  /* loop over all the padtemplates */
-  for (pads = GST_ELEMENT_GET_CLASS (element)->padtemplates; pads;
-      pads = g_list_next (pads)) {
-    GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data);
-    const gchar *templ_name;
-
-    /* we are only interested in source pads */
-    if (GST_PAD_TEMPLATE_DIRECTION (templ) != GST_PAD_SRC)
-      continue;
-
-    templ_name = GST_PAD_TEMPLATE_NAME_TEMPLATE (templ);
-    GST_DEBUG_OBJECT (decode_bin, "got a source pad template %s", templ_name);
-
-    /* figure out what kind of pad this is */
-    switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
-      case GST_PAD_SOMETIMES:
-      {
-        /* try to get the pad to see if it is already created or
-         * not */
-        GstPad *pad = gst_element_get_static_pad (element, templ_name);
-
-        if (pad) {
-          GST_DEBUG_OBJECT (decode_bin, "got the pad for sometimes template %s",
-              templ_name);
-          gst_object_unref (pad);
-        } else {
-          GST_DEBUG_OBJECT (decode_bin,
-              "did not get the sometimes pad of template %s", templ_name);
-          /* we have an element that will create dynamic pads */
-          return TRUE;
-        }
-        break;
-      }
-      default:
-        /* Don't care about ALWAYS or REQUEST pads */
-        break;
-    }
-  }
-  return FALSE;
-}
-
-/* This function will be called when a pad is disconnected for some reason */
-static void
-unlinked (GstPad * pad, GstPad * peerpad, GstDecodeBin * decode_bin)
-{
-  GstElement *element, *peer;
-
-  /* inactivate pad */
-  gst_pad_set_active (pad, GST_ACTIVATE_NONE);
-
-  peer = gst_pad_get_parent_element (peerpad);
-
-  if (!is_our_kid (peer, decode_bin))
-    goto exit;
-
-  GST_DEBUG_OBJECT (decode_bin, "pad %s:%s removal while alive - chained?",
-      GST_DEBUG_PAD_NAME (pad));
-
-  /* remove all elements linked to the peerpad */
-  remove_element_chain (decode_bin, peerpad);
-
-  /* Re-add as a dynamic element if needed, via close_link */
-  element = gst_pad_get_parent_element (pad);
-  if (element) {
-    if (elem_is_dynamic (element, decode_bin))
-      dynamic_add (element, NULL, decode_bin);
-
-    gst_object_unref (element);
-  }
-
-exit:
-  gst_object_unref (peer);
-}
-
-/* this function inspects the given element and tries to connect something
- * on the srcpads. If there are dynamic pads, it sets up a signal handler to
- * continue autoplugging when they become available */
-static void
-close_link (GstElement * element, GstDecodeBin * decode_bin)
-{
-  GList *pads;
-  gboolean dynamic = FALSE;
-  GList *to_connect = NULL;
-  gboolean more;
-
-  GST_DEBUG_OBJECT (decode_bin, "closing links with element %s",
-      GST_ELEMENT_NAME (element));
-
-  /* loop over all the padtemplates */
-  for (pads = GST_ELEMENT_GET_CLASS (element)->padtemplates; pads;
-      pads = g_list_next (pads)) {
-    GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data);
-    const gchar *templ_name;
-
-    /* we are only interested in source pads */
-    if (GST_PAD_TEMPLATE_DIRECTION (templ) != GST_PAD_SRC)
-      continue;
-
-    templ_name = GST_PAD_TEMPLATE_NAME_TEMPLATE (templ);
-    GST_DEBUG_OBJECT (decode_bin, "got a source pad template %s", templ_name);
-
-    /* figure out what kind of pad this is */
-    switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
-      case GST_PAD_ALWAYS:
-      {
-        /* get the pad that we need to autoplug */
-        GstPad *pad = gst_element_get_static_pad (element, templ_name);
-
-        if (pad) {
-          GST_DEBUG_OBJECT (decode_bin, "got the pad for always template %s",
-              templ_name);
-          /* here is the pad, we need to autoplug it */
-          to_connect = g_list_prepend (to_connect, pad);
-        } else {
-          /* strange, pad is marked as always but it's not
-           * there. Fix the element */
-          GST_WARNING_OBJECT (decode_bin,
-              "could not get the pad for always template %s", templ_name);
-        }
-        break;
-      }
-      case GST_PAD_SOMETIMES:
-      {
-        /* try to get the pad to see if it is already created or
-         * not */
-        GstPad *pad = gst_element_get_static_pad (element, templ_name);
-
-        if (pad) {
-          GST_DEBUG_OBJECT (decode_bin, "got the pad for sometimes template %s",
-              templ_name);
-          /* the pad is created, we need to autoplug it */
-          to_connect = g_list_prepend (to_connect, pad);
-        } else {
-          GST_DEBUG_OBJECT (decode_bin,
-              "did not get the sometimes pad of template %s", templ_name);
-          /* we have an element that will create dynamic pads */
-          dynamic = TRUE;
-        }
-        break;
-      }
-      case GST_PAD_REQUEST:
-        /* ignore request pads */
-        GST_DEBUG_OBJECT (decode_bin, "ignoring request padtemplate %s",
-            templ_name);
-        break;
-    }
-  }
-  if (dynamic) {
-    GST_DEBUG_OBJECT (decode_bin, "got a dynamic element here");
-    /* ok, this element has dynamic pads, set up the signal handlers to be
-     * notified of them */
-
-    dynamic_add (element, NULL, decode_bin);
-  }
-
-  /* Check if this is an element with more than 1 pad. If this element
-   * has more than 1 pad, we need to be carefull not to signal the
-   * no_more_pads signal after connecting the first pad. */
-  more = g_list_length (to_connect) > 1;
-
-  /* now loop over all the pads we need to connect */
-  for (pads = to_connect; pads; pads = g_list_next (pads)) {
-    GstPad *pad = GST_PAD_CAST (pads->data);
-    GstCaps *caps;
-
-    /* we have more pads if we have more than 1 pad to connect or
-     * dynamics. If we have only 1 pad and no dynamics, more will be
-     * set to FALSE and the no-more-pads signal will be fired. Note
-     * that this can change after the close_pad_link call. */
-    more |= gst_decode_bin_is_dynamic (decode_bin);
-
-    GST_DEBUG_OBJECT (decode_bin, "closing pad link for %s",
-        GST_OBJECT_NAME (pad));
-
-    /* continue autoplugging on the pads */
-    caps = gst_pad_get_caps (pad, NULL);
-    close_pad_link (element, pad, caps, decode_bin, more);
-    if (caps)
-      gst_caps_unref (caps);
-
-    gst_object_unref (pad);
-  }
-  g_list_free (to_connect);
-}
-
-/* this is the signal handler for the typefind element have_type signal.
- * It tries to continue autoplugging on the typefind src pad */
-static void
-type_found (GstElement * typefind, guint probability, GstCaps * caps,
-    GstDecodeBin * decode_bin)
-{
-  gboolean dynamic;
-  GstPad *pad;
-
-  GST_DEBUG_OBJECT (decode_bin, "typefind found caps %" GST_PTR_FORMAT, caps);
-
-  GST_OBJECT_LOCK (decode_bin);
-  if (decode_bin->shutting_down)
-    goto shutting_down;
-  GST_OBJECT_UNLOCK (decode_bin);
-
-  GST_STATE_LOCK (decode_bin);
-  if (decode_bin->shutting_down)
-    goto exit;
-
-  /* don't need the typefind anymore if we already found a type, we're not going
-   * to be able to do anything with it anyway except for generating errors */
-  if (decode_bin->have_type)
-    goto exit;
-
-  decode_bin->have_type = TRUE;
-
-  /* special-case text/plain: we only want to accept it as a raw type if it
-   * comes from a subtitle parser element or a demuxer, but not if it is the
-   * type of the entire stream, in which case we just want to error out */
-  if (typefind == decode_bin->typefind &&
-      gst_structure_has_name (gst_caps_get_structure (caps, 0), "text/plain")) {
-    gst_element_no_more_pads (GST_ELEMENT (decode_bin));
-    /* we can't handle this type of stream */
-    GST_ELEMENT_ERROR (decode_bin, STREAM, WRONG_TYPE,
-        (_("This appears to be a text file")),
-        ("decodebin cannot decode plain text files"));
-    goto exit;
-  }
-
-  /* autoplug the new pad with the caps that the signal gave us. */
-  pad = gst_element_get_static_pad (typefind, "src");
-  close_pad_link (typefind, pad, caps, decode_bin, FALSE);
-  gst_object_unref (pad);
-
-  dynamic = gst_decode_bin_is_dynamic (decode_bin);
-  if (dynamic == FALSE) {
-    GST_DEBUG_OBJECT (decode_bin, "we have no dynamic elements anymore");
-    /* if we have no dynamic elements, we know that no new pads
-     * will be created and we can signal out no_more_pads signal */
-    gst_element_no_more_pads (GST_ELEMENT (decode_bin));
-  } else {
-    /* more dynamic elements exist that could create new pads */
-    GST_DEBUG_OBJECT (decode_bin, "we have more dynamic elements");
-  }
-
-exit:
-  GST_STATE_UNLOCK (decode_bin);
-  return;
-
-shutting_down:
-  {
-    GST_DEBUG_OBJECT (decode_bin, "we are shutting down");
-    GST_OBJECT_UNLOCK (decode_bin);
-    return;
-  }
-}
-
-static void
-disconnect_unlinked_signals (GstDecodeBin * decode_bin, GstElement * element)
-{
-  GstIterator *pad_it = NULL;
-  gboolean done = FALSE;
-  GstPad *pad = NULL;
-  GValue item = { 0, };
-
-  pad_it = gst_element_iterate_src_pads (element);
-  while (!done) {
-    switch (gst_iterator_next (pad_it, &item)) {
-      case GST_ITERATOR_OK:
-        pad = g_value_get_object (&item);
-        g_signal_handlers_disconnect_by_func (pad, (gpointer) unlinked,
-            decode_bin);
-        g_value_reset (&item);
-        break;
-      case GST_ITERATOR_RESYNC:
-        gst_iterator_resync (pad_it);
-        break;
-      default:
-        done = TRUE;
-        break;
-    }
-  }
-  g_value_unset (&item);
-  gst_iterator_free (pad_it);
-}
-
-
-static void
-cleanup_decodebin (GstDecodeBin * decode_bin)
-{
-  GstIterator *elem_it = NULL, *gpad_it = NULL;
-  GstPad *typefind_pad = NULL;
-  gboolean done = FALSE;
-  GstElement *element = NULL;
-  GstPad *pad = NULL;
-  GValue item = { 0, };
-
-  g_return_if_fail (GST_IS_DECODE_BIN (decode_bin));
-
-  GST_DEBUG_OBJECT (decode_bin, "cleaning up decodebin");
-
-  typefind_pad = gst_element_get_static_pad (decode_bin->typefind, "src");
-  if (GST_IS_PAD (typefind_pad)) {
-    g_signal_handlers_block_by_func (typefind_pad, (gpointer) unlinked,
-        decode_bin);
-  }
-
-  elem_it = gst_bin_iterate_elements (GST_BIN (decode_bin));
-  while (!done) {
-    switch (gst_iterator_next (elem_it, &item)) {
-      case GST_ITERATOR_OK:
-        element = g_value_get_object (&item);
-        if (element != decode_bin->typefind && element != decode_bin->fakesink) {
-          GST_DEBUG_OBJECT (element, "removing autoplugged element");
-          disconnect_unlinked_signals (decode_bin, element);
-          gst_element_set_state (element, GST_STATE_NULL);
-          gst_bin_remove (GST_BIN (decode_bin), element);
-        }
-        g_value_reset (&item);
-        break;
-      case GST_ITERATOR_RESYNC:
-        gst_iterator_resync (elem_it);
-        break;
-      case GST_ITERATOR_ERROR:
-        done = TRUE;
-        break;
-      case GST_ITERATOR_DONE:
-        done = TRUE;
-        break;
-    }
-  }
-  g_value_unset (&item);
-  gst_iterator_free (elem_it);
-
-  done = FALSE;
-  gpad_it = gst_element_iterate_pads (GST_ELEMENT (decode_bin));
-  while (!done) {
-    switch (gst_iterator_next (gpad_it, &item)) {
-      case GST_ITERATOR_OK:
-        pad = g_value_get_object (&item);
-        GST_DEBUG_OBJECT (pad, "inspecting pad %s:%s",
-            GST_DEBUG_PAD_NAME (pad));
-        if (GST_IS_GHOST_PAD (pad) && GST_PAD_IS_SRC (pad)) {
-          GST_DEBUG_OBJECT (pad, "removing ghost pad");
-          gst_element_remove_pad (GST_ELEMENT (decode_bin), pad);
-        }
-        g_value_reset (&item);
-        break;
-      case GST_ITERATOR_RESYNC:
-        gst_iterator_resync (gpad_it);
-        break;
-      case GST_ITERATOR_ERROR:
-        done = TRUE;
-        break;
-      case GST_ITERATOR_DONE:
-        done = TRUE;
-        break;
-    }
-  }
-  g_value_unset (&item);
-  gst_iterator_free (gpad_it);
-
-  if (GST_IS_PAD (typefind_pad)) {
-    g_signal_handlers_unblock_by_func (typefind_pad, (gpointer) unlinked,
-        decode_bin);
-    g_signal_handlers_disconnect_by_func (typefind_pad, (gpointer) unlinked,
-        decode_bin);
-    gst_object_unref (typefind_pad);
-  }
-}
-
-static GstStateChangeReturn
-gst_decode_bin_change_state (GstElement * element, GstStateChange transition)
-{
-  GstStateChangeReturn ret;
-  GstDecodeBin *decode_bin;
-
-  decode_bin = GST_DECODE_BIN (element);
-
-  switch (transition) {
-    case GST_STATE_CHANGE_NULL_TO_READY:
-      decode_bin->numpads = 0;
-      decode_bin->numwaiting = 0;
-      decode_bin->dynamics = NULL;
-      if (decode_bin->typefind == NULL)
-        goto missing_typefind;
-      break;
-    case GST_STATE_CHANGE_READY_TO_PAUSED:
-      GST_OBJECT_LOCK (decode_bin);
-      decode_bin->shutting_down = FALSE;
-      decode_bin->have_type = FALSE;
-      GST_OBJECT_UNLOCK (decode_bin);
-
-      if (!add_fakesink (decode_bin))
-        goto missing_fakesink;
-      break;
-    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
-    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
-      break;
-    case GST_STATE_CHANGE_PAUSED_TO_READY:
-      GST_OBJECT_LOCK (decode_bin);
-      decode_bin->shutting_down = TRUE;
-      GST_OBJECT_UNLOCK (decode_bin);
-      break;
-    default:
-      break;
-  }
-
-  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-  if (ret == GST_STATE_CHANGE_FAILURE)
-    return ret;
-
-  switch (transition) {
-    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
-      break;
-    case GST_STATE_CHANGE_PAUSED_TO_READY:
-    case GST_STATE_CHANGE_READY_TO_NULL:
-      free_dynamics (decode_bin);
-      free_pad_probes (decode_bin);
-      cleanup_decodebin (decode_bin);
-      break;
-    default:
-      break;
-  }
-
-  return ret;
-/* ERRORS */
-missing_typefind:
-  {
-    gst_element_post_message (element,
-        gst_missing_element_message_new (element, "typefind"));
-    GST_ELEMENT_ERROR (element, CORE, MISSING_PLUGIN, (NULL), ("no typefind!"));
-    return GST_STATE_CHANGE_FAILURE;
-  }
-missing_fakesink:
-  {
-    gst_element_post_message (element,
-        gst_missing_element_message_new (element, "fakesink"));
-    GST_ELEMENT_ERROR (element, CORE, MISSING_PLUGIN, (NULL), ("no fakesink!"));
-    return GST_STATE_CHANGE_FAILURE;
-  }
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
-  GST_DEBUG_CATEGORY_INIT (gst_decode_bin_debug, "decodebin", 0, "decoder bin");
-
-#ifdef ENABLE_NLS
-  GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
-      LOCALEDIR);
-  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
-  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-#endif /* ENABLE_NLS */
-
-  return gst_element_register (plugin, "decodebin", GST_RANK_NONE,
-      GST_TYPE_DECODE_BIN);
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
-    GST_VERSION_MINOR,
-    "decodebin",
-    "decoder bin", plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
-    GST_PACKAGE_ORIGIN)
index a83fee1..f7a0432 100644 (file)
@@ -30,7 +30,6 @@
 #include "gstplayback.h"
 #include "gstplaysink.h"
 #include "gststreamselector.h"
-#include "gststreaminfo.h"
 #include "gstsubtitleoverlay.h"
 
 static gboolean
@@ -49,11 +48,9 @@ plugin_init (GstPlugin * plugin)
 
   /* ref class from a thread-safe context to work around missing bit of
    * thread-safety in GObject */
-  g_type_class_ref (GST_TYPE_STREAM_INFO);
   g_type_class_ref (GST_TYPE_STREAM_SELECTOR);
 
-  res = gst_play_bin_plugin_init (plugin);
-  res &= gst_play_bin2_plugin_init (plugin);
+  res = gst_play_bin2_plugin_init (plugin);
   res &= gst_play_sink_plugin_init (plugin);
   res &= gst_subtitle_overlay_plugin_init (plugin);
 
diff --git a/gst/playback/gstplaybasebin.c b/gst/playback/gstplaybasebin.c
deleted file mode 100644 (file)
index 492977a..0000000
+++ /dev/null
@@ -1,2823 +0,0 @@
-/* GStreamer
- * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gst/gst-i18n-plugin.h>
-#include <string.h>
-#include "gstplaybasebin.h"
-#include "gststreamselector.h"
-#include "gstplay-marshal.h"
-
-#include <gst/pbutils/pbutils.h>
-
-GST_DEBUG_CATEGORY_STATIC (gst_play_base_bin_debug);
-#define GST_CAT_DEFAULT gst_play_base_bin_debug
-
-#define DEFAULT_QUEUE_SIZE          (3 * GST_SECOND)
-#define DEFAULT_QUEUE_MIN_THRESHOLD ((DEFAULT_QUEUE_SIZE * 30) / 100)
-#define DEFAULT_QUEUE_THRESHOLD     ((DEFAULT_QUEUE_SIZE * 95) / 100)
-#define DEFAULT_CONNECTION_SPEED    0
-
-#define GROUP_LOCK(pbb) g_mutex_lock (pbb->group_lock)
-#define GROUP_UNLOCK(pbb) g_mutex_unlock (pbb->group_lock)
-#define GROUP_WAIT(pbb) g_cond_wait (pbb->group_cond, pbb->group_lock)
-#define GROUP_SIGNAL(pbb) g_cond_signal (pbb->group_cond)
-
-/* props */
-enum
-{
-  ARG_0,
-  ARG_URI,
-  ARG_SUBURI,
-  ARG_QUEUE_SIZE,
-  ARG_QUEUE_THRESHOLD,
-  ARG_QUEUE_MIN_THRESHOLD,
-  ARG_NSTREAMS,
-  ARG_STREAMINFO,
-  ARG_STREAMINFO_VALUES,
-  ARG_SOURCE,
-  ARG_VIDEO,
-  ARG_AUDIO,
-  ARG_TEXT,
-  ARG_SUBTITLE_ENCODING,
-  ARG_CONNECTION_SPEED
-};
-
-static void gst_play_base_bin_class_init (GstPlayBaseBinClass * klass);
-static void gst_play_base_bin_init (GstPlayBaseBin * play_base_bin);
-static void gst_play_base_bin_dispose (GObject * object);
-static void gst_play_base_bin_finalize (GObject * object);
-
-static void gst_play_base_bin_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * spec);
-static void gst_play_base_bin_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * spec);
-static void gst_play_base_bin_handle_message_func (GstBin * bin,
-    GstMessage * msg);
-
-static GstStateChangeReturn gst_play_base_bin_change_state (GstElement *
-    element, GstStateChange transition);
-
-static const GList *gst_play_base_bin_get_streaminfo (GstPlayBaseBin * bin);
-static GValueArray *gst_play_base_bin_get_streaminfo_value_array (GstPlayBaseBin
-    * play_base_bin);
-static void preroll_remove_overrun (GstElement * element,
-    GstPlayBaseBin * play_base_bin);
-static void queue_remove_probe (GstElement * queue, GstPlayBaseBin
-    * play_base_bin);
-
-static GstElement *make_decoder (GstPlayBaseBin * play_base_bin);
-static gboolean has_all_raw_caps (GstPad * pad, gboolean * all_raw);
-
-static gboolean prepare_output (GstPlayBaseBin * play_base_bin);
-static void set_active_source (GstPlayBaseBin * play_base_bin,
-    GstStreamType type, gint source_num);
-static GstProbeReturn probe_triggered (GstPad * pad, GstProbeType type,
-    gpointer type_data, gpointer user_data);
-static void setup_substreams (GstPlayBaseBin * play_base_bin);
-
-static GstPipelineClass *parent_class;
-
-/*
- * GObject playbasebin wrappers.
- */
-
-GType
-gst_play_base_bin_get_type (void)
-{
-  static GType gst_play_base_bin_type = 0;
-
-  if (!gst_play_base_bin_type) {
-    static const GTypeInfo gst_play_base_bin_info = {
-      sizeof (GstPlayBaseBinClass),
-      NULL,
-      NULL,
-      (GClassInitFunc) gst_play_base_bin_class_init,
-      NULL,
-      NULL,
-      sizeof (GstPlayBaseBin),
-      0,
-      (GInstanceInitFunc) gst_play_base_bin_init,
-      NULL
-    };
-
-    gst_play_base_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
-        "GstPlayBaseBin", &gst_play_base_bin_info, 0);
-  }
-
-  return gst_play_base_bin_type;
-}
-
-static void
-gst_play_base_bin_class_init (GstPlayBaseBinClass * klass)
-{
-  GObjectClass *gobject_klass;
-  GstElementClass *gstelement_klass;
-  GstBinClass *gstbin_klass;
-
-  gobject_klass = (GObjectClass *) klass;
-  gstelement_klass = (GstElementClass *) klass;
-  gstbin_klass = (GstBinClass *) klass;
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  gobject_klass->set_property = gst_play_base_bin_set_property;
-  gobject_klass->get_property = gst_play_base_bin_get_property;
-
-  g_object_class_install_property (gobject_klass, ARG_URI,
-      g_param_spec_string ("uri", "URI", "URI of the media to play",
-          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_SUBURI,
-      g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
-          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_klass, ARG_QUEUE_SIZE,
-      g_param_spec_uint64 ("queue-size", "Queue size",
-          "Size of internal queues in nanoseconds", 0, G_MAXINT64,
-          DEFAULT_QUEUE_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_QUEUE_THRESHOLD,
-      g_param_spec_uint64 ("queue-threshold", "Queue threshold",
-          "Buffering threshold of internal queues in nanoseconds", 0,
-          G_MAXINT64, DEFAULT_QUEUE_THRESHOLD,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_QUEUE_MIN_THRESHOLD,
-      g_param_spec_uint64 ("queue-min-threshold", "Queue min threshold",
-          "Buffering low threshold of internal queues in nanoseconds", 0,
-          G_MAXINT64, DEFAULT_QUEUE_MIN_THRESHOLD,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_klass, ARG_NSTREAMS,
-      g_param_spec_int ("nstreams", "NStreams", "number of streams",
-          0, G_MAXINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_STREAMINFO,
-      g_param_spec_pointer ("stream-info", "Stream info", "List of streaminfo",
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_STREAMINFO_VALUES,
-      g_param_spec_value_array ("stream-info-value-array",
-          "StreamInfo GValueArray", "value array of streaminfo",
-          g_param_spec_object ("streaminfo", "StreamInfo", "Streaminfo object",
-              GST_TYPE_STREAM_INFO, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS),
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_SOURCE,
-      g_param_spec_object ("source", "Source", "Source element",
-          GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_klass, ARG_VIDEO,
-      g_param_spec_int ("current-video", "Current video",
-          "Currently playing video stream (-1 = none)",
-          -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_AUDIO,
-      g_param_spec_int ("current-audio", "Current audio",
-          "Currently playing audio stream (-1 = none)",
-          -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_TEXT,
-      g_param_spec_int ("current-text", "Current text",
-          "Currently playing text stream (-1 = none)",
-          -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_SUBTITLE_ENCODING,
-      g_param_spec_string ("subtitle-encoding", "subtitle encoding",
-          "Encoding to assume if input subtitles are not in UTF-8 encoding. "
-          "If not set, the GST_SUBTITLE_ENCODING environment variable will "
-          "be checked for an encoding to use. If that is not set either, "
-          "ISO-8859-15 will be assumed.", NULL,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  /**
-   * GstPlayBaseBin:connection-speed
-   *
-   * Network connection speed in kbps (0 = unknown)
-   * <note><simpara>
-   * Since version 0.10.10 in #GstPlayBin, at 0.10.15 moved to #GstPlayBaseBin
-   * </simpara></note>
-   *
-   * Since: 0.10.10
-   */
-  g_object_class_install_property (gobject_klass, ARG_CONNECTION_SPEED,
-      g_param_spec_uint ("connection-speed", "Connection Speed",
-          "Network connection speed in kbps (0 = unknown)",
-          0, G_MAXUINT, DEFAULT_CONNECTION_SPEED,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-  GST_DEBUG_CATEGORY_INIT (gst_play_base_bin_debug, "playbasebin", 0,
-      "playbasebin");
-
-  gobject_klass->dispose = gst_play_base_bin_dispose;
-  gobject_klass->finalize = gst_play_base_bin_finalize;
-
-  gstbin_klass->handle_message =
-      GST_DEBUG_FUNCPTR (gst_play_base_bin_handle_message_func);
-
-  gstelement_klass->change_state =
-      GST_DEBUG_FUNCPTR (gst_play_base_bin_change_state);
-}
-
-static void
-gst_play_base_bin_init (GstPlayBaseBin * play_base_bin)
-{
-  play_base_bin->uri = NULL;
-  play_base_bin->suburi = NULL;
-  play_base_bin->need_rebuild = TRUE;
-  play_base_bin->is_stream = FALSE;
-  play_base_bin->source = NULL;
-  play_base_bin->decoders = NULL;
-  play_base_bin->subtitle = NULL;
-  play_base_bin->subencoding = NULL;
-  play_base_bin->subtitle_elements = NULL;
-  play_base_bin->sub_lock = g_mutex_new ();
-
-  play_base_bin->group_lock = g_mutex_new ();
-  play_base_bin->group_cond = g_cond_new ();
-
-  play_base_bin->building_group = NULL;
-  play_base_bin->queued_groups = NULL;
-
-  play_base_bin->queue_size = DEFAULT_QUEUE_SIZE;
-  play_base_bin->queue_threshold = DEFAULT_QUEUE_THRESHOLD;
-  play_base_bin->queue_min_threshold = DEFAULT_QUEUE_MIN_THRESHOLD;
-  play_base_bin->connection_speed = DEFAULT_CONNECTION_SPEED;
-}
-
-static void
-gst_play_base_bin_dispose (GObject * object)
-{
-  GstPlayBaseBin *play_base_bin;
-
-  play_base_bin = GST_PLAY_BASE_BIN (object);
-  g_free (play_base_bin->uri);
-  play_base_bin->uri = NULL;
-  g_free (play_base_bin->suburi);
-  play_base_bin->suburi = NULL;
-  g_free (play_base_bin->subencoding);
-  play_base_bin->subencoding = NULL;
-  if (play_base_bin->subtitle_elements) {
-    g_slist_free (play_base_bin->subtitle_elements);
-    play_base_bin->subtitle_elements = NULL;
-  }
-  G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-gst_play_base_bin_finalize (GObject * object)
-{
-  GstPlayBaseBin *play_base_bin = GST_PLAY_BASE_BIN (object);
-
-  g_mutex_free (play_base_bin->group_lock);
-  g_cond_free (play_base_bin->group_cond);
-
-  g_mutex_free (play_base_bin->sub_lock);
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-/*
- * playbasebingroup stuff.
- */
-
-static GstPlayBaseGroup *
-group_create (GstPlayBaseBin * play_base_bin)
-{
-  GstPlayBaseGroup *group;
-
-  group = g_new0 (GstPlayBaseGroup, 1);
-  group->bin = play_base_bin;
-  group->streaminfo_value_array = g_value_array_new (0);
-
-  GST_DEBUG_OBJECT (play_base_bin, "created new group %p", group);
-
-  return group;
-}
-
-/*
- * Gets the currently playing group.
- *
- * Callers must have group-lock held when calling this.
- */
-
-static GstPlayBaseGroup *
-get_active_group (GstPlayBaseBin * play_base_bin)
-{
-  GstPlayBaseGroup *group = NULL;
-
-  if (play_base_bin->queued_groups)
-    group = play_base_bin->queued_groups->data;
-
-  return group;
-}
-
-/*
- * get the group used for discovering the different streams.
- * This function creates a group is there is none.
- *
- * Callers must have group-lock held when calling this.
- */
-static GstPlayBaseGroup *
-get_building_group (GstPlayBaseBin * play_base_bin)
-{
-  GstPlayBaseGroup *group;
-
-  group = play_base_bin->building_group;
-  if (group == NULL) {
-    group = group_create (play_base_bin);
-    play_base_bin->building_group = group;
-  }
-
-  return group;
-}
-
-/*
- * Callers must have lock held when calling this!
- */
-
-static void
-group_destroy (GstPlayBaseGroup * group)
-{
-  GstPlayBaseBin *play_base_bin = group->bin;
-  gint n;
-
-  GST_LOG ("removing group %p", group);
-
-  /* remove the preroll queues */
-  for (n = 0; n < NUM_TYPES; n++) {
-    GstElement *element = group->type[n].preroll;
-    GstElement *fakesrc;
-    GstElement *sel;
-    const GList *item;
-
-    if (!element)
-      continue;
-
-    sel = group->type[n].selector;
-
-    /* remove any fakesrc elements for this preroll element */
-    for (item = sel->pads; item != NULL; item = item->next) {
-      GstPad *pad = GST_PAD (item->data);
-      guint sig_id;
-
-      if (GST_PAD_DIRECTION (pad) != GST_PAD_SINK)
-        continue;
-
-      sig_id =
-          GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pad), "unlinked_id"));
-
-      if (sig_id != 0) {
-        GST_LOG ("removing unlink signal %s:%s", GST_DEBUG_PAD_NAME (pad));
-        g_signal_handler_disconnect (G_OBJECT (pad), sig_id);
-        g_object_set_data (G_OBJECT (pad), "unlinked_id", GINT_TO_POINTER (0));
-      }
-
-      fakesrc = (GstElement *) g_object_get_data (G_OBJECT (pad), "fakesrc");
-      if (fakesrc != NULL) {
-        GST_LOG ("removing fakesrc from %s:%s",
-            GST_PAD_NAME (pad), GST_ELEMENT_NAME (GST_PAD_PARENT (pad)));
-        gst_element_set_state (fakesrc, GST_STATE_NULL);
-        gst_bin_remove (GST_BIN_CAST (play_base_bin), fakesrc);
-      }
-    }
-
-    /* if the group is currently being played, we have to remove the element
-     * from the thread */
-    gst_element_set_state (element, GST_STATE_NULL);
-    gst_element_set_state (group->type[n].selector, GST_STATE_NULL);
-
-    GST_LOG ("removing preroll element %s", GST_ELEMENT_NAME (element));
-
-    gst_bin_remove (group->type[n].bin, element);
-    gst_bin_remove (group->type[n].bin, group->type[n].selector);
-
-    group->type[n].preroll = NULL;
-    group->type[n].selector = NULL;
-    group->type[n].bin = NULL;
-  }
-
-  /* free the streaminfo too */
-  g_list_foreach (group->streaminfo, (GFunc) g_object_unref, NULL);
-  g_list_free (group->streaminfo);
-  g_value_array_free (group->streaminfo_value_array);
-  g_free (group);
-}
-
-/*
- * is called when the current building group is completely finished
- * and ready for playback
- *
- * This function grabs lock, so take care when calling.
- */
-static void
-group_commit (GstPlayBaseBin * play_base_bin, gboolean fatal, gboolean subtitle)
-{
-  GstPlayBaseGroup *group;
-  gboolean had_active_group;
-
-  GROUP_LOCK (play_base_bin);
-  group = play_base_bin->building_group;
-  had_active_group = (get_active_group (play_base_bin) != NULL);
-
-  GST_DEBUG_OBJECT (play_base_bin, "commit group %p, had active %d",
-      group, had_active_group);
-
-  /* if an element signalled a no-more-pads after we stopped due
-   * to preroll, the group is NULL. This is not an error */
-  if (group == NULL) {
-    if (!fatal) {
-      GROUP_UNLOCK (play_base_bin);
-      return;
-    } else {
-      GST_DEBUG_OBJECT (play_base_bin, "Group loading failed, bailing out");
-    }
-  } else {
-    if (!subtitle) {
-      gint n;
-
-      GST_DEBUG_OBJECT (play_base_bin, "group %p done", group);
-
-      play_base_bin->queued_groups =
-          g_list_append (play_base_bin->queued_groups, group);
-
-      play_base_bin->building_group = NULL;
-
-      /* remove signals. We don't want anymore signals from the preroll
-       * elements at this stage. */
-      for (n = 0; n < NUM_TYPES; n++) {
-        GstElement *element = group->type[n].preroll;
-
-        if (!element)
-          continue;
-
-        preroll_remove_overrun (element, play_base_bin);
-        /* if overrun is removed, probe alse has to be removed */
-        queue_remove_probe (element, play_base_bin);
-      }
-    } else {
-      /* this is a special subtitle bin, we don't commit the group but
-       * mark the subtitles as detected before we signal. */
-      GST_DEBUG_OBJECT (play_base_bin, "marking subtitle bin as complete");
-      play_base_bin->subtitle_done = TRUE;
-    }
-  }
-
-  GST_DEBUG_OBJECT (play_base_bin, "signal group done");
-  GROUP_SIGNAL (play_base_bin);
-  GST_DEBUG_OBJECT (play_base_bin, "signaled group done");
-
-  if (!subtitle && !had_active_group) {
-    if (!prepare_output (play_base_bin)) {
-      GROUP_UNLOCK (play_base_bin);
-      return;
-    }
-
-    setup_substreams (play_base_bin);
-    GST_DEBUG_OBJECT (play_base_bin, "Emitting signal");
-    GST_PLAY_BASE_BIN_GET_CLASS (play_base_bin)->setup_output_pads
-        (play_base_bin, group);
-    GST_DEBUG_OBJECT (play_base_bin, "done");
-
-    GROUP_UNLOCK (play_base_bin);
-
-    g_object_notify (G_OBJECT (play_base_bin), "stream-info");
-  } else {
-    GROUP_UNLOCK (play_base_bin);
-  }
-}
-
-/*
- * check if there are streams in the group that are not muted
- *
- * Callers must have group-lock held when calling this.
- */
-static gboolean
-group_is_muted (GstPlayBaseGroup * group)
-{
-  gint n;
-
-  for (n = 0; n < NUM_TYPES; n++) {
-    if (group->type[n].preroll && !group->type[n].done)
-      return FALSE;
-  }
-
-  return TRUE;
-}
-
-/*
- * Buffer/cache checking.
- */
-
-static inline void
-fill_buffer (GstPlayBaseBin * play_base_bin, gint percent)
-{
-  GST_DEBUG_OBJECT (play_base_bin, "buffering %d", percent);
-  gst_element_post_message (GST_ELEMENT_CAST (play_base_bin),
-      gst_message_new_buffering (GST_OBJECT_CAST (play_base_bin), percent));
-}
-
-static GstProbeReturn
-check_queue_event (GstPad * pad, GstProbeType type, gpointer type_data,
-    gpointer user_data)
-{
-  GstEvent *event = type_data;
-  GstElement *queue = GST_ELEMENT_CAST (user_data);
-
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_EOS:
-      GST_DEBUG ("EOS event, mark EOS");
-      g_object_set_data (G_OBJECT (queue), "eos", GINT_TO_POINTER (1));
-      break;
-    case GST_EVENT_FLUSH_STOP:
-      GST_DEBUG ("FLUSH_STOP event, remove EOS");
-      g_object_set_data (G_OBJECT (queue), "eos", NULL);
-      break;
-    default:
-      GST_DEBUG ("uninteresting event %s", GST_EVENT_TYPE_NAME (event));
-      break;
-  }
-  return GST_PROBE_OK;
-}
-
-static GstProbeReturn
-check_queue (GstPad * pad, GstProbeType type, gpointer type_data,
-    gpointer user_data)
-{
-  GstElement *queue = GST_ELEMENT_CAST (user_data);
-  GstPlayBaseBin *play_base_bin = g_object_get_data (G_OBJECT (queue), "pbb");
-  guint64 level = 0;
-
-  GST_DEBUG_OBJECT (queue, "check queue triggered");
-
-  g_object_get (G_OBJECT (queue), "current-level-time", &level, NULL);
-  GST_DEBUG_OBJECT (play_base_bin, "Queue size: %" GST_TIME_FORMAT,
-      GST_TIME_ARGS (level));
-
-  if (play_base_bin->queue_threshold > 0) {
-    level = level * 99 / play_base_bin->queue_threshold;
-    if (level > 99)
-      level = 99;
-  } else
-    level = 99;
-
-  fill_buffer (play_base_bin, level);
-
-  /* continue! */
-  return GST_PROBE_OK;
-}
-
-/* If a queue overruns and we are buffer in streaming mode (we have a min-time)
- * we can potentially create a deadlock when:
- *
- *  1) the max-bytes is hit and
- *  2) the min-time is not hit.
- *
- * We recover from this situation in this callback by
- * setting the max-bytes to unlimited if we see that there is
- * a current-time-level (which means some sort of timestamping is
- * done).
- */
-static void
-queue_deadlock_check (GstElement * queue, GstPlayBaseBin * play_base_bin)
-{
-  guint64 time, min_time;
-  guint bytes;
-
-  GST_DEBUG_OBJECT (play_base_bin, "overrun signal received from queue %s",
-      GST_ELEMENT_NAME (queue));
-
-  /* figure out where we are */
-  g_object_get (G_OBJECT (queue), "current-level-time", &time,
-      "current-level-bytes", &bytes, "min-threshold-time", &min_time, NULL);
-
-  GST_DEBUG_OBJECT (play_base_bin, "streaming mode, queue %s current %"
-      GST_TIME_FORMAT ", min %" GST_TIME_FORMAT
-      ", bytes %d", GST_ELEMENT_NAME (queue),
-      GST_TIME_ARGS (time), GST_TIME_ARGS (min_time), bytes);
-
-  /* if the bytes in the queue represent time, we disable bytes
-   * overrun checking to not cause deadlocks.
-   */
-  if (bytes && time != 0 && time < min_time) {
-    GST_DEBUG_OBJECT (play_base_bin,
-        "possible deadlock found, removing byte limit");
-
-    /* queue knows about time but is filled with bytes that do
-     * not represent min-threshold time, disable bytes checking so
-     * the queue can grow some more. */
-    g_object_set (G_OBJECT (queue), "max-size-bytes", 0, NULL);
-
-    /* bytes limit is removed, we cannot deadlock anymore */
-    g_signal_handlers_disconnect_by_func (queue,
-        (gpointer) queue_deadlock_check, play_base_bin);
-  } else {
-    GST_DEBUG_OBJECT (play_base_bin, "no deadlock");
-  }
-}
-
-static void
-queue_remove_probe (GstElement * queue, GstPlayBaseBin * play_base_bin)
-{
-  gpointer data;
-  GstPad *sinkpad;
-
-  data = g_object_get_data (G_OBJECT (queue), "probe");
-  sinkpad = gst_element_get_static_pad (queue, "sink");
-
-  if (data) {
-    GST_DEBUG_OBJECT (play_base_bin,
-        "Removing buffer probe from pad %s:%s (%p)",
-        GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
-
-    g_object_set_data (G_OBJECT (queue), "probe", NULL);
-    gst_pad_remove_probe (sinkpad, GPOINTER_TO_INT (data));
-  } else {
-    GST_DEBUG_OBJECT (play_base_bin,
-        "No buffer probe to remove from %s:%s (%p)",
-        GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
-  }
-  gst_object_unref (sinkpad);
-}
-
-/* Used for time-based buffering in streaming mode and is called when a queue
- * emits the running signal. This means that the high watermark threshold is
- * reached and the buffering is completed. */
-static void
-queue_threshold_reached (GstElement * queue, GstPlayBaseBin * play_base_bin)
-{
-  GstPlayBaseGroup *group;
-  gint n;
-
-  GST_DEBUG_OBJECT (play_base_bin, "running signal received from queue %s",
-      GST_ELEMENT_NAME (queue));
-
-  /* we disconnect the signal so that we don't get called for every buffer. */
-  g_signal_handlers_disconnect_by_func (queue,
-      (gpointer) queue_threshold_reached, play_base_bin);
-
-  if (g_object_get_data (G_OBJECT (queue), "eos")) {
-    GST_DEBUG_OBJECT (play_base_bin, "disable min threshold time, we are EOS");
-    g_object_set (queue, "min-threshold-time", (guint64) 0, NULL);
-  } else {
-    /* now place the limits at the low threshold. When we hit this limit, the
-     * underrun signal will be called. The underrun signal is always connected. */
-    GST_DEBUG_OBJECT (play_base_bin,
-        "setting min threshold time to %" G_GUINT64_FORMAT,
-        play_base_bin->queue_min_threshold);
-    g_object_set (queue, "min-threshold-time",
-        play_base_bin->queue_min_threshold, NULL);
-  }
-
-  GROUP_LOCK (play_base_bin);
-  group = get_active_group (play_base_bin);
-  if (!group) {
-    GROUP_UNLOCK (play_base_bin);
-    return;
-  }
-
-  /* we remove the probe now because we don't need it anymore to give progress
-   * about the buffering. */
-  for (n = 0; n < NUM_TYPES; n++) {
-    GstElement *element = group->type[n].preroll;
-
-    if (!element)
-      continue;
-
-    queue_remove_probe (element, play_base_bin);
-  }
-
-  GROUP_UNLOCK (play_base_bin);
-
-  /* we post a 100% buffering message to notify the app that buffering is
-   * completed and playback can start/continue */
-  if (play_base_bin->is_stream)
-    fill_buffer (play_base_bin, 100);
-}
-
-/* this signal will be fired when one of the queues with raw
- * data is filled. This means that the group building stage is over
- * and playback of the new queued group should start. This is a rather unusual
- * situation because normally the group is commited when the "no_more_pads"
- * signal is fired.
- */
-static void
-queue_overrun (GstElement * queue, GstPlayBaseBin * play_base_bin)
-{
-  GST_DEBUG_OBJECT (play_base_bin, "queue %s overrun",
-      GST_ELEMENT_NAME (queue));
-
-  preroll_remove_overrun (queue, play_base_bin);
-
-  group_commit (play_base_bin, FALSE,
-      GST_OBJECT_PARENT (GST_OBJECT_CAST (queue)) ==
-      GST_OBJECT_CAST (play_base_bin->subtitle));
-
-  /* notify end of buffering */
-  queue_threshold_reached (queue, play_base_bin);
-}
-
-/* this signal is only added when in streaming mode to catch underruns
- */
-static void
-queue_out_of_data (GstElement * queue, GstPlayBaseBin * play_base_bin)
-{
-  GST_DEBUG_OBJECT (play_base_bin, "underrun signal received from queue %s",
-      GST_ELEMENT_NAME (queue));
-
-  /* On underrun, we want to temoprarily pause playback, set a "min-size"
-   * threshold and wait for the running signal and then play again.
-   *
-   * This signal could never be called because the queue max-size limits are set
-   * too low. We take care of this possible deadlock in the the overrun signal
-   * handler. */
-  g_signal_connect (G_OBJECT (queue), "pushing",
-      G_CALLBACK (queue_threshold_reached), play_base_bin);
-  GST_DEBUG_OBJECT (play_base_bin,
-      "setting min threshold time to %" G_GUINT64_FORMAT,
-      (guint64) play_base_bin->queue_threshold);
-  g_object_set (queue, "min-threshold-time",
-      (guint64) play_base_bin->queue_threshold, NULL);
-
-  /* re-connect probe, this will fire feedback about the percentage that we
-   * buffered and is posted in the BUFFERING message. */
-  if (!g_object_get_data (G_OBJECT (queue), "probe")) {
-    GstPad *sinkpad;
-    guint id;
-
-    sinkpad = gst_element_get_static_pad (queue, "sink");
-    id = gst_pad_add_probe (sinkpad, GST_PROBE_TYPE_BUFFER, check_queue, queue,
-        NULL);
-    g_object_set_data (G_OBJECT (queue), "probe", GINT_TO_POINTER (id));
-    GST_DEBUG_OBJECT (play_base_bin,
-        "Re-attaching buffering probe to pad %s:%s %p",
-        GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
-    gst_object_unref (sinkpad);
-
-    fill_buffer (play_base_bin, 0);
-  }
-}
-
-/*
- * generate a preroll element which is simply a queue. While there
- * are still dynamic elements in the pipeline, we wait for one
- * of the queues to fill. The assumption is that all the dynamic
- * streams will be detected by that time.
- *
- * Callers must have the group-lock held when calling this.
- */
-static void
-gen_preroll_element (GstPlayBaseBin * play_base_bin,
-    GstPlayBaseGroup * group, GstStreamType type, GstPad * pad,
-    GstStreamInfo * info)
-{
-  GstElement *selector, *preroll;
-  gchar *name, *padname;
-  const gchar *prename;
-  guint overrun_sig;
-  GstPad *preroll_pad;
-  GstBin *target;
-  GstState state;
-
-  if (type == GST_STREAM_TYPE_VIDEO)
-    prename = "video";
-  else if (type == GST_STREAM_TYPE_TEXT)
-    prename = "text";
-  else if (type == GST_STREAM_TYPE_AUDIO)
-    prename = "audio";
-  else if (type == GST_STREAM_TYPE_SUBPICTURE)
-    prename = "subpicture";
-  else
-    g_return_if_reached ();
-
-  /* create stream selector */
-  selector = g_object_new (GST_TYPE_STREAM_SELECTOR, NULL);
-  padname = gst_pad_get_name (pad);
-  name = g_strdup_printf ("selector_%s_%s", prename, padname);
-  gst_object_set_name (GST_OBJECT_CAST (selector), name);
-  g_free (name);
-
-  /* create preroll queue */
-  name = g_strdup_printf ("preroll_%s_%s", prename, padname);
-  preroll = gst_element_factory_make ("queue", name);
-  g_free (name);
-  g_free (padname);
-
-  /* for buffering of raw data we ideally want to buffer a
-   * very small amount of buffers since the memory used by
-   * this raw data can be enormously huge.
-   *
-   * We use an upper limit of typically a few seconds here but
-   * cap in case no timestamps are set on the raw data (bad!).
-   *
-   * FIXME: we abuse this buffer to do network buffering since
-   * we can then easily do time-based buffering. The better
-   * solution would be to add a specific network queue right
-   * after the source that measures the datarate and scales this
-   * queue of encoded data instead.
-   */
-  if (play_base_bin->raw_decoding_mode) {
-    if (type == GST_STREAM_TYPE_VIDEO) {
-      g_object_set (G_OBJECT (preroll),
-          "max-size-buffers", 2, "max-size-bytes", 0,
-          "max-size-time", (guint64) 0, NULL);
-    } else {
-      g_object_set (G_OBJECT (preroll),
-          "max-size-buffers", 0, "max-size-bytes",
-          2 * 1024 * 1024, "max-size-time", play_base_bin->queue_size, NULL);
-    }
-  } else {
-    g_object_set (G_OBJECT (preroll),
-        "max-size-buffers", 0, "max-size-bytes",
-        ((type == GST_STREAM_TYPE_VIDEO) ? 25 : 2) * 1024 * 1024,
-        "max-size-time", play_base_bin->queue_size, NULL);
-  }
-
-  /* the overrun signal is always attached and serves two purposes:
-   *
-   *  1) when we are building a group and the overrun is called, we commit the
-   *     group. The reason being that if we fill the entire queue without a
-   *     normal group commit (with _no_more_pads()) we can assume the
-   *     audio/video is completely wacked or the element just does not know when
-   *     it is ready with all the pads (mpeg).
-   *  2) When we are doing network buffering, we keep track of low/high
-   *     watermarks in the queue. It is possible that we set the high watermark
-   *     higher than the max-size limits to trigger an overrun. In this case we
-   *     will never get a running signal but we can use the overrun signal to
-   *     detect this deadlock and correct it.
-   */
-  overrun_sig = g_signal_connect (G_OBJECT (preroll), "overrun",
-      G_CALLBACK (queue_overrun), play_base_bin);
-
-  /* keep a ref to the signal id so that we can disconnect the signal callback
-   * when we are done with the preroll */
-  g_object_set_data (G_OBJECT (preroll), "overrun_signal_id",
-      GINT_TO_POINTER (overrun_sig));
-
-  if (play_base_bin->is_stream &&
-      ((type == GST_STREAM_TYPE_VIDEO &&
-              group->type[GST_STREAM_TYPE_AUDIO - 1].npads == 0) ||
-          (type == GST_STREAM_TYPE_AUDIO &&
-              group->type[GST_STREAM_TYPE_VIDEO - 1].npads == 0))) {
-    GstPad *sinkpad;
-    guint id;
-
-    /* catch deadlocks when we are network buffering in time but the max-limit
-     * in bytes is hit. */
-    g_signal_connect (G_OBJECT (preroll), "overrun",
-        G_CALLBACK (queue_deadlock_check), play_base_bin);
-
-    /* attach pointer to playbasebin */
-    g_object_set_data (G_OBJECT (preroll), "pbb", play_base_bin);
-
-    /* give updates on queue size */
-    sinkpad = gst_element_get_static_pad (preroll, "sink");
-    id = gst_pad_add_probe (sinkpad, GST_PROBE_TYPE_BUFFER, check_queue,
-        preroll, NULL);
-    GST_DEBUG_OBJECT (play_base_bin, "Attaching probe to pad %s:%s (%p)",
-        GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
-    g_object_set_data (G_OBJECT (preroll), "probe", GINT_TO_POINTER (id));
-
-    /* catch eos and flush events so that we can ignore underruns */
-    id = gst_pad_add_probe (sinkpad, GST_PROBE_TYPE_EVENT, check_queue_event,
-        preroll, NULL);
-    g_object_set_data (G_OBJECT (preroll), "eos_probe", GINT_TO_POINTER (id));
-
-    gst_object_unref (sinkpad);
-
-    /* When we connect this queue, it will start running and immediatly
-     * fire an underrun. */
-    g_signal_connect (G_OBJECT (preroll), "underrun",
-        G_CALLBACK (queue_out_of_data), play_base_bin);
-    /* configure threshold and callbacks */
-    queue_out_of_data (preroll, play_base_bin);
-  }
-
-  /* listen for EOS so we can switch groups when one ended. */
-  preroll_pad = gst_element_get_static_pad (preroll, "src");
-  gst_pad_add_probe (preroll_pad, GST_PROBE_TYPE_EVENT, probe_triggered, info,
-      NULL);
-  gst_object_unref (preroll_pad);
-
-  /* add to group list */
-  group->type[type - 1].selector = selector;
-  group->type[type - 1].preroll = preroll;
-
-  /* figure out where the preroll element should go */
-  if (type == GST_STREAM_TYPE_TEXT && play_base_bin->subtitle)
-    target = GST_BIN_CAST (play_base_bin->subtitle);
-  else
-    target = GST_BIN_CAST (play_base_bin);
-
-  group->type[type - 1].bin = target;
-  gst_bin_add (target, selector);
-  gst_bin_add (target, preroll);
-
-  gst_element_link (selector, preroll);
-
-  /* figure out target state and set */
-  state = (GST_STATE (play_base_bin) == GST_STATE_PLAYING ?
-      GST_STATE_PLAYING : GST_STATE_PAUSED);
-
-  gst_element_set_state (selector, state);
-  gst_element_set_state (preroll, state);
-}
-
-static void
-preroll_remove_overrun (GstElement * element, GstPlayBaseBin * play_base_bin)
-{
-  guint overrun_sig;
-  GObject *obj = G_OBJECT (element);
-
-  overrun_sig = GPOINTER_TO_INT (g_object_get_data (obj, "overrun_signal_id"));
-  if (overrun_sig) {
-    GST_LOG_OBJECT (play_base_bin, "removing preroll signal %s",
-        GST_ELEMENT_NAME (element));
-    g_signal_handler_disconnect (obj, overrun_sig);
-    /* We have disconnected this signal, remove the signal_id from the object
-     * data */
-    g_object_set_data (obj, "overrun_signal_id", NULL);
-  }
-}
-
-static void
-remove_groups (GstPlayBaseBin * play_base_bin)
-{
-  GROUP_LOCK (play_base_bin);
-
-  /* first destroy the group we were building if any */
-  if (play_base_bin->building_group) {
-    group_destroy (play_base_bin->building_group);
-    play_base_bin->building_group = NULL;
-  }
-
-  /* remove the queued groups */
-  g_list_foreach (play_base_bin->queued_groups, (GFunc) group_destroy, NULL);
-  g_list_free (play_base_bin->queued_groups);
-  play_base_bin->queued_groups = NULL;
-
-  /* clear subs */
-  if (play_base_bin->subtitle) {
-    gst_element_set_state (play_base_bin->subtitle, GST_STATE_NULL);
-    gst_bin_remove (GST_BIN_CAST (play_base_bin), play_base_bin->subtitle);
-    play_base_bin->subtitle = NULL;
-  }
-
-  GROUP_UNLOCK (play_base_bin);
-}
-
-/*
- * Add/remove a single stream to current building group.
- *
- * Must be called with group-lock held.
- */
-static void
-add_stream (GstPlayBaseGroup * group, GstStreamInfo * info)
-{
-  GValue v = { 0, };
-  GST_DEBUG ("add stream to group %p", group);
-
-  /* keep ref to the group */
-  g_object_set_data (G_OBJECT (info), "group", group);
-
-  g_value_init (&v, G_TYPE_OBJECT);
-  g_value_set_object (&v, info);
-  g_value_array_append (group->streaminfo_value_array, &v);
-  g_value_unset (&v);
-  group->streaminfo = g_list_append (group->streaminfo, info);
-  if (info->type > 0 && info->type <= NUM_TYPES) {
-    group->type[info->type - 1].npads++;
-  }
-}
-
-static gboolean
-string_arr_has_str (const gchar * values[], const gchar * value)
-{
-  if (values && value) {
-    while (*values != NULL) {
-      if (strcmp (value, *values) == 0)
-        return TRUE;
-      ++values;
-    }
-  }
-  return FALSE;
-}
-
-/* mime types we are not handling on purpose right now, don't post a
- * missing-plugin message for these */
-static const gchar *blacklisted_mimes[] = {
-  "video/x-dvd-subpicture", NULL
-};
-
-#define IS_BLACKLISTED_MIME(type) (string_arr_has_str(blacklisted_mimes,type))
-
-static void
-gst_play_base_bin_handle_message_func (GstBin * bin, GstMessage * msg)
-{
-  if (gst_is_missing_plugin_message (msg)) {
-    gchar *detail;
-    guint i;
-
-    detail = gst_missing_plugin_message_get_installer_detail (msg);
-    for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
-      if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
-        GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
-        gst_message_unref (msg);
-        g_free (detail);
-        return;
-      }
-    }
-    g_free (detail);
-  }
-  GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
-}
-
-/*
- * signal fired when an unknown stream is found. We create a new
- * UNKNOWN streaminfo object.
- */
-static void
-unknown_type (GstElement * element, GstPad * pad, GstCaps * caps,
-    GstPlayBaseBin * play_base_bin)
-{
-  const gchar *type_name;
-  GstStreamInfo *info;
-  GstPlayBaseGroup *group;
-
-  type_name = gst_structure_get_name (gst_caps_get_structure (caps, 0));
-  if (type_name && !IS_BLACKLISTED_MIME (type_name)) {
-    gchar *capsstr;
-
-    capsstr = gst_caps_to_string (caps);
-    GST_DEBUG_OBJECT (play_base_bin, "don't know how to handle %s", capsstr);
-    /* FIXME, g_message() ? */
-    g_message ("don't know how to handle %s", capsstr);
-    g_free (capsstr);
-  } else {
-    /* don't spew stuff to the terminal or send message if it's blacklisted */
-    GST_DEBUG_OBJECT (play_base_bin, "media type %s not handled on purpose, "
-        "not posting a missing-plugin message on the bus", type_name);
-  }
-
-  GROUP_LOCK (play_base_bin);
-
-  group = get_building_group (play_base_bin);
-
-  /* add the stream to the list */
-  info = gst_stream_info_new (GST_OBJECT_CAST (pad), GST_STREAM_TYPE_UNKNOWN,
-      NULL, caps);
-  info->origin = GST_OBJECT_CAST (pad);
-  add_stream (group, info);
-
-  GROUP_UNLOCK (play_base_bin);
-}
-
-/* add a streaminfo that indicates that the stream is handled by the
- * given element. This usually means that a stream without actual data is
- * produced but one that is sunken by an element. Examples of this are:
- * cdaudio, a hardware decoder/sink, dvd meta bins etc...
- */
-static void
-add_element_stream (GstElement * element, GstPlayBaseBin * play_base_bin)
-{
-  GstStreamInfo *info;
-  GstPlayBaseGroup *group;
-
-  GROUP_LOCK (play_base_bin);
-
-  group = get_building_group (play_base_bin);
-
-  /* add the stream to the list */
-  info =
-      gst_stream_info_new (GST_OBJECT_CAST (element), GST_STREAM_TYPE_ELEMENT,
-      NULL, NULL);
-  info->origin = GST_OBJECT_CAST (element);
-  add_stream (group, info);
-
-  GROUP_UNLOCK (play_base_bin);
-}
-
-/* when the decoder element signals that no more pads will be generated, we
- * can commit the current group.
- */
-static void
-no_more_pads_full (GstElement * element, gboolean subs,
-    GstPlayBaseBin * play_base_bin)
-{
-  /* setup phase */
-  GST_DEBUG_OBJECT (element, "no more pads, %d pending",
-      play_base_bin->pending);
-
-  /* nothing pending, we can exit */
-  if (play_base_bin->pending == 0)
-    return;
-
-  /* the object has no pending no_more_pads */
-  if (!g_object_get_data (G_OBJECT (element), "pending"))
-    return;
-
-  g_object_set_data (G_OBJECT (element), "pending", NULL);
-
-  play_base_bin->pending--;
-
-  GST_DEBUG_OBJECT (element, "remove pending, now %d pending",
-      play_base_bin->pending);
-
-  if (play_base_bin->pending == 0) {
-    /* we can commit this group for playback now */
-    group_commit (play_base_bin, play_base_bin->is_stream, subs);
-  }
-}
-
-static void
-no_more_pads (GstElement * element, GstPlayBaseBin * play_base_bin)
-{
-  no_more_pads_full (element, FALSE, play_base_bin);
-}
-
-static void
-sub_no_more_pads (GstElement * element, GstPlayBaseBin * play_base_bin)
-{
-  no_more_pads_full (element, TRUE, play_base_bin);
-}
-
-static void
-source_no_more_pads (GstElement * element, GstPlayBaseBin * 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);
-  bin->src_np_sig_id = 0;
-  g_signal_handler_disconnect (G_OBJECT (element), bin->src_nmp_sig_id);
-  bin->src_nmp_sig_id = 0;
-
-  no_more_pads_full (element, FALSE, bin);
-}
-
-static GstProbeReturn
-probe_triggered (GstPad * pad, GstProbeType type, gpointer type_data,
-    gpointer user_data)
-{
-  GstEvent *event = type_data;
-  GstPlayBaseGroup *group;
-  GstPlayBaseBin *play_base_bin;
-  GstStreamInfo *info;
-  GstEventType etype;
-
-  etype = GST_EVENT_TYPE (event);
-
-  GST_LOG ("probe triggered, (%d) %s", type, gst_event_type_get_name (type));
-
-  /* we only care about EOS */
-  if (etype != GST_EVENT_EOS)
-    return GST_PROBE_OK;
-
-  info = GST_STREAM_INFO (user_data);
-  group = (GstPlayBaseGroup *) g_object_get_data (G_OBJECT (info), "group");
-  play_base_bin = group->bin;
-
-  if (etype == GST_EVENT_EOS) {
-    gint num_groups = 0;
-    gboolean have_left;
-
-    GST_DEBUG_OBJECT (play_base_bin, "probe got EOS in group %p", group);
-
-    GROUP_LOCK (play_base_bin);
-
-    /* mute this stream */
-    g_object_set (G_OBJECT (info), "mute", TRUE, NULL);
-    if (info->type > 0 && info->type <= NUM_TYPES)
-      group->type[info->type - 1].done = TRUE;
-
-    /* see if we have some more groups left to play */
-    num_groups = g_list_length (play_base_bin->queued_groups);
-    if (play_base_bin->building_group)
-      num_groups++;
-    have_left = (num_groups > 1);
-
-    /* see if the complete group is muted */
-    if (!group_is_muted (group)) {
-      /* group is not completely muted, we remove the EOS event
-       * and continue, eventually the other streams will be EOSed and
-       * we can switch out this group. */
-      GST_DEBUG ("group %p not completely muted", group);
-
-      GROUP_UNLOCK (play_base_bin);
-
-      /* remove the EOS if we have something left */
-      return (have_left ? GST_PROBE_DROP : GST_PROBE_OK);
-    }
-
-    if (have_left) {
-      /* ok, get rid of the current group then */
-      //group_destroy (group);
-      /* removing the current group brings the next group
-       * active */
-      play_base_bin->queued_groups =
-          g_list_remove (play_base_bin->queued_groups, group);
-      /* and wait for the next one to be ready */
-      while (!play_base_bin->queued_groups) {
-        GROUP_WAIT (play_base_bin);
-      }
-      group = play_base_bin->queued_groups->data;
-
-      /* now activate the next one */
-      setup_substreams (play_base_bin);
-      GST_DEBUG ("switching to next group %p - emitting signal", group);
-      /* and signal the new group */
-      GST_PLAY_BASE_BIN_GET_CLASS (play_base_bin)->setup_output_pads
-          (play_base_bin, group);
-
-      GROUP_UNLOCK (play_base_bin);
-
-      g_object_notify (G_OBJECT (play_base_bin), "stream-info");
-
-      /* get rid of the EOS event */
-      return GST_PROBE_DROP;
-    } else {
-      GROUP_UNLOCK (play_base_bin);
-      GST_LOG ("Last group done, EOS");
-    }
-  }
-
-  return GST_PROBE_OK;
-}
-
-/* This function will be called when the sinkpad of the preroll element
- * is unlinked, we have to connect something to the sinkpad or else the
- * state change will fail..
- */
-static void
-preroll_unlinked (GstPad * pad, GstPad * peerpad,
-    GstPlayBaseBin * play_base_bin)
-{
-  GstElement *fakesrc;
-  guint sig_id;
-  GstPad *srcpad;
-
-  /* make a fakesrc that will just emit one EOS */
-  fakesrc = gst_element_factory_make ("fakesrc", NULL);
-  g_object_set (G_OBJECT (fakesrc), "num-buffers", 0, NULL);
-
-  GST_DEBUG ("patching unlinked pad %s:%s", GST_DEBUG_PAD_NAME (pad));
-
-  srcpad = gst_element_get_static_pad (fakesrc, "src");
-  gst_bin_add (GST_BIN_CAST (play_base_bin), fakesrc);
-  gst_pad_link (srcpad, pad);
-  gst_object_unref (srcpad);
-
-  /* keep track of these patch elements */
-  g_object_set_data (G_OBJECT (pad), "fakesrc", fakesrc);
-
-  /* now unlink the unlinked signal so that it is not called again when
-   * we destroy the queue */
-  sig_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pad), "unlinked_id"));
-  if (sig_id != 0) {
-    g_signal_handler_disconnect (G_OBJECT (pad), sig_id);
-    g_object_set_data (G_OBJECT (pad), "unlinked_id", GINT_TO_POINTER (0));
-  }
-}
-
-/* Mute stream on first data - for header-is-in-stream-stuff
- * (vorbis, ogmtext). */
-static GstProbeReturn
-mute_stream (GstPad * pad, GstProbeType type, gpointer type_data, gpointer data)
-{
-  GstStreamInfo *info = GST_STREAM_INFO (data);
-  guint id;
-
-  GST_DEBUG ("mute stream triggered");
-
-  g_object_set (G_OBJECT (info), "mute", TRUE, NULL);
-  id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (info), "mute_probe"));
-  g_object_set_data (G_OBJECT (info), "mute_probe", NULL);
-  if (id > 0)
-    gst_pad_remove_probe (GST_PAD_CAST (info->object), id);
-
-  /* no data */
-  return GST_PROBE_DROP;
-}
-
-/* Eat data. */
-static GstProbeReturn
-silence_stream (GstPad * pad, GstProbeType type, gpointer type_data,
-    gpointer user_data)
-{
-  GST_DEBUG ("silence stream triggered");
-
-  /* no data */
-  return GST_PROBE_DROP;
-}
-
-/* Called by the signal handlers when a decodebin (main or subtitle) has
- * found a new raw pad.  We create a preroll element if needed and the
- * appropriate streaminfo. Commits the group if there will be no more pads
- * from decodebin */
-static void
-new_decoded_pad_full (GstElement * element, GstPad * pad, gboolean last,
-    GstPlayBaseBin * play_base_bin, gboolean is_subs)
-{
-  GstStructure *structure;
-  const gchar *mimetype;
-  GstCaps *caps;
-  GstStreamInfo *info;
-  GstStreamType type = GST_STREAM_TYPE_UNKNOWN;
-  GstPad *sinkpad;
-  GstPlayBaseGroup *group;
-  guint sig;
-  GstObject *parent;
-  gboolean first_pad;
-
-  GST_DEBUG ("play base: new decoded pad. Last: %d", last);
-
-  /* first see if this pad has interesting caps */
-  caps = gst_pad_get_caps (pad, NULL);
-  if (caps == NULL || gst_caps_is_empty (caps) || gst_caps_is_any (caps))
-    goto no_type;
-
-  /* get the mime type */
-  structure = gst_caps_get_structure (caps, 0);
-  mimetype = gst_structure_get_name (structure);
-
-  GROUP_LOCK (play_base_bin);
-
-  group = get_building_group (play_base_bin);
-
-  group->nstreams++;
-
-  parent = gst_object_get_parent (GST_OBJECT_CAST (element));
-  if (g_str_has_prefix (mimetype, "audio/") &&
-      parent != GST_OBJECT_CAST (play_base_bin->subtitle)) {
-    type = GST_STREAM_TYPE_AUDIO;
-  } else if (g_str_has_prefix (mimetype, "video/x-dvd-subpicture") &&
-      parent != GST_OBJECT_CAST (play_base_bin->subtitle)) {
-    type = GST_STREAM_TYPE_SUBPICTURE;
-  } else if (g_str_has_prefix (mimetype, "video/") &&
-      parent != GST_OBJECT_CAST (play_base_bin->subtitle)) {
-    type = GST_STREAM_TYPE_VIDEO;
-  } else if (g_str_has_prefix (mimetype, "text/")) {
-    type = GST_STREAM_TYPE_TEXT;
-  }
-  gst_object_unref (parent);
-
-  info = gst_stream_info_new (GST_OBJECT_CAST (pad), type, NULL, caps);
-  gst_caps_unref (caps);
-
-  if (type == GST_STREAM_TYPE_UNKNOWN) {
-    /* Unknown streams get added to the group, but the data
-     * just gets ignored */
-    add_stream (group, info);
-
-    GROUP_UNLOCK (play_base_bin);
-
-    /* signal the no more pads after adding the stream */
-    if (last)
-      no_more_pads_full (element, is_subs, play_base_bin);
-
-    return;
-  }
-
-  /* first pad of each type gets a selector + preroll queue */
-  first_pad = (group->type[type - 1].npads == 0);
-
-  if (first_pad) {
-    GST_DEBUG ("play base: pad needs new preroll");
-    gen_preroll_element (play_base_bin, group, type, pad, info);
-  }
-
-  /* add to stream selector */
-  sinkpad =
-      gst_element_get_request_pad (group->type[type - 1].selector, "sink%d");
-
-  /* make sure we catch unlink signals */
-  sig = g_signal_connect (G_OBJECT (sinkpad), "unlinked",
-      G_CALLBACK (preroll_unlinked), play_base_bin);
-  /* keep a ref to the signal id so that we can disconnect the signal callback */
-  g_object_set_data (G_OBJECT (sinkpad), "unlinked_id", GINT_TO_POINTER (sig));
-  /* Store a pointer to the stream selector pad for this stream */
-  g_object_set_data (G_OBJECT (pad), "pb_sel_pad", sinkpad);
-
-  gst_pad_link (pad, sinkpad);
-  gst_object_unref (sinkpad);
-
-  /* select 1st for now - we'll select a preferred one after preroll */
-  if (!first_pad) {
-    guint id;
-
-    GST_DEBUG ("Adding silence_stream data probe on type %d (npads %d)", type,
-        group->type[type - 1].npads);
-
-    id = gst_pad_add_probe (GST_PAD_CAST (pad), GST_PROBE_TYPE_DATA,
-        silence_stream, info, NULL);
-    g_object_set_data (G_OBJECT (pad), "eat_probe", GINT_TO_POINTER (id));
-  }
-
-  /* add the stream to the list */
-  add_stream (group, info);
-
-  GROUP_UNLOCK (play_base_bin);
-
-  /* signal the no more pads after adding the stream */
-  if (last)
-    no_more_pads_full (element, is_subs, play_base_bin);
-
-  return;
-
-  /* ERRORS */
-no_type:
-  {
-    g_warning ("no type on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
-    if (caps)
-      gst_caps_unref (caps);
-    return;
-  }
-}
-
-static void
-new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
-    GstPlayBaseBin * play_base_bin)
-{
-  new_decoded_pad_full (element, pad, last, play_base_bin, FALSE);
-}
-
-static void
-subs_new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
-    GstPlayBaseBin * play_base_bin)
-{
-  new_decoded_pad_full (element, pad, last, play_base_bin, TRUE);
-}
-
-static void
-set_encoding_element (GstElement * element, gchar * encoding)
-{
-  GST_DEBUG_OBJECT (element, "setting encoding to %s", GST_STR_NULL (encoding));
-  g_object_set (G_OBJECT (element), "subtitle-encoding", encoding, NULL);
-}
-
-
-static void
-decodebin_element_added_cb (GstBin * decodebin, GstElement * element,
-    gpointer data)
-{
-  GstPlayBaseBin *play_base_bin = GST_PLAY_BASE_BIN (data);
-  gchar *encoding;
-
-  if (!g_object_class_find_property (G_OBJECT_GET_CLASS (element),
-          "subtitle-encoding")) {
-    return;
-  }
-
-  g_mutex_lock (play_base_bin->sub_lock);
-  play_base_bin->subtitle_elements =
-      g_slist_append (play_base_bin->subtitle_elements, element);
-  encoding = g_strdup (play_base_bin->subencoding);
-  g_mutex_unlock (play_base_bin->sub_lock);
-
-  set_encoding_element (element, encoding);
-  g_free (encoding);
-}
-
-static void
-decodebin_element_removed_cb (GstBin * decodebin, GstElement * element,
-    gpointer data)
-{
-  GstPlayBaseBin *play_base_bin = GST_PLAY_BASE_BIN (data);
-
-  g_mutex_lock (play_base_bin->sub_lock);
-  play_base_bin->subtitle_elements =
-      g_slist_remove (play_base_bin->subtitle_elements, element);
-  g_mutex_unlock (play_base_bin->sub_lock);
-}
-
-
-/*
- * Generate source ! subparse bins.
- */
-
-static GstElement *
-setup_subtitle (GstPlayBaseBin * play_base_bin, gchar * sub_uri)
-{
-  GstElement *source, *subdecodebin, *subbin;
-
-  if (!gst_uri_is_valid (sub_uri))
-    goto invalid_uri;
-
-  source = gst_element_make_from_uri (GST_URI_SRC, sub_uri, NULL);
-  if (!source)
-    goto unknown_uri;
-
-  if (g_getenv ("USE_DECODEBIN2"))
-    subdecodebin = gst_element_factory_make ("decodebin2", "subtitle-decoder");
-  else
-    subdecodebin = gst_element_factory_make ("decodebin", "subtitle-decoder");
-  g_signal_connect (subdecodebin, "element-added",
-      G_CALLBACK (decodebin_element_added_cb), play_base_bin);
-  g_signal_connect (subdecodebin, "element-removed",
-      G_CALLBACK (decodebin_element_removed_cb), play_base_bin);
-  subbin = gst_bin_new ("subtitle-bin");
-  gst_bin_add_many (GST_BIN_CAST (subbin), source, subdecodebin, NULL);
-
-  gst_element_link (source, subdecodebin);
-
-  /* return the subtitle GstElement object */
-  return subbin;
-
-  /* WARNINGS */
-invalid_uri:
-  {
-    GST_ELEMENT_WARNING (play_base_bin, RESOURCE, NOT_FOUND,
-        (_("Invalid subtitle URI \"%s\", subtitles disabled."), sub_uri),
-        (NULL));
-    return NULL;
-  }
-unknown_uri:
-  {
-    gchar *prot = gst_uri_get_protocol (sub_uri);
-
-    if (prot) {
-      gchar *desc;
-
-      gst_element_post_message (GST_ELEMENT (play_base_bin),
-          gst_missing_uri_source_message_new (GST_ELEMENT (play_base_bin),
-              prot));
-
-      desc = gst_pb_utils_get_source_description (prot);
-      GST_ELEMENT_ERROR (play_base_bin, CORE, MISSING_PLUGIN,
-          (_("A %s plugin is required to play this stream, but not installed."),
-              desc), ("No URI handler to handle sub_uri: %s", sub_uri));
-      g_free (desc);
-      g_free (prot);
-    } else
-      goto invalid_uri;
-
-    return NULL;
-  }
-}
-
-/* helper function to lookup stuff in lists */
-static gboolean
-array_has_value (const gchar * values[], const gchar * value)
-{
-  gint i;
-
-  for (i = 0; values[i]; i++) {
-    if (g_str_has_prefix (value, values[i]))
-      return TRUE;
-  }
-  return FALSE;
-}
-
-/* list of URIs that we consider to be streams and that need buffering.
- * We have no mechanism yet to figure this out with a query. */
-static const gchar *stream_uris[] = { "http://", "mms://", "mmsh://",
-  "mmsu://", "mmst://", "myth://", NULL
-};
-
-/* blacklisted URIs, we know they will always fail. */
-static const gchar *blacklisted_uris[] = { NULL };
-
-/* mime types that we don't consider to be media types */
-static const gchar *no_media_mimes[] = {
-  "application/x-executable", "application/x-bzip", "application/x-gzip",
-  "application/zip", "application/x-compress", NULL
-};
-
-/* mime types we consider raw media */
-static const gchar *raw_mimes[] = {
-  "audio/x-raw", "video/x-raw", "video/x-dvd-subpicture", NULL
-};
-
-#define IS_STREAM_URI(uri)          (array_has_value (stream_uris, uri))
-#define IS_BLACKLISTED_URI(uri)     (array_has_value (blacklisted_uris, uri))
-#define IS_NO_MEDIA_MIME(mime)      (array_has_value (no_media_mimes, mime))
-#define IS_RAW_MIME(mime)           (array_has_value (raw_mimes, mime))
-
-/*
- * Generate and configure a source element.
- */
-static GstElement *
-gen_source_element (GstPlayBaseBin * play_base_bin, GstElement ** subbin)
-{
-  GstElement *source;
-
-  if (!play_base_bin->uri)
-    goto no_uri;
-
-  if (!gst_uri_is_valid (play_base_bin->uri))
-    goto invalid_uri;
-
-  if (IS_BLACKLISTED_URI (play_base_bin->uri))
-    goto uri_blacklisted;
-
-  if (play_base_bin->suburi) {
-    GST_LOG_OBJECT (play_base_bin, "Creating decoder for subtitles URI %s",
-        play_base_bin->suburi);
-    /* subtitle specified */
-    *subbin = setup_subtitle (play_base_bin, play_base_bin->suburi);
-  } else {
-    /* no subtitle specified */
-    *subbin = NULL;
-  }
-
-  source = gst_element_make_from_uri (GST_URI_SRC, play_base_bin->uri,
-      "source");
-  if (!source)
-    goto no_source;
-
-  play_base_bin->is_stream = IS_STREAM_URI (play_base_bin->uri);
-
-  /* make HTTP sources send extra headers so we get icecast
-   * metadata in case the stream is an icecast stream */
-  if (!strncmp (play_base_bin->uri, "http://", 7) &&
-      g_object_class_find_property (G_OBJECT_GET_CLASS (source),
-          "iradio-mode")) {
-    g_object_set (source, "iradio-mode", TRUE, NULL);
-  }
-
-  if (g_object_class_find_property (G_OBJECT_GET_CLASS (source),
-          "connection-speed")) {
-    GST_DEBUG_OBJECT (play_base_bin,
-        "setting connection-speed=%d to source element",
-        play_base_bin->connection_speed / 1000);
-    g_object_set (source, "connection-speed",
-        play_base_bin->connection_speed / 1000, NULL);
-  }
-
-  return source;
-
-  /* ERRORS */
-no_uri:
-  {
-    GST_ELEMENT_ERROR (play_base_bin, RESOURCE, NOT_FOUND,
-        (_("No URI specified to play from.")), (NULL));
-    return NULL;
-  }
-invalid_uri:
-  {
-    GST_ELEMENT_ERROR (play_base_bin, RESOURCE, NOT_FOUND,
-        (_("Invalid URI \"%s\"."), play_base_bin->uri), (NULL));
-    return NULL;
-  }
-uri_blacklisted:
-  {
-    GST_ELEMENT_ERROR (play_base_bin, RESOURCE, FAILED,
-        (_("RTSP streams cannot be played yet.")), (NULL));
-    return NULL;
-  }
-no_source:
-  {
-    gchar *prot = gst_uri_get_protocol (play_base_bin->uri);
-
-    /* whoops, could not create the source element, dig a little deeper to
-     * figure out what might be wrong. */
-    if (prot) {
-      gchar *desc;
-
-      gst_element_post_message (GST_ELEMENT (play_base_bin),
-          gst_missing_uri_source_message_new (GST_ELEMENT (play_base_bin),
-              prot));
-
-      desc = gst_pb_utils_get_source_description (prot);
-      GST_ELEMENT_ERROR (play_base_bin, CORE, MISSING_PLUGIN,
-          (_("A %s plugin is required to play this stream, but not installed."),
-              desc), ("No URI handler for %s", prot));
-      g_free (desc);
-      g_free (prot);
-    } else
-      goto invalid_uri;
-
-    return NULL;
-  }
-}
-
-/* is called when a dynamic source element created a new pad. */
-static void
-source_new_pad (GstElement * element, GstPad * pad, GstPlayBaseBin * bin)
-{
-  GstElement *decoder;
-  gboolean is_raw;
-
-  GST_DEBUG_OBJECT (bin, "Found new pad %s.%s in source element %s",
-      GST_DEBUG_PAD_NAME (pad), GST_ELEMENT_NAME (element));
-
-  /* if this is a pad with all raw caps, we can expose it */
-  if (has_all_raw_caps (pad, &is_raw) && is_raw) {
-    bin->raw_decoding_mode = TRUE;
-    /* it's all raw, create output pads. */
-    new_decoded_pad_full (element, pad, FALSE, bin, FALSE);
-    return;
-  }
-
-  /* not raw, create decoder */
-  decoder = make_decoder (bin);
-  if (!decoder)
-    goto no_decodebin;
-
-  /* and link to decoder */
-  if (!gst_element_link (bin->source, decoder))
-    goto could_not_link;
-
-  gst_element_set_state (decoder, GST_STATE_PAUSED);
-
-  return;
-
-  /* ERRORS */
-no_decodebin:
-  {
-    /* error was posted */
-    return;
-  }
-could_not_link:
-  {
-    GST_ELEMENT_ERROR (bin, CORE, NEGOTIATION,
-        (NULL), ("Can't link source to decoder element"));
-    return;
-  }
-}
-
-/*
- * Setup the substreams (is called right after group_commit () when
- * loading a new group, or after switching groups).
- *
- * Should be called with group-lock held.
- */
-static void
-setup_substreams (GstPlayBaseBin * play_base_bin)
-{
-  GstPlayBaseGroup *group;
-  gint n;
-  const GList *item;
-
-  GST_DEBUG_OBJECT (play_base_bin, "setting up substreams");
-
-  /* Remove the eat probes */
-  group = get_active_group (play_base_bin);
-  for (item = group->streaminfo; item; item = item->next) {
-    GstStreamInfo *info = item->data;
-    gpointer data;
-
-    data = g_object_get_data (G_OBJECT (info->object), "eat_probe");
-    if (data) {
-      gst_pad_remove_probe (GST_PAD_CAST (info->object),
-          GPOINTER_TO_INT (data));
-      g_object_set_data (G_OBJECT (info->object), "eat_probe", NULL);
-    }
-
-    /* now remove unknown pads */
-    if (info->type == GST_STREAM_TYPE_UNKNOWN) {
-      guint id;
-
-      id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (info), "mute_probe"));
-      if (id == 0) {
-        id = gst_pad_add_probe (GST_PAD_CAST (info->object),
-            GST_PROBE_TYPE_BUFFER, mute_stream, info, NULL);
-        g_object_set_data (G_OBJECT (info), "mute_probe", GINT_TO_POINTER (id));
-      }
-    }
-  }
-
-  /* now check if the requested current streams exist. If
-   * current >= num_streams, decrease current so at least
-   * we have output. Always keep it enabled. */
-  for (n = 0; n < NUM_TYPES; n++) {
-    if (play_base_bin->current[n] >= group->type[n].npads) {
-      GST_DEBUG_OBJECT (play_base_bin, "reset type %d to current 0", n);
-      play_base_bin->current[n] = 0;
-    }
-  }
-
-  /* now activate the right sources. Don't forget that during preroll,
-   * we set the first source to forwarding and ignored the rest. */
-  for (n = 0; n < NUM_TYPES; n++) {
-    GST_DEBUG_OBJECT (play_base_bin, "setting type %d to current %d", n,
-        play_base_bin->current[n]);
-    set_active_source (play_base_bin, n + 1, play_base_bin->current[n]);
-  }
-}
-
-/**
- * has_all_raw_caps:
- * @pad: a #GstPad
- * @all_raw: pointer to hold the result
- *
- * check if the caps of the pad are all raw. The caps are all raw if
- * all of its structures contain audio/x-raw or video/x-raw.
- *
- * 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)
-{
-  GstCaps *caps;
-  gint capssize;
-  guint i, num_raw = 0;
-  gboolean res = FALSE;
-
-  caps = gst_pad_get_caps (pad, NULL);
-  if (caps == NULL)
-    return FALSE;
-
-  capssize = gst_caps_get_size (caps);
-  /* no caps, skip and move to the next pad */
-  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 *mime_type;
-
-    s = gst_caps_get_structure (caps, i);
-    mime_type = gst_structure_get_name (s);
-
-    if (IS_RAW_MIME (mime_type))
-      ++num_raw;
-  }
-
-  *all_raw = (num_raw == capssize);
-  res = TRUE;
-
-done:
-  gst_caps_unref (caps);
-  return res;
-}
-
-/**
- * analyse_source:
- * @play_base_bin: a #GstPlayBaseBin
- * @is_raw: are all pads raw data
- * @have_out: does the source have output
- * @is_dynamic: is this a dynamic source
- *
- * Check the source of @play_base_bin and collect information about it.
- *
- * @is_raw will be set to TRUE if the source only produces raw pads. When this
- * function returns, all of the raw pad of the source will be added
- * to @play_base_bin.
- *
- * @have_out: will be set to TRUE if the source has output pads.
- *
- * @is_dynamic: TRUE if the element will create (more) pads dynamically later
- * on.
- *
- * Returns: FALSE if a fatal error occured while scanning.
- */
-static gboolean
-analyse_source (GstPlayBaseBin * play_base_bin, gboolean * is_raw,
-    gboolean * have_out, gboolean * is_dynamic)
-{
-  GstIterator *pads_iter;
-  gboolean done = FALSE;
-  gboolean res = TRUE;
-  GValue item = { 0, };
-
-  *have_out = FALSE;
-  *is_raw = FALSE;
-  *is_dynamic = FALSE;
-
-  pads_iter = gst_element_iterate_src_pads (play_base_bin->source);
-  while (!done) {
-    GstPad *pad = NULL;
-
-    switch (gst_iterator_next (pads_iter, &item)) {
-      case GST_ITERATOR_ERROR:
-        res = FALSE;
-        /* FALLTROUGH */
-      case GST_ITERATOR_DONE:
-        done = TRUE;
-        break;
-      case GST_ITERATOR_RESYNC:
-        /* reset results and resync */
-        *have_out = FALSE;
-        *is_raw = FALSE;
-        *is_dynamic = FALSE;
-        gst_iterator_resync (pads_iter);
-        break;
-      case GST_ITERATOR_OK:
-        pad = g_value_get_object (&item);
-        /* we now officially have an ouput pad */
-        *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)) {
-          g_value_reset (&item);
-          break;
-        }
-
-        /* caps on source pad are all raw, we can add the pad */
-        if (*is_raw) {
-          new_decoded_pad_full (play_base_bin->source, pad, FALSE,
-              play_base_bin, FALSE);
-        }
-
-        g_value_reset (&item);
-        break;
-    }
-  }
-  g_value_unset (&item);
-  gst_iterator_free (pads_iter);
-
-  if (!*have_out) {
-    GstElementClass *elemclass;
-    GList *walk;
-
-    /* element has no output pads, check for padtemplates that list SOMETIMES
-     * pads. */
-    elemclass = GST_ELEMENT_GET_CLASS (play_base_bin->source);
-
-    walk = gst_element_class_get_pad_template_list (elemclass);
-    while (walk != NULL) {
-      GstPadTemplate *templ;
-
-      templ = (GstPadTemplate *) walk->data;
-      if (GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC) {
-        if (GST_PAD_TEMPLATE_PRESENCE (templ) == GST_PAD_SOMETIMES) {
-          *is_dynamic = TRUE;
-          break;                /* only break out if we found a sometimes src pad
-                                   continue walking through if say a request src pad is found
-                                   elements such as mpegtsparse and dvbbasebin have request
-                                   and sometimes src pads */
-        }
-      }
-      walk = g_list_next (walk);
-    }
-  }
-
-  return res;
-}
-
-static void
-remove_decoders (GstPlayBaseBin * bin)
-{
-  GSList *walk;
-
-  for (walk = bin->decoders; walk; walk = g_slist_next (walk)) {
-    GstElement *decoder = GST_ELEMENT_CAST (walk->data);
-
-    GST_DEBUG_OBJECT (bin, "removing old decoder element");
-    /* Disconnect all the signal handlers we attached to the decodebin before
-     * we dispose of it */
-    g_signal_handlers_disconnect_by_func (decoder,
-        (gpointer) (decodebin_element_added_cb), bin);
-    g_signal_handlers_disconnect_by_func (decoder,
-        (gpointer) (decodebin_element_removed_cb), bin);
-    g_signal_handlers_disconnect_by_func (decoder,
-        (gpointer) (new_decoded_pad), bin);
-    g_signal_handlers_disconnect_by_func (decoder,
-        (gpointer) (no_more_pads), bin);
-    g_signal_handlers_disconnect_by_func (decoder,
-        (gpointer) (unknown_type), bin);
-
-    gst_element_set_state (decoder, GST_STATE_NULL);
-    gst_bin_remove (GST_BIN_CAST (bin), decoder);
-  }
-  g_slist_free (bin->decoders);
-  bin->decoders = NULL;
-}
-
-static GstElement *
-make_decoder (GstPlayBaseBin * play_base_bin)
-{
-  GstElement *decoder;
-
-  /* now create the decoder element */
-  if (g_getenv ("USE_DECODEBIN2"))
-    decoder = gst_element_factory_make ("decodebin2", NULL);
-  else
-    decoder = gst_element_factory_make ("decodebin", NULL);
-  if (!decoder)
-    goto no_decodebin;
-
-  g_signal_connect (decoder, "element-added",
-      G_CALLBACK (decodebin_element_added_cb), play_base_bin);
-  g_signal_connect (decoder, "element-removed",
-      G_CALLBACK (decodebin_element_removed_cb), play_base_bin);
-
-  gst_bin_add (GST_BIN_CAST (play_base_bin), decoder);
-
-  /* set up callbacks to create the links between decoded data
-   * and video/audio/subtitle rendering/output. */
-  g_signal_connect (G_OBJECT (decoder),
-      "new-decoded-pad", G_CALLBACK (new_decoded_pad), play_base_bin);
-  g_signal_connect (G_OBJECT (decoder), "no-more-pads",
-      G_CALLBACK (no_more_pads), play_base_bin);
-  g_signal_connect (G_OBJECT (decoder),
-      "unknown-type", G_CALLBACK (unknown_type), play_base_bin);
-  g_object_set_data (G_OBJECT (decoder), "pending", GINT_TO_POINTER (1));
-  play_base_bin->pending++;
-
-  GST_DEBUG_OBJECT (play_base_bin, "created decodebin, %d pending",
-      play_base_bin->pending);
-
-  play_base_bin->decoders = g_slist_prepend (play_base_bin->decoders, decoder);
-
-  return decoder;
-
-  /* ERRORS */
-no_decodebin:
-  {
-    GST_ELEMENT_ERROR (play_base_bin, CORE, MISSING_PLUGIN,
-        (_("Could not create \"decodebin\" element.")), (NULL));
-    return NULL;
-  }
-}
-
-static void
-remove_source (GstPlayBaseBin * bin)
-{
-  GstElement *source = bin->source;
-
-  if (source) {
-    GST_DEBUG_OBJECT (bin, "removing old src element");
-    gst_element_set_state (source, GST_STATE_NULL);
-
-    if (bin->src_np_sig_id) {
-      g_signal_handler_disconnect (G_OBJECT (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);
-      bin->src_nmp_sig_id = 0;
-    }
-    gst_bin_remove (GST_BIN_CAST (bin), source);
-    bin->source = NULL;
-  }
-}
-
-static GstBusSyncReply
-subbin_startup_sync_msg (GstBus * bus, GstMessage * msg, gpointer user_data)
-{
-  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
-    GstPlayBaseBin *play_base_bin;
-
-    play_base_bin = GST_PLAY_BASE_BIN (user_data);
-    if (!play_base_bin->subtitle_done) {
-      GST_WARNING_OBJECT (play_base_bin, "error starting up subtitle bin: %"
-          GST_PTR_FORMAT, msg);
-      play_base_bin->subtitle_done = TRUE;
-      GST_DEBUG_OBJECT (play_base_bin, "signal group done");
-      GROUP_SIGNAL (play_base_bin);
-      GST_DEBUG_OBJECT (play_base_bin, "signaled group done");
-    }
-  }
-  return GST_BUS_PASS;
-}
-
-/* construct and run the source and decoder elements until we found
- * all the streams or until a preroll queue has been filled.
-*/
-static gboolean
-setup_source (GstPlayBaseBin * play_base_bin)
-{
-  GstElement *subbin = NULL;
-  gboolean is_raw, have_out, is_dynamic;
-
-  if (!play_base_bin->need_rebuild)
-    return TRUE;
-  play_base_bin->raw_decoding_mode = FALSE;
-
-  GST_DEBUG_OBJECT (play_base_bin, "setup source");
-
-  /* delete old src */
-  remove_source (play_base_bin);
-
-  /* create and configure an element that can handle the uri */
-  if (!(play_base_bin->source = gen_source_element (play_base_bin, &subbin)))
-    goto no_source;
-
-  /* state will be merged later - if file is not found, error will be
-   * handled by the application right after. */
-  gst_bin_add (GST_BIN_CAST (play_base_bin), play_base_bin->source);
-  g_object_notify (G_OBJECT (play_base_bin), "source");
-
-  /* remove the old decoders now, if any */
-  remove_decoders (play_base_bin);
-
-  /* remove our previous preroll queues */
-  remove_groups (play_base_bin);
-
-  /* clear pending dynamic elements */
-  play_base_bin->pending = 0;
-
-  /* do subs */
-  if (subbin) {
-    GstElement *db;
-    GstBus *bus;
-
-    play_base_bin->subtitle = subbin;
-    db = gst_bin_get_by_name (GST_BIN_CAST (subbin), "subtitle-decoder");
-
-    /* do type detection, without adding (so no preroll) */
-    g_signal_connect (G_OBJECT (db), "new-decoded-pad",
-        G_CALLBACK (subs_new_decoded_pad), play_base_bin);
-    g_signal_connect (G_OBJECT (db), "no-more-pads",
-        G_CALLBACK (sub_no_more_pads), play_base_bin);
-    g_signal_connect (G_OBJECT (db), "unknown-type",
-        G_CALLBACK (unknown_type), play_base_bin);
-    g_object_set_data (G_OBJECT (db), "pending", GINT_TO_POINTER (1));
-    play_base_bin->pending++;
-
-    GST_DEBUG_OBJECT (play_base_bin, "we have subtitles, %d pending",
-        play_base_bin->pending);
-
-    if (!play_base_bin->is_stream) {
-      GstStateChangeReturn sret;
-
-      /* either when the queues are filled or when the decoder element
-       * has no more dynamic streams, the cond is unlocked. We can remove
-       * the signal handlers then
-       */
-      GST_DEBUG_OBJECT (play_base_bin, "starting subtitle bin");
-
-      /* for subtitles in a separate bin we will not commit the
-       * current building group since we need to add the other
-       * audio/video streams to the group. We check if we managed
-       * to commit the subtitle group using an extra flag. */
-      play_base_bin->subtitle_done = FALSE;
-
-      /* since subbin is still a stand-alone bin, we need to add a custom bus
-       * to intercept error messages, so we can stop waiting and continue */
-      bus = gst_bus_new ();
-      gst_element_set_bus (subbin, bus);
-      gst_bus_set_sync_handler (bus, subbin_startup_sync_msg, play_base_bin);
-
-      sret = gst_element_set_state (subbin, GST_STATE_PAUSED);
-      if (sret != GST_STATE_CHANGE_FAILURE) {
-        GROUP_LOCK (play_base_bin);
-        GST_DEBUG ("waiting for subtitle to complete...");
-        while (!play_base_bin->subtitle_done)
-          GROUP_WAIT (play_base_bin);
-        GST_DEBUG ("group done !");
-        GROUP_UNLOCK (play_base_bin);
-
-        if (!play_base_bin->building_group ||
-            play_base_bin->building_group->type[GST_STREAM_TYPE_TEXT -
-                1].npads == 0) {
-
-          GST_DEBUG ("No subtitle found - ignoring");
-          gst_element_set_state (subbin, GST_STATE_NULL);
-          gst_object_unref (play_base_bin->subtitle);
-          play_base_bin->subtitle = NULL;
-        } else {
-          GST_DEBUG_OBJECT (play_base_bin, "Subtitle set-up successful");
-        }
-      } else {
-        GST_WARNING_OBJECT (play_base_bin, "Failed to start subtitle bin");
-        gst_element_set_state (subbin, GST_STATE_NULL);
-        gst_object_unref (play_base_bin->subtitle);
-        play_base_bin->subtitle = NULL;
-      }
-
-      gst_bus_set_sync_handler (bus, NULL, NULL);
-      gst_element_set_bus (subbin, NULL);
-      gst_object_unref (bus);
-    }
-    gst_object_unref (db);
-  }
-  /* see if the source element emits raw audio/video all by itself,
-   * if so, we can create streams for the pads and be done with it.
-   * Also check that is has source pads, if not, we assume it will
-   * do everything itself.  */
-  if (!analyse_source (play_base_bin, &is_raw, &have_out, &is_dynamic))
-    goto invalid_source;
-
-  if (is_raw) {
-    GST_DEBUG_OBJECT (play_base_bin, "Source provides all raw data");
-    /* source provides raw data, we added the pads and we can now signal a
-     * no_more pads because we are done. */
-    group_commit (play_base_bin, play_base_bin->is_stream, FALSE);
-    return TRUE;
-  }
-  if (!have_out && !is_dynamic) {
-    GST_DEBUG_OBJECT (play_base_bin, "Source has no output pads");
-    /* create a stream to indicate that this uri is handled by a self
-     * contained element. We are now done. */
-    add_element_stream (play_base_bin->source, play_base_bin);
-    group_commit (play_base_bin, play_base_bin->is_stream, FALSE);
-    return TRUE;
-  }
-  if (is_dynamic) {
-    /* connect a handler for the new-pad signal */
-    play_base_bin->src_np_sig_id =
-        g_signal_connect (G_OBJECT (play_base_bin->source), "pad-added",
-        G_CALLBACK (source_new_pad), play_base_bin);
-    play_base_bin->src_nmp_sig_id =
-        g_signal_connect (G_OBJECT (play_base_bin->source), "no-more-pads",
-        G_CALLBACK (source_no_more_pads), play_base_bin);
-    g_object_set_data (G_OBJECT (play_base_bin->source), "pending",
-        GINT_TO_POINTER (1));
-    play_base_bin->pending++;
-    GST_DEBUG_OBJECT (play_base_bin,
-        "Source has dynamic output pads, %d pending", play_base_bin->pending);
-  } else {
-    GstElement *decoder;
-
-    /* no dynamic source, we can link now */
-    decoder = make_decoder (play_base_bin);
-    if (!decoder)
-      goto no_decodebin;
-
-    if (!gst_element_link (play_base_bin->source, decoder))
-      goto could_not_link;
-  }
-
-  if (play_base_bin->subtitle)
-    gst_bin_add (GST_BIN_CAST (play_base_bin), play_base_bin->subtitle);
-
-  play_base_bin->need_rebuild = FALSE;
-
-  return TRUE;
-
-  /* ERRORS */
-no_source:
-  {
-    /* error message was already posted */
-    return FALSE;
-  }
-invalid_source:
-  {
-    GST_ELEMENT_ERROR (play_base_bin, CORE, FAILED,
-        (_("Source element is invalid.")), (NULL));
-    return FALSE;
-  }
-no_decodebin:
-  {
-    /* message was posted */
-    return FALSE;
-  }
-could_not_link:
-  {
-    GST_ELEMENT_ERROR (play_base_bin, CORE, NEGOTIATION,
-        (NULL), ("Can't link source to decoder element"));
-    return FALSE;
-  }
-}
-
-static void
-finish_source (GstPlayBaseBin * play_base_bin)
-{
-  /* FIXME: no need to grab the group lock here? (tpm) */
-  if (get_active_group (play_base_bin) != NULL) {
-    if (play_base_bin->subtitle) {
-      /* make subs iterate from now on */
-      gst_bin_add (GST_BIN_CAST (play_base_bin), play_base_bin->subtitle);
-    }
-  }
-}
-
-/*
- * Caller must have group-lock held.
- *
- * We iterate over all detected streams in the streaminfo and try to find
- * impossible cases, like subtitles without video.
- */
-static gboolean
-prepare_output (GstPlayBaseBin * play_base_bin)
-{
-  const GList *item;
-  gboolean stream_found = FALSE, no_media = FALSE;
-  gboolean got_video = FALSE, got_subtitle = FALSE;
-  GstPlayBaseGroup *group;
-
-  group = get_active_group (play_base_bin);
-
-  /* check if we found any supported stream... if not, then
-   * we detected stream type (or the above would've failed),
-   * but linking/decoding failed - plugin probably missing. */
-  for (item = group ? group->streaminfo : NULL; item != NULL; item = item->next) {
-    GstStreamInfo *info = GST_STREAM_INFO (item->data);
-
-    if (info->type == GST_STREAM_TYPE_VIDEO) {
-      stream_found = TRUE;
-      got_video = TRUE;
-      break;
-    } else if (info->type == GST_STREAM_TYPE_ELEMENT) {
-      stream_found = TRUE;
-    } else if (info->type == GST_STREAM_TYPE_AUDIO) {
-      stream_found = TRUE;
-    } else if (info->type == GST_STREAM_TYPE_TEXT ||
-        info->type == GST_STREAM_TYPE_SUBPICTURE) {
-      got_subtitle = TRUE;
-    } else if (!item->prev && !item->next) {
-      /* We're no audio/video and the only stream... We could
-       * be something not-media that's detected because then our
-       * typefind doesn't mess up with mp3 (bz2, gz, elf, ...) */
-      if (info->caps && !gst_caps_is_empty (info->caps)) {
-        const gchar *mime =
-            gst_structure_get_name (gst_caps_get_structure (info->caps, 0));
-
-        no_media = IS_NO_MEDIA_MIME (mime);
-      }
-    }
-  }
-
-  if (!stream_found) {
-    if (got_subtitle) {
-      GST_ELEMENT_ERROR (play_base_bin, STREAM, WRONG_TYPE,
-          (_("Only a subtitle stream was detected. "
-                  "Either you are loading a subtitle file or some other type of "
-                  "text file, or the media file was not recognized.")), (NULL));
-    } else if (!no_media) {
-      GST_ELEMENT_ERROR (play_base_bin, STREAM, CODEC_NOT_FOUND,
-          (_("You do not have a decoder installed to handle this file. "
-                  "You might need to install the necessary plugins.")), (NULL));
-    } else {
-      GST_ELEMENT_ERROR (play_base_bin, STREAM, WRONG_TYPE,
-          (_("This is not a media file")), (NULL));
-    }
-    return FALSE;
-  } else if (got_subtitle && !got_video) {
-    GST_ELEMENT_ERROR (play_base_bin, STREAM, WRONG_TYPE,
-        (_("A subtitle stream was detected, but no video stream.")), (NULL));
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-/*
- * Multi-stream management. -1 = none.
- *
- * Caller has group-lock held.
- */
-static gint
-get_active_source (GstPlayBaseBin * play_base_bin, GstStreamType type)
-{
-  GstPlayBaseGroup *group;
-  GList *s;
-  gint num = 0;
-
-  group = get_active_group (play_base_bin);
-  if (!group)
-    return -1;
-
-  for (s = group->streaminfo; s; s = s->next) {
-    GstStreamInfo *info = s->data;
-
-    if (info->type == type) {
-      if (!info->mute && !g_object_get_data (G_OBJECT (info), "mute_probe")) {
-        return num;
-      } else {
-        num++;
-      }
-    }
-  }
-
-  return -1;
-}
-
-/* Kill pad reactivation on state change. */
-
-#if 0
-static void muted_group_change_state (GstElement * element,
-    gint old_state, gint new_state, gpointer data);
-#endif
-
-static void
-mute_group_type (GstPlayBaseGroup * group, GstStreamType type, gboolean mute)
-{
-  gboolean active = !mute;
-  GstPad *pad;
-
-  pad = gst_element_get_static_pad (group->type[type - 1].preroll, "src");
-  gst_pad_set_active (pad, active);
-  gst_object_unref (pad);
-  pad = gst_element_get_static_pad (group->type[type - 1].preroll, "sink");
-  gst_pad_set_active (pad, active);
-  gst_object_unref (pad);
-  pad = gst_element_get_static_pad (group->type[type - 1].selector, "src");
-  gst_pad_set_active (pad, active);
-  gst_object_unref (pad);
-
-#if 0
-  if (mute) {
-    g_signal_connect (group->type[type - 1].preroll, "state-changed",
-        G_CALLBACK (muted_group_change_state), group);
-  } else {
-    g_signal_handlers_disconnect_by_func (group->type[type - 1].preroll,
-        G_CALLBACK (muted_group_change_state), group);
-  }
-#endif
-}
-
-#if 0
-static void
-muted_group_change_state (GstElement * element,
-    gint old_state, gint new_state, gpointer data)
-{
-  GstPlayBaseGroup *group = data;
-
-  GROUP_LOCK (group->bin);
-
-  if (new_state == GST_STATE_PLAYING) {
-    gint n;
-
-    for (n = 0; n < NUM_TYPES; n++) {
-      if (group->type[n].selector == element) {
-        mute_group_type (group, n + 1, TRUE);
-      }
-    }
-  }
-
-  GROUP_UNLOCK (group->bin);
-}
-#endif
-
-static void
-set_subtitles_visible (GstPlayBaseBin * play_base_bin, gboolean visible)
-{
-  GstPlayBaseBinClass *klass = GST_PLAY_BASE_BIN_GET_CLASS (play_base_bin);
-
-  /* we use a vfunc for this since we don't have a reference to the
-   * textoverlay element, but playbin does */
-  if (klass != NULL && klass->set_subtitles_visible != NULL)
-    klass->set_subtitles_visible (play_base_bin, visible);
-}
-
-static void
-set_audio_mute (GstPlayBaseBin * play_base_bin, gboolean mute)
-{
-  GstPlayBaseBinClass *klass = GST_PLAY_BASE_BIN_GET_CLASS (play_base_bin);
-
-  /* we use a vfunc for this since we don't have a reference to the
-   * textoverlay element, but playbin does */
-  if (klass != NULL && klass->set_audio_mute != NULL)
-    klass->set_audio_mute (play_base_bin, mute);
-}
-
-/*
- * Caller has group-lock held.
- */
-
-static void
-set_active_source (GstPlayBaseBin * play_base_bin,
-    GstStreamType type, gint source_num)
-{
-  GstPlayBaseGroup *group;
-  GList *s;
-  gint num = 0;
-  gboolean have_active = FALSE;
-  GstElement *sel;
-
-  GST_LOG ("Changing active source of type %d to %d", type, source_num);
-  play_base_bin->current[type - 1] = source_num;
-
-  group = get_active_group (play_base_bin);
-  if (!group || !group->type[type - 1].preroll) {
-    GST_LOG ("No active group, or group for type %d has no preroll", type);
-    return;
-  }
-
-  /* HACK: instead of unlinking the subtitle input (= lots of hassle,
-   * especially if subtitles come from an external source), just tell
-   * textoverlay not to render them */
-  if (type == GST_STREAM_TYPE_TEXT) {
-    gboolean visible = (source_num != -1);
-
-    set_subtitles_visible (play_base_bin, visible);
-    if (!visible)
-      return;
-  } else if (type == GST_STREAM_TYPE_AUDIO) {
-    gboolean mute = (source_num == -1);
-
-    set_audio_mute (play_base_bin, mute);
-
-    if (mute)
-      return;
-  }
-
-  sel = group->type[type - 1].selector;
-
-  for (s = group->streaminfo; s; s = s->next) {
-    GstStreamInfo *info = s->data;
-
-    if (info->type == type) {
-      if (num == source_num) {
-        GstPad *sel_pad;
-
-        GST_LOG ("Unmuting (if already muted) source %d of type %d", source_num,
-            type);
-        g_object_set (info, "mute", FALSE, NULL);
-
-        /* Tell the stream selector which pad to accept */
-        sel_pad = GST_PAD_CAST (g_object_get_data (G_OBJECT (info->object),
-                "pb_sel_pad"));
-
-        if (sel && sel_pad != NULL) {
-          g_object_set (G_OBJECT (sel), "active-pad", sel_pad, NULL);
-        }
-
-        have_active = TRUE;
-      } else {
-        guint id;
-
-        GST_LOG_OBJECT (info->object, "Muting source %d of type %d", num, type);
-
-        id = gst_pad_add_probe (GST_PAD_CAST (info->object),
-            GST_PROBE_TYPE_BUFFER, mute_stream, info, NULL);
-        g_object_set_data (G_OBJECT (info), "mute_probe", GINT_TO_POINTER (id));
-      }
-      num++;
-    }
-  }
-
-  if (!have_active) {
-    GST_LOG ("Muting group type: %d", type);
-    g_object_set (sel, "active-pad", NULL, NULL);
-  } else {
-    GST_LOG ("Unmuting group type: %d", type);
-  }
-  mute_group_type (group, type, !have_active);
-}
-
-static void
-gst_play_base_bin_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec)
-{
-  GstPlayBaseBin *play_base_bin;
-
-  g_return_if_fail (GST_IS_PLAY_BASE_BIN (object));
-
-  play_base_bin = GST_PLAY_BASE_BIN (object);
-
-  switch (prop_id) {
-    case ARG_URI:
-    {
-      const gchar *uri = g_value_get_string (value);
-
-      if (uri == NULL) {
-        g_warning ("cannot set NULL uri");
-        return;
-      }
-      /* if we have no previous uri, or the new uri is different from the
-       * old one, replug */
-      if (play_base_bin->uri == NULL || strcmp (play_base_bin->uri, uri) != 0) {
-        g_free (play_base_bin->uri);
-        play_base_bin->uri = g_strdup (uri);
-
-        GST_DEBUG ("setting new uri to %s", uri);
-
-        play_base_bin->need_rebuild = TRUE;
-      }
-      break;
-    }
-    case ARG_SUBURI:{
-      const gchar *suburi = g_value_get_string (value);
-
-      if ((!suburi && !play_base_bin->suburi) ||
-          (suburi && play_base_bin->suburi &&
-              !strcmp (play_base_bin->suburi, suburi)))
-        return;
-      g_free (play_base_bin->suburi);
-      play_base_bin->suburi = g_strdup (suburi);
-      GST_DEBUG ("setting new .sub uri to %s", suburi);
-      play_base_bin->need_rebuild = TRUE;
-      break;
-    }
-    case ARG_QUEUE_SIZE:
-      play_base_bin->queue_size = g_value_get_uint64 (value);
-      break;
-    case ARG_QUEUE_THRESHOLD:
-      play_base_bin->queue_threshold = g_value_get_uint64 (value);
-      break;
-    case ARG_QUEUE_MIN_THRESHOLD:
-      play_base_bin->queue_min_threshold = g_value_get_uint64 (value);
-      break;
-    case ARG_CONNECTION_SPEED:
-      play_base_bin->connection_speed = g_value_get_uint (value) * 1000;
-      break;
-    case ARG_VIDEO:
-      GROUP_LOCK (play_base_bin);
-      set_active_source (play_base_bin,
-          GST_STREAM_TYPE_VIDEO, g_value_get_int (value));
-      GROUP_UNLOCK (play_base_bin);
-      break;
-    case ARG_AUDIO:
-      GROUP_LOCK (play_base_bin);
-      set_active_source (play_base_bin,
-          GST_STREAM_TYPE_AUDIO, g_value_get_int (value));
-      GROUP_UNLOCK (play_base_bin);
-      break;
-    case ARG_TEXT:
-      GROUP_LOCK (play_base_bin);
-      set_active_source (play_base_bin,
-          GST_STREAM_TYPE_TEXT, g_value_get_int (value));
-      GROUP_UNLOCK (play_base_bin);
-      break;
-    case ARG_SUBTITLE_ENCODING:
-    {
-      const gchar *encoding;
-      GSList *list;
-
-      encoding = g_value_get_string (value);
-      if (encoding && play_base_bin->subencoding &&
-          !strcmp (play_base_bin->subencoding, encoding)) {
-        return;
-      }
-      if (encoding == NULL && play_base_bin->subencoding == NULL)
-        return;
-
-      g_mutex_lock (play_base_bin->sub_lock);
-      g_free (play_base_bin->subencoding);
-      play_base_bin->subencoding = g_strdup (encoding);
-      list = g_slist_copy (play_base_bin->subtitle_elements);
-      g_slist_foreach (list, (GFunc) gst_object_ref, NULL);
-      g_mutex_unlock (play_base_bin->sub_lock);
-
-      /* we can't hold a lock when calling g_object_set() on a child, since
-       * the notify event will trigger GstObject to send a deep-notify event
-       * which will try to take the lock ... */
-      g_slist_foreach (list, (GFunc) set_encoding_element, (gpointer) encoding);
-      g_slist_foreach (list, (GFunc) gst_object_unref, NULL);
-      g_slist_free (list);
-      break;
-    }
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static void
-gst_play_base_bin_get_property (GObject * object, guint prop_id, GValue * value,
-    GParamSpec * pspec)
-{
-  GstPlayBaseBin *play_base_bin;
-
-  g_return_if_fail (GST_IS_PLAY_BASE_BIN (object));
-
-  play_base_bin = GST_PLAY_BASE_BIN (object);
-
-  switch (prop_id) {
-    case ARG_URI:
-      g_value_set_string (value, play_base_bin->uri);
-      break;
-    case ARG_SUBURI:
-      g_value_set_string (value, play_base_bin->suburi);
-      break;
-    case ARG_NSTREAMS:
-    {
-      GstPlayBaseGroup *group;
-
-      GROUP_LOCK (play_base_bin);
-      group = get_active_group (play_base_bin);
-      if (group) {
-        g_value_set_int (value, group->nstreams);
-      } else {
-        g_value_set_int (value, 0);
-      }
-      GROUP_UNLOCK (play_base_bin);
-      break;
-    }
-    case ARG_QUEUE_SIZE:
-      g_value_set_uint64 (value, play_base_bin->queue_size);
-      break;
-    case ARG_QUEUE_THRESHOLD:
-      g_value_set_uint64 (value, play_base_bin->queue_threshold);
-      break;
-    case ARG_QUEUE_MIN_THRESHOLD:
-      g_value_set_uint64 (value, play_base_bin->queue_min_threshold);
-      break;
-    case ARG_CONNECTION_SPEED:
-      g_value_set_uint (value, play_base_bin->connection_speed / 1000);
-      break;
-    case ARG_STREAMINFO:
-      /* FIXME: hold some kind of lock here, use iterator */
-      g_value_set_pointer (value,
-          (gpointer) gst_play_base_bin_get_streaminfo (play_base_bin));
-      break;
-    case ARG_STREAMINFO_VALUES:{
-      GValueArray *copy;
-
-      copy = gst_play_base_bin_get_streaminfo_value_array (play_base_bin);
-      g_value_take_boxed (value, copy);
-      break;
-    }
-    case ARG_SOURCE:
-      g_value_set_object (value, play_base_bin->source);
-      break;
-    case ARG_VIDEO:
-      GROUP_LOCK (play_base_bin);
-      g_value_set_int (value, get_active_source (play_base_bin,
-              GST_STREAM_TYPE_VIDEO));
-      GROUP_UNLOCK (play_base_bin);
-      break;
-    case ARG_AUDIO:
-      GROUP_LOCK (play_base_bin);
-      g_value_set_int (value, get_active_source (play_base_bin,
-              GST_STREAM_TYPE_AUDIO));
-      GROUP_UNLOCK (play_base_bin);
-      break;
-    case ARG_TEXT:
-      GROUP_LOCK (play_base_bin);
-      g_value_set_int (value, get_active_source (play_base_bin,
-              GST_STREAM_TYPE_TEXT));
-      GROUP_UNLOCK (play_base_bin);
-      break;
-    case ARG_SUBTITLE_ENCODING:
-      GST_OBJECT_LOCK (play_base_bin);
-      g_value_set_string (value, play_base_bin->subencoding);
-      GST_OBJECT_UNLOCK (play_base_bin);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static GstStateChangeReturn
-gst_play_base_bin_change_state (GstElement * element, GstStateChange transition)
-{
-  GstStateChangeReturn ret;
-  GstPlayBaseBin *play_base_bin;
-
-  play_base_bin = GST_PLAY_BASE_BIN (element);
-
-  switch (transition) {
-    case GST_STATE_CHANGE_READY_TO_PAUSED:
-      if (!setup_source (play_base_bin))
-        goto source_failed;
-      break;
-    default:
-      break;
-  }
-
-  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
-  switch (transition) {
-    case GST_STATE_CHANGE_READY_TO_PAUSED:
-      if (ret == GST_STATE_CHANGE_FAILURE)
-        goto cleanup_groups;
-
-      finish_source (play_base_bin);
-      break;
-      /* clean-up in both cases, READY=>NULL clean-up is if there was an error */
-    case GST_STATE_CHANGE_PAUSED_TO_READY:
-    case GST_STATE_CHANGE_READY_TO_NULL:
-      play_base_bin->need_rebuild = TRUE;
-      remove_decoders (play_base_bin);
-      remove_groups (play_base_bin);
-      remove_source (play_base_bin);
-      break;
-    default:
-      break;
-  }
-  return ret;
-
-  /* ERRORS */
-source_failed:
-  {
-    play_base_bin->need_rebuild = TRUE;
-
-    return GST_STATE_CHANGE_FAILURE;
-  }
-cleanup_groups:
-  {
-    /* clean up leftover groups */
-    remove_groups (play_base_bin);
-    play_base_bin->need_rebuild = TRUE;
-
-    return GST_STATE_CHANGE_FAILURE;
-  }
-}
-
-static const GList *
-gst_play_base_bin_get_streaminfo (GstPlayBaseBin * play_base_bin)
-{
-  GstPlayBaseGroup *group = get_active_group (play_base_bin);
-  GList *info = NULL;
-
-  if (group) {
-    info = group->streaminfo;
-  }
-  return info;
-}
-
-static GValueArray *
-gst_play_base_bin_get_streaminfo_value_array (GstPlayBaseBin * play_base_bin)
-{
-  GstPlayBaseGroup *group;
-  GValueArray *array = NULL;
-
-  GROUP_LOCK (play_base_bin);
-  group = get_active_group (play_base_bin);
-  if (group) {
-    array = g_value_array_copy (group->streaminfo_value_array);
-  } else {
-    array = g_value_array_new (0);
-  }
-  GROUP_UNLOCK (play_base_bin);
-
-  return array;
-}
diff --git a/gst/playback/gstplaybasebin.h b/gst/playback/gstplaybasebin.h
deleted file mode 100644 (file)
index c8c8649..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- *               <2007> Wim Taymans <wim.taymans@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_PLAYBASEBIN_H__
-#define __GST_PLAYBASEBIN_H__
-
-#include <gst/gst.h>
-#include "gststreaminfo.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_PLAY_BASE_BIN            (gst_play_base_bin_get_type())
-#define GST_PLAY_BASE_BIN(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BASE_BIN,GstPlayBaseBin))
-#define GST_PLAY_BASE_BIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BASE_BIN,GstPlayBaseBinClass))
-#define GST_IS_PLAY_BASE_BIN(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BASE_BIN))
-#define GST_IS_PLAY_BASE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BASE_BIN))
-#define GST_PLAY_BASE_BIN_GET_CLASS(obj) \
-  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PLAY_BASE_BIN, \
-                              GstPlayBaseBinClass))
-
-typedef struct _GstPlayBaseBin GstPlayBaseBin;
-typedef struct _GstPlayBaseBinClass GstPlayBaseBinClass;
-
-/* a GstPlayBaseGroup is a group of pads and streaminfo that together 
- * make up a playable stream. A new group is created from the current 
- * set of pads that are alive when the preroll elements are filled or 
- * when the no-more-pads signal is fired.
- *
- * We have to queue the groups as they can be created while the preroll
- * queues are still playing the old group. We monitor the EOS signals
- * on the preroll queues and when all the streams in the current group
- * have EOSed, we switch to the next queued group.
- */
-typedef struct
-{
-  GstPlayBaseBin *bin;  /* ref to the owner */
-
-  gint           nstreams;
-  GList         *streaminfo;
-  GValueArray   *streaminfo_value_array;
-
-  /* contained decoded elementary streams */
-  struct {
-    gint         npads;
-    GstBin      *bin;
-    GstElement  *preroll;
-    GstElement  *selector;
-    gboolean     done;
-#define NUM_TYPES 4
-  } type[NUM_TYPES]; /* AUDIO, VIDEO, TEXT, SUBPIC */
-} GstPlayBaseGroup;
-
-struct _GstPlayBaseBin {
-  GstPipeline    pipeline;
-        
-  /* properties */
-  guint64        queue_size;
-  guint64        queue_threshold;
-  guint64        queue_min_threshold;
-  /* connection speed in bits/sec (0 = unknown) */
-  guint          connection_speed;
-  
-
-  /* currently loaded media */
-  gint           current[NUM_TYPES];
-  gchar         *uri, *suburi;
-  gboolean       is_stream;
-  GstElement    *source;
-  GSList        *decoders;
-  GstElement    *subtitle;              /* additional filesrc ! subparse bin */
-  gboolean       subtitle_done;
-  gboolean       need_rebuild;
-  gboolean       raw_decoding_mode;     /* Use smaller queues when source outputs raw data */
-
-  GSList        *subtitle_elements;     /* subtitle elements that have 'subtitle-encoding' property */
-  gchar         *subencoding;           /* encoding to propagate to the above subtitle elements     */
-  GMutex        *sub_lock;              /* protecting subtitle_elements and subencoding members     */
-
-  /* group management - using own lock */
-  GMutex        *group_lock;            /* lock and mutex to signal availability of new group */
-  GCond         *group_cond;
-  GstPlayBaseGroup *building_group;     /* the group that we are constructing */
-  GList         *queued_groups;         /* the constructed groups, head is the active one */
-
-  /* for dynamic sources */
-  guint          src_np_sig_id;                /* new-pad signal id */
-  guint          src_nmp_sig_id;        /* no-more-pads signal id */
-  gint           pending;
-};
-
-struct _GstPlayBaseBinClass {
-  GstPipelineClass parent_class;
-
-  /* virtual fuctions */
-  gboolean (*setup_output_pads) (GstPlayBaseBin *play_base_bin,
-                                 GstPlayBaseGroup *group);
-
-  void     (*set_subtitles_visible) (GstPlayBaseBin *play_base_bin,
-                                     gboolean visible);
-  void     (*set_audio_mute)        (GstPlayBaseBin *play_base_bin,
-                                     gboolean mute);
-};
-
-GType gst_play_base_bin_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_PLAYBASEBIN_H__ */
-
diff --git a/gst/playback/gstplaybin.c b/gst/playback/gstplaybin.c
deleted file mode 100644 (file)
index 8ff5e98..0000000
+++ /dev/null
@@ -1,1991 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-playbin
- *
- * Playbin provides a stand-alone everything-in-one abstraction for an
- * audio and/or video player.
- *
- * <note>
- * This element is deprecated and no longer supported. You should use
- * the #playbin2 element instead.
- * </note>
- *
- * It can handle both audio and video files and features
- * <itemizedlist>
- * <listitem>
- * automatic file type recognition and based on that automatic
- * selection and usage of the right audio/video/subtitle demuxers/decoders
- * </listitem>
- * <listitem>
- * visualisations for audio files
- * </listitem>
- * <listitem>
- * subtitle support for video files
- * </listitem>
- * <listitem>
- * stream selection between different audio/subtitles streams
- * </listitem>
- * <listitem>
- * meta info (tag) extraction
- * </listitem>
- * <listitem>
- * easy access to the last video frame
- * </listitem>
- * <listitem>
- * buffering when playing streams over a network
- * </listitem>
- * <listitem>
- * volume control
- * </listitem>
- * </itemizedlist>
- *
- * <refsect2>
- * <title>Usage</title>
- * <para>
- * A playbin element can be created just like any other element using
- * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin:uri
- * property. This must be an absolute URI, relative file paths are not allowed.
- * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
- *
- * Playbin is a #GstPipeline. It will notify the application of everything
- * that's happening (errors, end of stream, tags found, state changes, etc.)
- * by posting messages on its #GstBus. The application needs to watch the
- * bus.
- *
- * Playback can be initiated by setting the element to PLAYING state using
- * gst_element_set_state(). Note that the state change will take place in
- * the background in a separate thread, when the function returns playback
- * is probably not happening yet and any errors might not have occured yet.
- * Applications using playbin should ideally be written to deal with things
- * completely asynchroneous.
- *
- * When playback has finished (an EOS message has been received on the bus)
- * or an error has occured (an ERROR message has been received on the bus) or
- * the user wants to play a different track, playbin should be set back to
- * READY or NULL state, then the #GstPlayBin:uri property should be set to the
- * new location and then playbin be set to PLAYING state again.
- *
- * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
- * on the playbin element. Again, the seek will not be executed
- * instantaneously, but will be done in a background thread. When the seek
- * call returns the seek will most likely still be in process. An application
- * may wait for the seek to finish (or fail) using gst_element_get_state() with
- * -1 as the timeout, but this will block the user interface and is not
- * recommended at all.
- *
- * Applications may query the current position and duration of the stream
- * via gst_element_query_position() and gst_element_query_duration() and
- * setting the format passed to GST_FORMAT_TIME. If the query was successful,
- * the duration or position will have been returned in units of nanoseconds.
- * </para>
- * </refsect2>
- * <refsect2>
- * <title>Advanced Usage: specifying the audio and video sink</title>
- * <para>
- * By default, if no audio sink or video sink has been specified via the
- * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property, playbin will use
- * the autoaudiosink and autovideosink elements to find the first-best
- * available output method.
- * This should work in most cases, but is not always desirable. Often either
- * the user or application might want to specify more explicitly what to use
- * for audio and video output.
- *
- * If the application wants more control over how audio or video should be
- * output, it may create the audio/video sink elements itself (for example
- * using gst_element_factory_make()) and provide them to playbin using the
- * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property.
- *
- * GNOME-based applications, for example, will usually want to create
- * gconfaudiosink and gconfvideosink elements and make playbin use those,
- * so that output happens to whatever the user has configured in the GNOME
- * Multimedia System Selector confinguration dialog.
- *
- * The sink elements do not necessarily need to be ready-made sinks. It is
- * possible to create container elements that look like a sink to playbin,
- * but in reality contain a number of custom elements linked together. This
- * can be achieved by creating a #GstBin and putting elements in there and
- * linking them, and then creating a sink #GstGhostPad for the bin and pointing
- * it to the sink pad of the first element within the bin. This can be used
- * for a number of purposes, for example to force output to a particular
- * format or to modify or observe the data before it is output.
- *
- * It is also possible to 'suppress' audio and/or video output by using
- * 'fakesink' elements (or capture it from there using the fakesink element's
- * "handoff" signal, which, nota bene, is fired from the streaming thread!).
- * </para>
- * </refsect2>
- * <refsect2>
- * <title>Retrieving Tags and Other Meta Data</title>
- * <para>
- * Most of the common meta data (artist, title, etc.) can be retrieved by
- * watching for TAG messages on the pipeline's bus (see above).
- *
- * Other more specific meta information like width/height/framerate of video
- * streams or samplerate/number of channels of audio streams can be obtained
- * using the  #GstPlayBaseBin:stream-info property, which will return a GList of
- * stream info objects, one for each stream. These are opaque objects that can
- * only be accessed via the standard GObject property interface, ie. g_object_get().
- * Each stream info object has the following properties:
- * <itemizedlist>
- * <listitem>"object" (GstObject) (the decoder source pad usually)</listitem>
- * <listitem>"type" (enum) (if this is an audio/video/subtitle stream)</listitem>
- * <listitem>"decoder" (string) (name of decoder used to decode this stream)</listitem>
- * <listitem>"mute" (boolean) (to mute or unmute this stream)</listitem>
- * <listitem>"caps" (GstCaps) (caps of the decoded stream)</listitem>
- * <listitem>"language-code" (string) (ISO-639 language code for this stream, mostly used for audio/subtitle streams)</listitem>
- * <listitem>"codec" (string) (format this stream was encoded in)</listitem>
- * </itemizedlist>
- * Stream information from the #GstPlayBaseBin:stream-info property is best queried once
- * playbin has changed into PAUSED or PLAYING state (which can be detected
- * via a state-changed message on the #GstBus where old_state=READY and
- * new_state=PAUSED), since before that the list might not be complete yet or
- * not contain all available information (like language-codes).
- * </para>
- * </refsect2>
- * <refsect2>
- * <title>Buffering</title>
- * Playbin handles buffering automatically for the most part, but applications
- * need to handle parts of the buffering process as well. Whenever playbin is
- * buffering, it will post BUFFERING messages on the bus with a percentage
- * value that shows the progress of the buffering process. Applications need
- * to set playbin to PLAYING or PAUSED state in response to these messages.
- * They may also want to convey the buffering progress to the user in some
- * way. Here is how to extract the percentage information from the message
- * (requires GStreamer >= 0.10.11):
- * |[
- * switch (GST_MESSAGE_TYPE (msg)) {
- *   case GST_MESSAGE_BUFFERING: {
- *     gint percent = 0;
- *     gst_message_parse_buffering (msg, &amp;percent);
- *     g_print ("Buffering (%%u percent done)", percent);
- *     break;
- *   }
- *   ...
- * }
- * ]|
- * Note that applications should keep/set the pipeline in the PAUSED state when
- * a BUFFERING message is received with a buffer percent value < 100 and set
- * the pipeline back to PLAYING state when a BUFFERING message with a value
- * of 100 percent is received (if PLAYING is the desired state, that is).
- * </refsect2>
- * <refsect2>
- * <title>Embedding the video window in your application</title>
- * By default, playbin (or rather the video sinks used) will create their own
- * window. Applications will usually want to force output to a window of their
- * own, however. This can be done using the #GstXOverlay interface, which most
- * video sinks implement. See the documentation there for more details.
- * </refsect2>
- * <refsect2>
- * <title>Specifying which CD/DVD device to use</title>
- * The device to use for CDs/DVDs needs to be set on the source element
- * playbin creates before it is opened. The only way to do this at the moment
- * is to connect to playbin's "notify::source" signal, which will be emitted
- * by playbin when it has created the source element for a particular URI.
- * In the signal callback you can check if the source element has a "device"
- * property and set it appropriately. In future ways might be added to specify
- * the device as part of the URI, but at the time of writing this is not
- * possible yet.
- * </refsect2>
- * <refsect2>
- * <title>Examples</title>
- * |[
- * gst-launch -v playbin uri=file:///path/to/somefile.avi
- * ]| This will play back the given AVI video file, given that the video and
- * audio decoders required to decode the content are installed. Since no
- * special audio sink or video sink is supplied (not possible via gst-launch),
- * playbin will try to find a suitable audio and video sink automatically
- * using the autoaudiosink and autovideosink elements.
- * |[
- * gst-launch -v playbin uri=cdda://4
- * ]| This will play back track 4 on an audio CD in your disc drive (assuming
- * the drive is detected automatically by the plugin).
- * |[
- * gst-launch -v playbin uri=dvd://1
- * ]| This will play back title 1 of a DVD in your disc drive (assuming
- * the drive is detected automatically by the plugin).
- * </refsect2>
- *
- * Deprecated: use playbin2 instead
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-#include <gst/gst.h>
-
-#include <gst/gst-i18n-plugin.h>
-#include <gst/pbutils/pbutils.h>
-
-#include "gstplaybasebin.h"
-#include "gstplayback.h"
-
-GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
-#define GST_CAT_DEFAULT gst_play_bin_debug
-
-#define GST_TYPE_PLAY_BIN               (gst_play_bin_get_type())
-#define GST_PLAY_BIN(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
-#define GST_PLAY_BIN_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
-#define GST_IS_PLAY_BIN(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
-#define GST_IS_PLAY_BIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
-
-#define VOLUME_MAX_DOUBLE 10.0
-
-typedef struct _GstPlayBin GstPlayBin;
-typedef struct _GstPlayBinClass GstPlayBinClass;
-
-/**
- * GstPlayBin:
- *
- * High-level player element
- */
-struct _GstPlayBin
-{
-  GstPlayBaseBin parent;
-
-  /* the configurable elements */
-  GstElement *fakesink;
-  GstElement *audio_sink;
-  GstElement *video_sink;
-  GstElement *visualisation;
-  GstElement *pending_visualisation;
-  GstElement *volume_element;
-  GstElement *textoverlay_element;
-  GstElement *spu_element;
-  gfloat volume;
-
-  /* these are the currently active sinks */
-  GList *sinks;
-
-  /* the last captured frame for snapshots */
-  GstBuffer *frame;
-
-  /* our cache for the sinks */
-  GHashTable *cache;
-
-  /* font description */
-  gchar *font_desc;
-
-  /* indication if the pipeline is live */
-  gboolean is_live;
-
-  /* probes */
-  gulong text_id;
-  gulong sub_id;
-};
-
-struct _GstPlayBinClass
-{
-  GstPlayBaseBinClass parent_class;
-};
-
-/* props */
-enum
-{
-  ARG_0,
-  ARG_AUDIO_SINK,
-  ARG_VIDEO_SINK,
-  ARG_VIS_PLUGIN,
-  ARG_VOLUME,
-  ARG_FRAME,
-  ARG_FONT_DESC
-};
-
-/* signals */
-enum
-{
-  LAST_SIGNAL
-};
-
-static void gst_play_bin_class_init (GstPlayBinClass * klass);
-static void gst_play_bin_init (GstPlayBin * play_bin);
-static void gst_play_bin_dispose (GObject * object);
-
-static gboolean setup_sinks (GstPlayBaseBin * play_base_bin,
-    GstPlayBaseGroup * group);
-static void remove_sinks (GstPlayBin * play_bin);
-static void playbin_set_subtitles_visible (GstPlayBaseBin * play_base_bin,
-    gboolean visible);
-static void playbin_set_audio_mute (GstPlayBaseBin * play_base_bin,
-    gboolean mute);
-
-static void gst_play_bin_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * spec);
-static void gst_play_bin_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * spec);
-
-static gboolean gst_play_bin_send_event (GstElement * element,
-    GstEvent * event);
-static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
-    GstStateChange transition);
-
-static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
-
-static GstElementClass *parent_class;
-
-//static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
-
-static GType
-gst_play_bin_get_type (void)
-{
-  static GType gst_play_bin_type = 0;
-
-  if (!gst_play_bin_type) {
-    static const GTypeInfo gst_play_bin_info = {
-      sizeof (GstPlayBinClass),
-      NULL,
-      NULL,
-      (GClassInitFunc) gst_play_bin_class_init,
-      NULL,
-      NULL,
-      sizeof (GstPlayBin),
-      0,
-      (GInstanceInitFunc) gst_play_bin_init,
-      NULL
-    };
-
-    gst_play_bin_type = g_type_register_static (GST_TYPE_PLAY_BASE_BIN,
-        "GstPlayBin", &gst_play_bin_info, 0);
-  }
-
-  return gst_play_bin_type;
-}
-
-static void
-gst_play_bin_class_init (GstPlayBinClass * klass)
-{
-  GObjectClass *gobject_klass;
-  GstElementClass *gstelement_klass;
-  GstBinClass *gstbin_klass;
-  GstPlayBaseBinClass *playbasebin_klass;
-
-  gobject_klass = (GObjectClass *) klass;
-  gstelement_klass = (GstElementClass *) klass;
-  gstbin_klass = (GstBinClass *) klass;
-  playbasebin_klass = (GstPlayBaseBinClass *) klass;
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  gobject_klass->set_property = gst_play_bin_set_property;
-  gobject_klass->get_property = gst_play_bin_get_property;
-
-  g_object_class_install_property (gobject_klass, ARG_VIDEO_SINK,
-      g_param_spec_object ("video-sink", "Video Sink",
-          "the video output element to use (NULL = default sink)",
-          GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_AUDIO_SINK,
-      g_param_spec_object ("audio-sink", "Audio Sink",
-          "the audio output element to use (NULL = default sink)",
-          GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_VIS_PLUGIN,
-      g_param_spec_object ("vis-plugin", "Vis plugin",
-          "the visualization element to use (NULL = none)",
-          GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  /**
-   * GstPlayBin:volume:
-   *
-   * Get or set the current audio stream volume. 1.0 means 100%,
-   * 0.0 means mute. This uses a linear volume scale.
-   *
-   */
-  g_object_class_install_property (gobject_klass, ARG_VOLUME,
-      g_param_spec_double ("volume", "volume", "volume",
-          0.0, VOLUME_MAX_DOUBLE, 1.0,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_FRAME,
-      g_param_spec_boxed ("frame", "Frame",
-          "The last frame (NULL = no video available)", GST_TYPE_BUFFER,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_FONT_DESC,
-      g_param_spec_string ("subtitle-font-desc", "Subtitle font description",
-          "Pango font description of font " "to be used for subtitle rendering",
-          NULL, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
-
-  gobject_klass->dispose = gst_play_bin_dispose;
-
-  gst_element_class_set_details_simple (gstelement_klass,
-      "Player Bin", "Generic/Bin/Player",
-      "Autoplug and play media from an uri",
-      "Wim Taymans <wim.taymans@gmail.com>");
-
-  gstelement_klass->change_state =
-      GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
-  gstelement_klass->send_event = GST_DEBUG_FUNCPTR (gst_play_bin_send_event);
-
-  gstbin_klass->handle_message =
-      GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
-
-  playbasebin_klass->setup_output_pads = setup_sinks;
-  playbasebin_klass->set_subtitles_visible = playbin_set_subtitles_visible;
-  playbasebin_klass->set_audio_mute = playbin_set_audio_mute;
-}
-
-static void
-gst_play_bin_init (GstPlayBin * play_bin)
-{
-  play_bin->video_sink = NULL;
-  play_bin->audio_sink = NULL;
-  play_bin->visualisation = NULL;
-  play_bin->pending_visualisation = NULL;
-  play_bin->volume_element = NULL;
-  play_bin->textoverlay_element = NULL;
-  play_bin->spu_element = NULL;
-  play_bin->volume = 1.0;
-  play_bin->sinks = NULL;
-  play_bin->frame = NULL;
-  play_bin->font_desc = NULL;
-  play_bin->cache = g_hash_table_new_full (g_str_hash, g_str_equal,
-      NULL, (GDestroyNotify) gst_object_unref);
-}
-
-static void
-gst_play_bin_dispose (GObject * object)
-{
-  GstPlayBin *play_bin;
-
-  play_bin = GST_PLAY_BIN (object);
-
-  if (play_bin->cache != NULL) {
-    remove_sinks (play_bin);
-    g_hash_table_destroy (play_bin->cache);
-    play_bin->cache = NULL;
-  }
-
-  if (play_bin->audio_sink != NULL) {
-    gst_element_set_state (play_bin->audio_sink, GST_STATE_NULL);
-    gst_object_unref (play_bin->audio_sink);
-    play_bin->audio_sink = NULL;
-  }
-  if (play_bin->video_sink != NULL) {
-    gst_element_set_state (play_bin->video_sink, GST_STATE_NULL);
-    gst_object_unref (play_bin->video_sink);
-    play_bin->video_sink = NULL;
-  }
-  if (play_bin->visualisation != NULL) {
-    gst_element_set_state (play_bin->visualisation, GST_STATE_NULL);
-    gst_object_unref (play_bin->visualisation);
-    play_bin->visualisation = NULL;
-  }
-  if (play_bin->pending_visualisation != NULL) {
-    gst_element_set_state (play_bin->pending_visualisation, GST_STATE_NULL);
-    gst_object_unref (play_bin->pending_visualisation);
-    play_bin->pending_visualisation = NULL;
-  }
-  if (play_bin->textoverlay_element != NULL) {
-    gst_object_unref (play_bin->textoverlay_element);
-    play_bin->textoverlay_element = NULL;
-  }
-  if (play_bin->volume_element) {
-    gst_object_unref (play_bin->volume_element);
-    play_bin->volume_element = NULL;
-  }
-  if (play_bin->spu_element != NULL) {
-    gst_object_unref (play_bin->spu_element);
-    play_bin->spu_element = NULL;
-  }
-  g_free (play_bin->font_desc);
-  play_bin->font_desc = NULL;
-
-  G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static GstProbeReturn
-gst_play_bin_vis_blocked (GstPad * tee_pad, GstProbeType type,
-    gpointer type_data, gpointer user_data)
-{
-  GstPlayBin *play_bin = GST_PLAY_BIN (user_data);
-  GstBin *vis_bin = NULL;
-  GstPad *vis_sink_pad = NULL, *vis_src_pad = NULL, *vqueue_pad = NULL;
-  GstState bin_state;
-  GstElement *pending_visualisation;
-
-  GST_OBJECT_LOCK (play_bin);
-  pending_visualisation = play_bin->pending_visualisation;
-  play_bin->pending_visualisation = NULL;
-  GST_OBJECT_UNLOCK (play_bin);
-
-  /* We want to disable visualisation */
-  if (!GST_IS_ELEMENT (pending_visualisation)) {
-    /* Set visualisation element to READY */
-    gst_element_set_state (play_bin->visualisation, GST_STATE_READY);
-    goto beach;
-  }
-
-  vis_bin =
-      GST_BIN_CAST (gst_object_get_parent (GST_OBJECT_CAST
-          (play_bin->visualisation)));
-
-  if (!GST_IS_BIN (vis_bin) || !GST_IS_PAD (tee_pad)) {
-    goto beach;
-  }
-
-  vis_src_pad = gst_element_get_static_pad (play_bin->visualisation, "src");
-  vis_sink_pad = gst_pad_get_peer (tee_pad);
-
-  /* Can be fakesink */
-  if (GST_IS_PAD (vis_src_pad)) {
-    vqueue_pad = gst_pad_get_peer (vis_src_pad);
-  }
-
-  if (!GST_IS_PAD (vis_sink_pad)) {
-    goto beach;
-  }
-
-  /* Check the bin's state */
-  GST_OBJECT_LOCK (vis_bin);
-  bin_state = GST_STATE (vis_bin);
-  GST_OBJECT_UNLOCK (vis_bin);
-
-  /* Unlink */
-  gst_pad_unlink (tee_pad, vis_sink_pad);
-  gst_object_unref (vis_sink_pad);
-  vis_sink_pad = NULL;
-
-  if (GST_IS_PAD (vqueue_pad)) {
-    gst_pad_unlink (vis_src_pad, vqueue_pad);
-    gst_object_unref (vis_src_pad);
-    vis_src_pad = NULL;
-  }
-
-  /* Remove from vis_bin */
-  gst_bin_remove (vis_bin, play_bin->visualisation);
-  /* Set state to NULL */
-  gst_element_set_state (play_bin->visualisation, GST_STATE_NULL);
-  /* And loose our ref */
-  gst_object_unref (play_bin->visualisation);
-
-  if (pending_visualisation) {
-    /* Ref this new visualisation element before adding to the bin */
-    gst_object_ref (pending_visualisation);
-    /* Add the new one */
-    gst_bin_add (vis_bin, pending_visualisation);
-    /* Synchronizing state */
-    gst_element_set_state (pending_visualisation, bin_state);
-
-    vis_sink_pad = gst_element_get_static_pad (pending_visualisation, "sink");
-    vis_src_pad = gst_element_get_static_pad (pending_visualisation, "src");
-
-    if (!GST_IS_PAD (vis_sink_pad) || !GST_IS_PAD (vis_src_pad)) {
-      goto beach;
-    }
-
-    /* Link */
-    gst_pad_link (tee_pad, vis_sink_pad);
-    gst_pad_link (vis_src_pad, vqueue_pad);
-  }
-
-  /* We are done */
-  gst_object_unref (play_bin->visualisation);
-  play_bin->visualisation = pending_visualisation;
-
-beach:
-  if (vis_sink_pad) {
-    gst_object_unref (vis_sink_pad);
-  }
-  if (vis_src_pad) {
-    gst_object_unref (vis_src_pad);
-  }
-  if (vqueue_pad) {
-    gst_object_unref (vqueue_pad);
-  }
-  if (vis_bin) {
-    gst_object_unref (vis_bin);
-  }
-
-  /* unblock the pad and remove the probe */
-  return GST_PROBE_REMOVE;
-}
-
-static void
-gst_play_bin_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec)
-{
-  GstPlayBin *play_bin;
-
-  play_bin = GST_PLAY_BIN (object);
-
-  switch (prop_id) {
-    case ARG_VIDEO_SINK:
-      if (play_bin->video_sink != NULL) {
-        gst_object_unref (play_bin->video_sink);
-      }
-      play_bin->video_sink = g_value_get_object (value);
-      if (play_bin->video_sink != NULL) {
-        gst_object_ref_sink (play_bin->video_sink);
-      }
-      /* when changing the videosink, we just remove the
-       * video pipeline from the cache so that it will be
-       * regenerated with the new sink element */
-      g_hash_table_remove (play_bin->cache, "vbin");
-      break;
-    case ARG_AUDIO_SINK:
-      if (play_bin->audio_sink != NULL) {
-        gst_object_unref (play_bin->audio_sink);
-      }
-      if (play_bin->volume_element != NULL) {
-        gst_object_unref (play_bin->volume_element);
-        play_bin->volume_element = NULL;
-      }
-      play_bin->audio_sink = g_value_get_object (value);
-      if (play_bin->audio_sink != NULL) {
-        gst_object_ref_sink (play_bin->audio_sink);
-      }
-      g_hash_table_remove (play_bin->cache, "abin");
-      break;
-    case ARG_VIS_PLUGIN:
-    {
-      GstElement *pending_visualisation =
-          GST_ELEMENT_CAST (g_value_get_object (value));
-
-      /* Take ownership */
-      if (pending_visualisation) {
-        gst_object_ref_sink (pending_visualisation);
-      }
-
-      /* Do we already have a visualisation change pending ? */
-      GST_OBJECT_LOCK (play_bin);
-      if (play_bin->pending_visualisation) {
-        gst_object_unref (play_bin->pending_visualisation);
-        play_bin->pending_visualisation = pending_visualisation;
-        GST_OBJECT_UNLOCK (play_bin);
-      } else {
-        GST_OBJECT_UNLOCK (play_bin);
-        /* Was there a visualisation already set ? */
-        if (play_bin->visualisation != NULL) {
-          GstBin *vis_bin = NULL;
-
-          vis_bin =
-              GST_BIN_CAST (gst_object_get_parent (GST_OBJECT_CAST
-                  (play_bin->visualisation)));
-
-          /* Check if the visualisation is already in a bin */
-          if (GST_IS_BIN (vis_bin)) {
-            GstPad *vis_sink_pad = NULL, *tee_pad = NULL;
-
-            /* Now get tee pad and block it async */
-            vis_sink_pad = gst_element_get_static_pad (play_bin->visualisation,
-                "sink");
-            if (!GST_IS_PAD (vis_sink_pad)) {
-              goto beach;
-            }
-            tee_pad = gst_pad_get_peer (vis_sink_pad);
-            if (!GST_IS_PAD (tee_pad)) {
-              goto beach;
-            }
-
-            play_bin->pending_visualisation = pending_visualisation;
-            /* Block with callback */
-            gst_pad_add_probe (tee_pad, GST_PROBE_TYPE_BLOCK,
-                gst_play_bin_vis_blocked, play_bin, NULL);
-          beach:
-            if (vis_sink_pad) {
-              gst_object_unref (vis_sink_pad);
-            }
-            if (tee_pad) {
-              gst_object_unref (tee_pad);
-            }
-            gst_object_unref (vis_bin);
-          } else {
-            play_bin->visualisation = pending_visualisation;
-          }
-        } else {
-          play_bin->visualisation = pending_visualisation;
-        }
-      }
-      break;
-    }
-    case ARG_VOLUME:
-      play_bin->volume = g_value_get_double (value);
-      if (play_bin->volume_element) {
-        g_object_set (G_OBJECT (play_bin->volume_element), "volume",
-            play_bin->volume, NULL);
-      }
-      break;
-    case ARG_FONT_DESC:
-      g_free (play_bin->font_desc);
-      play_bin->font_desc = g_strdup (g_value_get_string (value));
-      if (play_bin->textoverlay_element) {
-        g_object_set (G_OBJECT (play_bin->textoverlay_element),
-            "font-desc", g_value_get_string (value), NULL);
-      }
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static void
-gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
-    GParamSpec * pspec)
-{
-  GstPlayBin *play_bin;
-
-  play_bin = GST_PLAY_BIN (object);
-
-  switch (prop_id) {
-    case ARG_VIDEO_SINK:
-      g_value_set_object (value, play_bin->video_sink);
-      break;
-    case ARG_AUDIO_SINK:
-      g_value_set_object (value, play_bin->audio_sink);
-      break;
-    case ARG_VIS_PLUGIN:
-      g_value_set_object (value, play_bin->visualisation);
-      break;
-    case ARG_VOLUME:
-      g_value_set_double (value, play_bin->volume);
-      break;
-    case ARG_FRAME:{
-      GstBuffer *cur_frame = NULL;
-
-      gst_buffer_replace (&cur_frame, play_bin->frame);
-      gst_value_take_buffer (value, cur_frame);
-      break;
-    }
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-/* signal fired when the identity has received a new buffer. This is used for
- * making screenshots.
- */
-static void
-handoff (GstElement * identity, GstBuffer * frame, gpointer data)
-{
-  GstPlayBin *play_bin = GST_PLAY_BIN (data);
-
-#if 0
-  /* applications need to know the buffer caps,
-   * make sure they are always set on the frame */
-  if (GST_BUFFER_CAPS (frame) == NULL) {
-    GstPad *pad;
-
-    if ((pad = gst_element_get_static_pad (identity, "sink"))) {
-      gst_buffer_set_caps (frame, GST_PAD_CAPS (pad));
-      gst_object_unref (pad);
-    }
-  }
-#endif
-
-  gst_buffer_replace (&play_bin->frame, frame);
-}
-
-static void
-post_missing_element_message (GstPlayBin * playbin, const gchar * name)
-{
-  GstMessage *msg;
-
-  msg = gst_missing_element_message_new (GST_ELEMENT_CAST (playbin), name);
-  gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
-}
-
-/* make the element (bin) that contains the elements needed to perform
- * video display. We connect a handoff signal to identity so that we
- * can grab snapshots. Identity's sinkpad is ghosted to vbin.
- *
- *  +-------------------------------------------------------------+
- *  | vbin                                                        |
- *  |      +--------+   +----------+   +----------+   +---------+ |
- *  |      |identity|   |colorspace|   |videoscale|   |videosink| |
- *  |   +-sink     src-sink       src-sink       src-sink       | |
- *  |   |  +---+----+   +----------+   +----------+   +---------+ |
- * sink-+      |                                                  |
- *  +----------|--------------------------------------------------+
- *           handoff
- */
-static GstElement *
-gen_video_element (GstPlayBin * play_bin)
-{
-  GstElement *element;
-  GstElement *conv;
-
-  GstElement *scale;
-  GstElement *sink;
-  GstElement *identity;
-  GstPad *pad;
-
-  /* first see if we have it in the cache */
-  element = g_hash_table_lookup (play_bin->cache, "vbin");
-  if (element != NULL) {
-    return element;
-  }
-
-  if (play_bin->video_sink) {
-    sink = play_bin->video_sink;
-  } else {
-    sink = gst_element_factory_make ("autovideosink", "videosink");
-    if (sink == NULL) {
-      sink = gst_element_factory_make ("xvimagesink", "videosink");
-    }
-    if (sink == NULL)
-      goto no_sinks;
-  }
-  gst_object_ref (sink);
-  g_hash_table_insert (play_bin->cache, (gpointer) "video_sink", sink);
-
-  /* create a bin to hold objects, as we create them we add them to this bin so
-   * that when something goes wrong we only need to unref the bin */
-  element = gst_bin_new ("vbin");
-  gst_bin_add (GST_BIN_CAST (element), sink);
-
-  conv = gst_element_factory_make ("ffmpegcolorspace", "vconv");
-  if (conv == NULL)
-    goto no_colorspace;
-  gst_bin_add (GST_BIN_CAST (element), conv);
-
-  scale = gst_element_factory_make ("videoscale", "vscale");
-  if (scale == NULL)
-    goto no_videoscale;
-  gst_bin_add (GST_BIN_CAST (element), scale);
-
-  identity = gst_element_factory_make ("identity", "id");
-  g_object_set (identity, "silent", TRUE, NULL);
-  g_signal_connect (identity, "handoff", G_CALLBACK (handoff), play_bin);
-  gst_bin_add (GST_BIN_CAST (element), identity);
-
-  gst_element_link_pads (identity, "src", conv, "sink");
-  gst_element_link_pads (conv, "src", scale, "sink");
-  /* be more careful with the pad from the custom sink element, it might not
-   * be named 'sink' */
-  if (!gst_element_link_pads (scale, "src", sink, NULL))
-    goto link_failed;
-
-  pad = gst_element_get_static_pad (identity, "sink");
-  gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
-  gst_object_unref (pad);
-
-  gst_element_set_state (element, GST_STATE_READY);
-
-  /* since we're gonna add it to a bin but don't want to lose it,
-   * we keep a reference. */
-  gst_object_ref (element);
-  g_hash_table_insert (play_bin->cache, (gpointer) "vbin", element);
-
-  return element;
-
-  /* ERRORS */
-no_sinks:
-  {
-    post_missing_element_message (play_bin, "autovideosink");
-    GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
-        (_("Both autovideosink and xvimagesink elements are missing.")),
-        (NULL));
-    return NULL;
-  }
-no_colorspace:
-  {
-    post_missing_element_message (play_bin, "ffmpegcolorspace");
-    GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
-        (_("Missing element '%s' - check your GStreamer installation."),
-            "ffmpegcolorspace"), (NULL));
-    gst_object_unref (element);
-    return NULL;
-  }
-
-no_videoscale:
-  {
-    post_missing_element_message (play_bin, "videoscale");
-    GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
-        (_("Missing element '%s' - check your GStreamer installation."),
-            "videoscale"), ("possibly a liboil version mismatch?"));
-    gst_object_unref (element);
-    return NULL;
-  }
-link_failed:
-  {
-    GST_ELEMENT_ERROR (play_bin, CORE, PAD,
-        (NULL), ("Failed to configure the video sink."));
-    gst_object_unref (element);
-    return NULL;
-  }
-}
-
-/* make an element for playback of video with subtitles embedded.
- *
- *  +--------------------------------------------------+
- *  | tbin                  +-------------+            |
- *  |          +-----+      | textoverlay |   +------+ |
- *  |          | csp | +--video_sink      |   | vbin | |
- * video_sink-sink  src+ +-text_sink    src---sink   | |
- *  |          +-----+   |  +-------------+   +------+ |
- * text_sink-------------+                             |
- *  +--------------------------------------------------+
- *
- *  If there is no subtitle renderer this function will simply return the
- *  videosink without the text_sink pad.
- */
-static GstElement *
-add_text_element (GstPlayBin * play_bin, GstElement * vbin)
-{
-  GstElement *element, *csp, *overlay;
-  GstPad *pad;
-
-  /* Text overlay */
-  overlay = gst_element_factory_make ("textoverlay", "overlay");
-
-  /* If no overlay return the video bin without subtitle support. */
-  if (!overlay)
-    goto no_overlay;
-
-  /* Create our bin */
-  element = gst_bin_new ("textbin");
-
-  /* Set some parameters */
-  g_object_set (G_OBJECT (overlay),
-      "halign", "center", "valign", "bottom", NULL);
-  if (play_bin->font_desc) {
-    g_object_set (G_OBJECT (overlay), "font-desc", play_bin->font_desc, NULL);
-  }
-
-  /* Take a ref */
-  play_bin->textoverlay_element = GST_ELEMENT_CAST (gst_object_ref (overlay));
-
-  /* we know this will succeed, as the video bin already created one before */
-  csp = gst_element_factory_make ("ffmpegcolorspace", "subtitlecsp");
-
-  /* Add our elements */
-  gst_bin_add_many (GST_BIN_CAST (element), csp, overlay, vbin, NULL);
-
-  /* Link */
-  gst_element_link_pads (csp, "src", overlay, "video_sink");
-  gst_element_link_pads (overlay, "src", vbin, "sink");
-
-  /* Add ghost pads on the subtitle bin */
-  pad = gst_element_get_static_pad (overlay, "text_sink");
-  gst_element_add_pad (element, gst_ghost_pad_new ("text_sink", pad));
-  gst_object_unref (pad);
-
-  pad = gst_element_get_static_pad (csp, "sink");
-  gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
-  gst_object_unref (pad);
-
-  /* If the vbin provides a subpicture sink pad, ghost it too */
-  pad = gst_element_get_static_pad (vbin, "subpicture_sink");
-  if (pad) {
-    gst_element_add_pad (element, gst_ghost_pad_new ("subpicture_sink", pad));
-    gst_object_unref (pad);
-  }
-
-  /* Set state to READY */
-  gst_element_set_state (element, GST_STATE_READY);
-
-  return element;
-
-  /* ERRORS */
-no_overlay:
-  {
-    post_missing_element_message (play_bin, "textoverlay");
-    GST_WARNING_OBJECT (play_bin,
-        "No overlay (pango) element, subtitles disabled");
-    return vbin;
-  }
-}
-
-/* make an element for rendering DVD subpictures onto output video
- *
- *  +---------------------------------------------+
- *  | tbin                   +--------+           |
- *  |          +-----+       |        |  +------+ |
- *  |          | csp | src-videosink  |  | vbin | |
- * video_sink-sink  src+     |       src-sink   | |
- *  |          +-----+   +subpicture  |  +------+ |
- * subpicture_pad--------+   +--------+           |
- *  +---------- ----------------------------------+
- *
- */
-static GstElement *
-add_spu_element (GstPlayBin * play_bin, GstElement * vbin)
-{
-  GstElement *element, *csp, *overlay;
-  GstPad *pad;
-
-  /* DVD spu overlay */
-  GST_DEBUG_OBJECT (play_bin, "Attempting to insert DVD SPU element");
-
-  overlay = gst_element_factory_make ("dvdspu", "overlay");
-
-  /* If no overlay return the video bin without subpicture support. */
-  if (!overlay)
-    goto no_overlay;
-
-  /* Create our bin */
-  element = gst_bin_new ("spubin");
-
-  /* Take a ref */
-  play_bin->spu_element = GST_ELEMENT_CAST (gst_object_ref (overlay));
-
-  /* we know this will succeed, as the video bin already created one before */
-  csp = gst_element_factory_make ("ffmpegcolorspace", "spucsp");
-
-  /* Add our elements */
-  gst_bin_add_many (GST_BIN_CAST (element), csp, overlay, vbin, NULL);
-
-  /* Link */
-  gst_element_link_pads (csp, "src", overlay, "video");
-  gst_element_link_pads (overlay, "src", vbin, "sink");
-
-  /* Add ghost pad on the subpicture bin so it looks like vbin */
-  pad = gst_element_get_static_pad (csp, "sink");
-  gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
-  gst_object_unref (pad);
-
-  pad = gst_element_get_static_pad (overlay, "subpicture");
-  gst_element_add_pad (element, gst_ghost_pad_new ("subpicture_sink", pad));
-  gst_object_unref (pad);
-
-  /* Set state to READY */
-  gst_element_set_state (element, GST_STATE_READY);
-
-  return element;
-
-  /* ERRORS */
-no_overlay:
-  {
-    post_missing_element_message (play_bin, "dvdspu");
-    GST_WARNING_OBJECT (play_bin,
-        "No DVD overlay (dvdspu) element. "
-        "menu highlight/subtitles unavailable");
-    return vbin;
-  }
-}
-
-/* make the element (bin) that contains the elements needed to perform
- * audio playback.
- *
- *  +-------------------------------------------------------------+
- *  | abin                                                        |
- *  |      +---------+   +----------+   +---------+   +---------+ |
- *  |      |audioconv|   |audioscale|   | volume  |   |audiosink| |
- *  |   +-sink      src-sink       src-sink      src-sink       | |
- *  |   |  +---------+   +----------+   +---------+   +---------+ |
- * sink-+                                                         |
- *  +-------------------------------------------------------------+
- */
-static GstElement *
-gen_audio_element (GstPlayBin * play_bin)
-{
-  gboolean res;
-  GstElement *element;
-  GstElement *conv;
-  GstElement *scale;
-  GstElement *sink;
-  GstElement *volume;
-  GstPad *pad;
-
-  element = g_hash_table_lookup (play_bin->cache, "abin");
-  if (element != NULL)
-    return element;
-
-  if (play_bin->audio_sink) {
-    sink = play_bin->audio_sink;
-  } else {
-    sink = gst_element_factory_make ("autoaudiosink", "audiosink");
-    if (sink == NULL) {
-      sink = gst_element_factory_make ("alsasink", "audiosink");
-    }
-    if (sink == NULL)
-      goto no_sinks;
-
-    play_bin->audio_sink = GST_ELEMENT_CAST (gst_object_ref (sink));
-  }
-
-  gst_object_ref (sink);
-  g_hash_table_insert (play_bin->cache, (gpointer) "audio_sink", sink);
-
-  element = gst_bin_new ("abin");
-  gst_bin_add (GST_BIN_CAST (element), sink);
-
-  conv = gst_element_factory_make ("audioconvert", "aconv");
-  if (conv == NULL)
-    goto no_audioconvert;
-  gst_bin_add (GST_BIN_CAST (element), conv);
-
-  scale = gst_element_factory_make ("audioresample", "aresample");
-  if (scale == NULL)
-    goto no_audioresample;
-  gst_bin_add (GST_BIN_CAST (element), scale);
-
-  volume = gst_element_factory_make ("volume", "volume");
-  if (volume == NULL)
-    goto no_volume;
-  g_object_set (G_OBJECT (volume), "volume", play_bin->volume, NULL);
-  play_bin->volume_element = GST_ELEMENT_CAST (gst_object_ref (volume));
-  gst_bin_add (GST_BIN_CAST (element), volume);
-
-  res = gst_element_link_pads (conv, "src", scale, "sink");
-  res &= gst_element_link_pads (scale, "src", volume, "sink");
-  res &= gst_element_link_pads (volume, "src", sink, NULL);
-  if (!res)
-    goto link_failed;
-
-  pad = gst_element_get_static_pad (conv, "sink");
-  gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
-  gst_object_unref (pad);
-
-  gst_element_set_state (element, GST_STATE_READY);
-
-  /* since we're gonna add it to a bin but don't want to lose it,
-   * we keep a reference. */
-  gst_object_ref (element);
-  g_hash_table_insert (play_bin->cache, (gpointer) "abin", element);
-
-  return element;
-
-  /* ERRORS */
-no_sinks:
-  {
-    post_missing_element_message (play_bin, "autoaudiosink");
-    GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
-        (_("Both autoaudiosink and alsasink elements are missing.")), (NULL));
-    return NULL;
-  }
-no_audioconvert:
-  {
-    post_missing_element_message (play_bin, "audioconvert");
-    GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
-        (_("Missing element '%s' - check your GStreamer installation."),
-            "audioconvert"), ("possibly a liboil version mismatch?"));
-    gst_object_unref (element);
-    return NULL;
-  }
-no_audioresample:
-  {
-    post_missing_element_message (play_bin, "audioresample");
-    GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
-        (_("Missing element '%s' - check your GStreamer installation."),
-            "audioresample"), ("possibly a liboil version mismatch?"));
-    gst_object_unref (element);
-    return NULL;
-  }
-no_volume:
-  {
-    post_missing_element_message (play_bin, "volume");
-    GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
-        (_("Missing element '%s' - check your GStreamer installation."),
-            "volume"), ("possibly a liboil version mismatch?"));
-    gst_object_unref (element);
-    return NULL;
-  }
-link_failed:
-  {
-    GST_ELEMENT_ERROR (play_bin, CORE, PAD,
-        (NULL), ("Failed to configure the audio sink."));
-    gst_object_unref (element);
-    return NULL;
-  }
-}
-
-/* make the element (bin) that contains the elements needed to perform
- * visualisation ouput.  The idea is to split the audio using tee, then
- * sending the output to the regular audio bin and the other output to
- * the vis plugin that transforms it into a video that is rendered with the
- * normal video bin. The video and audio bins are run in threads to make sure
- * they don't block eachother.
- *
- *  +-----------------------------------------------------------------------+
- *  | visbin                                                                |
- *  |      +------+   +--------+   +----------------+                       |
- *  |      | tee  |   | aqueue |   |   abin ...     |                       |
- *  |   +-sink   src-sink     src-sink              |                       |
- *  |   |  |      |   +--------+   +----------------+                       |
- *  |   |  |      |                                                         |
- *  |   |  |      |   +------+   +------------+   +------+   +-----------+  |
- *  |   |  |      |   |vqueue|   | audioconv  |   | vis  |   | vbin ...  |  |
- *  |   |  |     src-sink   src-sink + samp  src-sink   src-sink         |  |
- *  |   |  |      |   +------+   +------------+   +------+   +-----------+  |
- *  |   |  |      |                                                         |
- *  |   |  +------+                                                         |
- * sink-+                                                                   |
- *  +-----------------------------------------------------------------------+
- */
-static GstElement *
-gen_vis_element (GstPlayBin * play_bin)
-{
-  gboolean res;
-  GstElement *element;
-  GstElement *tee;
-  GstElement *asink;
-  GstElement *vsink;
-  GstElement *conv;
-  GstElement *resamp;
-  GstElement *conv2;
-  GstElement *vis;
-  GstElement *vqueue, *aqueue;
-  GstPad *pad, *rpad;
-
-  /* errors are already posted when these fail. */
-  asink = gen_audio_element (play_bin);
-  if (!asink)
-    return NULL;
-  vsink = gen_video_element (play_bin);
-  if (!vsink) {
-    gst_object_unref (asink);
-    return NULL;
-  }
-
-  element = gst_bin_new ("visbin");
-  tee = gst_element_factory_make ("tee", "tee");
-
-  vqueue = gst_element_factory_make ("queue", "vqueue");
-  aqueue = gst_element_factory_make ("queue", "aqueue");
-
-  gst_bin_add (GST_BIN_CAST (element), asink);
-  gst_bin_add (GST_BIN_CAST (element), vqueue);
-  gst_bin_add (GST_BIN_CAST (element), aqueue);
-  gst_bin_add (GST_BIN_CAST (element), vsink);
-  gst_bin_add (GST_BIN_CAST (element), tee);
-
-  conv = gst_element_factory_make ("audioconvert", "aconv");
-  if (conv == NULL)
-    goto no_audioconvert;
-  gst_bin_add (GST_BIN_CAST (element), conv);
-
-  resamp = gst_element_factory_make ("audioresample", "aresamp");
-  if (resamp == NULL)
-    goto no_audioresample;
-  gst_bin_add (GST_BIN_CAST (element), resamp);
-
-  conv2 = gst_element_factory_make ("audioconvert", "aconv2");
-  if (conv2 == NULL)
-    goto no_audioconvert;
-  gst_bin_add (GST_BIN_CAST (element), conv2);
-
-  if (play_bin->visualisation) {
-    gst_object_ref (play_bin->visualisation);
-    vis = play_bin->visualisation;
-  } else {
-    vis = gst_element_factory_make ("goom", "vis");
-    if (!vis)
-      goto no_goom;
-  }
-  gst_bin_add (GST_BIN_CAST (element), vis);
-
-  res = gst_element_link_pads (vqueue, "src", conv, "sink");
-  res &= gst_element_link_pads (conv, "src", resamp, "sink");
-  res &= gst_element_link_pads (resamp, "src", conv2, "sink");
-  res &= gst_element_link_pads (conv2, "src", vis, "sink");
-  res &= gst_element_link_pads (vis, "src", vsink, "sink");
-  if (!res)
-    goto link_failed;
-
-  pad = gst_element_get_static_pad (aqueue, "sink");
-  rpad = gst_element_get_request_pad (tee, "src%d");
-  gst_pad_link (rpad, pad);
-  gst_object_unref (rpad);
-  gst_object_unref (pad);
-  gst_element_link_pads (aqueue, "src", asink, "sink");
-
-  pad = gst_element_get_static_pad (vqueue, "sink");
-  rpad = gst_element_get_request_pad (tee, "src%d");
-  gst_pad_link (rpad, pad);
-  gst_object_unref (rpad);
-  gst_object_unref (pad);
-
-  pad = gst_element_get_static_pad (tee, "sink");
-  gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
-  gst_object_unref (pad);
-
-  return element;
-
-  /* ERRORS */
-no_audioconvert:
-  {
-    post_missing_element_message (play_bin, "audioconvert");
-    GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
-        (_("Missing element '%s' - check your GStreamer installation."),
-            "audioconvert"), ("possibly a liboil version mismatch?"));
-    gst_object_unref (element);
-    return NULL;
-  }
-no_audioresample:
-  {
-    post_missing_element_message (play_bin, "audioresample");
-    GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
-        (_("Missing element '%s' - check your GStreamer installation."),
-            "audioresample"), (NULL));
-    gst_object_unref (element);
-    return NULL;
-  }
-no_goom:
-  {
-    post_missing_element_message (play_bin, "goom");
-    GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
-        (_("Missing element '%s' - check your GStreamer installation."),
-            "goom"), (NULL));
-    gst_object_unref (element);
-    return NULL;
-  }
-link_failed:
-  {
-    GST_ELEMENT_ERROR (play_bin, CORE, PAD,
-        (NULL), ("Failed to configure the visualisation element."));
-    gst_object_unref (element);
-    return NULL;
-  }
-}
-
-/* get rid of all installed sinks */
-static void
-remove_sinks (GstPlayBin * play_bin)
-{
-  GList *sinks;
-  GstObject *parent;
-  GstElement *element;
-  GstPad *pad, *peer;
-
-  if (play_bin->cache == NULL)
-    return;
-
-  GST_DEBUG ("removesinks");
-  element = g_hash_table_lookup (play_bin->cache, "abin");
-  if (element != NULL) {
-    parent = gst_element_get_parent (element);
-    if (parent != NULL) {
-      /* we remove the element from the parent so that
-       * there is no unwanted state change when the parent
-       * is disposed */
-      play_bin->sinks = g_list_remove (play_bin->sinks, element);
-      gst_element_set_state (element, GST_STATE_NULL);
-      gst_bin_remove (GST_BIN_CAST (parent), element);
-      gst_object_unref (parent);
-    }
-    pad = gst_element_get_static_pad (element, "sink");
-    if (pad != NULL) {
-      peer = gst_pad_get_peer (pad);
-      if (peer != NULL) {
-        gst_pad_unlink (peer, pad);
-        gst_object_unref (peer);
-      }
-      gst_object_unref (pad);
-    }
-  }
-  element = g_hash_table_lookup (play_bin->cache, "vbin");
-  if (element != NULL) {
-    parent = gst_element_get_parent (element);
-    if (parent != NULL) {
-      play_bin->sinks = g_list_remove (play_bin->sinks, element);
-      gst_element_set_state (element, GST_STATE_NULL);
-      gst_bin_remove (GST_BIN_CAST (parent), element);
-      gst_object_unref (parent);
-    }
-    pad = gst_element_get_static_pad (element, "sink");
-    if (pad != NULL) {
-      peer = gst_pad_get_peer (pad);
-      if (peer != NULL) {
-        gst_pad_unlink (peer, pad);
-        gst_object_unref (peer);
-      }
-      gst_object_unref (pad);
-    }
-  }
-
-  for (sinks = play_bin->sinks; sinks; sinks = g_list_next (sinks)) {
-    GstElement *element = GST_ELEMENT_CAST (sinks->data);
-    GstPad *pad;
-    GstPad *peer;
-
-    pad = gst_element_get_static_pad (element, "sink");
-
-    GST_LOG ("removing sink %p", element);
-
-    peer = gst_pad_get_peer (pad);
-    if (peer) {
-      gst_pad_unlink (peer, pad);
-      gst_object_unref (peer);
-    }
-    gst_object_unref (pad);
-
-    gst_element_set_state (element, GST_STATE_NULL);
-    gst_bin_remove (GST_BIN_CAST (play_bin), element);
-  }
-  g_list_free (play_bin->sinks);
-  play_bin->sinks = NULL;
-
-  if (play_bin->visualisation) {
-    GstElement *vis_bin;
-
-    vis_bin =
-        GST_ELEMENT_CAST (gst_element_get_parent (play_bin->visualisation));
-
-    gst_element_set_state (play_bin->visualisation, GST_STATE_NULL);
-
-    if (vis_bin) {
-      gst_bin_remove (GST_BIN_CAST (vis_bin), play_bin->visualisation);
-      gst_object_unref (vis_bin);
-    }
-  }
-
-  if (play_bin->frame) {
-    gst_buffer_unref (play_bin->frame);
-    play_bin->frame = NULL;
-  }
-
-  if (play_bin->textoverlay_element) {
-    gst_object_unref (play_bin->textoverlay_element);
-    play_bin->textoverlay_element = NULL;
-  }
-}
-
-/* loop over the streams and set up the pipeline to play this
- * media file. First we count the number of audio and video streams.
- * If there is no video stream but there exists an audio stream,
- * we install a visualisation pipeline.
- *
- * Also make sure to only connect the first audio and video pad. FIXME
- * this should eventually be handled with a tuner interface so that
- * one can switch the streams.
- *
- * This function takes ownership of @sink.*
- */
-static gboolean
-add_sink (GstPlayBin * play_bin, GstElement * sink, GstPad * srcpad,
-    GstPad * subtitle_pad)
-{
-  GstPad *sinkpad;
-  GstPadLinkReturn linkres;
-  GstElement *parent;
-  GstStateChangeReturn stateret;
-  GstState state;
-
-  g_return_val_if_fail (sink != NULL, FALSE);
-
-  state = GST_STATE_PAUSED;
-
-  /* this is only for debugging */
-  parent = gst_pad_get_parent_element (srcpad);
-  if (parent) {
-    GST_DEBUG ("Adding sink %" GST_PTR_FORMAT
-        " with state %d (parent: %d, peer: %d)", sink,
-        GST_STATE (sink), GST_STATE (play_bin), GST_STATE (parent));
-    gst_object_unref (parent);
-  }
-  gst_bin_add (GST_BIN_CAST (play_bin), sink);
-
-  /* bring it to the required state so we can link to the peer without
-   * breaking the flow */
-  stateret = gst_element_set_state (sink, state);
-  if (stateret == GST_STATE_CHANGE_FAILURE)
-    goto state_failed;
-
-  /* we found a sink for this stream, now try to install it */
-  sinkpad = gst_element_get_static_pad (sink, "sink");
-  linkres = gst_pad_link (srcpad, sinkpad);
-  gst_object_unref (sinkpad);
-
-  /* try to link the pad of the sink to the stream */
-  if (GST_PAD_LINK_FAILED (linkres))
-    goto link_failed;
-
-  if (GST_IS_PAD (subtitle_pad)) {
-    sinkpad = gst_element_get_static_pad (sink, "text_sink");
-    linkres = gst_pad_link (subtitle_pad, sinkpad);
-    gst_object_unref (sinkpad);
-  }
-
-  /* try to link the subtitle pad of the sink to the stream, this is not
-   * fatal. */
-  if (GST_PAD_LINK_FAILED (linkres))
-    goto subtitle_failed;
-
-done:
-  /* we got the sink succesfully linked, now keep the sink
-   * in our internal list */
-  play_bin->sinks = g_list_prepend (play_bin->sinks, sink);
-
-  return TRUE;
-
-  /* ERRORS */
-state_failed:
-  {
-    gst_element_set_state (sink, GST_STATE_NULL);
-    gst_bin_remove (GST_BIN_CAST (play_bin), sink);
-    GST_DEBUG_OBJECT (play_bin, "state change failure when adding sink");
-    return FALSE;
-  }
-link_failed:
-  {
-    gchar *capsstr;
-    GstCaps *caps;
-
-    /* could not link this stream */
-    caps = gst_pad_get_caps (srcpad, NULL);
-    capsstr = gst_caps_to_string (caps);
-    g_warning ("could not link %s: %d", capsstr, linkres);
-    GST_DEBUG_OBJECT (play_bin,
-        "link failed when adding sink, caps %s, reason %d", capsstr, linkres);
-    g_free (capsstr);
-    gst_caps_unref (caps);
-
-    gst_element_set_state (sink, GST_STATE_NULL);
-    gst_bin_remove (GST_BIN_CAST (play_bin), sink);
-    return FALSE;
-  }
-subtitle_failed:
-  {
-    GstCaps *caps;
-
-    /* could not link this stream */
-    caps = gst_pad_get_caps (subtitle_pad, NULL);
-    GST_WARNING_OBJECT (play_bin, "subtitle link failed when adding sink, "
-        "caps = %" GST_PTR_FORMAT ", reason %d", caps, linkres);
-    gst_caps_unref (caps);
-
-    /* not fatal */
-    goto done;
-  }
-}
-
-static gboolean
-setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group)
-{
-  GstPlayBin *play_bin = GST_PLAY_BIN (play_base_bin);
-  gboolean have_video = FALSE;
-  gboolean need_vis = FALSE;
-  gboolean need_text = FALSE;
-  gboolean need_spu = FALSE;
-  GstPad *textsrcpad = NULL, *pad = NULL, *origtextsrcpad = NULL;
-  GstElement *sink;
-  gboolean res = TRUE;
-
-  /* get rid of existing sinks */
-  if (play_bin->sinks) {
-    remove_sinks (play_bin);
-  }
-  GST_DEBUG_OBJECT (play_base_bin, "setupsinks");
-
-  /* find out what to do */
-  have_video = (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0);
-  need_spu = (group->type[GST_STREAM_TYPE_SUBPICTURE - 1].npads != 0);
-
-  if (have_video && group->type[GST_STREAM_TYPE_TEXT - 1].npads > 0) {
-    need_text = TRUE;
-  } else if (!have_video &&
-      group->type[GST_STREAM_TYPE_AUDIO - 1].npads > 0 &&
-      play_bin->visualisation != NULL) {
-    need_vis = TRUE;
-  }
-
-  /* now actually connect everything */
-
-  /* link audio */
-  if (group->type[GST_STREAM_TYPE_AUDIO - 1].npads > 0) {
-    if (need_vis) {
-      sink = gen_vis_element (play_bin);
-    } else {
-      sink = gen_audio_element (play_bin);
-    }
-    if (!sink)
-      return FALSE;
-
-    pad =
-        gst_element_get_static_pad (group->type[GST_STREAM_TYPE_AUDIO -
-            1].preroll, "src");
-    res = add_sink (play_bin, sink, pad, NULL);
-    gst_object_unref (pad);
-  }
-
-  /* link video */
-  if (have_video) {
-    /* Create the video rendering bin, error is posted when this fails. */
-    sink = gen_video_element (play_bin);
-    if (!sink)
-      return FALSE;
-    if (need_spu) {
-      sink = add_spu_element (play_bin, sink);
-    }
-
-    if (need_text) {
-      GstObject *parent = NULL, *grandparent = NULL;
-      GstPad *ghost = NULL;
-
-      /* Add the subtitle overlay element into the video sink */
-      sink = add_text_element (play_bin, sink);
-
-      /* Link the incoming subtitle stream into the output bin */
-      textsrcpad =
-          gst_element_get_static_pad (group->type[GST_STREAM_TYPE_TEXT -
-              1].preroll, "src");
-
-      /* This pad is from subtitle-bin, we need to create a ghost pad to have
-         common grandparents */
-      parent = gst_object_get_parent (GST_OBJECT_CAST (textsrcpad));
-      if (!parent) {
-        GST_WARNING_OBJECT (textsrcpad, "subtitle pad has no parent !");
-        gst_object_unref (textsrcpad);
-        textsrcpad = NULL;
-        goto beach;
-      }
-
-      grandparent = gst_object_get_parent (parent);
-      if (!grandparent) {
-        GST_WARNING_OBJECT (textsrcpad, "subtitle pad has no grandparent !");
-        gst_object_unref (parent);
-        gst_object_unref (textsrcpad);
-        textsrcpad = NULL;
-        goto beach;
-      }
-
-      /* We ghost the pad on subtitle_bin only, if the text pad is from the
-         media demuxer we keep it as it is */
-      if (!GST_IS_PLAY_BIN (grandparent)) {
-        GST_DEBUG_OBJECT (textsrcpad, "this subtitle pad is from a subtitle "
-            "file, ghosting to a suitable hierarchy");
-        /* Block the pad first, because as soon as we add a ghostpad, the queue
-         * will try and start pushing */
-        play_bin->text_id =
-            gst_pad_add_probe (textsrcpad, GST_PROBE_TYPE_BLOCK, NULL, NULL,
-            NULL);
-        origtextsrcpad = gst_object_ref (textsrcpad);
-
-        ghost = gst_ghost_pad_new ("text_src", textsrcpad);
-        if (!GST_IS_PAD (ghost)) {
-          GST_WARNING_OBJECT (textsrcpad, "failed creating ghost pad for "
-              "subtitle-bin");
-          gst_object_unref (parent);
-          gst_object_unref (grandparent);
-          gst_object_unref (textsrcpad);
-          textsrcpad = NULL;
-          goto beach;
-        }
-
-        gst_pad_set_active (ghost, TRUE);
-        if (gst_element_add_pad (GST_ELEMENT_CAST (grandparent), ghost)) {
-          gst_object_unref (textsrcpad);
-          textsrcpad = gst_object_ref (ghost);
-        } else {
-          GST_WARNING_OBJECT (ghost, "failed adding ghost pad on subtitle-bin");
-          gst_pad_set_active (ghost, FALSE);
-          gst_object_unref (ghost);
-          gst_object_unref (textsrcpad);
-          textsrcpad = NULL;
-        }
-      } else {
-        GST_DEBUG_OBJECT (textsrcpad, "this subtitle pad is from the demuxer "
-            "no changes to hierarchy needed");
-      }
-
-      gst_object_unref (parent);
-      gst_object_unref (grandparent);
-    }
-  beach:
-    if (!sink)
-      return FALSE;
-    pad =
-        gst_element_get_static_pad (group->type[GST_STREAM_TYPE_VIDEO -
-            1].preroll, "src");
-    res = add_sink (play_bin, sink, pad, textsrcpad);
-    gst_object_unref (pad);
-    if (textsrcpad)
-      gst_object_unref (textsrcpad);
-    if (origtextsrcpad) {
-      if (play_bin->text_id) {
-        gst_pad_remove_probe (origtextsrcpad, play_bin->text_id);
-        play_bin->text_id = 0;
-      }
-      gst_object_unref (origtextsrcpad);
-    }
-
-    /* If we have a DVD subpicture stream, link it to the SPU now */
-    if (need_spu) {
-      GstPad *subpic_pad;
-      GstPad *spu_sink_pad;
-
-      subpic_pad =
-          gst_element_get_static_pad (group->type[GST_STREAM_TYPE_SUBPICTURE
-              - 1].preroll, "src");
-      spu_sink_pad = gst_element_get_static_pad (sink, "subpicture_sink");
-      if (subpic_pad && spu_sink_pad) {
-        GST_LOG_OBJECT (play_bin, "Linking DVD subpicture stream onto SPU");
-        play_bin->sub_id =
-            gst_pad_add_probe (subpic_pad, GST_PROBE_TYPE_BLOCK, NULL, NULL,
-            NULL);
-        if (gst_pad_link (subpic_pad, spu_sink_pad) != GST_PAD_LINK_OK) {
-          GST_WARNING_OBJECT (play_bin,
-              "Failed to link DVD subpicture stream onto SPU");
-        }
-        if (play_bin->sub_id) {
-          gst_pad_remove_probe (subpic_pad, play_bin->sub_id);
-          play_bin->sub_id = 0;
-        }
-      }
-      if (subpic_pad)
-        gst_object_unref (subpic_pad);
-      if (spu_sink_pad)
-        gst_object_unref (spu_sink_pad);
-    }
-  }
-
-  /* remove the sinks now, pipeline get_state will now wait for the
-   * sinks to preroll */
-  if (play_bin->fakesink) {
-    gst_element_set_state (play_bin->fakesink, GST_STATE_NULL);
-    gst_bin_remove (GST_BIN_CAST (play_bin), play_bin->fakesink);
-    play_bin->fakesink = NULL;
-  }
-
-  return res;
-}
-
-static void
-playbin_set_subtitles_visible (GstPlayBaseBin * play_base_bin, gboolean visible)
-{
-  GstPlayBin *playbin = GST_PLAY_BIN (play_base_bin);
-
-  /* we're ignoring the case of someone setting the 'current-text' property
-   * before textoverlay is set up (which is probably okay, since playbasebin
-   * will just select the first subtitle stream as active stream regardless) */
-  if (playbin->textoverlay_element != NULL) {
-    GST_LOG_OBJECT (playbin, "setting subtitle visibility to %d", visible);
-    g_object_set (playbin->textoverlay_element, "silent", !visible, NULL);
-  }
-}
-
-static void
-playbin_set_audio_mute (GstPlayBaseBin * play_base_bin, gboolean mute)
-{
-  GstPlayBin *playbin = GST_PLAY_BIN (play_base_bin);
-
-  if (playbin->volume_element) {
-    g_object_set (G_OBJECT (playbin->volume_element), "mute", mute, NULL);
-  }
-}
-
-/* Send an event to our sinks until one of them works; don't then send to the
- * remaining sinks (unlike GstBin)
- */
-static gboolean
-gst_play_bin_send_event_to_sink (GstPlayBin * play_bin, GstEvent * event)
-{
-  GList *sinks = play_bin->sinks;
-  gboolean res = TRUE;
-
-  while (sinks) {
-    GstElement *sink = GST_ELEMENT_CAST (sinks->data);
-
-    gst_event_ref (event);
-    if ((res = gst_element_send_event (sink, event))) {
-      GST_DEBUG_OBJECT (play_bin,
-          "Sent event succesfully to sink %" GST_PTR_FORMAT, sink);
-      break;
-    }
-    GST_DEBUG_OBJECT (play_bin,
-        "Event failed when sent to sink %" GST_PTR_FORMAT, sink);
-
-    sinks = g_list_next (sinks);
-  }
-
-  gst_event_unref (event);
-
-  return res;
-}
-
-/* We only want to send the event to a single sink (overriding GstBin's
- * behaviour), but we want to keep GstPipeline's behaviour - wrapping seek
- * events appropriately. So, this is a messy duplication of code. */
-static gboolean
-gst_play_bin_send_event (GstElement * element, GstEvent * event)
-{
-  gboolean res = FALSE;
-  GstEventType event_type = GST_EVENT_TYPE (event);
-
-  switch (event_type) {
-    case GST_EVENT_SEEK:
-      GST_DEBUG_OBJECT (element, "Sending seek event to a sink");
-      res = gst_play_bin_send_event_to_sink (GST_PLAY_BIN (element), event);
-      break;
-    default:
-      res = parent_class->send_event (element, event);
-      break;
-  }
-
-  return res;
-}
-
-static void
-value_list_append_structure_list (GValue * list_val, GstStructure ** first,
-    GList * structure_list)
-{
-  GList *l;
-
-  for (l = structure_list; l != NULL; l = l->next) {
-    GValue val = { 0, };
-
-    if (*first == NULL)
-      *first = gst_structure_copy ((GstStructure *) l->data);
-
-    g_value_init (&val, GST_TYPE_STRUCTURE);
-    g_value_take_boxed (&val, gst_structure_copy ((GstStructure *) l->data));
-    gst_value_list_append_value (list_val, &val);
-    g_value_unset (&val);
-  }
-}
-
-/* if it's a redirect message with multiple redirect locations we might
- * want to pick a different 'best' location depending on the required
- * bitrates and the connection speed */
-static GstMessage *
-gst_play_bin_handle_redirect_message (GstPlayBin * playbin, GstMessage * msg)
-{
-  const GValue *locations_list, *location_val;
-  GstMessage *new_msg;
-  GstStructure *new_structure = NULL;
-  GList *l_good = NULL, *l_neutral = NULL, *l_bad = NULL;
-  GValue new_list = { 0, };
-  guint size, i;
-  GstPlayBaseBin *playbasebin = GST_PLAY_BASE_BIN (playbin);
-  guint connection_speed = playbasebin->connection_speed;
-  const GstStructure *structure;
-
-  GST_DEBUG_OBJECT (playbin, "redirect message: %" GST_PTR_FORMAT, msg);
-  GST_DEBUG_OBJECT (playbin, "connection speed: %u", connection_speed);
-
-  structure = gst_message_get_structure (msg);
-  if (connection_speed == 0 || structure == NULL)
-    return msg;
-
-  locations_list = gst_structure_get_value (structure, "locations");
-  if (locations_list == NULL)
-    return msg;
-
-  size = gst_value_list_get_size (locations_list);
-  if (size < 2)
-    return msg;
-
-  /* maintain existing order as much as possible, just sort references
-   * with too high a bitrate to the end (the assumption being that if
-   * bitrates are given they are given for all interesting streams and
-   * that the you-need-at-least-version-xyz redirect has the same bitrate
-   * as the lowest referenced redirect alternative) */
-  for (i = 0; i < size; ++i) {
-    const GstStructure *s;
-    gint bitrate = 0;
-
-    location_val = gst_value_list_get_value (locations_list, i);
-    s = (const GstStructure *) g_value_get_boxed (location_val);
-    if (!gst_structure_get_int (s, "minimum-bitrate", &bitrate) || bitrate <= 0) {
-      GST_DEBUG_OBJECT (playbin, "no bitrate: %" GST_PTR_FORMAT, s);
-      l_neutral = g_list_append (l_neutral, (gpointer) s);
-    } else if (bitrate > connection_speed) {
-      GST_DEBUG_OBJECT (playbin, "bitrate too high: %" GST_PTR_FORMAT, s);
-      l_bad = g_list_append (l_bad, (gpointer) s);
-    } else if (bitrate <= connection_speed) {
-      GST_DEBUG_OBJECT (playbin, "bitrate OK: %" GST_PTR_FORMAT, s);
-      l_good = g_list_append (l_good, (gpointer) s);
-    }
-  }
-
-  g_value_init (&new_list, GST_TYPE_LIST);
-  value_list_append_structure_list (&new_list, &new_structure, l_good);
-  value_list_append_structure_list (&new_list, &new_structure, l_neutral);
-  value_list_append_structure_list (&new_list, &new_structure, l_bad);
-  gst_structure_set_value (new_structure, "locations", &new_list);
-  g_value_unset (&new_list);
-
-  g_list_free (l_good);
-  g_list_free (l_neutral);
-  g_list_free (l_bad);
-
-  new_msg = gst_message_new_element (msg->src, new_structure);
-  gst_message_unref (msg);
-
-  GST_DEBUG_OBJECT (playbin, "new redirect message: %" GST_PTR_FORMAT, new_msg);
-  return new_msg;
-}
-
-static void
-gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
-{
-  const GstStructure *structure;
-
-  structure = gst_message_get_structure (msg);
-  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT && structure != NULL
-      && gst_structure_has_name (structure, "redirect")) {
-    msg = gst_play_bin_handle_redirect_message (GST_PLAY_BIN (bin), msg);
-  }
-
-  GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
-}
-
-static GstStateChangeReturn
-gst_play_bin_change_state (GstElement * element, GstStateChange transition)
-{
-  GstStateChangeReturn ret;
-  GstPlayBin *play_bin;
-
-  play_bin = GST_PLAY_BIN (element);
-
-
-  switch (transition) {
-    case GST_STATE_CHANGE_READY_TO_PAUSED:
-      /* this really is the easiest way to make the state change return
-       * ASYNC until we added the sinks */
-      if (!play_bin->fakesink) {
-        play_bin->fakesink = gst_element_factory_make ("fakesink", "test");
-        gst_bin_add (GST_BIN_CAST (play_bin), play_bin->fakesink);
-      }
-      break;
-    default:
-      break;
-  }
-
-  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-  if (ret == GST_STATE_CHANGE_FAILURE)
-    return ret;
-
-  switch (transition) {
-    case GST_STATE_CHANGE_READY_TO_PAUSED:
-      /* remember us being a live pipeline */
-      play_bin->is_live = (ret == GST_STATE_CHANGE_NO_PREROLL);
-      GST_DEBUG_OBJECT (play_bin, "is live: %d", play_bin->is_live);
-      break;
-    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
-      /* FIXME Release audio device when we implement that */
-      break;
-    case GST_STATE_CHANGE_PAUSED_TO_READY:
-    case GST_STATE_CHANGE_READY_TO_NULL:
-      /* remove sinks we added */
-      remove_sinks (play_bin);
-      /* and there might be a fakesink we need to clean up now */
-      if (play_bin->fakesink) {
-        gst_element_set_state (play_bin->fakesink, GST_STATE_NULL);
-        gst_bin_remove (GST_BIN_CAST (play_bin), play_bin->fakesink);
-        play_bin->fakesink = NULL;
-      }
-      break;
-    default:
-      break;
-  }
-
-  return ret;
-}
-
-gboolean
-gst_play_bin_plugin_init (GstPlugin * plugin)
-{
-  GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin", 0, "play bin");
-
-  return gst_element_register (plugin, "playbin", GST_RANK_NONE,
-      GST_TYPE_PLAY_BIN);
-}
diff --git a/gst/playback/gststreaminfo.c b/gst/playback/gststreaminfo.c
deleted file mode 100644 (file)
index cfbc9b2..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-#include <gst/gst.h>
-#include "gststreaminfo.h"
-
-GST_DEBUG_CATEGORY_STATIC (gst_streaminfo_debug);
-#define GST_CAT_DEFAULT gst_streaminfo_debug
-
-/* props */
-enum
-{
-  ARG_0,
-  ARG_PAD,
-  ARG_TYPE,
-  ARG_DECODER,
-  ARG_MUTE,
-  ARG_CAPS,
-  ARG_LANG_CODE,
-  ARG_CODEC
-};
-
-/* signals */
-enum
-{
-  SIGNAL_MUTED,
-  LAST_SIGNAL
-};
-
-static guint gst_stream_info_signals[LAST_SIGNAL] = { 0 };
-
-#define GST_TYPE_STREAM_TYPE (gst_stream_type_get_type())
-static GType
-gst_stream_type_get_type (void)
-{
-  static GType stream_type_type = 0;
-  static const GEnumValue stream_type[] = {
-    {GST_STREAM_TYPE_UNKNOWN, "Unknown stream", "unknown"},
-    {GST_STREAM_TYPE_AUDIO, "Audio stream", "audio"},
-    {GST_STREAM_TYPE_VIDEO, "Video stream", "video"},
-    {GST_STREAM_TYPE_TEXT, "Text stream", "text"},
-    {GST_STREAM_TYPE_SUBPICTURE, "Subpicture stream", "subpicture"},
-    {GST_STREAM_TYPE_ELEMENT,
-        "Stream handled by element", "element"},
-    {0, NULL, NULL},
-  };
-
-  if (!stream_type_type) {
-    stream_type_type = g_enum_register_static ("GstStreamType", stream_type);
-  }
-  return stream_type_type;
-}
-
-static void gst_stream_info_class_init (GstStreamInfoClass * klass);
-static void gst_stream_info_init (GstStreamInfo * stream_info);
-static void gst_stream_info_dispose (GObject * object);
-
-static void stream_info_change_state (GstElement * element,
-    gint old_state, gint new_state, gpointer data);
-
-static void gst_stream_info_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * spec);
-static void gst_stream_info_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * spec);
-
-static GObjectClass *parent_class;
-
-//static guint gst_stream_info_signals[LAST_SIGNAL] = { 0 };
-
-GType
-gst_stream_info_get_type (void)
-{
-  static GType gst_stream_info_type = 0;
-
-  if (!gst_stream_info_type) {
-    static const GTypeInfo gst_stream_info_info = {
-      sizeof (GstStreamInfoClass),
-      NULL,
-      NULL,
-      (GClassInitFunc) gst_stream_info_class_init,
-      NULL,
-      NULL,
-      sizeof (GstStreamInfo),
-      0,
-      (GInstanceInitFunc) gst_stream_info_init,
-      NULL
-    };
-    gst_stream_info_type = g_type_register_static (G_TYPE_OBJECT,
-        "GstStreamInfo", &gst_stream_info_info, 0);
-  }
-
-  return gst_stream_info_type;
-}
-
-static void
-gst_stream_info_class_init (GstStreamInfoClass * klass)
-{
-  GObjectClass *gobject_klass;
-
-  gobject_klass = (GObjectClass *) klass;
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  gobject_klass->set_property = gst_stream_info_set_property;
-  gobject_klass->get_property = gst_stream_info_get_property;
-
-  g_object_class_install_property (gobject_klass, ARG_PAD,
-      g_param_spec_object ("object", "object",
-          "Source Pad or object of the stream", GST_TYPE_OBJECT,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_TYPE,
-      g_param_spec_enum ("type", "Type", "Type of the stream",
-          GST_TYPE_STREAM_TYPE, GST_STREAM_TYPE_UNKNOWN,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_DECODER,
-      g_param_spec_string ("decoder", "Decoder",
-          "The decoder used to decode the stream", NULL,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_MUTE,
-      g_param_spec_boolean ("mute", "Mute", "Mute or unmute this stream", FALSE,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_CAPS,
-      g_param_spec_boxed ("caps", "Capabilities",
-          "Capabilities (or type) of this stream", GST_TYPE_CAPS,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_LANG_CODE,
-      g_param_spec_string ("language-code", "Language code",
-          "Language code for this stream, conforming to ISO-639-1", NULL,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, ARG_CODEC,
-      g_param_spec_string ("codec", "Codec", "Codec used to encode the stream",
-          NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
-  gst_stream_info_signals[SIGNAL_MUTED] =
-      g_signal_new ("muted", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
-      G_STRUCT_OFFSET (GstStreamInfoClass, muted), NULL, NULL,
-      gst_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
-
-  gobject_klass->dispose = gst_stream_info_dispose;
-
-  GST_DEBUG_CATEGORY_INIT (gst_streaminfo_debug, "streaminfo", 0,
-      "Playbin Stream Info");
-}
-
-
-static void
-gst_stream_info_init (GstStreamInfo * stream_info)
-{
-  stream_info->object = NULL;
-  stream_info->origin = NULL;
-  stream_info->type = GST_STREAM_TYPE_UNKNOWN;
-  stream_info->decoder = NULL;
-  stream_info->mute = FALSE;
-  stream_info->caps = NULL;
-}
-
-static GstProbeReturn
-cb_probe (GstPad * pad, GstProbeType type, gpointer type_data,
-    gpointer user_data)
-{
-  GstEvent *e = type_data;
-  GstStreamInfo *info = user_data;
-
-  if (GST_EVENT_TYPE (e) == GST_EVENT_TAG) {
-    gchar *codec, *lang;
-    GstTagList *list;
-
-    gst_event_parse_tag (e, &list);
-
-    if (info->type != GST_STREAM_TYPE_AUDIO &&
-        gst_tag_list_get_string (list, GST_TAG_VIDEO_CODEC, &codec)) {
-      g_free (info->codec);
-      info->codec = codec;
-      GST_LOG_OBJECT (pad, "codec = %s (video)", codec);
-      g_object_notify (G_OBJECT (info), "codec");
-    } else if (info->type != GST_STREAM_TYPE_VIDEO &&
-        gst_tag_list_get_string (list, GST_TAG_AUDIO_CODEC, &codec)) {
-      g_free (info->codec);
-      info->codec = codec;
-      GST_LOG_OBJECT (pad, "codec = %s (audio)", codec);
-      g_object_notify (G_OBJECT (info), "codec");
-    } else if (gst_tag_list_get_string (list, GST_TAG_CODEC, &codec)) {
-      g_free (info->codec);
-      info->codec = codec;
-      GST_LOG_OBJECT (pad, "codec = %s (generic)", codec);
-      g_object_notify (G_OBJECT (info), "codec");
-    }
-    if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
-      g_free (info->langcode);
-      info->langcode = lang;
-      GST_LOG_OBJECT (pad, "language-code = %s", lang);
-      g_object_notify (G_OBJECT (info), "language-code");
-    }
-  }
-
-  return TRUE;
-}
-
-GstStreamInfo *
-gst_stream_info_new (GstObject * object,
-    GstStreamType type, const gchar * decoder, const GstCaps * caps)
-{
-  GstStreamInfo *info;
-
-  info = g_object_new (GST_TYPE_STREAM_INFO, NULL);
-
-  gst_object_ref (object);
-  if (GST_IS_PAD (object)) {
-    gst_pad_add_probe (GST_PAD_CAST (object), GST_PROBE_TYPE_EVENT,
-        cb_probe, info, NULL);
-  }
-  info->object = object;
-  info->type = type;
-  info->decoder = g_strdup (decoder);
-  info->origin = object;
-  if (caps) {
-    info->caps = gst_caps_copy (caps);
-  }
-
-  return info;
-}
-
-static void
-gst_stream_info_dispose (GObject * object)
-{
-  GstStreamInfo *stream_info;
-
-  stream_info = GST_STREAM_INFO (object);
-
-  if (stream_info->object) {
-    GstElement *parent;
-
-    parent = gst_pad_get_parent_element ((GstPad *)
-        GST_PAD_CAST (stream_info->object));
-    if (parent != NULL) {
-      g_signal_handlers_disconnect_by_func (parent,
-          (gpointer) stream_info_change_state, stream_info);
-      gst_object_unref (parent);
-    }
-
-    gst_object_unref (stream_info->object);
-    stream_info->object = NULL;
-  }
-  stream_info->origin = NULL;
-  stream_info->type = GST_STREAM_TYPE_UNKNOWN;
-  g_free (stream_info->decoder);
-  stream_info->decoder = NULL;
-  g_free (stream_info->langcode);
-  stream_info->langcode = NULL;
-  g_free (stream_info->codec);
-  stream_info->codec = NULL;
-  if (stream_info->caps) {
-    gst_caps_unref (stream_info->caps);
-    stream_info->caps = NULL;
-  }
-
-  if (G_OBJECT_CLASS (parent_class)->dispose) {
-    G_OBJECT_CLASS (parent_class)->dispose (object);
-  }
-}
-
-static void
-stream_info_change_state (GstElement * element,
-    gint old_state, gint new_state, gpointer data)
-{
-  GstStreamInfo *stream_info = data;
-
-  if (new_state == GST_STATE_PLAYING) {
-    /* state change will annoy us */
-    g_return_if_fail (stream_info->mute == TRUE);
-    GST_DEBUG_OBJECT (stream_info, "Re-muting pads after state-change");
-    //gst_pad_set_active_recursive (GST_PAD (stream_info->object), FALSE);
-    g_warning ("FIXME");
-  }
-}
-
-gboolean
-gst_stream_info_set_mute (GstStreamInfo * stream_info, gboolean mute)
-{
-  g_return_val_if_fail (GST_IS_STREAM_INFO (stream_info), FALSE);
-
-  if (stream_info->type == GST_STREAM_TYPE_ELEMENT) {
-    g_warning ("cannot mute element stream");
-    return FALSE;
-  }
-
-  if (mute != stream_info->mute) {
-    /* nothing really happens here. it looks like gstplaybasebin installs a
-     * buffer probe hat drops buffers when muting. but the this removes it self
-     * after first call.
-     */
-
-    stream_info->mute = mute;
-#if 0
-    gst_pad_set_active ((GstPad *) GST_PAD_CAST (stream_info->object), !mute);
-#endif
-#if 0
-    {
-      GstElement *element;
-
-      element = gst_pad_get_parent_element ((GstPad *)
-          GST_PAD_CAST (stream_info->object));
-      if (element) {
-        if (mute) {
-          g_signal_connect (element, "state-changed",
-              G_CALLBACK (stream_info_change_state), stream_info);
-        } else {
-          g_signal_handlers_disconnect_by_func (element,
-              G_CALLBACK (stream_info_change_state), stream_info);
-        }
-        gst_object_unref (element);
-      }
-    }
-#endif
-  }
-  return TRUE;
-}
-
-gboolean
-gst_stream_info_is_mute (GstStreamInfo * stream_info)
-{
-  g_return_val_if_fail (GST_IS_STREAM_INFO (stream_info), TRUE);
-
-  return stream_info->mute;
-}
-
-static void
-gst_stream_info_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec)
-{
-  GstStreamInfo *stream_info;
-
-  g_return_if_fail (GST_IS_STREAM_INFO (object));
-
-  stream_info = GST_STREAM_INFO (object);
-
-  switch (prop_id) {
-    case ARG_MUTE:
-      gst_stream_info_set_mute (stream_info, g_value_get_boolean (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static void
-gst_stream_info_get_property (GObject * object, guint prop_id, GValue * value,
-    GParamSpec * pspec)
-{
-  GstStreamInfo *stream_info;
-
-  g_return_if_fail (GST_IS_STREAM_INFO (object));
-
-  stream_info = GST_STREAM_INFO (object);
-
-  switch (prop_id) {
-    case ARG_PAD:
-      g_value_set_object (value, stream_info->object);
-      break;
-    case ARG_TYPE:
-      g_value_set_enum (value, stream_info->type);
-      break;
-    case ARG_DECODER:
-      g_value_set_string (value, stream_info->decoder);
-      break;
-    case ARG_MUTE:
-      g_value_set_boolean (value, stream_info->mute);
-      break;
-    case ARG_CAPS:
-      g_value_set_boxed (value, stream_info->caps);
-      break;
-    case ARG_LANG_CODE:
-      g_value_set_string (value, stream_info->langcode);
-      break;
-    case ARG_CODEC:
-      g_value_set_string (value, stream_info->codec);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
diff --git a/gst/playback/gststreaminfo.h b/gst/playback/gststreaminfo.h
deleted file mode 100644 (file)
index b4157ea..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- *               <2007> Wim Taymans <wim.taymans@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-#ifndef __GST_STREAMINFO_H__
-#define __GST_STREAMINFO_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_STREAM_INFO            (gst_stream_info_get_type())
-#define GST_STREAM_INFO(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_STREAM_INFO,GstStreamInfo))
-#define GST_STREAM_INFO_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_STREAM_INFO,GstStreamInfoClass))
-#define GST_IS_STREAM_INFO(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_STREAM_INFO))
-#define GST_IS_STREAM_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_STREAM_INFO))
-
-typedef struct _GstStreamInfo GstStreamInfo;
-typedef struct _GstStreamInfoClass GstStreamInfoClass;
-
-typedef enum {
-  GST_STREAM_TYPE_UNKNOWN = 0,
-  GST_STREAM_TYPE_AUDIO   = 1,    /* an audio stream */
-  GST_STREAM_TYPE_VIDEO   = 2,    /* a video stream */
-  GST_STREAM_TYPE_TEXT    = 3,    /* a subtitle/text stream */
-  GST_STREAM_TYPE_SUBPICTURE = 4, /* a subtitle in picture-form */
-  GST_STREAM_TYPE_ELEMENT = 5    /* stream handled by an element */
-} GstStreamType;
-
-struct _GstStreamInfo {
-  GObject        parent;
-
-  GstObject     *object;        /* pad/element providing/handling this stream */
-  GstStreamType  type;          /* the type of the provided stream */
-  gchar         *decoder;       /* string describing the decoder */
-  gboolean       mute;          /* is the stream muted or not */
-  GstObject     *origin;        /* the real object providing this stream, this can
-                                   be different from the object as the object can be
-                                   a queue pad, inserted for preroll. */
-  GstCaps       *caps;          /* the caps of the stream */
-
-  /* this is tream information cached here because the streaminfo may be
-   * created before the app can know about it. */
-  gchar         *langcode,
-                *codec;
-};
-
-struct _GstStreamInfoClass {
-  GObjectClass   parent_class;
-
-  /* signals */
-  void (*muted) (GstStreamInfo *info, gboolean mute);
-};
-
-GType gst_stream_info_get_type (void);
-
-GstStreamInfo*  gst_stream_info_new             (GstObject     *object,
-                                                 GstStreamType  type,
-                                                 const gchar   *decoder,
-                                                 const GstCaps *caps);
-
-gboolean        gst_stream_info_set_mute        (GstStreamInfo *stream_info, 
-                                                 gboolean mute);
-gboolean        gst_stream_info_is_mute         (GstStreamInfo *stream_info);
-
-
-G_END_DECLS
-
-#endif /* __GST_STREAMINFO_H__ */