gst_plugins_base/gst/playback/gstplaybin2.c
branchRCL_3
changeset 30 7e817e7e631c
parent 29 567bb019e3e3
--- a/gst_plugins_base/gst/playback/gstplaybin2.c	Tue Aug 31 15:30:33 2010 +0300
+++ b/gst_plugins_base/gst/playback/gstplaybin2.c	Wed Sep 01 12:16:41 2010 +0100
@@ -20,13 +20,12 @@
 /**
  * SECTION:element-playbin2
  *
- * Playbin2 provides a stand-alone everything-in-one abstraction for an
+ * <refsect2>
+ * <para>
+ * Playbin provides a stand-alone everything-in-one abstraction for an
  * audio and/or video player.
- *
- * At this stage, playbin2 is considered UNSTABLE. The API provided in the
- * signals and properties may yet change in the near future. When playbin2
- * is stable, it will probably replace #playbin
- *
+ * </para>
+ * <para>
  * It can handle both audio and video files and features
  * <itemizedlist>
  * <listitem>
@@ -37,11 +36,10 @@
  * visualisations for audio files
  * </listitem>
  * <listitem>
- * subtitle support for video files. Subtitles can be store in external
- * files.
+ * subtitle support for video files
  * </listitem>
  * <listitem>
- * stream selection between different video/audio/subtitles streams
+ * stream selection between different audio/subtitles streams
  * </listitem>
  * <listitem>
  * meta info (tag) extraction
@@ -53,36 +51,39 @@
  * buffering when playing streams over a network
  * </listitem>
  * <listitem>
- * volume control with mute option
+ * volume control
  * </listitem>
  * </itemizedlist>
- *
- * <refsect2>
+ * </para>
  * <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 #GstPlayBin2:uri
+ * gst_element_factory_make(). The file/URI to play should be set via the "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
- *
+ * </para>
+ * <para>
  * 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.
- *
+ * </para>
+ * <para>
  * 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.
- *
+ * </para>
+ * <para>
  * 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 #GstPlayBin2:uri property should be set to the 
- * new location and then playbin be set to PLAYING state again.
- *
+ * READY or NULL state, then the "uri" property should be set to the new
+ * location and then playbin be set to PLAYING state again.
+ * </para>
+ * <para>
  * 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
@@ -90,33 +91,35 @@
  * 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.
- *
+ * </para>
+ * <para>
  * 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
- * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property, playbin will use the autoaudiosink
+ * "audio-sink" or "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.
- *
+ * </para>
+ * <para>
  * 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
- * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property.
- *
+ * "audio-sink" or "video-sink" property.
+ * </para>
+ * <para>
  * 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 configuration dialog.
- *
+ * Multimedia System Selector confinguration dialog.
+ * </para>
+ * <para>
  * 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
@@ -125,25 +128,41 @@
  * 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.
- *
+ * </para>
+ * <para>
  * 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).
- *
+ * </para>
+ * <para>
  * Other more specific meta information like width/height/framerate of video
  * streams or samplerate/number of channels of audio streams can be obtained
- * from the negotiated caps on the sink pads of the sinks.
+ * using the "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 stream-info properties is best queried once
+ * playbin has changed into PAUSED or PLAYING state (which can be detected
+ * via a state-changed message on the bus 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>
+ * <para>
  * 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
@@ -152,7 +171,9 @@
  * 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):
- * |[
+ * </para>
+ * <para>
+ * <programlisting>
  * switch (GST_MESSAGE_TYPE (msg)) {
  *   case GST_MESSAGE_BUFFERING: {
  *     gint percent = 0;
@@ -162,21 +183,21 @@
  *   }
  *   ...
  * }
- * ]|
+ * </programlisting>
  * 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>
+ * </para>
  * <title>Embedding the video window in your application</title>
+ * <para>
  * 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
+ * own, however. This can be done using the GstXOverlay interface, which most
  * video sinks implement. See the documentation there for more details.
- * </refsect2>
- * <refsect2>
+ * </para>
  * <title>Specifying which CD/DVD device to use</title>
+ * <para>
  * 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
@@ -185,34 +206,35 @@
  * 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>Handling redirects</title>
+ * </para>
+ * <title>Examples</title>
  * <para>
- * Some elements may post 'redirect' messages on the bus to tell the
- * application to open another location. These are element messages containing
- * a structure named 'redirect' along with a 'new-location' field of string
- * type. The new location may be a relative or an absolute URI. Examples
- * for such redirects can be found in many quicktime movie trailers.
- * </para>
- * </refsect2>
- * <refsect2>
- * <title>Examples</title>
- * |[
+ * Here is a simple pipeline to play back a video or audio file:
+ * <programlisting>
  * gst-launch -v playbin uri=file:///path/to/somefile.avi
- * ]| This will play back the given AVI video file, given that the video and
+ * </programlisting>
+ * 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.
- * |[
+ * </para>
+ * <para>
+ * Here is a another pipeline to play track 4 of an audio CD:
+ * <programlisting>
  * gst-launch -v playbin uri=cdda://4
- * ]| This will play back track 4 on an audio CD in your disc drive (assuming
+ * </programlisting>
+ * This will play back track 4 on an audio CD in your disc drive (assuming
  * the drive is detected automatically by the plugin).
- * |[
+ * </para>
+ * <para>
+ * Here is a another pipeline to play title 1 of a DVD:
+ * <programlisting>
  * gst-launch -v playbin uri=dvd://1
- * ]| This will play back title 1 of a DVD in your disc drive (assuming
+ * </programlisting>
+ * This will play back title 1 of a DVD in your disc drive (assuming
  * the drive is detected automatically by the plugin).
+ * </para>
  * </refsect2>
  */
 
@@ -230,9 +252,13 @@
 #include "gstplay-marshal.h"
 #include "gstplaysink.h"
 #include "gstfactorylists.h"
-#include "gstinputselector.h"
 #include "gstscreenshot.h"
+#include "gststreaminfo.h"
+#include "gststreamselector.h"
 
+#ifdef __SYMBIAN32__
+#include <glib_global.h>
+#endif
 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
 #define GST_CAT_DEFAULT gst_play_bin_debug
 
@@ -252,7 +278,7 @@
 /* has the info for a selector and provides the link to the sink */
 struct _GstSourceSelect
 {
-  const gchar *media_list[3];   /* the media types for the selector */
+  const gchar *media;           /* the media type of the selector */
   GstPlaySinkType type;         /* the sink pad type of the selector */
 
   GstElement *selector;         /* the selector */
@@ -261,18 +287,12 @@
   GstPad *sinkpad;              /* the sinkpad of the sink when the selector is linked */
 };
 
-#define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
-#define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
-#define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
-
 /* a structure to hold the objects for decoding a uri and the subtitle uri
  */
 struct _GstSourceGroup
 {
   GstPlayBin *playbin;
 
-  GMutex *lock;
-
   gboolean valid;               /* the group has valid info to start playback */
   gboolean active;              /* the group is active */
 
@@ -281,107 +301,41 @@
   gchar *suburi;
   GValueArray *streaminfo;
   GstElement *source;
+  gchar *subencoding;           /* encoding to propagate to the subtitle elements */
 
   GPtrArray *video_channels;    /* links to selector pads */
   GPtrArray *audio_channels;    /* links to selector pads */
   GPtrArray *text_channels;     /* links to selector pads */
-  GPtrArray *subp_channels;     /* links to selector pads */
-
-  GstElement *audio_sink;       /* autoplugged audio and video sinks */
-  GstElement *video_sink;
 
   /* uridecodebins for uri and subtitle uri */
   GstElement *uridecodebin;
   GstElement *suburidecodebin;
-  gint pending;
-
-  gulong pad_added_id;
-  gulong pad_removed_id;
-  gulong no_more_pads_id;
-  gulong notify_source_id;
-  gulong drained_id;
-  gulong autoplug_factories_id;
-  gulong autoplug_select_id;
-
-  gulong sub_pad_added_id;
-  gulong sub_pad_removed_id;
-  gulong sub_no_more_pads_id;
 
   /* selectors for different streams */
   GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST];
 };
 
-#define GST_PLAY_BIN_GET_LOCK(bin) (((GstPlayBin*)(bin))->lock)
-#define GST_PLAY_BIN_LOCK(bin) (g_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
-#define GST_PLAY_BIN_UNLOCK(bin) (g_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
-
-/* lock to protect dynamic callbacks, like no-more-pads */
-#define GST_PLAY_BIN_DYN_LOCK(bin)    g_mutex_lock ((bin)->dyn_lock)
-#define GST_PLAY_BIN_DYN_UNLOCK(bin)  g_mutex_unlock ((bin)->dyn_lock)
-
-/* lock for shutdown */
-#define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label)           \
-G_STMT_START {                                          \
-  if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown)))   \
-    goto label;                                         \
-  GST_PLAY_BIN_DYN_LOCK (bin);                          \
-  if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
-    GST_PLAY_BIN_DYN_UNLOCK (bin);                      \
-    goto label;                                         \
-  }                                                     \
-} G_STMT_END
-
-/* unlock for shutdown */
-#define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin)         \
-  GST_PLAY_BIN_DYN_UNLOCK (bin);                  \
-
-/**
- * GstPlayBin2:
- *
- * playbin element structure
- */
 struct _GstPlayBin
 {
   GstPipeline parent;
 
-  GMutex *lock;                 /* to protect group switching */
-
   /* the groups, we use a double buffer to switch between current and next */
   GstSourceGroup groups[2];     /* array with group info */
   GstSourceGroup *curr_group;   /* pointer to the currently playing group */
   GstSourceGroup *next_group;   /* pointer to the next group */
 
+  gboolean about_to_finish;     /* the about-to-finish signal is emited */
+
   /* properties */
   guint connection_speed;       /* connection speed in bits/sec (0 = unknown) */
   gint current_video;           /* the currently selected stream */
   gint current_audio;           /* the currently selected stream */
   gint current_text;            /* the currently selected stream */
-  gchar *encoding;              /* subtitle encoding */
-
-  guint64 buffer_duration;      /* When buffering, the max buffer duration (ns) */
-  guint buffer_size;            /* When buffering, the max buffer size (bytes) */
 
   /* our play sink */
   GstPlaySink *playsink;
 
-  /* the last activated source */
-  GstElement *source;
-
-  /* lock protecting dynamic adding/removing */
-  GMutex *dyn_lock;
-  /* if we are shutting down or not */
-  gint shutdown;
-
   GValueArray *elements;        /* factories we can use for selecting elements */
-
-  gboolean have_selector;       /* set to FALSE when we fail to create an
-                                 * input-selector, so that we only post a
-                                 * warning once */
-
-  GstElement *audio_sink;       /* configured audio sink, or NULL      */
-  GstElement *video_sink;       /* configured video sink, or NULL      */
-  GstElement *subpic_sink;      /* configured subpicture sink, or NULL */
-  GstElement *text_sink;        /* configured text sink, or NULL       */
 };
 
 struct _GstPlayBinClass
@@ -397,11 +351,6 @@
   void (*audio_changed) (GstPlayBin * playbin);
   void (*text_changed) (GstPlayBin * playbin);
 
-  /* notify app that the tags of audio/video/text streams changed */
-  void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
-  void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
-  void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
-
   /* get audio/video/text tags for a stream */
   GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
   GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
@@ -409,11 +358,6 @@
 
   /* get the last video frame and convert it to the given caps */
   GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
-
-  /* get audio/video/text pad for a stream */
-  GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
-  GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
-  GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
 };
 
 /* props */
@@ -432,15 +376,11 @@
 #define DEFAULT_AUDIO_SINK        NULL
 #define DEFAULT_VIDEO_SINK        NULL
 #define DEFAULT_VIS_PLUGIN        NULL
-#define DEFAULT_TEXT_SINK         NULL
-#define DEFAULT_SUBPIC_SINK       NULL
 #define DEFAULT_VOLUME            1.0
 #define DEFAULT_MUTE              FALSE
 #define DEFAULT_FRAME             NULL
 #define DEFAULT_FONT_DESC         NULL
 #define DEFAULT_CONNECTION_SPEED  0
-#define DEFAULT_BUFFER_DURATION   -1
-#define DEFAULT_BUFFER_SIZE       -1
 
 enum
 {
@@ -459,35 +399,23 @@
   PROP_AUDIO_SINK,
   PROP_VIDEO_SINK,
   PROP_VIS_PLUGIN,
-  PROP_TEXT_SINK,
-  PROP_SUBPIC_SINK,
   PROP_VOLUME,
   PROP_MUTE,
   PROP_FRAME,
   PROP_FONT_DESC,
-  PROP_CONNECTION_SPEED,
-  PROP_BUFFER_SIZE,
-  PROP_BUFFER_DURATION,
-  PROP_LAST
+  PROP_CONNECTION_SPEED
 };
 
 /* signals */
 enum
 {
   SIGNAL_ABOUT_TO_FINISH,
-  SIGNAL_CONVERT_FRAME,
   SIGNAL_VIDEO_CHANGED,
   SIGNAL_AUDIO_CHANGED,
   SIGNAL_TEXT_CHANGED,
-  SIGNAL_VIDEO_TAGS_CHANGED,
-  SIGNAL_AUDIO_TAGS_CHANGED,
-  SIGNAL_TEXT_TAGS_CHANGED,
   SIGNAL_GET_VIDEO_TAGS,
   SIGNAL_GET_AUDIO_TAGS,
   SIGNAL_GET_TEXT_TAGS,
-  SIGNAL_GET_VIDEO_PAD,
-  SIGNAL_GET_AUDIO_PAD,
-  SIGNAL_GET_TEXT_PAD,
   LAST_SIGNAL
 };
 
@@ -515,11 +443,7 @@
 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
     GstCaps * caps);
 
-static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
-static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
-static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
-
-static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
+static gboolean setup_next_source (GstPlayBin * playbin);
 
 static GstElementClass *parent_class;
 
@@ -608,50 +532,49 @@
   gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_bin_finalize);
 
   /**
-   * GstPlayBin2:uri
+   * GstPlayBin:uri
    *
    * Set the next URI that playbin will play. This property can be set from the
    * about-to-finish signal to queue the next media file.
    */
   g_object_class_install_property (gobject_klass, PROP_URI,
       g_param_spec_string ("uri", "URI", "URI of the media to play",
-          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          NULL, G_PARAM_READWRITE));
 
   /**
-   * GstPlayBin2:suburi
+   * GstPlayBin:suburi
    *
    * Set the next subtitle URI that playbin will play. This property can be
    * set from the about-to-finish signal to queue the next subtitle media file.
    */
   g_object_class_install_property (gobject_klass, PROP_SUBURI,
       g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
-          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          NULL, G_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_klass, PROP_SOURCE,
       g_param_spec_object ("source", "Source", "Source element",
-          GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+          GST_TYPE_ELEMENT, G_PARAM_READABLE));
+
 
   /**
-   * GstPlayBin2:flags
+   * GstPlayBin:flags
    *
    * Control the behaviour of playbin.
    */
   g_object_class_install_property (gobject_klass, PROP_FLAGS,
       g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
-          GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS, G_PARAM_READWRITE));
 
   /**
-   * GstPlayBin2:n-video
+   * GstPlayBin:n-video
    *
    * Get the total number of available video streams. 
    */
   g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
       g_param_spec_int ("n-video", "Number Video",
-          "Total number of video streams", 0, G_MAXINT, 0,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+          "Total number of video streams", 0, G_MAXINT, 0, G_PARAM_READABLE));
   /**
-   * GstPlayBin2:current-video
+   * GstPlayBin:current-video
    *
    * Get or set the currently playing video stream. By default the first video
    * stream with data is played.
@@ -659,18 +582,17 @@
   g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
       g_param_spec_int ("current-video", "Current Video",
           "Currently playing video stream (-1 = auto)",
-          -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          -1, G_MAXINT, -1, G_PARAM_READWRITE));
   /**
-   * GstPlayBin2:n-audio
+   * GstPlayBin:n-audio
    *
    * Get the total number of available audio streams. 
    */
   g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
       g_param_spec_int ("n-audio", "Number Audio",
-          "Total number of audio streams", 0, G_MAXINT, 0,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+          "Total number of audio streams", 0, G_MAXINT, 0, G_PARAM_READABLE));
   /**
-   * GstPlayBin2:current-audio
+   * GstPlayBin:current-audio
    *
    * Get or set the currently playing audio stream. By default the first audio
    * stream with data is played.
@@ -678,18 +600,17 @@
   g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
       g_param_spec_int ("current-audio", "Current audio",
           "Currently playing audio stream (-1 = auto)",
-          -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          -1, G_MAXINT, -1, G_PARAM_READWRITE));
   /**
-   * GstPlayBin2:n-text
+   * GstPlayBin:n-text
    *
    * Get the total number of available subtitle streams. 
    */
   g_object_class_install_property (gobject_klass, PROP_N_TEXT,
       g_param_spec_int ("n-text", "Number Text",
-          "Total number of text streams", 0, G_MAXINT, 0,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+          "Total number of text streams", 0, G_MAXINT, 0, G_PARAM_READABLE));
   /**
-   * GstPlayBin2:current-text:
+   * GstPlayBin:current-text
    *
    * Get or set the currently playing subtitle stream. By default the first
    * subtitle stream with data is played.
@@ -697,49 +618,39 @@
   g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
       g_param_spec_int ("current-text", "Current Text",
           "Currently playing text stream (-1 = auto)",
-          -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          -1, G_MAXINT, -1, G_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_klass, PROP_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));
+          "ISO-8859-15 will be assumed.", NULL, G_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_klass, PROP_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));
+          GST_TYPE_ELEMENT, G_PARAM_READWRITE));
   g_object_class_install_property (gobject_klass, PROP_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));
+          GST_TYPE_ELEMENT, G_PARAM_READWRITE));
   g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
       g_param_spec_object ("vis-plugin", "Vis plugin",
-          "the visualization element to use (NULL = default)",
-          GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
-      g_param_spec_object ("text-sink", "Text plugin",
-          "the text output element to use (NULL = default textoverlay)",
-          GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, PROP_SUBPIC_SINK,
-      g_param_spec_object ("subpic-sink", "Subpicture plugin",
-          "the subpicture output element to use (NULL = default dvdspu)",
-          GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          "the visualization element to use (NULL = none)",
+          GST_TYPE_ELEMENT, G_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_klass, PROP_VOLUME,
-      g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
-          0.0, VOLUME_MAX_DOUBLE, 1.0,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+      g_param_spec_double ("volume", "Volume", "The audio volume",
+          0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE));
   g_object_class_install_property (gobject_klass, PROP_MUTE,
       g_param_spec_boolean ("mute", "Mute",
           "Mute the audio channel without changing the volume", FALSE,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          G_PARAM_READWRITE));
 
   /**
-   * GstPlayBin2:frame:
-   * @playbin: a #GstPlayBin2
+   * GstPlayBin::frame
+   * @playbin: a #GstPlayBin
    *
    * Get the currently rendered or prerolled frame in the sink.
    * The #GstCaps on the buffer will describe the format of the buffer.
@@ -747,37 +658,23 @@
   g_object_class_install_property (gobject_klass, PROP_FRAME,
       gst_param_spec_mini_object ("frame", "Frame",
           "The last frame (NULL = no video available)",
-          GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+          GST_TYPE_BUFFER, G_PARAM_READABLE));
   g_object_class_install_property (gobject_klass, PROP_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));
+          "to be used for subtitle rendering", NULL, G_PARAM_WRITABLE));
 
   g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
       g_param_spec_uint ("connection-speed", "Connection Speed",
           "Network connection speed in kbps (0 = unknown)",
-          0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
-      g_param_spec_int ("buffer-size", "Buffer size (bytes)",
-          "Buffer size when buffering network streams",
-          -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
-      g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
-          "Buffer duration when buffering network streams",
-          -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
+          0, G_MAXUINT, DEFAULT_CONNECTION_SPEED, G_PARAM_READWRITE));
   /**
-   * GstPlayBin2::about-to-finish
-   * @playbin: a #GstPlayBin2
+   * GstPlayBin::about-to-finish:
+   * @playbin: a #GstPlayBin
    *
    * This signal is emitted when the current uri is about to finish. You can
-   * set the uri and suburi to make sure that playback continues.
+   * set the next-uri and next-suburi to make sure that playback continues.
    */
   gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
       g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
@@ -786,10 +683,10 @@
       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
 
   /**
-   * GstPlayBin2::video-changed
-   * @playbin: a #GstPlayBin2
+   * GstPlayBin::video-changed
+   * @playbin: a #GstPlayBin
    *
-   * This signal is emitted whenever the number or order of the video
+   * This signal is emited whenever the number or order of the video
    * streams has changed. The application will most likely want to select
    * a new video stream.
    */
@@ -799,10 +696,10 @@
       G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
   /**
-   * GstPlayBin2::audio-changed
-   * @playbin: a #GstPlayBin2
+   * GstPlayBin::audio-changed
+   * @playbin: a #GstPlayBin
    *
-   * This signal is emitted whenever the number or order of the audio
+   * This signal is emited whenever the number or order of the audio
    * streams has changed. The application will most likely want to select
    * a new audio stream.
    */
@@ -812,10 +709,10 @@
       G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
   /**
-   * GstPlayBin2::text-changed
-   * @playbin: a #GstPlayBin2
+   * GstPlayBin::text-changed
+   * @playbin: a #GstPlayBin
    *
-   * This signal is emitted whenever the number or order of the text
+   * This signal is emited whenever the number or order of the text
    * streams has changed. The application will most likely want to select
    * a new text stream.
    */
@@ -826,56 +723,8 @@
       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
 
   /**
-   * GstPlayBin2::video-tags-changed
-   * @playbin: a #GstPlayBin2
-   * @stream: stream index with changed tags
-   *
-   * This signal is emitted whenever the tags of a video stream have changed.
-   * The application will most likely want to get the new tags.
-   *
-   * Since: 0.10.24
-   */
-  gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
-      g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST,
-      G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
-      gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
-
-  /**
-   * GstPlayBin2::audio-tags-changed
-   * @playbin: a #GstPlayBin2
-   * @stream: stream index with changed tags
-   *
-   * This signal is emitted whenever the tags of an audio stream have changed.
-   * The application will most likely want to get the new tags.
-   *
-   * Since: 0.10.24
-   */
-  gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
-      g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST,
-      G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
-      gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
-
-  /**
-   * GstPlayBin2::text-tags-changed
-   * @playbin: a #GstPlayBin2
-   * @stream: stream index with changed tags
-   *
-   * This signal is emitted whenever the tags of a text stream have changed.
-   * The application will most likely want to get the new tags.
-   *
-   * Since: 0.10.24
-   */
-  gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
-      g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST,
-      G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
-      gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
-
-  /**
-   * GstPlayBin2::get-video-tags
-   * @playbin: a #GstPlayBin2
+   * GstPlayBin::get-video-tags
+   * @playbin: a #GstPlayBin
    * @stream: a video stream number
    *
    * Action signal to retrieve the tags of a specific video stream number.
@@ -890,8 +739,8 @@
       G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
   /**
-   * GstPlayBin2::get-audio-tags
-   * @playbin: a #GstPlayBin2
+   * GstPlayBin::get-audio-tags
+   * @playbin: a #GstPlayBin
    * @stream: an audio stream number
    *
    * Action signal to retrieve the tags of a specific audio stream number.
@@ -906,8 +755,8 @@
       G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
   /**
-   * GstPlayBin2::get-text-tags
-   * @playbin: a #GstPlayBin2
+   * GstPlayBin::get-text-tags
+   * @playbin: a #GstPlayBin
    * @stream: a text stream number
    *
    * Action signal to retrieve the tags of a specific text stream number.
@@ -922,8 +771,8 @@
       G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
   /**
-   * GstPlayBin2::convert-frame
-   * @playbin: a #GstPlayBin2
+   * GstPlayBin::convert-frame
+   * @playbin: a #GstPlayBin
    * @caps: the target format of the frame
    *
    * Action signal to retrieve the currently playing video frame in the format
@@ -936,74 +785,18 @@
    * %NULL is returned when no current buffer can be retrieved or when the
    * conversion failed.
    */
-  gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
+  gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
       g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
       G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
       gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
 
-  /**
-   * GstPlayBin2::get-video-pad
-   * @playbin: a #GstPlayBin2
-   * @stream: a video stream number
-   *
-   * Action signal to retrieve the stream-selector sinkpad for a specific 
-   * video stream.
-   * This pad can be used for notifications of caps changes, stream-specific
-   * queries, etc.
-   *
-   * Returns: a #GstPad, or NULL when the stream number does not exist.
-   */
-  gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
-      g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-      G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
-      gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
-  /**
-   * GstPlayBin2::get-audio-pad
-   * @playbin: a #GstPlayBin2
-   * @stream: an audio stream number
-   *
-   * Action signal to retrieve the stream-selector sinkpad for a specific 
-   * audio stream.
-   * This pad can be used for notifications of caps changes, stream-specific
-   * queries, etc.
-   *
-   * Returns: a #GstPad, or NULL when the stream number does not exist.
-   */
-  gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
-      g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-      G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
-      gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
-  /**
-   * GstPlayBin2::get-text-pad
-   * @playbin: a #GstPlayBin2
-   * @stream: a text stream number
-   *
-   * Action signal to retrieve the stream-selector sinkpad for a specific 
-   * text stream.
-   * This pad can be used for notifications of caps changes, stream-specific
-   * queries, etc.
-   *
-   * Returns: a #GstPad, or NULL when the stream number does not exist.
-   */
-  gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
-      g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-      G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
-      gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
-
   klass->get_video_tags = gst_play_bin_get_video_tags;
   klass->get_audio_tags = gst_play_bin_get_audio_tags;
   klass->get_text_tags = gst_play_bin_get_text_tags;
 
   klass->convert_frame = gst_play_bin_convert_frame;
 
-  klass->get_video_pad = gst_play_bin_get_video_pad;
-  klass->get_audio_pad = gst_play_bin_get_audio_pad;
-  klass->get_text_pad = gst_play_bin_get_text_pad;
-
   gst_element_class_set_details (gstelement_klass, &gst_play_bin_details);
 
   gstelement_klass->change_state =
@@ -1020,50 +813,23 @@
   group->video_channels = g_ptr_array_new ();
   group->audio_channels = g_ptr_array_new ();
   group->text_channels = g_ptr_array_new ();
-  group->subp_channels = g_ptr_array_new ();
-  group->lock = g_mutex_new ();
-  /* init selectors. The selector is found by finding the first prefix that
-   * matches the media. */
+  /* init selectors */
   group->playbin = playbin;
-  /* If you add any items to these lists, check that media_list[] is defined
-   * above to be large enough to hold MAX(items)+1, so as to accomodate a
-   * NULL terminator (set when the memory is zeroed on allocation) */
-  group->selector[0].media_list[0] = "audio/x-raw-";
+  group->selector[0].media = "audio/x-raw-";
   group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
   group->selector[0].channels = group->audio_channels;
-  group->selector[1].media_list[0] = "audio/";
+  group->selector[1].media = "audio/";
   group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO;
   group->selector[1].channels = group->audio_channels;
-  group->selector[2].media_list[0] = "video/x-raw-";
+  group->selector[2].media = "video/x-raw-";
   group->selector[2].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
   group->selector[2].channels = group->video_channels;
-  group->selector[3].media_list[0] = "video/x-dvd-subpicture";
-  group->selector[3].media_list[1] = "subpicture/x-pgs";
-  group->selector[3].type = GST_PLAY_SINK_TYPE_SUBPIC;
-  group->selector[3].channels = group->subp_channels;
-  group->selector[4].media_list[0] = "video/";
-  group->selector[4].type = GST_PLAY_SINK_TYPE_VIDEO;
-  group->selector[4].channels = group->video_channels;
-  group->selector[5].media_list[0] = "text/";
-  group->selector[5].type = GST_PLAY_SINK_TYPE_TEXT;
-  group->selector[5].channels = group->text_channels;
-}
-
-static void
-free_group (GstPlayBin * playbin, GstSourceGroup * group)
-{
-  g_free (group->uri);
-  g_ptr_array_free (group->video_channels, TRUE);
-  g_ptr_array_free (group->audio_channels, TRUE);
-  g_ptr_array_free (group->text_channels, TRUE);
-  g_ptr_array_free (group->subp_channels, TRUE);
-  g_mutex_free (group->lock);
-  if (group->audio_sink)
-    gst_object_unref (group->audio_sink);
-  group->audio_sink = NULL;
-  if (group->video_sink)
-    gst_object_unref (group->video_sink);
-  group->video_sink = NULL;
+  group->selector[3].media = "video/";
+  group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO;
+  group->selector[3].channels = group->video_channels;
+  group->selector[4].media = "text/";
+  group->selector[4].type = GST_PLAY_SINK_TYPE_TEXT;
+  group->selector[4].channels = group->text_channels;
 }
 
 static void
@@ -1071,12 +837,6 @@
 {
   GstFactoryListType type;
 
-  playbin->lock = g_mutex_new ();
-  playbin->dyn_lock = g_mutex_new ();
-
-  /* assume we can create a selector */
-  playbin->have_selector = TRUE;
-
   /* init groups */
   playbin->curr_group = &playbin->groups[0];
   playbin->next_group = &playbin->groups[1];
@@ -1093,14 +853,9 @@
   gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
   gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
 
-  playbin->encoding = g_strdup (DEFAULT_SUBTITLE_ENCODING);
-
   playbin->current_video = DEFAULT_CURRENT_VIDEO;
   playbin->current_audio = DEFAULT_CURRENT_AUDIO;
   playbin->current_text = DEFAULT_CURRENT_TEXT;
-
-  playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
-  playbin->buffer_size = DEFAULT_BUFFER_SIZE;
 }
 
 static void
@@ -1110,24 +865,7 @@
 
   playbin = GST_PLAY_BIN (object);
 
-  free_group (playbin, &playbin->groups[0]);
-  free_group (playbin, &playbin->groups[1]);
-
-  if (playbin->source)
-    gst_object_unref (playbin->source);
-  if (playbin->video_sink)
-    gst_object_unref (playbin->video_sink);
-  if (playbin->audio_sink)
-    gst_object_unref (playbin->audio_sink);
-  if (playbin->text_sink)
-    gst_object_unref (playbin->text_sink);
-  if (playbin->subpic_sink)
-    gst_object_unref (playbin->subpic_sink);
-
   g_value_array_free (playbin->elements);
-  g_free (playbin->encoding);
-  g_mutex_free (playbin->lock);
-  g_mutex_free (playbin->dyn_lock);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -1142,18 +880,17 @@
     return;
   }
 
-  GST_PLAY_BIN_LOCK (playbin);
+  GST_OBJECT_LOCK (playbin);
   group = playbin->next_group;
 
-  GST_SOURCE_GROUP_LOCK (group);
-  /* store the uri in the next group we will play */
+  /* if we have no previous uri, or the new uri is different from the
+   * old one, replug */
   g_free (group->uri);
   group->uri = g_strdup (uri);
   group->valid = TRUE;
-  GST_SOURCE_GROUP_UNLOCK (group);
 
-  GST_DEBUG ("set new uri to %s", uri);
-  GST_PLAY_BIN_UNLOCK (playbin);
+  GST_DEBUG ("setting new uri to %s", uri);
+  GST_OBJECT_UNLOCK (playbin);
 }
 
 static void
@@ -1161,38 +898,24 @@
 {
   GstSourceGroup *group;
 
-  GST_PLAY_BIN_LOCK (playbin);
+  GST_OBJECT_LOCK (playbin);
   group = playbin->next_group;
 
-  GST_SOURCE_GROUP_LOCK (group);
+  if ((!suburi && !group->suburi) ||
+      (suburi && group->suburi && !strcmp (group->suburi, suburi)))
+    goto done;
+
   g_free (group->suburi);
   group->suburi = g_strdup (suburi);
-  GST_SOURCE_GROUP_UNLOCK (group);
 
   GST_DEBUG ("setting new .sub uri to %s", suburi);
 
-  GST_PLAY_BIN_UNLOCK (playbin);
-}
-
-static void
-gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
-{
-  gst_play_sink_set_flags (playbin->playsink, flags);
-  gst_play_sink_reconfigure (playbin->playsink);
-}
-
-static GstPlayFlags
-gst_play_bin_get_flags (GstPlayBin * playbin)
-{
-  GstPlayFlags flags;
-
-  flags = gst_play_sink_get_flags (playbin->playsink);
-
-  return flags;
+done:
+  GST_OBJECT_UNLOCK (playbin);
 }
 
 /* get the currently playing group or if nothing is playing, the next
- * group. Must be called with the PLAY_BIN_LOCK. */
+ * group. Must be called with the LOCK. */
 static GstSourceGroup *
 get_group (GstPlayBin * playbin)
 {
@@ -1204,65 +927,13 @@
   return result;
 }
 
-static GstPad *
-gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
-{
-  GstPad *sinkpad = NULL;
-  GstSourceGroup *group;
-
-  GST_PLAY_BIN_LOCK (playbin);
-  group = get_group (playbin);
-  if (stream < group->video_channels->len) {
-    sinkpad = g_ptr_array_index (group->video_channels, stream);
-    gst_object_ref (sinkpad);
-  }
-  GST_PLAY_BIN_UNLOCK (playbin);
-
-  return sinkpad;
-}
-
-static GstPad *
-gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
-{
-  GstPad *sinkpad = NULL;
-  GstSourceGroup *group;
-
-  GST_PLAY_BIN_LOCK (playbin);
-  group = get_group (playbin);
-  if (stream < group->audio_channels->len) {
-    sinkpad = g_ptr_array_index (group->audio_channels, stream);
-    gst_object_ref (sinkpad);
-  }
-  GST_PLAY_BIN_UNLOCK (playbin);
-
-  return sinkpad;
-}
-
-static GstPad *
-gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
-{
-  GstPad *sinkpad = NULL;
-  GstSourceGroup *group;
-
-  GST_PLAY_BIN_LOCK (playbin);
-  group = get_group (playbin);
-  if (stream < group->text_channels->len) {
-    sinkpad = g_ptr_array_index (group->text_channels, stream);
-    gst_object_ref (sinkpad);
-  }
-  GST_PLAY_BIN_UNLOCK (playbin);
-
-  return sinkpad;
-}
-
-
 static GstTagList *
 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
 {
   GstTagList *result;
   GstPad *sinkpad;
 
-  if (!channels || stream >= channels->len)
+  if (!channels || channels->len < stream)
     return NULL;
 
   sinkpad = g_ptr_array_index (channels, stream);
@@ -1277,10 +948,10 @@
   GstTagList *result;
   GstSourceGroup *group;
 
-  GST_PLAY_BIN_LOCK (playbin);
+  GST_OBJECT_LOCK (playbin);
   group = get_group (playbin);
   result = get_tags (playbin, group->video_channels, stream);
-  GST_PLAY_BIN_UNLOCK (playbin);
+  GST_OBJECT_UNLOCK (playbin);
 
   return result;
 }
@@ -1291,10 +962,10 @@
   GstTagList *result;
   GstSourceGroup *group;
 
-  GST_PLAY_BIN_LOCK (playbin);
+  GST_OBJECT_LOCK (playbin);
   group = get_group (playbin);
   result = get_tags (playbin, group->audio_channels, stream);
-  GST_PLAY_BIN_UNLOCK (playbin);
+  GST_OBJECT_UNLOCK (playbin);
 
   return result;
 }
@@ -1305,10 +976,10 @@
   GstTagList *result;
   GstSourceGroup *group;
 
-  GST_PLAY_BIN_LOCK (playbin);
+  GST_OBJECT_LOCK (playbin);
   group = get_group (playbin);
   result = get_tags (playbin, group->text_channels, stream);
-  GST_PLAY_BIN_UNLOCK (playbin);
+  GST_OBJECT_UNLOCK (playbin);
 
   return result;
 }
@@ -1329,36 +1000,6 @@
   return result;
 }
 
-/* Returns current stream number, or -1 if none has been selected yet */
-static int
-get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
-{
-  /* Internal API cleanup would make this easier... */
-  int i;
-  GstPad *pad, *current;
-  GstObject *selector = NULL;
-  int ret = -1;
-
-  for (i = 0; i < channels->len; i++) {
-    pad = g_ptr_array_index (channels, i);
-    if ((selector = gst_pad_get_parent (pad))) {
-      g_object_get (selector, "active-pad", &current, NULL);
-      gst_object_unref (selector);
-
-      if (pad == current) {
-        gst_object_unref (current);
-        ret = i;
-        break;
-      }
-
-      if (current)
-        gst_object_unref (current);
-    }
-  }
-
-  return ret;
-}
-
 static gboolean
 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
 {
@@ -1366,12 +1007,12 @@
   GPtrArray *channels;
   GstPad *sinkpad;
 
-  GST_PLAY_BIN_LOCK (playbin);
+  GST_OBJECT_LOCK (playbin);
   group = get_group (playbin);
   if (!(channels = group->video_channels))
     goto no_channels;
 
-  if (stream == -1 || channels->len <= stream) {
+  if (stream == -1 || channels->len < stream) {
     sinkpad = NULL;
   } else {
     /* take channel from selected stream */
@@ -1380,7 +1021,7 @@
 
   if (sinkpad)
     gst_object_ref (sinkpad);
-  GST_PLAY_BIN_UNLOCK (playbin);
+  GST_OBJECT_UNLOCK (playbin);
 
   if (sinkpad) {
     GstObject *selector;
@@ -1396,7 +1037,7 @@
 
 no_channels:
   {
-    GST_PLAY_BIN_UNLOCK (playbin);
+    GST_OBJECT_UNLOCK (playbin);
     return FALSE;
   }
 }
@@ -1408,12 +1049,12 @@
   GPtrArray *channels;
   GstPad *sinkpad;
 
-  GST_PLAY_BIN_LOCK (playbin);
+  GST_OBJECT_LOCK (playbin);
   group = get_group (playbin);
   if (!(channels = group->audio_channels))
     goto no_channels;
 
-  if (stream == -1 || channels->len <= stream) {
+  if (stream == -1 || channels->len < stream) {
     sinkpad = NULL;
   } else {
     /* take channel from selected stream */
@@ -1422,7 +1063,7 @@
 
   if (sinkpad)
     gst_object_ref (sinkpad);
-  GST_PLAY_BIN_UNLOCK (playbin);
+  GST_OBJECT_UNLOCK (playbin);
 
   if (sinkpad) {
     GstObject *selector;
@@ -1438,7 +1079,7 @@
 
 no_channels:
   {
-    GST_PLAY_BIN_UNLOCK (playbin);
+    GST_OBJECT_UNLOCK (playbin);
     return FALSE;
   }
 }
@@ -1450,12 +1091,12 @@
   GPtrArray *channels;
   GstPad *sinkpad;
 
-  GST_PLAY_BIN_LOCK (playbin);
+  GST_OBJECT_LOCK (playbin);
   group = get_group (playbin);
   if (!(channels = group->text_channels))
     goto no_channels;
 
-  if (stream == -1 || channels->len <= stream) {
+  if (stream == -1 || channels->len < stream) {
     sinkpad = NULL;
   } else {
     /* take channel from selected stream */
@@ -1464,7 +1105,7 @@
 
   if (sinkpad)
     gst_object_ref (sinkpad);
-  GST_PLAY_BIN_UNLOCK (playbin);
+  GST_OBJECT_UNLOCK (playbin);
 
   if (sinkpad) {
     GstObject *selector;
@@ -1480,56 +1121,12 @@
 
 no_channels:
   {
-    GST_PLAY_BIN_UNLOCK (playbin);
+    GST_OBJECT_UNLOCK (playbin);
     return FALSE;
   }
 }
 
 static void
-gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
-{
-  GstElement *elem;
-
-  GST_PLAY_BIN_LOCK (playbin);
-  g_free (playbin->encoding);
-  playbin->encoding = g_strdup (encoding);
-
-  /* set subtitles on all current and next decodebins. */
-  if ((elem = playbin->groups[0].uridecodebin))
-    g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
-  if ((elem = playbin->groups[0].suburidecodebin))
-    g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
-  if ((elem = playbin->groups[1].uridecodebin))
-    g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
-  if ((elem = playbin->groups[1].suburidecodebin))
-    g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
-  GST_PLAY_BIN_UNLOCK (playbin);
-}
-
-static void
-gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
-    const gchar * dbg, GstElement * sink)
-{
-  GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
-
-  GST_PLAY_BIN_LOCK (playbin);
-  if (*elem != sink) {
-    GstElement *old;
-
-    old = *elem;
-    if (sink) {
-      gst_object_ref (sink);
-      gst_object_sink (sink);
-    }
-    *elem = sink;
-    if (old)
-      gst_object_unref (old);
-  }
-  GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
-  GST_PLAY_BIN_UNLOCK (playbin);
-}
-
-static void
 gst_play_bin_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
 {
@@ -1545,7 +1142,7 @@
       gst_play_bin_set_suburi (playbin, g_value_get_string (value));
       break;
     case PROP_FLAGS:
-      gst_play_bin_set_flags (playbin, g_value_get_flags (value));
+      gst_play_sink_set_flags (playbin->playsink, g_value_get_flags (value));
       break;
     case PROP_CURRENT_VIDEO:
       gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
@@ -1557,28 +1154,15 @@
       gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
       break;
     case PROP_SUBTITLE_ENCODING:
-      gst_play_bin_set_encoding (playbin, g_value_get_string (value));
       break;
     case PROP_VIDEO_SINK:
-      gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
-          g_value_get_object (value));
       break;
     case PROP_AUDIO_SINK:
-      gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
-          g_value_get_object (value));
       break;
     case PROP_VIS_PLUGIN:
       gst_play_sink_set_vis_plugin (playbin->playsink,
           g_value_get_object (value));
       break;
-    case PROP_TEXT_SINK:
-      gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
-          g_value_get_object (value));
-      break;
-    case PROP_SUBPIC_SINK:
-      gst_play_bin_set_sink (playbin, &playbin->subpic_sink, "subpicture",
-          g_value_get_object (value));
-      break;
     case PROP_VOLUME:
       gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
       break;
@@ -1586,19 +1170,11 @@
       gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
       break;
     case PROP_FONT_DESC:
-      gst_play_sink_set_font_desc (playbin->playsink,
-          g_value_get_string (value));
       break;
     case PROP_CONNECTION_SPEED:
-      GST_PLAY_BIN_LOCK (playbin);
+      GST_OBJECT_LOCK (playbin);
       playbin->connection_speed = g_value_get_uint (value) * 1000;
-      GST_PLAY_BIN_UNLOCK (playbin);
-      break;
-    case PROP_BUFFER_SIZE:
-      playbin->buffer_size = g_value_get_int (value);
-      break;
-    case PROP_BUFFER_DURATION:
-      playbin->buffer_duration = g_value_get_int64 (value);
+      GST_OBJECT_UNLOCK (playbin);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1606,24 +1182,6 @@
   }
 }
 
-static GstElement *
-gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
-    const gchar * dbg, GstPlaySinkType type)
-{
-  GstElement *sink;
-
-  sink = gst_play_sink_get_sink (playbin->playsink, type);
-
-  GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
-      GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
-      dbg, sink, dbg, *elem);
-
-  if (sink == NULL)
-    sink = *elem;
-
-  return sink;
-}
-
 static void
 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
     GParamSpec * pspec)
@@ -1637,111 +1195,85 @@
     {
       GstSourceGroup *group;
 
-      GST_PLAY_BIN_LOCK (playbin);
+      GST_OBJECT_LOCK (playbin);
       group = get_group (playbin);
       g_value_set_string (value, group->uri);
-      GST_PLAY_BIN_UNLOCK (playbin);
+      GST_OBJECT_UNLOCK (playbin);
       break;
     }
     case PROP_SUBURI:
     {
       GstSourceGroup *group;
 
-      GST_PLAY_BIN_LOCK (playbin);
+      GST_OBJECT_LOCK (playbin);
       group = get_group (playbin);
       g_value_set_string (value, group->suburi);
-      GST_PLAY_BIN_UNLOCK (playbin);
+      GST_OBJECT_UNLOCK (playbin);
       break;
     }
     case PROP_SOURCE:
-    {
-      GST_OBJECT_LOCK (playbin);
-      g_value_set_object (value, playbin->source);
-      GST_OBJECT_UNLOCK (playbin);
       break;
-    }
     case PROP_FLAGS:
-      g_value_set_flags (value, gst_play_bin_get_flags (playbin));
+      g_value_set_flags (value, gst_play_sink_get_flags (playbin->playsink));
       break;
     case PROP_N_VIDEO:
     {
       GstSourceGroup *group;
       gint n_video;
 
-      GST_PLAY_BIN_LOCK (playbin);
+      GST_OBJECT_LOCK (playbin);
       group = get_group (playbin);
       n_video = (group->video_channels ? group->video_channels->len : 0);
       g_value_set_int (value, n_video);
-      GST_PLAY_BIN_UNLOCK (playbin);
+      GST_OBJECT_UNLOCK (playbin);
       break;
     }
     case PROP_CURRENT_VIDEO:
-      GST_PLAY_BIN_LOCK (playbin);
+      GST_OBJECT_LOCK (playbin);
       g_value_set_int (value, playbin->current_video);
-      GST_PLAY_BIN_UNLOCK (playbin);
+      GST_OBJECT_UNLOCK (playbin);
       break;
     case PROP_N_AUDIO:
     {
       GstSourceGroup *group;
       gint n_audio;
 
-      GST_PLAY_BIN_LOCK (playbin);
+      GST_OBJECT_LOCK (playbin);
       group = get_group (playbin);
       n_audio = (group->audio_channels ? group->audio_channels->len : 0);
       g_value_set_int (value, n_audio);
-      GST_PLAY_BIN_UNLOCK (playbin);
+      GST_OBJECT_UNLOCK (playbin);
       break;
     }
     case PROP_CURRENT_AUDIO:
-      GST_PLAY_BIN_LOCK (playbin);
+      GST_OBJECT_LOCK (playbin);
       g_value_set_int (value, playbin->current_audio);
-      GST_PLAY_BIN_UNLOCK (playbin);
+      GST_OBJECT_UNLOCK (playbin);
       break;
     case PROP_N_TEXT:
     {
       GstSourceGroup *group;
       gint n_text;
 
-      GST_PLAY_BIN_LOCK (playbin);
+      GST_OBJECT_LOCK (playbin);
       group = get_group (playbin);
       n_text = (group->text_channels ? group->text_channels->len : 0);
       g_value_set_int (value, n_text);
-      GST_PLAY_BIN_UNLOCK (playbin);
+      GST_OBJECT_UNLOCK (playbin);
       break;
     }
     case PROP_CURRENT_TEXT:
-      GST_PLAY_BIN_LOCK (playbin);
+      GST_OBJECT_LOCK (playbin);
       g_value_set_int (value, playbin->current_text);
-      GST_PLAY_BIN_UNLOCK (playbin);
+      GST_OBJECT_UNLOCK (playbin);
       break;
     case PROP_SUBTITLE_ENCODING:
-      GST_PLAY_BIN_LOCK (playbin);
-      g_value_set_string (value, playbin->encoding);
-      GST_PLAY_BIN_UNLOCK (playbin);
       break;
     case PROP_VIDEO_SINK:
-      g_value_set_object (value,
-          gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
-              "video", GST_PLAY_SINK_TYPE_VIDEO));
       break;
     case PROP_AUDIO_SINK:
-      g_value_set_object (value,
-          gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
-              "audio", GST_PLAY_SINK_TYPE_AUDIO));
       break;
     case PROP_VIS_PLUGIN:
-      g_value_set_object (value,
-          gst_play_sink_get_vis_plugin (playbin->playsink));
-      break;
-    case PROP_TEXT_SINK:
-      g_value_set_object (value,
-          gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
-              "text", GST_PLAY_SINK_TYPE_TEXT));
-      break;
-    case PROP_SUBPIC_SINK:
-      g_value_set_object (value,
-          gst_play_bin_get_current_sink (playbin, &playbin->subpic_sink,
-              "subpicture", GST_PLAY_SINK_TYPE_SUBPIC));
       break;
     case PROP_VOLUME:
       g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
@@ -1753,22 +1285,10 @@
       gst_value_take_buffer (value, gst_play_bin_convert_frame (playbin, NULL));
       break;
     case PROP_FONT_DESC:
-      g_value_take_string (value,
-          gst_play_sink_get_font_desc (playbin->playsink));
       break;
     case PROP_CONNECTION_SPEED:
-      GST_PLAY_BIN_LOCK (playbin);
+      GST_OBJECT_LOCK (playbin);
       g_value_set_uint (value, playbin->connection_speed / 1000);
-      GST_PLAY_BIN_UNLOCK (playbin);
-      break;
-    case PROP_BUFFER_SIZE:
-      GST_OBJECT_LOCK (playbin);
-      g_value_set_int (value, playbin->buffer_size);
-      GST_OBJECT_UNLOCK (playbin);
-      break;
-    case PROP_BUFFER_DURATION:
-      GST_OBJECT_LOCK (playbin);
-      g_value_set_int64 (value, playbin->buffer_duration);
       GST_OBJECT_UNLOCK (playbin);
       break;
     default:
@@ -1780,7 +1300,7 @@
 /* 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", "subpicture/x-pgs", NULL
+  "video/x-dvd-subpicture", NULL
 };
 
 static void
@@ -1804,118 +1324,8 @@
   GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
 }
 
-static void
-selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
-    GstPlayBin * playbin)
-{
-  gchar *property;
-  GstSourceGroup *group;
-  GstSourceSelect *select = NULL;
-  int i;
-
-  GST_PLAY_BIN_LOCK (playbin);
-  group = get_group (playbin);
-
-  for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
-    if (selector == G_OBJECT (group->selector[i].selector)) {
-      select = &group->selector[i];
-    }
-  }
-
-  /* We got a pad-change after our group got switched out; no need to notify */
-  if (!select) {
-    GST_PLAY_BIN_UNLOCK (playbin);
-    return;
-  }
-
-  switch (select->type) {
-    case GST_PLAY_SINK_TYPE_VIDEO:
-    case GST_PLAY_SINK_TYPE_VIDEO_RAW:
-      property = "current-video";
-      playbin->current_video = get_current_stream_number (playbin,
-          group->video_channels);
-      break;
-    case GST_PLAY_SINK_TYPE_AUDIO:
-    case GST_PLAY_SINK_TYPE_AUDIO_RAW:
-      property = "current-audio";
-      playbin->current_audio = get_current_stream_number (playbin,
-          group->audio_channels);
-      break;
-    case GST_PLAY_SINK_TYPE_TEXT:
-      property = "current-text";
-      playbin->current_text = get_current_stream_number (playbin,
-          group->text_channels);
-      break;
-    default:
-      property = NULL;
-  }
-  GST_PLAY_BIN_UNLOCK (playbin);
-
-  if (property)
-    g_object_notify (G_OBJECT (playbin), property);
-}
-
-static void
-selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
-{
-  /* no nothing */
-  GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
-}
-
-/* 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;
-}
-
-typedef struct
-{
-  GstPlayBin *playbin;
-  gint stream_id;
-  GstPlaySinkType type;
-} NotifyTagsData;
-
-static void
-notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
-{
-  NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
-  gint signal;
-
-  GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
-      " with stream id %d and type %d have changed",
-      object, ntdata->stream_id, ntdata->type);
-
-  switch (ntdata->type) {
-    case GST_PLAY_SINK_TYPE_VIDEO:
-    case GST_PLAY_SINK_TYPE_VIDEO_RAW:
-      signal = SIGNAL_VIDEO_TAGS_CHANGED;
-      break;
-    case GST_PLAY_SINK_TYPE_AUDIO:
-    case GST_PLAY_SINK_TYPE_AUDIO_RAW:
-      signal = SIGNAL_AUDIO_TAGS_CHANGED;
-      break;
-    case GST_PLAY_SINK_TYPE_TEXT:
-      signal = SIGNAL_TEXT_TAGS_CHANGED;
-      break;
-    default:
-      signal = -1;
-      break;
-  }
-
-  if (signal >= 0)
-    g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
-        ntdata->stream_id);
-}
-
 /* this function is called when a new pad is added to decodebin. We check the
- * type of the pad and add it to the selector element of the group. 
+ * type of the pad and add it to the selecter element of the group. 
  */
 static void
 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
@@ -1928,7 +1338,6 @@
   GstPadLinkReturn res;
   GstSourceSelect *select = NULL;
   gint i;
-  gboolean changed = FALSE;
 
   playbin = group->playbin;
 
@@ -1942,7 +1351,7 @@
 
   /* major type of the pad, this determines the selector to use */
   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
-    if (array_has_value (group->selector[i].media_list, name)) {
+    if (g_str_has_prefix (name, group->selector[i].media)) {
       select = &group->selector[i];
       break;
     }
@@ -1952,127 +1361,43 @@
   if (select == NULL)
     goto unknown_type;
 
-  GST_SOURCE_GROUP_LOCK (group);
-  if (select->selector == NULL && playbin->have_selector) {
+  if (select->selector == NULL) {
     /* no selector, create one */
     GST_DEBUG_OBJECT (playbin, "creating new selector");
-    select->selector = g_object_new (GST_TYPE_INPUT_SELECTOR, NULL);
-    /* the above can't fail, but we keep the error handling around for when
-     * the selector plugin has moved to -base or -good and we stop using an
-     * internal copy of input-selector */
-    if (select->selector == NULL) {
-      /* post the missing selector message only once */
-      playbin->have_selector = FALSE;
-      gst_element_post_message (GST_ELEMENT_CAST (playbin),
-          gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
-              "input-selector"));
-      GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
-          (_("Missing element '%s' - check your GStreamer installation."),
-              "input-selector"), (NULL));
-    } else {
-      g_signal_connect (select->selector, "notify::active-pad",
-          G_CALLBACK (selector_active_pad_changed), playbin);
+    select->selector = g_object_new (GST_TYPE_STREAM_SELECTOR, NULL);
+    if (select->selector == NULL)
+      goto no_selector;
 
-      GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
-      gst_bin_add (GST_BIN_CAST (playbin), select->selector);
-      gst_element_set_state (select->selector, GST_STATE_PAUSED);
-    }
-  }
+    GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
+    gst_bin_add (GST_BIN_CAST (playbin), select->selector);
+    gst_element_set_state (select->selector, GST_STATE_PAUSED);
 
-  if (select->srcpad == NULL) {
-    if (select->selector) {
-      /* save source pad of the selector */
-      select->srcpad = gst_element_get_static_pad (select->selector, "src");
-    } else {
-      /* no selector, use the pad as the source pad then */
-      select->srcpad = gst_object_ref (pad);
-    }
-    /* block the selector srcpad. It's possible that multiple decodebins start
-     * pushing data into the selectors before we have a chance to collect all
-     * streams and connect the sinks, resulting in not-linked errors. After we
-     * configured the sinks we will unblock them all. */
-    gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
+    /* save source pad */
+    select->srcpad = gst_element_get_pad (select->selector, "src");
   }
 
   /* get sinkpad for the new stream */
-  if (select->selector) {
-    if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
-      gulong notify_tags_handler = 0;
-      NotifyTagsData *ntdata;
-
-      GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
-          GST_DEBUG_PAD_NAME (sinkpad));
-
-      /* store the selector for the pad */
-      g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
+  if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
+    GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
+        GST_DEBUG_PAD_NAME (sinkpad));
 
-      /* connect to the notify::tags signal for our
-       * own *-tags-changed signals
-       */
-      ntdata = g_new0 (NotifyTagsData, 1);
-      ntdata->playbin = playbin;
-      ntdata->stream_id = select->channels->len;
-      ntdata->type = select->type;
+    /* store the selector for the pad */
+    g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
 
-      notify_tags_handler =
-          g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
-          G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
-          (GConnectFlags) 0);
-      g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
-          (gpointer) notify_tags_handler);
-
-      /* store the pad in the array */
-      GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
-      g_ptr_array_add (select->channels, sinkpad);
-
-      res = gst_pad_link (pad, sinkpad);
-      if (GST_PAD_LINK_FAILED (res))
-        goto link_failed;
-
-      /* store selector pad so we can release it */
-      g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
+    /* store the pad in the array */
+    GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
+    g_ptr_array_add (select->channels, sinkpad);
 
-      changed = TRUE;
-      GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
-          GST_DEBUG_PAD_NAME (pad), select->selector);
-    }
-  } else {
-    /* no selector, don't configure anything, we'll link the new pad directly to
-     * the sink. */
-    changed = FALSE;
-    sinkpad = NULL;
-  }
-  GST_SOURCE_GROUP_UNLOCK (group);
+    res = gst_pad_link (pad, sinkpad);
+    if (GST_PAD_LINK_FAILED (res))
+      goto link_failed;
 
-  if (changed) {
-    int signal;
-    switch (select->type) {
-      case GST_PLAY_SINK_TYPE_VIDEO:
-      case GST_PLAY_SINK_TYPE_VIDEO_RAW:
-        /* we want to return NOT_LINKED for unselected pads but only for audio
-         * and video pads because text pads might come from an external file. */
-        g_object_set (sinkpad, "always-ok", FALSE, NULL);
-        signal = SIGNAL_VIDEO_CHANGED;
-        break;
-      case GST_PLAY_SINK_TYPE_AUDIO:
-      case GST_PLAY_SINK_TYPE_AUDIO_RAW:
-        g_object_set (sinkpad, "always-ok", FALSE, NULL);
-        signal = SIGNAL_AUDIO_CHANGED;
-        break;
-      case GST_PLAY_SINK_TYPE_TEXT:
-        signal = SIGNAL_TEXT_CHANGED;
-        break;
-      case GST_PLAY_SINK_TYPE_SUBPIC:
-      default:
-        signal = -1;
-    }
+    /* store selector pad so we can release it */
+    g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
+  }
+  GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
+      GST_DEBUG_PAD_NAME (pad), select->selector);
 
-    if (signal >= 0)
-      g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
-  }
-
-done:
-  gst_caps_unref (caps);
   return;
 
   /* ERRORS */
@@ -2080,19 +1405,24 @@
   {
     GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
         name, GST_DEBUG_PAD_NAME (pad));
-    goto done;
+    return;
+  }
+no_selector:
+  {
+    GST_ERROR_OBJECT (playbin, "could not create selector for pad %s:%s",
+        GST_DEBUG_PAD_NAME (pad));
+    return;
   }
 link_failed:
   {
     GST_ERROR_OBJECT (playbin,
         "failed to link pad %s:%s to selector, reason %d",
         GST_DEBUG_PAD_NAME (pad), res);
-    GST_SOURCE_GROUP_UNLOCK (group);
-    goto done;
+    return;
   }
 }
 
-/* called when a pad is removed from the uridecodebin. We unlink the pad from
+/* called when a pad is removed form the uridecodebin. We unlink the pad from
  * the selector. This will make the selector select a new pad. */
 static void
 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
@@ -2107,21 +1437,11 @@
   GST_DEBUG_OBJECT (playbin,
       "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
 
-  GST_SOURCE_GROUP_LOCK (group);
   /* get the selector sinkpad */
   if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
     goto not_linked;
 
   if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
-    gulong notify_tags_handler;
-
-    notify_tags_handler =
-        (gulong) g_object_get_data (G_OBJECT (peer),
-        "playbin2.notify_tags_handler");
-    if (notify_tags_handler != 0)
-      g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
-    g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
-
     /* remove the pad from the array */
     g_ptr_array_remove (select->channels, peer);
     GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
@@ -2133,18 +1453,14 @@
   /* get selector, this can be NULL when the element is removing the pads
    * because it's being disposed. */
   selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
-  if (!selector) {
-    gst_object_unref (peer);
+  if (!selector)
     goto no_selector;
-  }
 
   /* release the pad to the selector, this will make the selector choose a new
    * pad. */
   gst_element_release_request_pad (selector, peer);
-  gst_object_unref (peer);
 
   gst_object_unref (selector);
-  GST_SOURCE_GROUP_UNLOCK (group);
 
   return;
 
@@ -2152,13 +1468,11 @@
 not_linked:
   {
     GST_DEBUG_OBJECT (playbin, "pad not linked");
-    GST_SOURCE_GROUP_UNLOCK (group);
     return;
   }
 no_selector:
   {
     GST_DEBUG_OBJECT (playbin, "selector not found");
-    GST_SOURCE_GROUP_UNLOCK (group);
     return;
   }
 }
@@ -2178,137 +1492,46 @@
   GstPlayBin *playbin;
   GstPadLinkReturn res;
   gint i;
-  gboolean configure;
 
   playbin = group->playbin;
 
   GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
 
-  GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
-
-  GST_SOURCE_GROUP_LOCK (group);
   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
     GstSourceSelect *select = &group->selector[i];
 
-    /* check if the specific media type was detected and thus has a selector
-     * created for it. If there is the media type, get a sinkpad from the sink
-     * and link it. We only do this if we have not yet requested the sinkpad
-     * before. */
-    if (select->srcpad && select->sinkpad == NULL) {
-      GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
+    if (select->selector) {
       select->sinkpad =
           gst_play_sink_request_pad (playbin->playsink, select->type);
       res = gst_pad_link (select->srcpad, select->sinkpad);
-      GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
-          select->media_list[0], res);
-      if (res != GST_PAD_LINK_OK) {
-        GST_ELEMENT_ERROR (playbin, CORE, PAD,
-            ("Internal playbin error."),
-            ("Failed to link selector to sink. Error %d", res));
-      }
+      GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d", select->media,
+          res);
     }
   }
-  GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
-      group->pending - 1);
-
-  if (group->pending > 0)
-    group->pending--;
-
-  if (group->pending == 0) {
-    /* we are the last group to complete, we will configure the output and then
-     * signal the other waiters. */
-    GST_LOG_OBJECT (playbin, "last group complete");
-    configure = TRUE;
-  } else {
-    GST_LOG_OBJECT (playbin, "have more pending groups");
-    configure = FALSE;
-  }
-  GST_SOURCE_GROUP_UNLOCK (group);
+  /* configure the modes now */
+  gst_play_sink_reconfigure (playbin->playsink);
+}
 
-  if (configure) {
-    /* if we have custom sinks, configure them now */
-    GST_SOURCE_GROUP_LOCK (group);
-    if (group->audio_sink) {
-      GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
-          group->audio_sink);
-      gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
-          group->audio_sink);
-    } else {
-      GST_INFO_OBJECT (playbin, "setting default audio sink %" GST_PTR_FORMAT,
-          playbin->audio_sink);
-      gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
-          playbin->audio_sink);
-    }
-    if (group->video_sink) {
-      GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
-          group->video_sink);
-      gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
-          group->video_sink);
-    } else {
-      GST_INFO_OBJECT (playbin, "setting default video sink %" GST_PTR_FORMAT,
-          playbin->video_sink);
-      gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
-          playbin->video_sink);
-    }
-    gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
-        playbin->text_sink);
-    gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_SUBPIC,
-        playbin->subpic_sink);
-    GST_SOURCE_GROUP_UNLOCK (group);
+/* send an EOS event to all of the selectors */
+static void
+perform_eos (GstPlayBin * playbin, GstSourceGroup * group)
+{
+  GstEvent *event;
+  gint i;
 
-    GST_LOG_OBJECT (playbin, "reconfigure sink");
-    /* we configure the modes if we were the last decodebin to complete. */
-    gst_play_sink_reconfigure (playbin->playsink);
-
-    /* signal the other decodebins that they can continue now. */
-    GST_SOURCE_GROUP_LOCK (group);
-    /* unblock all selectors */
-    for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
-      GstSourceSelect *select = &group->selector[i];
+  GST_DEBUG_OBJECT (playbin, "doing EOS in group %p", group);
 
-      if (select->srcpad) {
-        GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
-            select->srcpad);
-        gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
-            NULL);
-      }
-    }
-    GST_SOURCE_GROUP_UNLOCK (group);
-  }
-
-  GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
-
-  return;
+  event = gst_event_new_eos ();
+  for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
+    GstSourceSelect *select = &group->selector[i];
 
-shutdown:
-  {
-    GST_DEBUG ("ignoring, we are shutting down");
-    /* Request a flushing pad from playsink that we then link to the selector.
-     * Then we unblock the selectors so that they stop with a WRONG_STATE
-     * instead of a NOT_LINKED error.
-     */
-    GST_SOURCE_GROUP_LOCK (group);
-    for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
-      GstSourceSelect *select = &group->selector[i];
-
-      if (select->srcpad) {
-        if (select->sinkpad == NULL) {
-          GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
-          select->sinkpad =
-              gst_play_sink_request_pad (playbin->playsink,
-              GST_PLAY_SINK_TYPE_FLUSHING);
-          res = gst_pad_link (select->srcpad, select->sinkpad);
-          GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
-        }
-        GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
-            select->srcpad);
-        gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
-            NULL);
-      }
+    if (select->selector) {
+      GST_DEBUG_OBJECT (playbin, "send EOS in selector %s", select->media);
+      gst_event_ref (event);
+      gst_pad_push_event (select->srcpad, event);
     }
-    GST_SOURCE_GROUP_UNLOCK (group);
-    return;
   }
+  gst_event_unref (event);
 }
 
 static void
@@ -2320,13 +1543,21 @@
 
   GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
 
+  /* mark use as sending out the about-to-finish signal. When the app sets a URI
+   * when this signal is emited, we're marking it as next-uri */
+  playbin->about_to_finish = TRUE;
+
   /* after this call, we should have a next group to activate or we EOS */
   g_signal_emit (G_OBJECT (playbin),
       gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
 
-  /* now activate the next group. If the app did not set a uri, this will
+  playbin->about_to_finish = FALSE;
+
+  /* now activate the next group. If the app did not set a next-uri, this will
    * fail and we can do EOS */
-  setup_next_source (playbin, GST_STATE_PAUSED);
+  if (!setup_next_source (playbin)) {
+    perform_eos (playbin, group);
+  }
 }
 
 /* Called when we must provide a list of factories to plug to @pad with @caps.
@@ -2356,8 +1587,8 @@
 
 /* We are asked to select an element. See if the next element to check
  * is a sink. If this is the case, we see if the sink works by setting it to
- * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
- * expose the raw pad so that we can setup the mixers. */
+ * READY. If the sink works, we return -2 to make decodebin expose the raw pad
+ * so that we can setup the mixers. */
 static GstAutoplugSelectResult
 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
     GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
@@ -2365,8 +1596,6 @@
   GstPlayBin *playbin;
   GstElement *element;
   const gchar *klass;
-  GstPlaySinkType type;
-  GstElement **sinkp;
 
   playbin = group->playbin;
 
@@ -2383,44 +1612,6 @@
   /* it's a sink, see if an instance of it actually works */
   GST_DEBUG_OBJECT (playbin, "we found a sink");
 
-  klass = gst_element_factory_get_klass (factory);
-
-  /* figure out the klass */
-  if (strstr (klass, "Audio")) {
-    GST_DEBUG_OBJECT (playbin, "we found an audio sink");
-    type = GST_PLAY_SINK_TYPE_AUDIO;
-    sinkp = &group->audio_sink;
-  } else if (strstr (klass, "Video")) {
-    GST_DEBUG_OBJECT (playbin, "we found a video sink");
-    type = GST_PLAY_SINK_TYPE_VIDEO;
-    sinkp = &group->video_sink;
-  } else {
-    /* unknown klass, skip this element */
-    GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
-    return GST_AUTOPLUG_SELECT_SKIP;
-  }
-
-  /* if we are asked to do visualisations and it's an audio sink, skip the
-   * element. We can only do visualisations with raw sinks */
-  if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
-    if (type == GST_PLAY_SINK_TYPE_AUDIO) {
-      GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
-      return GST_AUTOPLUG_SELECT_SKIP;
-    }
-  }
-
-  /* now see if we already have a sink element */
-  GST_SOURCE_GROUP_LOCK (group);
-  if (*sinkp) {
-    GST_DEBUG_OBJECT (playbin, "we already have a pending sink, expose pad");
-    /* for now, just assume that we can link the pad to this same sink. FIXME,
-     * check that we can link this new pad to this sink as well. */
-    GST_SOURCE_GROUP_UNLOCK (group);
-    return GST_AUTOPLUG_SELECT_EXPOSE;
-  }
-  GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
-  GST_SOURCE_GROUP_UNLOCK (group);
-
   if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
     GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
         gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
@@ -2438,24 +1629,19 @@
     return GST_AUTOPLUG_SELECT_SKIP;
   }
 
-  /* remember the sink in the group now, the element is floating, we take
-   * ownership now */
-  GST_SOURCE_GROUP_LOCK (group);
-  if (*sinkp == NULL) {
-    /* store the sink in the group, we will configure it later when we
-     * reconfigure the sink */
-    GST_DEBUG_OBJECT (playbin, "remember sink");
-    gst_object_ref (element);
-    gst_object_sink (element);
-    *sinkp = element;
+  /* at this point, we have the sink working, configure it in playsink */
+  klass = gst_element_factory_get_klass (factory);
+
+  /* get klass to figure out if it's audio or video */
+  if (strstr (klass, "Audio")) {
+    GST_DEBUG_OBJECT (playbin, "configure audio sink");
+    gst_play_sink_set_audio_sink (playbin->playsink, element);
+  } else if (strstr (klass, "Video")) {
+    GST_DEBUG_OBJECT (playbin, "configure video sink");
+    gst_play_sink_set_video_sink (playbin->playsink, element);
   } else {
-    /* some other thread configured a sink while we were testing the sink, set
-     * the sink back to NULL and assume we can use the other sink */
-    GST_DEBUG_OBJECT (playbin, "another sink was found, expose pad");
-    gst_element_set_state (element, GST_STATE_NULL);
-    gst_object_unref (element);
+    GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
   }
-  GST_SOURCE_GROUP_UNLOCK (group);
 
   /* tell decodebin to expose the pad because we are going to use this
    * sink */
@@ -2464,202 +1650,67 @@
   return GST_AUTOPLUG_SELECT_EXPOSE;
 }
 
-static void
-notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
-    GstSourceGroup * group)
-{
-  GstPlayBin *playbin;
-  GstElement *source;
-
-  playbin = group->playbin;
-
-  g_object_get (group->uridecodebin, "source", &source, NULL);
-
-  GST_OBJECT_LOCK (playbin);
-  if (playbin->source)
-    gst_object_unref (playbin->source);
-  playbin->source = source;
-  GST_OBJECT_UNLOCK (playbin);
-
-  g_object_notify (G_OBJECT (playbin), "source");
-}
-
-/* must be called with the group lock */
 static gboolean
-group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
-    gboolean locked)
-{
-  GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
-
-  if (group->uridecodebin)
-    gst_element_set_locked_state (group->uridecodebin, locked);
-  if (group->suburidecodebin)
-    gst_element_set_locked_state (group->suburidecodebin, locked);
-
-  return TRUE;
-}
-
-#define REMOVE_SIGNAL(obj,id)            \
-if (id) {                                \
-  g_signal_handler_disconnect (obj, id); \
-  id = 0;                                \
-}
-
-/* must be called with PLAY_BIN_LOCK */
-static gboolean
-activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
+activate_group (GstPlayBin * playbin, GstSourceGroup * group)
 {
   GstElement *uridecodebin;
-  GstElement *suburidecodebin = NULL;
 
   g_return_val_if_fail (group->valid, FALSE);
   g_return_val_if_fail (!group->active, FALSE);
 
-  GST_DEBUG_OBJECT (playbin, "activating group %p", group);
+  if (group->uridecodebin) {
+    gst_element_set_state (group->uridecodebin, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
+    group->uridecodebin = NULL;
+  }
 
-  GST_SOURCE_GROUP_LOCK (group);
-  if (group->uridecodebin) {
-    GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
-    REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
-    REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
-    REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
-    REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
-    REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
-    REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
-    REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
-    gst_element_set_state (group->uridecodebin, GST_STATE_NULL);
-    uridecodebin = group->uridecodebin;
-  } else {
-    GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
-    uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
-    if (!uridecodebin)
-      goto no_decodebin;
-    gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
-    group->uridecodebin = uridecodebin;
-  }
+  uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
+  if (!uridecodebin)
+    goto no_decodebin;
 
   /* configure connection speed */
-  g_object_set (uridecodebin, "connection-speed",
-      playbin->connection_speed / 1000, NULL);
-  if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_DOWNLOAD)
-    g_object_set (uridecodebin, "download", TRUE, NULL);
-  else
-    g_object_set (uridecodebin, "download", FALSE, NULL);
-  /* configure subtitle encoding */
-  g_object_set (uridecodebin, "subtitle-encoding", playbin->encoding, NULL);
+  g_object_set (uridecodebin, "connection-speed", playbin->connection_speed,
+      NULL);
   /* configure uri */
   g_object_set (uridecodebin, "uri", group->uri, NULL);
-  g_object_set (uridecodebin, "buffer-duration", playbin->buffer_duration,
-      NULL);
-  g_object_set (uridecodebin, "buffer-size", playbin->buffer_size, NULL);
 
   /* connect pads and other things */
-  group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
-      G_CALLBACK (pad_added_cb), group);
-  group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
-      G_CALLBACK (pad_removed_cb), group);
-  group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
-      G_CALLBACK (no_more_pads_cb), group);
-  group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
-      G_CALLBACK (notify_source_cb), group);
-  /* we have 1 pending no-more-pads */
-  group->pending = 1;
-
+  g_signal_connect (uridecodebin, "pad-added", G_CALLBACK (pad_added_cb),
+      group);
+  g_signal_connect (uridecodebin, "pad-removed", G_CALLBACK (pad_removed_cb),
+      group);
+  g_signal_connect (uridecodebin, "no-more-pads", G_CALLBACK (no_more_pads_cb),
+      group);
   /* is called when the uridecodebin is out of data and we can switch to the
    * next uri */
-  group->drained_id =
-      g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
-      group);
+  g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb), group);
 
   /* will be called when a new media type is found. We return a list of decoders
    * including sinks for decodebin to try */
-  group->autoplug_factories_id =
-      g_signal_connect (uridecodebin, "autoplug-factories",
+  g_signal_connect (uridecodebin, "autoplug-factories",
       G_CALLBACK (autoplug_factories_cb), group);
-  group->autoplug_select_id = g_signal_connect (uridecodebin, "autoplug-select",
+
+  g_signal_connect (uridecodebin, "autoplug-select",
       G_CALLBACK (autoplug_select_cb), group);
 
-  if (group->suburi) {
-    /* subtitles */
-    if (group->suburidecodebin) {
-      GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
-      REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
-      REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
-      REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
-      gst_element_set_state (group->suburidecodebin, GST_STATE_NULL);
-      suburidecodebin = group->suburidecodebin;
-    } else {
-      GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
-      suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
-      if (!suburidecodebin)
-        goto no_decodebin;
-
-      gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
-      group->suburidecodebin = suburidecodebin;
-    }
-
-    /* configure connection speed */
-    g_object_set (suburidecodebin, "connection-speed",
-        playbin->connection_speed, NULL);
-    /* configure subtitle encoding */
-    g_object_set (suburidecodebin, "subtitle-encoding", playbin->encoding,
-        NULL);
-    /* configure uri */
-    g_object_set (suburidecodebin, "uri", group->suburi, NULL);
+  /*  */
+  gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
+  group->uridecodebin = uridecodebin;
 
-    /* connect pads and other things */
-    group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
-        G_CALLBACK (pad_added_cb), group);
-    group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
-        "pad-removed", G_CALLBACK (pad_removed_cb), group);
-    group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
-        "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
-
-    /* we have 2 pending no-more-pads */
-    group->pending = 2;
-  }
+  gst_element_set_state (uridecodebin, GST_STATE_PAUSED);
 
-  /* release the group lock before setting the state of the decodebins, they
-   * might fire signals in this thread that we need to handle with the
-   * group_lock taken. */
-  GST_SOURCE_GROUP_UNLOCK (group);
-
-  if (suburidecodebin) {
-    if (gst_element_set_state (suburidecodebin,
-            target) == GST_STATE_CHANGE_FAILURE)
-      goto suburidecodebin_failure;
-  }
-  if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
-    goto uridecodebin_failure;
-
-  GST_SOURCE_GROUP_LOCK (group);
-  /* alow state changes of the playbin2 affect the group elements now */
-  group_set_locked_state_unlocked (playbin, group, FALSE);
   group->active = TRUE;
-  GST_SOURCE_GROUP_UNLOCK (group);
 
   return TRUE;
 
   /* ERRORS */
 no_decodebin:
   {
-    GST_SOURCE_GROUP_UNLOCK (group);
-    return FALSE;
-  }
-suburidecodebin_failure:
-  {
-    GST_DEBUG_OBJECT (playbin, "failed state change of subtitle uridecodebin");
-    return FALSE;
-  }
-uridecodebin_failure:
-  {
-    GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
     return FALSE;
   }
 }
 
-/* unlink a group of uridecodebins from the sink.
- * must be called with PLAY_BIN_LOCK */
+/* unlink a group of uridecodebins from the sink */
 static gboolean
 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
 {
@@ -2670,46 +1721,27 @@
 
   GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
 
-  GST_SOURCE_GROUP_LOCK (group);
-  group->active = FALSE;
   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
     GstSourceSelect *select = &group->selector[i];
 
-    GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
-
-    if (select->srcpad) {
-      if (select->sinkpad) {
-        GST_LOG_OBJECT (playbin, "unlinking from sink");
-        gst_pad_unlink (select->srcpad, select->sinkpad);
+    if (!select->selector)
+      continue;
 
-        /* release back */
-        GST_LOG_OBJECT (playbin, "release sink pad");
-        gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
-        select->sinkpad = NULL;
-      }
-      gst_object_unref (select->srcpad);
-      select->srcpad = NULL;
-    }
+    GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media);
+    gst_pad_unlink (select->srcpad, select->sinkpad);
 
-    if (select->selector) {
-      gst_element_set_state (select->selector, GST_STATE_NULL);
-      gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
-      select->selector = NULL;
-    }
+    /* release back */
+    gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
+    select->sinkpad = NULL;
+
+    gst_object_unref (select->srcpad);
+    select->srcpad = NULL;
+
+    gst_element_set_state (select->selector, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
+    select->selector = NULL;
   }
-  /* delete any custom sinks we might have */
-  if (group->audio_sink)
-    gst_object_unref (group->audio_sink);
-  group->audio_sink = NULL;
-  if (group->video_sink)
-    gst_object_unref (group->video_sink);
-  group->video_sink = NULL;
-  /* we still have the decodebins added to the playbin2 but we can't remove them
-   * yet or change their state because this function might be called from the
-   * streaming threads, instead block the state so that state changes on the
-   * playbin2 don't affect us anymore */
-  group_set_locked_state_unlocked (playbin, group, TRUE);
-  GST_SOURCE_GROUP_UNLOCK (group);
+  group->active = FALSE;
 
   return TRUE;
 }
@@ -2718,14 +1750,13 @@
  * configured. It swaps out the current_group and activates the valid 
  * next_group. */
 static gboolean
-setup_next_source (GstPlayBin * playbin, GstState target)
+setup_next_source (GstPlayBin * playbin)
 {
   GstSourceGroup *new_group, *old_group;
 
   GST_DEBUG_OBJECT (playbin, "setup sources");
 
   /* see if there is a next group */
-  GST_PLAY_BIN_LOCK (playbin);
   new_group = playbin->next_group;
   if (!new_group || !new_group->valid)
     goto no_next_group;
@@ -2739,13 +1770,12 @@
   }
 
   /* activate the new group */
-  if (!activate_group (playbin, new_group, target))
+  if (!activate_group (playbin, new_group))
     goto activate_failed;
 
   /* swap old and new */
   playbin->curr_group = new_group;
   playbin->next_group = old_group;
-  GST_PLAY_BIN_UNLOCK (playbin);
 
   return TRUE;
 
@@ -2753,19 +1783,17 @@
 no_next_group:
   {
     GST_DEBUG_OBJECT (playbin, "no next group");
-    GST_PLAY_BIN_UNLOCK (playbin);
     return FALSE;
   }
 activate_failed:
   {
     GST_DEBUG_OBJECT (playbin, "activate failed");
-    GST_PLAY_BIN_UNLOCK (playbin);
     return FALSE;
   }
 }
 
 /* The group that is currently playing is copied again to the
- * next_group so that it will start playing the next time.
+ * next_group.
  */
 static gboolean
 save_current_group (GstPlayBin * playbin)
@@ -2775,7 +1803,6 @@
   GST_DEBUG_OBJECT (playbin, "save current group");
 
   /* see if there is a current group */
-  GST_PLAY_BIN_LOCK (playbin);
   curr_group = playbin->curr_group;
   if (curr_group && curr_group->valid) {
     /* unlink our pads with the sink */
@@ -2784,27 +1811,6 @@
   /* swap old and new */
   playbin->curr_group = playbin->next_group;
   playbin->next_group = curr_group;
-  GST_PLAY_BIN_UNLOCK (playbin);
-
-  return TRUE;
-}
-
-/* clear the locked state from all groups. This function is called before a
- * state change to NULL is performed on them. */
-static gboolean
-groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
-{
-  GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
-      locked);
-
-  GST_PLAY_BIN_LOCK (playbin);
-  GST_SOURCE_GROUP_LOCK (playbin->curr_group);
-  group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
-  GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
-  GST_SOURCE_GROUP_LOCK (playbin->next_group);
-  group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
-  GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
-  GST_PLAY_BIN_UNLOCK (playbin);
 
   return TRUE;
 }
@@ -2819,48 +1825,16 @@
 
   switch (transition) {
     case GST_STATE_CHANGE_READY_TO_PAUSED:
-      GST_LOG_OBJECT (playbin, "clearing shutdown flag");
-      g_atomic_int_set (&playbin->shutdown, 0);
-      if (!setup_next_source (playbin, GST_STATE_READY))
+      if (!setup_next_source (playbin))
         goto source_failed;
       break;
-    case GST_STATE_CHANGE_PAUSED_TO_READY:
-      /* FIXME unlock our waiting groups */
-      GST_LOG_OBJECT (playbin, "setting shutdown flag");
-      g_atomic_int_set (&playbin->shutdown, 1);
-
-      /* wait for all callbacks to end by taking the lock.
-       * No dynamic (critical) new callbacks will
-       * be able to happen as we set the shutdown flag. */
-      GST_PLAY_BIN_DYN_LOCK (playbin);
-      GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
-      GST_PLAY_BIN_DYN_UNLOCK (playbin);
-      break;
-    case GST_STATE_CHANGE_READY_TO_NULL:
-      /* unlock so that all groups go to NULL */
-      groups_set_locked_state (playbin, FALSE);
-      break;
     default:
       break;
   }
 
   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-  if (ret == GST_STATE_CHANGE_FAILURE) {
-    if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
-      GstSourceGroup *curr_group;
-
-      curr_group = playbin->curr_group;
-      if (curr_group && curr_group->valid) {
-        /* unlink our pads with the sink */
-        deactivate_group (playbin, curr_group);
-      }
-
-      /* Swap current and next group back */
-      playbin->curr_group = playbin->next_group;
-      playbin->next_group = curr_group;
-    }
+  if (ret == GST_STATE_CHANGE_FAILURE)
     return ret;
-  }
 
   switch (transition) {
     case GST_STATE_CHANGE_READY_TO_PAUSED:
@@ -2871,11 +1845,6 @@
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       save_current_group (playbin);
       break;
-    case GST_STATE_CHANGE_READY_TO_NULL:
-      /* make sure the groups don't perform a state change anymore until we
-       * enable them again */
-      groups_set_locked_state (playbin, TRUE);
-      break;
     default:
       break;
   }
@@ -2898,9 +1867,6 @@
 {
   GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
 
-  g_type_class_ref (gst_input_selector_get_type ());
-  g_type_class_ref (gst_selector_pad_get_type ());
-
   return gst_element_register (plugin, "playbin2", GST_RANK_NONE,
       GST_TYPE_PLAY_BIN);
 }