Add -Wmissing-declarations -Wmissing-prototypes to warning flags
[platform/upstream/gstreamer.git] / gst / playback / gstplaybin2.c
1 /* GStreamer
2  * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:element-playbin2
22  *
23  * Playbin2 provides a stand-alone everything-in-one abstraction for an
24  * audio and/or video player.
25  *
26  * At this stage, playbin2 is considered UNSTABLE. The API provided in the
27  * signals and properties may yet change in the near future. When playbin2
28  * is stable, it will probably replace #playbin
29  *
30  * It can handle both audio and video files and features
31  * <itemizedlist>
32  * <listitem>
33  * automatic file type recognition and based on that automatic
34  * selection and usage of the right audio/video/subtitle demuxers/decoders
35  * </listitem>
36  * <listitem>
37  * visualisations for audio files
38  * </listitem>
39  * <listitem>
40  * subtitle support for video files. Subtitles can be store in external
41  * files.
42  * </listitem>
43  * <listitem>
44  * stream selection between different video/audio/subtitles streams
45  * </listitem>
46  * <listitem>
47  * meta info (tag) extraction
48  * </listitem>
49  * <listitem>
50  * easy access to the last video frame
51  * </listitem>
52  * <listitem>
53  * buffering when playing streams over a network
54  * </listitem>
55  * <listitem>
56  * volume control with mute option
57  * </listitem>
58  * </itemizedlist>
59  *
60  * <refsect2>
61  * <title>Usage</title>
62  * <para>
63  * A playbin element can be created just like any other element using
64  * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin2:uri
65  * property. This must be an absolute URI, relative file paths are not allowed.
66  * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
67  *
68  * Playbin is a #GstPipeline. It will notify the application of everything
69  * that's happening (errors, end of stream, tags found, state changes, etc.)
70  * by posting messages on its #GstBus. The application needs to watch the
71  * bus.
72  *
73  * Playback can be initiated by setting the element to PLAYING state using
74  * gst_element_set_state(). Note that the state change will take place in
75  * the background in a separate thread, when the function returns playback
76  * is probably not happening yet and any errors might not have occured yet.
77  * Applications using playbin should ideally be written to deal with things
78  * completely asynchroneous.
79  *
80  * When playback has finished (an EOS message has been received on the bus)
81  * or an error has occured (an ERROR message has been received on the bus) or
82  * the user wants to play a different track, playbin should be set back to
83  * READY or NULL state, then the #GstPlayBin2:uri property should be set to the
84  * new location and then playbin be set to PLAYING state again.
85  *
86  * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
87  * on the playbin element. Again, the seek will not be executed
88  * instantaneously, but will be done in a background thread. When the seek
89  * call returns the seek will most likely still be in process. An application
90  * may wait for the seek to finish (or fail) using gst_element_get_state() with
91  * -1 as the timeout, but this will block the user interface and is not
92  * recommended at all.
93  *
94  * Applications may query the current position and duration of the stream
95  * via gst_element_query_position() and gst_element_query_duration() and
96  * setting the format passed to GST_FORMAT_TIME. If the query was successful,
97  * the duration or position will have been returned in units of nanoseconds.
98  * </para>
99  * </refsect2>
100  * <refsect2>
101  * <title>Advanced Usage: specifying the audio and video sink</title>
102  * <para>
103  * By default, if no audio sink or video sink has been specified via the
104  * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property, playbin will use the autoaudiosink
105  * and autovideosink elements to find the first-best available output method.
106  * This should work in most cases, but is not always desirable. Often either
107  * the user or application might want to specify more explicitly what to use
108  * for audio and video output.
109  *
110  * If the application wants more control over how audio or video should be
111  * output, it may create the audio/video sink elements itself (for example
112  * using gst_element_factory_make()) and provide them to playbin using the
113  * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property.
114  *
115  * GNOME-based applications, for example, will usually want to create
116  * gconfaudiosink and gconfvideosink elements and make playbin use those,
117  * so that output happens to whatever the user has configured in the GNOME
118  * Multimedia System Selector configuration dialog.
119  *
120  * The sink elements do not necessarily need to be ready-made sinks. It is
121  * possible to create container elements that look like a sink to playbin,
122  * but in reality contain a number of custom elements linked together. This
123  * can be achieved by creating a #GstBin and putting elements in there and
124  * linking them, and then creating a sink #GstGhostPad for the bin and pointing
125  * it to the sink pad of the first element within the bin. This can be used
126  * for a number of purposes, for example to force output to a particular
127  * format or to modify or observe the data before it is output.
128  *
129  * It is also possible to 'suppress' audio and/or video output by using
130  * 'fakesink' elements (or capture it from there using the fakesink element's
131  * "handoff" signal, which, nota bene, is fired from the streaming thread!).
132  * </para>
133  * </refsect2>
134  * <refsect2>
135  * <title>Retrieving Tags and Other Meta Data</title>
136  * <para>
137  * Most of the common meta data (artist, title, etc.) can be retrieved by
138  * watching for TAG messages on the pipeline's bus (see above).
139  *
140  * Other more specific meta information like width/height/framerate of video
141  * streams or samplerate/number of channels of audio streams can be obtained
142  * from the negotiated caps on the sink pads of the sinks.
143  * </para>
144  * </refsect2>
145  * <refsect2>
146  * <title>Buffering</title>
147  * Playbin handles buffering automatically for the most part, but applications
148  * need to handle parts of the buffering process as well. Whenever playbin is
149  * buffering, it will post BUFFERING messages on the bus with a percentage
150  * value that shows the progress of the buffering process. Applications need
151  * to set playbin to PLAYING or PAUSED state in response to these messages.
152  * They may also want to convey the buffering progress to the user in some
153  * way. Here is how to extract the percentage information from the message
154  * (requires GStreamer >= 0.10.11):
155  * |[
156  * switch (GST_MESSAGE_TYPE (msg)) {
157  *   case GST_MESSAGE_BUFFERING: {
158  *     gint percent = 0;
159  *     gst_message_parse_buffering (msg, &amp;percent);
160  *     g_print ("Buffering (%%u percent done)", percent);
161  *     break;
162  *   }
163  *   ...
164  * }
165  * ]|
166  * Note that applications should keep/set the pipeline in the PAUSED state when
167  * a BUFFERING message is received with a buffer percent value < 100 and set
168  * the pipeline back to PLAYING state when a BUFFERING message with a value
169  * of 100 percent is received (if PLAYING is the desired state, that is).
170  * </refsect2>
171  * <refsect2>
172  * <title>Embedding the video window in your application</title>
173  * By default, playbin (or rather the video sinks used) will create their own
174  * window. Applications will usually want to force output to a window of their
175  * own, however. This can be done using the #GstXOverlay interface, which most
176  * video sinks implement. See the documentation there for more details.
177  * </refsect2>
178  * <refsect2>
179  * <title>Specifying which CD/DVD device to use</title>
180  * The device to use for CDs/DVDs needs to be set on the source element
181  * playbin creates before it is opened. The only way to do this at the moment
182  * is to connect to playbin's "notify::source" signal, which will be emitted
183  * by playbin when it has created the source element for a particular URI.
184  * In the signal callback you can check if the source element has a "device"
185  * property and set it appropriately. In future ways might be added to specify
186  * the device as part of the URI, but at the time of writing this is not
187  * possible yet.
188  * </refsect2>
189  * <refsect2>
190  * <title>Handling redirects</title>
191  * <para>
192  * Some elements may post 'redirect' messages on the bus to tell the
193  * application to open another location. These are element messages containing
194  * a structure named 'redirect' along with a 'new-location' field of string
195  * type. The new location may be a relative or an absolute URI. Examples
196  * for such redirects can be found in many quicktime movie trailers.
197  * </para>
198  * </refsect2>
199  * <refsect2>
200  * <title>Examples</title>
201  * |[
202  * gst-launch -v playbin uri=file:///path/to/somefile.avi
203  * ]| This will play back the given AVI video file, given that the video and
204  * audio decoders required to decode the content are installed. Since no
205  * special audio sink or video sink is supplied (not possible via gst-launch),
206  * playbin will try to find a suitable audio and video sink automatically
207  * using the autoaudiosink and autovideosink elements.
208  * |[
209  * gst-launch -v playbin uri=cdda://4
210  * ]| This will play back track 4 on an audio CD in your disc drive (assuming
211  * the drive is detected automatically by the plugin).
212  * |[
213  * gst-launch -v playbin uri=dvd://1
214  * ]| This will play back title 1 of a DVD in your disc drive (assuming
215  * the drive is detected automatically by the plugin).
216  * </refsect2>
217  */
218
219 #ifdef HAVE_CONFIG_H
220 #include "config.h"
221 #endif
222
223 #include <string.h>
224 #include <gst/gst.h>
225
226 #include <gst/gst-i18n-plugin.h>
227 #include <gst/pbutils/pbutils.h>
228 #include <gst/interfaces/streamvolume.h>
229
230 #include "gstplay-enum.h"
231 #include "gstplay-marshal.h"
232 #include "gstplayback.h"
233 #include "gstplaysink.h"
234 #include "gstfactorylists.h"
235 #include "gstinputselector.h"
236 #include "gstscreenshot.h"
237 #include "gstsubtitleoverlay.h"
238
239 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
240 #define GST_CAT_DEFAULT gst_play_bin_debug
241
242 #define GST_TYPE_PLAY_BIN               (gst_play_bin_get_type())
243 #define GST_PLAY_BIN(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
244 #define GST_PLAY_BIN_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
245 #define GST_IS_PLAY_BIN(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
246 #define GST_IS_PLAY_BIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
247
248 #define VOLUME_MAX_DOUBLE 10.0
249
250 typedef struct _GstPlayBin GstPlayBin;
251 typedef struct _GstPlayBinClass GstPlayBinClass;
252 typedef struct _GstSourceGroup GstSourceGroup;
253 typedef struct _GstSourceSelect GstSourceSelect;
254
255 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
256
257 /* has the info for a selector and provides the link to the sink */
258 struct _GstSourceSelect
259 {
260   const gchar *media_list[8];   /* the media types for the selector */
261   SourceSelectGetMediaCapsFunc get_media_caps;  /* more complex caps for the selector */
262   GstPlaySinkType type;         /* the sink pad type of the selector */
263
264   GstElement *selector;         /* the selector */
265   GPtrArray *channels;
266   GstPad *srcpad;               /* the source pad of the selector */
267   GstPad *sinkpad;              /* the sinkpad of the sink when the selector
268                                  * is linked
269                                  */
270
271   gulong src_event_probe_id;
272   gulong sink_event_probe_id;
273   GstClockTime group_start_accum;
274 };
275
276 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
277 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
278 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
279
280 /* a structure to hold the objects for decoding a uri and the subtitle uri
281  */
282 struct _GstSourceGroup
283 {
284   GstPlayBin *playbin;
285
286   GMutex *lock;
287
288   gboolean valid;               /* the group has valid info to start playback */
289   gboolean active;              /* the group is active */
290
291   /* properties */
292   gchar *uri;
293   gchar *suburi;
294   GValueArray *streaminfo;
295   GstElement *source;
296
297   GPtrArray *video_channels;    /* links to selector pads */
298   GPtrArray *audio_channels;    /* links to selector pads */
299   GPtrArray *text_channels;     /* links to selector pads */
300
301   GstElement *audio_sink;       /* autoplugged audio and video sinks */
302   GstElement *video_sink;
303
304   /* uridecodebins for uri and subtitle uri */
305   GstElement *uridecodebin;
306   GstElement *suburidecodebin;
307   gint pending;
308   gboolean sub_pending;
309
310   gulong pad_added_id;
311   gulong pad_removed_id;
312   gulong no_more_pads_id;
313   gulong notify_source_id;
314   gulong drained_id;
315   gulong autoplug_factories_id;
316   gulong autoplug_select_id;
317   gulong autoplug_continue_id;
318
319   gulong sub_pad_added_id;
320   gulong sub_pad_removed_id;
321   gulong sub_no_more_pads_id;
322   gulong sub_autoplug_continue_id;
323
324   GMutex *stream_changed_pending_lock;
325   GList *stream_changed_pending;
326
327   /* selectors for different streams */
328   GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST];
329 };
330
331 #define GST_PLAY_BIN_GET_LOCK(bin) (((GstPlayBin*)(bin))->lock)
332 #define GST_PLAY_BIN_LOCK(bin) (g_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
333 #define GST_PLAY_BIN_UNLOCK(bin) (g_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
334
335 /* lock to protect dynamic callbacks, like no-more-pads */
336 #define GST_PLAY_BIN_DYN_LOCK(bin)    g_mutex_lock ((bin)->dyn_lock)
337 #define GST_PLAY_BIN_DYN_UNLOCK(bin)  g_mutex_unlock ((bin)->dyn_lock)
338
339 /* lock for shutdown */
340 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label)           \
341 G_STMT_START {                                          \
342   if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown)))   \
343     goto label;                                         \
344   GST_PLAY_BIN_DYN_LOCK (bin);                          \
345   if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
346     GST_PLAY_BIN_DYN_UNLOCK (bin);                      \
347     goto label;                                         \
348   }                                                     \
349 } G_STMT_END
350
351 /* unlock for shutdown */
352 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin)         \
353   GST_PLAY_BIN_DYN_UNLOCK (bin);                  \
354
355 /**
356  * GstPlayBin2:
357  *
358  * playbin element structure
359  */
360 struct _GstPlayBin
361 {
362   GstPipeline parent;
363
364   GMutex *lock;                 /* to protect group switching */
365
366   /* the groups, we use a double buffer to switch between current and next */
367   GstSourceGroup groups[2];     /* array with group info */
368   GstSourceGroup *curr_group;   /* pointer to the currently playing group */
369   GstSourceGroup *next_group;   /* pointer to the next group */
370
371   /* properties */
372   guint connection_speed;       /* connection speed in bits/sec (0 = unknown) */
373   gint current_video;           /* the currently selected stream */
374   gint current_audio;           /* the currently selected stream */
375   gint current_text;            /* the currently selected stream */
376
377   guint64 buffer_duration;      /* When buffering, the max buffer duration (ns) */
378   guint buffer_size;            /* When buffering, the max buffer size (bytes) */
379
380   /* our play sink */
381   GstPlaySink *playsink;
382
383   /* the last activated source */
384   GstElement *source;
385
386   /* lock protecting dynamic adding/removing */
387   GMutex *dyn_lock;
388   /* if we are shutting down or not */
389   gint shutdown;
390
391   GMutex *elements_lock;
392   guint32 elements_cookie;
393   GValueArray *elements;        /* factories we can use for selecting elements */
394
395   gboolean have_selector;       /* set to FALSE when we fail to create an
396                                  * input-selector, so that we only post a
397                                  * warning once */
398
399   GstElement *audio_sink;       /* configured audio sink, or NULL      */
400   GstElement *video_sink;       /* configured video sink, or NULL      */
401   GstElement *text_sink;        /* configured text sink, or NULL       */
402
403   struct
404   {
405     gboolean valid;
406     GstFormat format;
407     gint64 duration;
408   } duration[5];                /* cached durations */
409
410   GstSegment segments[3];       /* Video/Audio/Text segments */
411 };
412
413 struct _GstPlayBinClass
414 {
415   GstPipelineClass parent_class;
416
417   /* notify app that the current uri finished decoding and it is possible to
418    * queue a new one for gapless playback */
419   void (*about_to_finish) (GstPlayBin * playbin);
420
421   /* notify app that number of audio/video/text streams changed */
422   void (*video_changed) (GstPlayBin * playbin);
423   void (*audio_changed) (GstPlayBin * playbin);
424   void (*text_changed) (GstPlayBin * playbin);
425
426   /* notify app that the tags of audio/video/text streams changed */
427   void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
428   void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
429   void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
430
431   /* get audio/video/text tags for a stream */
432   GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
433   GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
434   GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
435
436   /* get the last video frame and convert it to the given caps */
437   GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
438
439   /* get audio/video/text pad for a stream */
440   GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
441   GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
442   GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
443 };
444
445 /* props */
446 #define DEFAULT_URI               NULL
447 #define DEFAULT_SUBURI            NULL
448 #define DEFAULT_SOURCE            NULL
449 #define DEFAULT_FLAGS             GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
450                                   GST_PLAY_FLAG_SOFT_VOLUME
451 #define DEFAULT_N_VIDEO           0
452 #define DEFAULT_CURRENT_VIDEO     -1
453 #define DEFAULT_N_AUDIO           0
454 #define DEFAULT_CURRENT_AUDIO     -1
455 #define DEFAULT_N_TEXT            0
456 #define DEFAULT_CURRENT_TEXT      -1
457 #define DEFAULT_SUBTITLE_ENCODING NULL
458 #define DEFAULT_AUDIO_SINK        NULL
459 #define DEFAULT_VIDEO_SINK        NULL
460 #define DEFAULT_VIS_PLUGIN        NULL
461 #define DEFAULT_TEXT_SINK         NULL
462 #define DEFAULT_VOLUME            1.0
463 #define DEFAULT_MUTE              FALSE
464 #define DEFAULT_FRAME             NULL
465 #define DEFAULT_FONT_DESC         NULL
466 #define DEFAULT_CONNECTION_SPEED  0
467 #define DEFAULT_BUFFER_DURATION   -1
468 #define DEFAULT_BUFFER_SIZE       -1
469
470 enum
471 {
472   PROP_0,
473   PROP_URI,
474   PROP_SUBURI,
475   PROP_SOURCE,
476   PROP_FLAGS,
477   PROP_N_VIDEO,
478   PROP_CURRENT_VIDEO,
479   PROP_N_AUDIO,
480   PROP_CURRENT_AUDIO,
481   PROP_N_TEXT,
482   PROP_CURRENT_TEXT,
483   PROP_SUBTITLE_ENCODING,
484   PROP_AUDIO_SINK,
485   PROP_VIDEO_SINK,
486   PROP_VIS_PLUGIN,
487   PROP_TEXT_SINK,
488   PROP_VOLUME,
489   PROP_MUTE,
490   PROP_FRAME,
491   PROP_FONT_DESC,
492   PROP_CONNECTION_SPEED,
493   PROP_BUFFER_SIZE,
494   PROP_BUFFER_DURATION,
495   PROP_LAST
496 };
497
498 /* signals */
499 enum
500 {
501   SIGNAL_ABOUT_TO_FINISH,
502   SIGNAL_CONVERT_FRAME,
503   SIGNAL_VIDEO_CHANGED,
504   SIGNAL_AUDIO_CHANGED,
505   SIGNAL_TEXT_CHANGED,
506   SIGNAL_VIDEO_TAGS_CHANGED,
507   SIGNAL_AUDIO_TAGS_CHANGED,
508   SIGNAL_TEXT_TAGS_CHANGED,
509   SIGNAL_GET_VIDEO_TAGS,
510   SIGNAL_GET_AUDIO_TAGS,
511   SIGNAL_GET_TEXT_TAGS,
512   SIGNAL_GET_VIDEO_PAD,
513   SIGNAL_GET_AUDIO_PAD,
514   SIGNAL_GET_TEXT_PAD,
515   LAST_SIGNAL
516 };
517
518 static void gst_play_bin_class_init (GstPlayBinClass * klass);
519 static void gst_play_bin_init (GstPlayBin * playbin);
520 static void gst_play_bin_finalize (GObject * object);
521
522 static void gst_play_bin_set_property (GObject * object, guint prop_id,
523     const GValue * value, GParamSpec * spec);
524 static void gst_play_bin_get_property (GObject * object, guint prop_id,
525     GValue * value, GParamSpec * spec);
526
527 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
528     GstStateChange transition);
529
530 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
531 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
532
533 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
534     gint stream);
535 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
536     gint stream);
537 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
538     gint stream);
539
540 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
541     GstCaps * caps);
542
543 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
544 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
545 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
546
547 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
548
549 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
550 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
551     GstSourceGroup * group);
552
553 static void gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
554     gboolean block);
555 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
556     suburidecodebin);
557
558 static GstElementClass *parent_class;
559
560 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
561
562 static const GstElementDetails gst_play_bin_details =
563 GST_ELEMENT_DETAILS ("Player Bin 2",
564     "Generic/Bin/Player",
565     "Autoplug and play media from an uri",
566     "Wim Taymans <wim.taymans@gmail.com>");
567
568 #define REMOVE_SIGNAL(obj,id)            \
569 if (id) {                                \
570   g_signal_handler_disconnect (obj, id); \
571   id = 0;                                \
572 }
573
574 static void
575 gst_play_marshal_BUFFER__BOXED (GClosure * closure,
576     GValue * return_value G_GNUC_UNUSED,
577     guint n_param_values,
578     const GValue * param_values,
579     gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
580 {
581   typedef GstBuffer *(*GMarshalFunc_OBJECT__BOXED) (gpointer data1,
582       gpointer arg_1, gpointer data2);
583   register GMarshalFunc_OBJECT__BOXED callback;
584   register GCClosure *cc = (GCClosure *) closure;
585   register gpointer data1, data2;
586   GstBuffer *v_return;
587
588   g_return_if_fail (return_value != NULL);
589   g_return_if_fail (n_param_values == 2);
590
591   if (G_CCLOSURE_SWAP_DATA (closure)) {
592     data1 = closure->data;
593     data2 = g_value_peek_pointer (param_values + 0);
594   } else {
595     data1 = g_value_peek_pointer (param_values + 0);
596     data2 = closure->data;
597   }
598   callback =
599       (GMarshalFunc_OBJECT__BOXED) (marshal_data ? marshal_data : cc->callback);
600
601   v_return = callback (data1, g_value_get_boxed (param_values + 1), data2);
602
603   gst_value_take_buffer (return_value, v_return);
604 }
605
606 static GType
607 gst_play_bin_get_type (void)
608 {
609   static GType gst_play_bin_type = 0;
610
611   if (!gst_play_bin_type) {
612     static const GTypeInfo gst_play_bin_info = {
613       sizeof (GstPlayBinClass),
614       NULL,
615       NULL,
616       (GClassInitFunc) gst_play_bin_class_init,
617       NULL,
618       NULL,
619       sizeof (GstPlayBin),
620       0,
621       (GInstanceInitFunc) gst_play_bin_init,
622       NULL
623     };
624     static const GInterfaceInfo svol_info = {
625       NULL, NULL, NULL
626     };
627
628     gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
629         "GstPlayBin2", &gst_play_bin_info, 0);
630
631     g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
632         &svol_info);
633   }
634
635   return gst_play_bin_type;
636 }
637
638 static void
639 gst_play_bin_class_init (GstPlayBinClass * klass)
640 {
641   GObjectClass *gobject_klass;
642   GstElementClass *gstelement_klass;
643   GstBinClass *gstbin_klass;
644
645   gobject_klass = (GObjectClass *) klass;
646   gstelement_klass = (GstElementClass *) klass;
647   gstbin_klass = (GstBinClass *) klass;
648
649   parent_class = g_type_class_peek_parent (klass);
650
651   gobject_klass->set_property = gst_play_bin_set_property;
652   gobject_klass->get_property = gst_play_bin_get_property;
653
654   gobject_klass->finalize = gst_play_bin_finalize;
655
656   /**
657    * GstPlayBin2:uri
658    *
659    * Set the next URI that playbin will play. This property can be set from the
660    * about-to-finish signal to queue the next media file.
661    */
662   g_object_class_install_property (gobject_klass, PROP_URI,
663       g_param_spec_string ("uri", "URI", "URI of the media to play",
664           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
665
666   /**
667    * GstPlayBin2:suburi
668    *
669    * Set the next subtitle URI that playbin will play. This property can be
670    * set from the about-to-finish signal to queue the next subtitle media file.
671    */
672   g_object_class_install_property (gobject_klass, PROP_SUBURI,
673       g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
674           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
675
676   g_object_class_install_property (gobject_klass, PROP_SOURCE,
677       g_param_spec_object ("source", "Source", "Source element",
678           GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
679
680   /**
681    * GstPlayBin2:flags
682    *
683    * Control the behaviour of playbin.
684    */
685   g_object_class_install_property (gobject_klass, PROP_FLAGS,
686       g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
687           GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
688           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
689
690   /**
691    * GstPlayBin2:n-video
692    *
693    * Get the total number of available video streams.
694    */
695   g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
696       g_param_spec_int ("n-video", "Number Video",
697           "Total number of video streams", 0, G_MAXINT, 0,
698           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
699   /**
700    * GstPlayBin2:current-video
701    *
702    * Get or set the currently playing video stream. By default the first video
703    * stream with data is played.
704    */
705   g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
706       g_param_spec_int ("current-video", "Current Video",
707           "Currently playing video stream (-1 = auto)",
708           -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
709   /**
710    * GstPlayBin2:n-audio
711    *
712    * Get the total number of available audio streams.
713    */
714   g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
715       g_param_spec_int ("n-audio", "Number Audio",
716           "Total number of audio streams", 0, G_MAXINT, 0,
717           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
718   /**
719    * GstPlayBin2:current-audio
720    *
721    * Get or set the currently playing audio stream. By default the first audio
722    * stream with data is played.
723    */
724   g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
725       g_param_spec_int ("current-audio", "Current audio",
726           "Currently playing audio stream (-1 = auto)",
727           -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
728   /**
729    * GstPlayBin2:n-text
730    *
731    * Get the total number of available subtitle streams.
732    */
733   g_object_class_install_property (gobject_klass, PROP_N_TEXT,
734       g_param_spec_int ("n-text", "Number Text",
735           "Total number of text streams", 0, G_MAXINT, 0,
736           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
737   /**
738    * GstPlayBin2:current-text:
739    *
740    * Get or set the currently playing subtitle stream. By default the first
741    * subtitle stream with data is played.
742    */
743   g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
744       g_param_spec_int ("current-text", "Current Text",
745           "Currently playing text stream (-1 = auto)",
746           -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
747
748   g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
749       g_param_spec_string ("subtitle-encoding", "subtitle encoding",
750           "Encoding to assume if input subtitles are not in UTF-8 encoding. "
751           "If not set, the GST_SUBTITLE_ENCODING environment variable will "
752           "be checked for an encoding to use. If that is not set either, "
753           "ISO-8859-15 will be assumed.", NULL,
754           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
755
756   g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
757       g_param_spec_object ("video-sink", "Video Sink",
758           "the video output element to use (NULL = default sink)",
759           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
760   g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
761       g_param_spec_object ("audio-sink", "Audio Sink",
762           "the audio output element to use (NULL = default sink)",
763           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
764   g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
765       g_param_spec_object ("vis-plugin", "Vis plugin",
766           "the visualization element to use (NULL = default)",
767           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
768   g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
769       g_param_spec_object ("text-sink", "Text plugin",
770           "the text output element to use (NULL = default textoverlay)",
771           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
772
773   /**
774    * GstPlayBin2:volume:
775    *
776    * Get or set the current audio stream volume. 1.0 means 100%,
777    * 0.0 means mute. This uses a linear volume scale.
778    *
779    */
780   g_object_class_install_property (gobject_klass, PROP_VOLUME,
781       g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
782           0.0, VOLUME_MAX_DOUBLE, 1.0,
783           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
784   g_object_class_install_property (gobject_klass, PROP_MUTE,
785       g_param_spec_boolean ("mute", "Mute",
786           "Mute the audio channel without changing the volume", FALSE,
787           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
788
789   /**
790    * GstPlayBin2:frame:
791    * @playbin: a #GstPlayBin2
792    *
793    * Get the currently rendered or prerolled frame in the sink.
794    * The #GstCaps on the buffer will describe the format of the buffer.
795    */
796   g_object_class_install_property (gobject_klass, PROP_FRAME,
797       gst_param_spec_mini_object ("frame", "Frame",
798           "The last frame (NULL = no video available)",
799           GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
800   g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
801       g_param_spec_string ("subtitle-font-desc",
802           "Subtitle font description",
803           "Pango font description of font "
804           "to be used for subtitle rendering", NULL,
805           G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
806
807   g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
808       g_param_spec_uint ("connection-speed", "Connection Speed",
809           "Network connection speed in kbps (0 = unknown)",
810           0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
811           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
812
813   g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
814       g_param_spec_int ("buffer-size", "Buffer size (bytes)",
815           "Buffer size when buffering network streams",
816           -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
817           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
818   g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
819       g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
820           "Buffer duration when buffering network streams",
821           -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
822           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
823
824   /**
825    * GstPlayBin2::about-to-finish
826    * @playbin: a #GstPlayBin2
827    *
828    * This signal is emitted when the current uri is about to finish. You can
829    * set the uri and suburi to make sure that playback continues.
830    */
831   gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
832       g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
833       G_SIGNAL_RUN_LAST,
834       G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
835       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
836
837   /**
838    * GstPlayBin2::video-changed
839    * @playbin: a #GstPlayBin2
840    *
841    * This signal is emitted whenever the number or order of the video
842    * streams has changed. The application will most likely want to select
843    * a new video stream.
844    */
845   gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
846       g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
847       G_SIGNAL_RUN_LAST,
848       G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
849       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
850   /**
851    * GstPlayBin2::audio-changed
852    * @playbin: a #GstPlayBin2
853    *
854    * This signal is emitted whenever the number or order of the audio
855    * streams has changed. The application will most likely want to select
856    * a new audio stream.
857    */
858   gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
859       g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
860       G_SIGNAL_RUN_LAST,
861       G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
862       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
863   /**
864    * GstPlayBin2::text-changed
865    * @playbin: a #GstPlayBin2
866    *
867    * This signal is emitted whenever the number or order of the text
868    * streams has changed. The application will most likely want to select
869    * a new text stream.
870    */
871   gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
872       g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
873       G_SIGNAL_RUN_LAST,
874       G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
875       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
876
877   /**
878    * GstPlayBin2::video-tags-changed
879    * @playbin: a #GstPlayBin2
880    * @stream: stream index with changed tags
881    *
882    * This signal is emitted whenever the tags of a video stream have changed.
883    * The application will most likely want to get the new tags.
884    *
885    * Since: 0.10.24
886    */
887   gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
888       g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
889       G_SIGNAL_RUN_LAST,
890       G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
891       gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
892
893   /**
894    * GstPlayBin2::audio-tags-changed
895    * @playbin: a #GstPlayBin2
896    * @stream: stream index with changed tags
897    *
898    * This signal is emitted whenever the tags of an audio stream have changed.
899    * The application will most likely want to get the new tags.
900    *
901    * Since: 0.10.24
902    */
903   gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
904       g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
905       G_SIGNAL_RUN_LAST,
906       G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
907       gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
908
909   /**
910    * GstPlayBin2::text-tags-changed
911    * @playbin: a #GstPlayBin2
912    * @stream: stream index with changed tags
913    *
914    * This signal is emitted whenever the tags of a text stream have changed.
915    * The application will most likely want to get the new tags.
916    *
917    * Since: 0.10.24
918    */
919   gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
920       g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
921       G_SIGNAL_RUN_LAST,
922       G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
923       gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
924
925   /**
926    * GstPlayBin2::get-video-tags
927    * @playbin: a #GstPlayBin2
928    * @stream: a video stream number
929    *
930    * Action signal to retrieve the tags of a specific video stream number.
931    * This information can be used to select a stream.
932    *
933    * Returns: a GstTagList with tags or NULL when the stream number does not
934    * exist.
935    */
936   gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
937       g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
938       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
939       G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
940       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
941   /**
942    * GstPlayBin2::get-audio-tags
943    * @playbin: a #GstPlayBin2
944    * @stream: an audio stream number
945    *
946    * Action signal to retrieve the tags of a specific audio stream number.
947    * This information can be used to select a stream.
948    *
949    * Returns: a GstTagList with tags or NULL when the stream number does not
950    * exist.
951    */
952   gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
953       g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
954       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
955       G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
956       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
957   /**
958    * GstPlayBin2::get-text-tags
959    * @playbin: a #GstPlayBin2
960    * @stream: a text stream number
961    *
962    * Action signal to retrieve the tags of a specific text stream number.
963    * This information can be used to select a stream.
964    *
965    * Returns: a GstTagList with tags or NULL when the stream number does not
966    * exist.
967    */
968   gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
969       g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
970       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
971       G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
972       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
973   /**
974    * GstPlayBin2::convert-frame
975    * @playbin: a #GstPlayBin2
976    * @caps: the target format of the frame
977    *
978    * Action signal to retrieve the currently playing video frame in the format
979    * specified by @caps.
980    * If @caps is %NULL, no conversion will be performed and this function is
981    * equivalent to the #GstPlayBin::frame property.
982    *
983    * Returns: a #GstBuffer of the current video frame converted to #caps.
984    * The caps on the buffer will describe the final layout of the buffer data.
985    * %NULL is returned when no current buffer can be retrieved or when the
986    * conversion failed.
987    */
988   gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
989       g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
990       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
991       G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
992       gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
993
994   /**
995    * GstPlayBin2::get-video-pad
996    * @playbin: a #GstPlayBin2
997    * @stream: a video stream number
998    *
999    * Action signal to retrieve the stream-selector sinkpad for a specific
1000    * video stream.
1001    * This pad can be used for notifications of caps changes, stream-specific
1002    * queries, etc.
1003    *
1004    * Returns: a #GstPad, or NULL when the stream number does not exist.
1005    */
1006   gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1007       g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1008       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1009       G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1010       gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1011   /**
1012    * GstPlayBin2::get-audio-pad
1013    * @playbin: a #GstPlayBin2
1014    * @stream: an audio stream number
1015    *
1016    * Action signal to retrieve the stream-selector sinkpad for a specific
1017    * audio stream.
1018    * This pad can be used for notifications of caps changes, stream-specific
1019    * queries, etc.
1020    *
1021    * Returns: a #GstPad, or NULL when the stream number does not exist.
1022    */
1023   gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1024       g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1025       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1026       G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1027       gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1028   /**
1029    * GstPlayBin2::get-text-pad
1030    * @playbin: a #GstPlayBin2
1031    * @stream: a text stream number
1032    *
1033    * Action signal to retrieve the stream-selector sinkpad for a specific
1034    * text stream.
1035    * This pad can be used for notifications of caps changes, stream-specific
1036    * queries, etc.
1037    *
1038    * Returns: a #GstPad, or NULL when the stream number does not exist.
1039    */
1040   gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1041       g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1042       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1043       G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1044       gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1045
1046   klass->get_video_tags = gst_play_bin_get_video_tags;
1047   klass->get_audio_tags = gst_play_bin_get_audio_tags;
1048   klass->get_text_tags = gst_play_bin_get_text_tags;
1049
1050   klass->convert_frame = gst_play_bin_convert_frame;
1051
1052   klass->get_video_pad = gst_play_bin_get_video_pad;
1053   klass->get_audio_pad = gst_play_bin_get_audio_pad;
1054   klass->get_text_pad = gst_play_bin_get_text_pad;
1055
1056   gst_element_class_set_details (gstelement_klass, &gst_play_bin_details);
1057
1058   gstelement_klass->change_state =
1059       GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1060   gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1061
1062   gstbin_klass->handle_message =
1063       GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1064 }
1065
1066 static void
1067 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1068 {
1069   /* store the array for the different channels */
1070   group->video_channels = g_ptr_array_new ();
1071   group->audio_channels = g_ptr_array_new ();
1072   group->text_channels = g_ptr_array_new ();
1073   group->lock = g_mutex_new ();
1074   /* init selectors. The selector is found by finding the first prefix that
1075    * matches the media. */
1076   group->playbin = playbin;
1077   /* If you add any items to these lists, check that media_list[] is defined
1078    * above to be large enough to hold MAX(items)+1, so as to accomodate a
1079    * NULL terminator (set when the memory is zeroed on allocation) */
1080   group->selector[0].media_list[0] = "audio/x-raw-";
1081   group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
1082   group->selector[0].channels = group->audio_channels;
1083   group->selector[1].media_list[0] = "audio/";
1084   group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO;
1085   group->selector[1].channels = group->audio_channels;
1086   group->selector[2].media_list[0] = "text/";
1087   group->selector[2].media_list[1] = "application/x-subtitle";
1088   group->selector[2].media_list[2] = "application/x-ssa";
1089   group->selector[2].media_list[3] = "application/x-ass";
1090   group->selector[2].media_list[4] = "video/x-dvd-subpicture";
1091   group->selector[2].media_list[5] = "subpicture/";
1092   group->selector[2].media_list[6] = "subtitle/";
1093   group->selector[2].get_media_caps = gst_subtitle_overlay_create_factory_caps;
1094   group->selector[2].type = GST_PLAY_SINK_TYPE_TEXT;
1095   group->selector[2].channels = group->text_channels;
1096   group->selector[3].media_list[0] = "video/x-raw-";
1097   group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
1098   group->selector[3].channels = group->video_channels;
1099   group->selector[4].media_list[0] = "video/";
1100   group->selector[4].type = GST_PLAY_SINK_TYPE_VIDEO;
1101   group->selector[4].channels = group->video_channels;
1102 }
1103
1104 static void
1105 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1106 {
1107   g_free (group->uri);
1108   g_free (group->suburi);
1109   g_ptr_array_free (group->video_channels, TRUE);
1110   g_ptr_array_free (group->audio_channels, TRUE);
1111   g_ptr_array_free (group->text_channels, TRUE);
1112
1113   g_mutex_free (group->lock);
1114   if (group->audio_sink)
1115     gst_object_unref (group->audio_sink);
1116   group->audio_sink = NULL;
1117   if (group->video_sink)
1118     gst_object_unref (group->video_sink);
1119   group->video_sink = NULL;
1120
1121   g_list_free (group->stream_changed_pending);
1122   group->stream_changed_pending = NULL;
1123
1124   if (group->stream_changed_pending_lock)
1125     g_mutex_free (group->stream_changed_pending_lock);
1126   group->stream_changed_pending_lock = NULL;
1127 }
1128
1129 static void
1130 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1131 {
1132   g_object_notify (G_OBJECT (playbin), "volume");
1133 }
1134
1135 static void
1136 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1137 {
1138   g_object_notify (G_OBJECT (playbin), "mute");
1139 }
1140
1141 /* Must be called with elements lock! */
1142 static void
1143 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1144 {
1145   if (!playbin->elements ||
1146       playbin->elements_cookie !=
1147       gst_default_registry_get_feature_list_cookie ()) {
1148     if (playbin->elements)
1149       g_value_array_free (playbin->elements);
1150     playbin->elements =
1151         gst_factory_list_get_elements (GST_FACTORY_LIST_DECODER |
1152         GST_FACTORY_LIST_SINK);
1153     playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1154   }
1155 }
1156
1157 static void
1158 gst_play_bin_init (GstPlayBin * playbin)
1159 {
1160   playbin->lock = g_mutex_new ();
1161   playbin->dyn_lock = g_mutex_new ();
1162
1163   /* assume we can create a selector */
1164   playbin->have_selector = TRUE;
1165
1166   /* init groups */
1167   playbin->curr_group = &playbin->groups[0];
1168   playbin->next_group = &playbin->groups[1];
1169   init_group (playbin, &playbin->groups[0]);
1170   init_group (playbin, &playbin->groups[1]);
1171
1172   /* first filter out the interesting element factories */
1173   playbin->elements_lock = g_mutex_new ();
1174   gst_play_bin_update_elements_list (playbin);
1175   GST_FACTORY_LIST_DEBUG (playbin->elements);
1176
1177   /* add sink */
1178   playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1179   gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1180   gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1181   /* Connect to notify::volume and notify::mute signals for proxying */
1182   g_signal_connect (playbin->playsink, "notify::volume",
1183       G_CALLBACK (notify_volume_cb), playbin);
1184   g_signal_connect (playbin->playsink, "notify::mute",
1185       G_CALLBACK (notify_mute_cb), playbin);
1186
1187   playbin->current_video = DEFAULT_CURRENT_VIDEO;
1188   playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1189   playbin->current_text = DEFAULT_CURRENT_TEXT;
1190
1191   playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1192   playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1193 }
1194
1195 static void
1196 gst_play_bin_finalize (GObject * object)
1197 {
1198   GstPlayBin *playbin;
1199
1200   playbin = GST_PLAY_BIN (object);
1201
1202   free_group (playbin, &playbin->groups[0]);
1203   free_group (playbin, &playbin->groups[1]);
1204
1205   if (playbin->source)
1206     gst_object_unref (playbin->source);
1207   if (playbin->video_sink)
1208     gst_object_unref (playbin->video_sink);
1209   if (playbin->audio_sink)
1210     gst_object_unref (playbin->audio_sink);
1211   if (playbin->text_sink)
1212     gst_object_unref (playbin->text_sink);
1213
1214   g_value_array_free (playbin->elements);
1215   g_mutex_free (playbin->lock);
1216   g_mutex_free (playbin->dyn_lock);
1217   g_mutex_free (playbin->elements_lock);
1218
1219   G_OBJECT_CLASS (parent_class)->finalize (object);
1220 }
1221
1222 static void
1223 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1224 {
1225   GstSourceGroup *group;
1226
1227   if (uri == NULL) {
1228     g_warning ("cannot set NULL uri");
1229     return;
1230   }
1231
1232   GST_PLAY_BIN_LOCK (playbin);
1233   group = playbin->next_group;
1234
1235   GST_SOURCE_GROUP_LOCK (group);
1236   /* store the uri in the next group we will play */
1237   g_free (group->uri);
1238   group->uri = g_strdup (uri);
1239   group->valid = TRUE;
1240   GST_SOURCE_GROUP_UNLOCK (group);
1241
1242   GST_DEBUG ("set new uri to %s", uri);
1243   GST_PLAY_BIN_UNLOCK (playbin);
1244 }
1245
1246 static void
1247 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1248 {
1249   GstSourceGroup *group;
1250
1251   GST_PLAY_BIN_LOCK (playbin);
1252   group = playbin->next_group;
1253
1254   GST_SOURCE_GROUP_LOCK (group);
1255   g_free (group->suburi);
1256   group->suburi = g_strdup (suburi);
1257   GST_SOURCE_GROUP_UNLOCK (group);
1258
1259   GST_DEBUG ("setting new .sub uri to %s", suburi);
1260
1261   GST_PLAY_BIN_UNLOCK (playbin);
1262 }
1263
1264 static void
1265 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1266 {
1267   gst_play_sink_set_flags (playbin->playsink, flags);
1268   gst_play_sink_reconfigure (playbin->playsink);
1269 }
1270
1271 static GstPlayFlags
1272 gst_play_bin_get_flags (GstPlayBin * playbin)
1273 {
1274   GstPlayFlags flags;
1275
1276   flags = gst_play_sink_get_flags (playbin->playsink);
1277
1278   return flags;
1279 }
1280
1281 /* get the currently playing group or if nothing is playing, the next
1282  * group. Must be called with the PLAY_BIN_LOCK. */
1283 static GstSourceGroup *
1284 get_group (GstPlayBin * playbin)
1285 {
1286   GstSourceGroup *result;
1287
1288   if (!(result = playbin->curr_group))
1289     result = playbin->next_group;
1290
1291   return result;
1292 }
1293
1294 static GstPad *
1295 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1296 {
1297   GstPad *sinkpad = NULL;
1298   GstSourceGroup *group;
1299
1300   GST_PLAY_BIN_LOCK (playbin);
1301   group = get_group (playbin);
1302   if (stream < group->video_channels->len) {
1303     sinkpad = g_ptr_array_index (group->video_channels, stream);
1304     gst_object_ref (sinkpad);
1305   }
1306   GST_PLAY_BIN_UNLOCK (playbin);
1307
1308   return sinkpad;
1309 }
1310
1311 static GstPad *
1312 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1313 {
1314   GstPad *sinkpad = NULL;
1315   GstSourceGroup *group;
1316
1317   GST_PLAY_BIN_LOCK (playbin);
1318   group = get_group (playbin);
1319   if (stream < group->audio_channels->len) {
1320     sinkpad = g_ptr_array_index (group->audio_channels, stream);
1321     gst_object_ref (sinkpad);
1322   }
1323   GST_PLAY_BIN_UNLOCK (playbin);
1324
1325   return sinkpad;
1326 }
1327
1328 static GstPad *
1329 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1330 {
1331   GstPad *sinkpad = NULL;
1332   GstSourceGroup *group;
1333
1334   GST_PLAY_BIN_LOCK (playbin);
1335   group = get_group (playbin);
1336   if (stream < group->text_channels->len) {
1337     sinkpad = g_ptr_array_index (group->text_channels, stream);
1338     gst_object_ref (sinkpad);
1339   }
1340   GST_PLAY_BIN_UNLOCK (playbin);
1341
1342   return sinkpad;
1343 }
1344
1345
1346 static GstTagList *
1347 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1348 {
1349   GstTagList *result;
1350   GstPad *sinkpad;
1351
1352   if (!channels || stream >= channels->len)
1353     return NULL;
1354
1355   sinkpad = g_ptr_array_index (channels, stream);
1356   g_object_get (sinkpad, "tags", &result, NULL);
1357
1358   return result;
1359 }
1360
1361 static GstTagList *
1362 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1363 {
1364   GstTagList *result;
1365   GstSourceGroup *group;
1366
1367   GST_PLAY_BIN_LOCK (playbin);
1368   group = get_group (playbin);
1369   result = get_tags (playbin, group->video_channels, stream);
1370   GST_PLAY_BIN_UNLOCK (playbin);
1371
1372   return result;
1373 }
1374
1375 static GstTagList *
1376 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1377 {
1378   GstTagList *result;
1379   GstSourceGroup *group;
1380
1381   GST_PLAY_BIN_LOCK (playbin);
1382   group = get_group (playbin);
1383   result = get_tags (playbin, group->audio_channels, stream);
1384   GST_PLAY_BIN_UNLOCK (playbin);
1385
1386   return result;
1387 }
1388
1389 static GstTagList *
1390 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1391 {
1392   GstTagList *result;
1393   GstSourceGroup *group;
1394
1395   GST_PLAY_BIN_LOCK (playbin);
1396   group = get_group (playbin);
1397   result = get_tags (playbin, group->text_channels, stream);
1398   GST_PLAY_BIN_UNLOCK (playbin);
1399
1400   return result;
1401 }
1402
1403 static GstBuffer *
1404 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1405 {
1406   GstBuffer *result;
1407
1408   result = gst_play_sink_get_last_frame (playbin->playsink);
1409   if (result != NULL && caps != NULL) {
1410     GstBuffer *temp;
1411
1412     temp = gst_play_frame_conv_convert (result, caps);
1413     gst_buffer_unref (result);
1414     result = temp;
1415   }
1416   return result;
1417 }
1418
1419 /* Returns current stream number, or -1 if none has been selected yet */
1420 static int
1421 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1422 {
1423   /* Internal API cleanup would make this easier... */
1424   int i;
1425   GstPad *pad, *current;
1426   GstObject *selector = NULL;
1427   int ret = -1;
1428
1429   for (i = 0; i < channels->len; i++) {
1430     pad = g_ptr_array_index (channels, i);
1431     if ((selector = gst_pad_get_parent (pad))) {
1432       g_object_get (selector, "active-pad", &current, NULL);
1433       gst_object_unref (selector);
1434
1435       if (pad == current) {
1436         gst_object_unref (current);
1437         ret = i;
1438         break;
1439       }
1440
1441       if (current)
1442         gst_object_unref (current);
1443     }
1444   }
1445
1446   return ret;
1447 }
1448
1449 static gboolean
1450 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1451 {
1452   GstSourceGroup *group;
1453   GPtrArray *channels;
1454   GstPad *sinkpad;
1455
1456   GST_PLAY_BIN_LOCK (playbin);
1457   group = get_group (playbin);
1458   if (!(channels = group->video_channels))
1459     goto no_channels;
1460
1461   if (stream == -1 || channels->len <= stream) {
1462     sinkpad = NULL;
1463   } else {
1464     /* take channel from selected stream */
1465     sinkpad = g_ptr_array_index (channels, stream);
1466   }
1467
1468   if (sinkpad)
1469     gst_object_ref (sinkpad);
1470   GST_PLAY_BIN_UNLOCK (playbin);
1471
1472   if (sinkpad) {
1473     GstObject *selector;
1474
1475     if ((selector = gst_pad_get_parent (sinkpad))) {
1476       /* activate the selected pad */
1477       g_object_set (selector, "active-pad", sinkpad, NULL);
1478       gst_object_unref (selector);
1479     }
1480     gst_object_unref (sinkpad);
1481   }
1482   return TRUE;
1483
1484 no_channels:
1485   {
1486     GST_PLAY_BIN_UNLOCK (playbin);
1487     return FALSE;
1488   }
1489 }
1490
1491 static gboolean
1492 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1493 {
1494   GstSourceGroup *group;
1495   GPtrArray *channels;
1496   GstPad *sinkpad;
1497
1498   GST_PLAY_BIN_LOCK (playbin);
1499   group = get_group (playbin);
1500   if (!(channels = group->audio_channels))
1501     goto no_channels;
1502
1503   if (stream == -1 || channels->len <= stream) {
1504     sinkpad = NULL;
1505   } else {
1506     /* take channel from selected stream */
1507     sinkpad = g_ptr_array_index (channels, stream);
1508   }
1509
1510   if (sinkpad)
1511     gst_object_ref (sinkpad);
1512   GST_PLAY_BIN_UNLOCK (playbin);
1513
1514   if (sinkpad) {
1515     GstObject *selector;
1516
1517     if ((selector = gst_pad_get_parent (sinkpad))) {
1518       /* activate the selected pad */
1519       g_object_set (selector, "active-pad", sinkpad, NULL);
1520       gst_object_unref (selector);
1521     }
1522     gst_object_unref (sinkpad);
1523   }
1524   return TRUE;
1525
1526 no_channels:
1527   {
1528     GST_PLAY_BIN_UNLOCK (playbin);
1529     return FALSE;
1530   }
1531 }
1532
1533 static void
1534 _suburidecodebin_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
1535 {
1536   GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
1537 }
1538
1539 static void
1540 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1541 {
1542   GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1543   GstPad *sinkpad;
1544
1545   if (it && gst_iterator_next (it, (gpointer) & sinkpad) == GST_ITERATOR_OK
1546       && sinkpad) {
1547     GstEvent *event;
1548
1549     event =
1550         gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1551         GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1552     if (!gst_pad_send_event (sinkpad, event)) {
1553       event =
1554           gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1555           GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1556       if (!gst_pad_send_event (sinkpad, event))
1557         GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1558     }
1559
1560     gst_object_unref (sinkpad);
1561   }
1562
1563   if (it)
1564     gst_iterator_free (it);
1565 }
1566
1567 static void
1568 gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
1569     gboolean block)
1570 {
1571   GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1572   gboolean done = FALSE;
1573
1574   GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1575
1576   if (!it)
1577     return;
1578   while (!done) {
1579     GstPad *sinkpad;
1580
1581     switch (gst_iterator_next (it, (gpointer) & sinkpad)) {
1582       case GST_ITERATOR_OK:
1583         gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
1584             NULL);
1585         gst_object_unref (sinkpad);
1586         break;
1587       case GST_ITERATOR_DONE:
1588         done = TRUE;
1589         break;
1590       case GST_ITERATOR_RESYNC:
1591         gst_iterator_resync (it);
1592         break;
1593       case GST_ITERATOR_ERROR:
1594         done = TRUE;
1595         break;
1596     }
1597   }
1598   gst_iterator_free (it);
1599 }
1600
1601 static gboolean
1602 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1603 {
1604   GstSourceGroup *group;
1605   GPtrArray *channels;
1606   GstPad *sinkpad;
1607
1608   GST_PLAY_BIN_LOCK (playbin);
1609   group = get_group (playbin);
1610   if (!(channels = group->text_channels))
1611     goto no_channels;
1612
1613   if (stream == -1 || channels->len <= stream) {
1614     sinkpad = NULL;
1615   } else {
1616     /* take channel from selected stream */
1617     sinkpad = g_ptr_array_index (channels, stream);
1618   }
1619
1620   if (sinkpad)
1621     gst_object_ref (sinkpad);
1622   GST_PLAY_BIN_UNLOCK (playbin);
1623
1624   if (sinkpad) {
1625     GstObject *selector;
1626
1627     if ((selector = gst_pad_get_parent (sinkpad))) {
1628       GstPad *old_sinkpad;
1629
1630       g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1631
1632       if (old_sinkpad != sinkpad) {
1633         gboolean need_unblock, need_block, need_seek;
1634         GstPad *src, *peer = NULL, *oldpeer = NULL;
1635         GstElement *parent_element = NULL, *old_parent_element = NULL;
1636
1637         /* Now check if we need to seek the suburidecodebin to the beginning
1638          * or if we need to block all suburidecodebin sinkpads or if we need
1639          * to unblock all suburidecodebin sinkpads
1640          */
1641         if (sinkpad)
1642           peer = gst_pad_get_peer (sinkpad);
1643         if (old_sinkpad)
1644           oldpeer = gst_pad_get_peer (old_sinkpad);
1645
1646         if (peer)
1647           parent_element = gst_pad_get_parent_element (peer);
1648         if (oldpeer)
1649           old_parent_element = gst_pad_get_parent_element (oldpeer);
1650
1651         need_block = (old_parent_element == group->suburidecodebin
1652             && parent_element != old_parent_element);
1653         need_unblock = (parent_element == group->suburidecodebin
1654             && parent_element != old_parent_element);
1655         need_seek = (parent_element == group->suburidecodebin);
1656
1657         if (peer)
1658           gst_object_unref (peer);
1659         if (oldpeer)
1660           gst_object_unref (oldpeer);
1661         if (parent_element)
1662           gst_object_unref (parent_element);
1663         if (old_parent_element)
1664           gst_object_unref (old_parent_element);
1665
1666         /* Block all suburidecodebin sinkpads */
1667         if (need_block)
1668           gst_play_bin_suburidecodebin_block (group->suburidecodebin, TRUE);
1669
1670         /* activate the selected pad */
1671         g_object_set (selector, "active-pad", sinkpad, NULL);
1672
1673         src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1674         peer = gst_pad_get_peer (src);
1675         if (peer) {
1676           GstStructure *s;
1677           GstEvent *event;
1678           /* Flush the subtitle renderer to remove any
1679            * currently displayed subtitles. This event will
1680            * never travel outside subtitleoverlay!
1681            */
1682           s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1683           event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1684           gst_pad_send_event (peer, event);
1685           gst_object_unref (peer);
1686         }
1687         gst_object_unref (src);
1688
1689         /* Unblock pads if necessary */
1690         if (need_unblock)
1691           gst_play_bin_suburidecodebin_block (group->suburidecodebin, FALSE);
1692
1693         /* seek to the beginning */
1694         if (need_seek)
1695           gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1696       }
1697       gst_object_unref (selector);
1698
1699       if (old_sinkpad)
1700         gst_object_unref (old_sinkpad);
1701     }
1702     gst_object_unref (sinkpad);
1703   }
1704   return TRUE;
1705
1706 no_channels:
1707   {
1708     GST_PLAY_BIN_UNLOCK (playbin);
1709     return FALSE;
1710   }
1711 }
1712
1713 static void
1714 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1715     const gchar * dbg, GstElement * sink)
1716 {
1717   GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1718
1719   GST_PLAY_BIN_LOCK (playbin);
1720   if (*elem != sink) {
1721     GstElement *old;
1722
1723     old = *elem;
1724     if (sink)
1725       gst_object_ref_sink (sink);
1726
1727     *elem = sink;
1728     if (old)
1729       gst_object_unref (old);
1730   }
1731   GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1732   GST_PLAY_BIN_UNLOCK (playbin);
1733 }
1734
1735 static void
1736 gst_play_bin_set_property (GObject * object, guint prop_id,
1737     const GValue * value, GParamSpec * pspec)
1738 {
1739   GstPlayBin *playbin;
1740
1741   playbin = GST_PLAY_BIN (object);
1742
1743   switch (prop_id) {
1744     case PROP_URI:
1745       gst_play_bin_set_uri (playbin, g_value_get_string (value));
1746       break;
1747     case PROP_SUBURI:
1748       gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1749       break;
1750     case PROP_FLAGS:
1751       gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1752       break;
1753     case PROP_CURRENT_VIDEO:
1754       gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1755       break;
1756     case PROP_CURRENT_AUDIO:
1757       gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1758       break;
1759     case PROP_CURRENT_TEXT:
1760       gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1761       break;
1762     case PROP_SUBTITLE_ENCODING:
1763       gst_play_sink_set_subtitle_encoding (playbin->playsink,
1764           g_value_get_string (value));
1765       break;
1766     case PROP_VIDEO_SINK:
1767       gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1768           g_value_get_object (value));
1769       break;
1770     case PROP_AUDIO_SINK:
1771       gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1772           g_value_get_object (value));
1773       break;
1774     case PROP_VIS_PLUGIN:
1775       gst_play_sink_set_vis_plugin (playbin->playsink,
1776           g_value_get_object (value));
1777       break;
1778     case PROP_TEXT_SINK:
1779       gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1780           g_value_get_object (value));
1781       break;
1782     case PROP_VOLUME:
1783       gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1784       break;
1785     case PROP_MUTE:
1786       gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1787       break;
1788     case PROP_FONT_DESC:
1789       gst_play_sink_set_font_desc (playbin->playsink,
1790           g_value_get_string (value));
1791       break;
1792     case PROP_CONNECTION_SPEED:
1793       GST_PLAY_BIN_LOCK (playbin);
1794       playbin->connection_speed = g_value_get_uint (value) * 1000;
1795       GST_PLAY_BIN_UNLOCK (playbin);
1796       break;
1797     case PROP_BUFFER_SIZE:
1798       playbin->buffer_size = g_value_get_int (value);
1799       break;
1800     case PROP_BUFFER_DURATION:
1801       playbin->buffer_duration = g_value_get_int64 (value);
1802       break;
1803     default:
1804       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1805       break;
1806   }
1807 }
1808
1809 static GstElement *
1810 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1811     const gchar * dbg, GstPlaySinkType type)
1812 {
1813   GstElement *sink;
1814
1815   sink = gst_play_sink_get_sink (playbin->playsink, type);
1816
1817   GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1818       GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1819       dbg, sink, dbg, *elem);
1820
1821   if (sink == NULL) {
1822     GST_PLAY_BIN_LOCK (playbin);
1823     if ((sink = *elem))
1824       gst_object_ref (sink);
1825     GST_PLAY_BIN_UNLOCK (playbin);
1826   }
1827
1828   return sink;
1829 }
1830
1831 static void
1832 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1833     GParamSpec * pspec)
1834 {
1835   GstPlayBin *playbin;
1836
1837   playbin = GST_PLAY_BIN (object);
1838
1839   switch (prop_id) {
1840     case PROP_URI:
1841     {
1842       GstSourceGroup *group;
1843
1844       GST_PLAY_BIN_LOCK (playbin);
1845       group = get_group (playbin);
1846       g_value_set_string (value, group->uri);
1847       GST_PLAY_BIN_UNLOCK (playbin);
1848       break;
1849     }
1850     case PROP_SUBURI:
1851     {
1852       GstSourceGroup *group;
1853
1854       GST_PLAY_BIN_LOCK (playbin);
1855       group = get_group (playbin);
1856       g_value_set_string (value, group->suburi);
1857       GST_PLAY_BIN_UNLOCK (playbin);
1858       break;
1859     }
1860     case PROP_SOURCE:
1861     {
1862       GST_OBJECT_LOCK (playbin);
1863       g_value_set_object (value, playbin->source);
1864       GST_OBJECT_UNLOCK (playbin);
1865       break;
1866     }
1867     case PROP_FLAGS:
1868       g_value_set_flags (value, gst_play_bin_get_flags (playbin));
1869       break;
1870     case PROP_N_VIDEO:
1871     {
1872       GstSourceGroup *group;
1873       gint n_video;
1874
1875       GST_PLAY_BIN_LOCK (playbin);
1876       group = get_group (playbin);
1877       n_video = (group->video_channels ? group->video_channels->len : 0);
1878       g_value_set_int (value, n_video);
1879       GST_PLAY_BIN_UNLOCK (playbin);
1880       break;
1881     }
1882     case PROP_CURRENT_VIDEO:
1883       GST_PLAY_BIN_LOCK (playbin);
1884       g_value_set_int (value, playbin->current_video);
1885       GST_PLAY_BIN_UNLOCK (playbin);
1886       break;
1887     case PROP_N_AUDIO:
1888     {
1889       GstSourceGroup *group;
1890       gint n_audio;
1891
1892       GST_PLAY_BIN_LOCK (playbin);
1893       group = get_group (playbin);
1894       n_audio = (group->audio_channels ? group->audio_channels->len : 0);
1895       g_value_set_int (value, n_audio);
1896       GST_PLAY_BIN_UNLOCK (playbin);
1897       break;
1898     }
1899     case PROP_CURRENT_AUDIO:
1900       GST_PLAY_BIN_LOCK (playbin);
1901       g_value_set_int (value, playbin->current_audio);
1902       GST_PLAY_BIN_UNLOCK (playbin);
1903       break;
1904     case PROP_N_TEXT:
1905     {
1906       GstSourceGroup *group;
1907       gint n_text;
1908
1909       GST_PLAY_BIN_LOCK (playbin);
1910       group = get_group (playbin);
1911       n_text = (group->text_channels ? group->text_channels->len : 0);
1912       g_value_set_int (value, n_text);
1913       GST_PLAY_BIN_UNLOCK (playbin);
1914       break;
1915     }
1916     case PROP_CURRENT_TEXT:
1917       GST_PLAY_BIN_LOCK (playbin);
1918       g_value_set_int (value, playbin->current_text);
1919       GST_PLAY_BIN_UNLOCK (playbin);
1920       break;
1921     case PROP_SUBTITLE_ENCODING:
1922       GST_PLAY_BIN_LOCK (playbin);
1923       g_value_take_string (value,
1924           gst_play_sink_get_subtitle_encoding (playbin->playsink));
1925       GST_PLAY_BIN_UNLOCK (playbin);
1926       break;
1927     case PROP_VIDEO_SINK:
1928       g_value_take_object (value,
1929           gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
1930               "video", GST_PLAY_SINK_TYPE_VIDEO));
1931       break;
1932     case PROP_AUDIO_SINK:
1933       g_value_take_object (value,
1934           gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
1935               "audio", GST_PLAY_SINK_TYPE_AUDIO));
1936       break;
1937     case PROP_VIS_PLUGIN:
1938       g_value_take_object (value,
1939           gst_play_sink_get_vis_plugin (playbin->playsink));
1940       break;
1941     case PROP_TEXT_SINK:
1942       g_value_take_object (value,
1943           gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
1944               "text", GST_PLAY_SINK_TYPE_TEXT));
1945       break;
1946     case PROP_VOLUME:
1947       g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
1948       break;
1949     case PROP_MUTE:
1950       g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
1951       break;
1952     case PROP_FRAME:
1953       gst_value_take_buffer (value, gst_play_bin_convert_frame (playbin, NULL));
1954       break;
1955     case PROP_FONT_DESC:
1956       g_value_take_string (value,
1957           gst_play_sink_get_font_desc (playbin->playsink));
1958       break;
1959     case PROP_CONNECTION_SPEED:
1960       GST_PLAY_BIN_LOCK (playbin);
1961       g_value_set_uint (value, playbin->connection_speed / 1000);
1962       GST_PLAY_BIN_UNLOCK (playbin);
1963       break;
1964     case PROP_BUFFER_SIZE:
1965       GST_OBJECT_LOCK (playbin);
1966       g_value_set_int (value, playbin->buffer_size);
1967       GST_OBJECT_UNLOCK (playbin);
1968       break;
1969     case PROP_BUFFER_DURATION:
1970       GST_OBJECT_LOCK (playbin);
1971       g_value_set_int64 (value, playbin->buffer_duration);
1972       GST_OBJECT_UNLOCK (playbin);
1973       break;
1974     default:
1975       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1976       break;
1977   }
1978 }
1979
1980 static void
1981 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
1982     gboolean valid, GstQuery * query)
1983 {
1984   GstFormat fmt;
1985   gint64 duration;
1986   gint i;
1987
1988   GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
1989   gst_query_parse_duration (query, &fmt, &duration);
1990
1991   for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
1992     if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
1993       playbin->duration[i].valid = valid;
1994       playbin->duration[i].format = fmt;
1995       playbin->duration[i].duration = valid ? duration : -1;
1996       break;
1997     }
1998   }
1999 }
2000
2001 static void
2002 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2003 {
2004   const GstFormat formats[] =
2005       { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2006   gboolean ret;
2007   GstQuery *query;
2008   gint i;
2009
2010   GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2011   for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2012     query = gst_query_new_duration (formats[i]);
2013     ret =
2014         GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2015         query);
2016     gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2017     gst_query_unref (query);
2018   }
2019 }
2020
2021 static gboolean
2022 gst_play_bin_query (GstElement * element, GstQuery * query)
2023 {
2024   GstPlayBin *playbin = GST_PLAY_BIN (element);
2025   gboolean ret;
2026
2027   /* During a group switch we shouldn't allow duration queries
2028    * because it's not clear if the old or new group's duration
2029    * is returned and if the sinks are already playing new data
2030    * or old data. See bug #585969
2031    *
2032    * While we're at it, also don't do any other queries during
2033    * a group switch or any other event that causes topology changes
2034    * by taking the playbin lock in any case.
2035    */
2036   GST_PLAY_BIN_LOCK (playbin);
2037
2038   if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2039     GstSourceGroup *group = playbin->curr_group;
2040     gboolean pending;
2041
2042     GST_SOURCE_GROUP_LOCK (group);
2043     if (group->stream_changed_pending_lock) {
2044       g_mutex_lock (group->stream_changed_pending_lock);
2045       pending = group->pending || group->stream_changed_pending;
2046       g_mutex_unlock (group->stream_changed_pending_lock);
2047     } else {
2048       pending = group->pending;
2049     }
2050     if (pending) {
2051       GstFormat fmt;
2052       gint i;
2053
2054       ret = FALSE;
2055       gst_query_parse_duration (query, &fmt, NULL);
2056       for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2057         if (fmt == playbin->duration[i].format) {
2058           ret = playbin->duration[i].valid;
2059           gst_query_set_duration (query, fmt,
2060               (ret ? playbin->duration[i].duration : -1));
2061           break;
2062         }
2063       }
2064       GST_DEBUG_OBJECT (playbin,
2065           "Taking cached duration because of pending group switch: %d", ret);
2066       GST_SOURCE_GROUP_UNLOCK (group);
2067       GST_PLAY_BIN_UNLOCK (playbin);
2068       return ret;
2069     }
2070     GST_SOURCE_GROUP_UNLOCK (group);
2071   }
2072
2073   ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2074
2075   if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2076     gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2077   GST_PLAY_BIN_UNLOCK (playbin);
2078
2079   return ret;
2080 }
2081
2082 /* mime types we are not handling on purpose right now, don't post a
2083  * missing-plugin message for these */
2084 static const gchar *blacklisted_mimes[] = {
2085   NULL
2086 };
2087
2088 static void
2089 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2090 {
2091   GstPlayBin *playbin = GST_PLAY_BIN (bin);
2092   GstSourceGroup *group;
2093
2094   if (gst_is_missing_plugin_message (msg)) {
2095     gchar *detail;
2096     guint i;
2097
2098     detail = gst_missing_plugin_message_get_installer_detail (msg);
2099     for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2100       if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2101         GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2102         gst_message_unref (msg);
2103         g_free (detail);
2104         return;
2105       }
2106     }
2107     g_free (detail);
2108   } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2109     const GstStructure *s = gst_message_get_structure (msg);
2110
2111     /* Drop all stream-changed messages except the last one */
2112     if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2113       guint32 seqnum = gst_message_get_seqnum (msg);
2114       GList *l, *l_prev;
2115
2116       group = playbin->curr_group;
2117       g_mutex_lock (group->stream_changed_pending_lock);
2118       for (l = group->stream_changed_pending; l;) {
2119         guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2120
2121         if (l_seqnum == seqnum) {
2122           l_prev = l;
2123           l = l->next;
2124           group->stream_changed_pending =
2125               g_list_delete_link (group->stream_changed_pending, l_prev);
2126           if (group->stream_changed_pending) {
2127             gst_message_unref (msg);
2128             msg = NULL;
2129             break;
2130           }
2131         } else {
2132           l = l->next;
2133         }
2134       }
2135       g_mutex_unlock (group->stream_changed_pending_lock);
2136     }
2137   } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2138       GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2139     GstObject *src = GST_OBJECT_CAST (msg->src);
2140
2141     /* Ignore async state changes from the uridecodebin children,
2142      * see bug #602000. */
2143     group = playbin->curr_group;
2144     if (src && (group = playbin->curr_group) &&
2145         ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2146             || (group->suburidecodebin
2147                 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2148       GST_DEBUG_OBJECT (playbin,
2149           "Ignoring async state change of uridecodebin: %s",
2150           GST_OBJECT_NAME (src));
2151       gst_message_unref (msg);
2152       msg = NULL;
2153     }
2154   } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2155     /* If we get an error of the subtitle uridecodebin transform
2156      * them into warnings and disable the subtitles */
2157     group = playbin->curr_group;
2158     if (group && group->suburidecodebin) {
2159       if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2160                   (group->suburidecodebin)))) {
2161         GError *err;
2162         gchar *debug = NULL;
2163         GstMessage *new_msg;
2164         GstIterator *it;
2165         gboolean done = FALSE;
2166
2167         gst_message_parse_error (msg, &err, &debug);
2168         new_msg = gst_message_new_warning (msg->src, err, debug);
2169
2170         gst_message_unref (msg);
2171         g_error_free (err);
2172         g_free (debug);
2173         msg = new_msg;
2174
2175         REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2176         REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2177         REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2178         REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2179
2180         it = gst_element_iterate_src_pads (group->suburidecodebin);
2181         while (it && !done) {
2182           GstPad *p = NULL;
2183           GstIteratorResult res;
2184
2185           res = gst_iterator_next (it, (gpointer) & p);
2186
2187           switch (res) {
2188             case GST_ITERATOR_DONE:
2189               done = TRUE;
2190               break;
2191             case GST_ITERATOR_OK:
2192               pad_removed_cb (NULL, p, group);
2193               gst_object_unref (p);
2194               break;
2195
2196             case GST_ITERATOR_RESYNC:
2197               gst_iterator_resync (it);
2198               break;
2199             case GST_ITERATOR_ERROR:
2200               done = TRUE;
2201               break;
2202           }
2203         }
2204         if (it)
2205           gst_iterator_free (it);
2206
2207         gst_object_ref (group->suburidecodebin);
2208         gst_bin_remove (bin, group->suburidecodebin);
2209         gst_element_set_locked_state (group->suburidecodebin, FALSE);
2210
2211         if (group->sub_pending) {
2212           group->sub_pending = FALSE;
2213           no_more_pads_cb (NULL, group);
2214         }
2215       }
2216     }
2217   }
2218
2219   if (msg)
2220     GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2221 }
2222
2223 static void
2224 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2225     GstPlayBin * playbin)
2226 {
2227   gchar *property;
2228   GstSourceGroup *group;
2229   GstSourceSelect *select = NULL;
2230   int i;
2231
2232   GST_PLAY_BIN_LOCK (playbin);
2233   group = get_group (playbin);
2234
2235   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2236     if (selector == G_OBJECT (group->selector[i].selector)) {
2237       select = &group->selector[i];
2238     }
2239   }
2240
2241   /* We got a pad-change after our group got switched out; no need to notify */
2242   if (!select) {
2243     GST_PLAY_BIN_UNLOCK (playbin);
2244     return;
2245   }
2246
2247   switch (select->type) {
2248     case GST_PLAY_SINK_TYPE_VIDEO:
2249     case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2250       property = "current-video";
2251       playbin->current_video = get_current_stream_number (playbin,
2252           group->video_channels);
2253       break;
2254     case GST_PLAY_SINK_TYPE_AUDIO:
2255     case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2256       property = "current-audio";
2257       playbin->current_audio = get_current_stream_number (playbin,
2258           group->audio_channels);
2259       break;
2260     case GST_PLAY_SINK_TYPE_TEXT:
2261       property = "current-text";
2262       playbin->current_text = get_current_stream_number (playbin,
2263           group->text_channels);
2264       break;
2265     default:
2266       property = NULL;
2267   }
2268   GST_PLAY_BIN_UNLOCK (playbin);
2269
2270   if (property)
2271     g_object_notify (G_OBJECT (playbin), property);
2272 }
2273
2274 static void
2275 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
2276 {
2277   /* no nothing */
2278   GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
2279 }
2280
2281 /* helper function to lookup stuff in lists */
2282 static gboolean
2283 array_has_value (const gchar * values[], const gchar * value)
2284 {
2285   gint i;
2286
2287   for (i = 0; values[i]; i++) {
2288     if (g_str_has_prefix (value, values[i]))
2289       return TRUE;
2290   }
2291   return FALSE;
2292 }
2293
2294 typedef struct
2295 {
2296   GstPlayBin *playbin;
2297   gint stream_id;
2298   GstPlaySinkType type;
2299 } NotifyTagsData;
2300
2301 static void
2302 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2303 {
2304   NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2305   gint signal;
2306
2307   GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2308       " with stream id %d and type %d have changed",
2309       object, ntdata->stream_id, ntdata->type);
2310
2311   switch (ntdata->type) {
2312     case GST_PLAY_SINK_TYPE_VIDEO:
2313     case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2314       signal = SIGNAL_VIDEO_TAGS_CHANGED;
2315       break;
2316     case GST_PLAY_SINK_TYPE_AUDIO:
2317     case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2318       signal = SIGNAL_AUDIO_TAGS_CHANGED;
2319       break;
2320     case GST_PLAY_SINK_TYPE_TEXT:
2321       signal = SIGNAL_TEXT_TAGS_CHANGED;
2322       break;
2323     default:
2324       signal = -1;
2325       break;
2326   }
2327
2328   if (signal >= 0)
2329     g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2330         ntdata->stream_id);
2331 }
2332
2333 typedef struct
2334 {
2335   GstPlayBin *playbin;
2336   GstSourceGroup *group;
2337   GstPlaySinkType type;
2338 } PlaySinkEventProbeData;
2339
2340 static gboolean
2341 _playsink_src_event_probe_cb (GstPad * pad, GstEvent * event,
2342     PlaySinkEventProbeData * data)
2343 {
2344   if (GST_EVENT_TYPE (event) == GST_EVENT_QOS) {
2345     GstEvent *new_event;
2346     GstStructure *s;
2347     gdouble proportion;
2348     GstClockTimeDiff diff;
2349     GstClockTime group_start_accum =
2350         data->group->selector[data->type].group_start_accum;
2351     GstClockTime timestamp;
2352
2353     s = (GstStructure *) gst_event_get_structure (event);
2354     if (gst_structure_has_field (s, "playbin2-adjusted-event"))
2355       return TRUE;
2356
2357     /* If we have no group start accumulator yet, this is
2358      * a QOS event for the previous group or this stream
2359      * has a non-time segment.
2360      */
2361     if (!GST_CLOCK_TIME_IS_VALID (group_start_accum))
2362       return FALSE;
2363
2364     /* If the group start accumulator is 0, this is the first
2365      * group and we don't need to do everything below
2366      */
2367     if (group_start_accum == 0)
2368       return TRUE;
2369
2370     gst_event_parse_qos (event, &proportion, &diff, &timestamp);
2371
2372     /* If the running time timestamp is smaller than the accumulator,
2373      * the event is for a buffer from the previous group
2374      */
2375     if (timestamp >= group_start_accum)
2376       timestamp -= group_start_accum;
2377     else
2378       return FALSE;
2379
2380     /* That case is invalid for QoS events, also it means that
2381      * we have switched the group but receive QoS events of
2382      * the previous group.
2383      */
2384     if (diff < 0 && -diff > timestamp)
2385       return FALSE;
2386
2387     new_event = gst_event_new_qos (proportion, diff, timestamp);
2388     s = (GstStructure *) gst_event_get_structure (new_event);
2389     gst_structure_set (s, "playbin2-adjusted-event", G_TYPE_BOOLEAN, TRUE,
2390         NULL);
2391     gst_pad_send_event (pad, new_event);
2392
2393     return FALSE;
2394   }
2395
2396   return TRUE;
2397 }
2398
2399 static gboolean
2400 _playsink_sink_event_probe_cb (GstPad * pad, GstEvent * event,
2401     PlaySinkEventProbeData * data)
2402 {
2403   guint index;
2404
2405   if (data->type == GST_PLAY_SINK_TYPE_VIDEO
2406       || data->type == GST_PLAY_SINK_TYPE_VIDEO_RAW)
2407     index = 0;
2408   else if (data->type == GST_PLAY_SINK_TYPE_AUDIO
2409       || data->type == GST_PLAY_SINK_TYPE_AUDIO_RAW)
2410     index = 1;
2411   else if (data->type == GST_PLAY_SINK_TYPE_TEXT)
2412     index = 2;
2413   else
2414     g_assert_not_reached ();
2415
2416   if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
2417     GstPlayBin *playbin = data->playbin;
2418     GstSegment *segment;
2419     gboolean update;
2420     GstFormat format;
2421     gdouble rate, applied_rate;
2422     gint64 start, stop, pos;
2423
2424     segment = &playbin->segments[index];
2425
2426     gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
2427         &format, &start, &stop, &pos);
2428     if (segment->format != format)
2429       gst_segment_init (segment, format);
2430     gst_segment_set_newsegment_full (segment, update, rate, applied_rate,
2431         format, start, stop, pos);
2432
2433     if (format != GST_FORMAT_TIME)
2434       data->group->selector[data->type].group_start_accum = GST_CLOCK_TIME_NONE;
2435     else if (!GST_CLOCK_TIME_IS_VALID (data->group->selector[data->type].
2436             group_start_accum))
2437       data->group->selector[data->type].group_start_accum = segment->accum;
2438   } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2439     gst_segment_init (&data->playbin->segments[index], GST_FORMAT_UNDEFINED);
2440   }
2441
2442   return TRUE;
2443 }
2444
2445 /* this function is called when a new pad is added to decodebin. We check the
2446  * type of the pad and add it to the selector element of the group. 
2447  */
2448 static void
2449 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2450 {
2451   GstPlayBin *playbin;
2452   GstCaps *caps;
2453   const GstStructure *s;
2454   const gchar *name;
2455   GstPad *sinkpad;
2456   GstPadLinkReturn res;
2457   GstSourceSelect *select = NULL;
2458   gint i;
2459   gboolean changed = FALSE;
2460
2461   playbin = group->playbin;
2462
2463   caps = gst_pad_get_caps_reffed (pad);
2464   s = gst_caps_get_structure (caps, 0);
2465   name = gst_structure_get_name (s);
2466
2467   GST_DEBUG_OBJECT (playbin,
2468       "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2469       GST_DEBUG_PAD_NAME (pad), caps, group);
2470
2471   /* major type of the pad, this determines the selector to use */
2472   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2473     if (array_has_value (group->selector[i].media_list, name)) {
2474       select = &group->selector[i];
2475       break;
2476     } else if (group->selector[i].get_media_caps) {
2477       GstCaps *media_caps = group->selector[i].get_media_caps ();
2478
2479       if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2480         select = &group->selector[i];
2481         gst_caps_unref (media_caps);
2482         break;
2483       }
2484       gst_caps_unref (media_caps);
2485     }
2486   }
2487   /* no selector found for the media type, don't bother linking it to a
2488    * selector. This will leave the pad unlinked and thus ignored. */
2489   if (select == NULL)
2490     goto unknown_type;
2491
2492   GST_SOURCE_GROUP_LOCK (group);
2493   if (select->selector == NULL && playbin->have_selector) {
2494     /* no selector, create one */
2495     GST_DEBUG_OBJECT (playbin, "creating new selector");
2496     select->selector = g_object_new (GST_TYPE_INPUT_SELECTOR, NULL);
2497     /* the above can't fail, but we keep the error handling around for when
2498      * the selector plugin has moved to -base or -good and we stop using an
2499      * internal copy of input-selector */
2500     if (select->selector == NULL) {
2501       /* post the missing selector message only once */
2502       playbin->have_selector = FALSE;
2503       gst_element_post_message (GST_ELEMENT_CAST (playbin),
2504           gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2505               "input-selector"));
2506       GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2507           (_("Missing element '%s' - check your GStreamer installation."),
2508               "input-selector"), (NULL));
2509     } else {
2510       g_signal_connect (select->selector, "notify::active-pad",
2511           G_CALLBACK (selector_active_pad_changed), playbin);
2512
2513       GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2514       gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2515       gst_element_set_state (select->selector, GST_STATE_PAUSED);
2516     }
2517   }
2518
2519   if (select->srcpad == NULL) {
2520     PlaySinkEventProbeData *data = g_new (PlaySinkEventProbeData, 1);
2521
2522     if (select->selector) {
2523       /* save source pad of the selector */
2524       select->srcpad = gst_element_get_static_pad (select->selector, "src");
2525     } else {
2526       /* no selector, use the pad as the source pad then */
2527       select->srcpad = gst_object_ref (pad);
2528     }
2529
2530     /* Install an event probe */
2531     data->playbin = playbin;
2532     data->group = group;
2533     data->type = select->type;
2534     select->src_event_probe_id =
2535         gst_pad_add_event_probe_full (select->srcpad,
2536         G_CALLBACK (_playsink_src_event_probe_cb), data,
2537         (GDestroyNotify) g_free);
2538
2539     select->group_start_accum = -1;
2540
2541     /* block the selector srcpad. It's possible that multiple decodebins start
2542      * pushing data into the selectors before we have a chance to collect all
2543      * streams and connect the sinks, resulting in not-linked errors. After we
2544      * configured the sinks we will unblock them all. */
2545     GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2546     gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
2547   }
2548
2549   /* get sinkpad for the new stream */
2550   if (select->selector) {
2551     if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2552       gulong notify_tags_handler = 0;
2553       NotifyTagsData *ntdata;
2554
2555       GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2556           GST_DEBUG_PAD_NAME (sinkpad));
2557
2558       /* store the selector for the pad */
2559       g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2560
2561       /* connect to the notify::tags signal for our
2562        * own *-tags-changed signals
2563        */
2564       ntdata = g_new0 (NotifyTagsData, 1);
2565       ntdata->playbin = playbin;
2566       ntdata->stream_id = select->channels->len;
2567       ntdata->type = select->type;
2568
2569       notify_tags_handler =
2570           g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2571           G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2572           (GConnectFlags) 0);
2573       g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2574           (gpointer) notify_tags_handler);
2575
2576       /* store the pad in the array */
2577       GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2578       g_ptr_array_add (select->channels, sinkpad);
2579
2580       res = gst_pad_link (pad, sinkpad);
2581       if (GST_PAD_LINK_FAILED (res))
2582         goto link_failed;
2583
2584       /* store selector pad so we can release it */
2585       g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2586
2587       changed = TRUE;
2588       GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2589           GST_DEBUG_PAD_NAME (pad), select->selector);
2590     }
2591   } else {
2592     /* no selector, don't configure anything, we'll link the new pad directly to
2593      * the sink. */
2594     changed = FALSE;
2595     sinkpad = NULL;
2596   }
2597   GST_SOURCE_GROUP_UNLOCK (group);
2598
2599   if (changed) {
2600     int signal;
2601     gboolean always_ok = (decodebin == group->suburidecodebin);
2602
2603     switch (select->type) {
2604       case GST_PLAY_SINK_TYPE_VIDEO:
2605       case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2606         /* we want to return NOT_LINKED for unselected pads but only for pads
2607          * from the normal uridecodebin. This makes sure that subtitle streams
2608          * are not raced past audio/video from decodebin2's multiqueue.
2609          * For pads from suburidecodebin OK should always be returned, otherwise
2610          * it will most likely stop. */
2611         g_object_set (sinkpad, "always-ok", always_ok, NULL);
2612         signal = SIGNAL_VIDEO_CHANGED;
2613         break;
2614       case GST_PLAY_SINK_TYPE_AUDIO:
2615       case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2616         g_object_set (sinkpad, "always-ok", always_ok, NULL);
2617         signal = SIGNAL_AUDIO_CHANGED;
2618         break;
2619       case GST_PLAY_SINK_TYPE_TEXT:
2620         g_object_set (sinkpad, "always-ok", always_ok, NULL);
2621         signal = SIGNAL_TEXT_CHANGED;
2622         break;
2623       default:
2624         signal = -1;
2625     }
2626
2627     if (signal >= 0)
2628       g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2629   }
2630
2631 done:
2632   gst_caps_unref (caps);
2633   return;
2634
2635   /* ERRORS */
2636 unknown_type:
2637   {
2638     GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2639         name, GST_DEBUG_PAD_NAME (pad));
2640     goto done;
2641   }
2642 link_failed:
2643   {
2644     GST_ERROR_OBJECT (playbin,
2645         "failed to link pad %s:%s to selector, reason %d",
2646         GST_DEBUG_PAD_NAME (pad), res);
2647     GST_SOURCE_GROUP_UNLOCK (group);
2648     goto done;
2649   }
2650 }
2651
2652 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2653  * the selector. This will make the selector select a new pad. */
2654 static void
2655 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2656 {
2657   GstPlayBin *playbin;
2658   GstPad *peer;
2659   GstElement *selector;
2660   GstSourceSelect *select;
2661
2662   playbin = group->playbin;
2663
2664   GST_DEBUG_OBJECT (playbin,
2665       "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2666
2667   GST_SOURCE_GROUP_LOCK (group);
2668   /* get the selector sinkpad */
2669   if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2670     goto not_linked;
2671
2672   if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2673     gulong notify_tags_handler;
2674
2675     notify_tags_handler =
2676         (gulong) g_object_get_data (G_OBJECT (peer),
2677         "playbin2.notify_tags_handler");
2678     if (notify_tags_handler != 0)
2679       g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2680     g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2681
2682     /* remove the pad from the array */
2683     g_ptr_array_remove (select->channels, peer);
2684     GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2685   }
2686
2687   /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2688   gst_pad_unlink (pad, peer);
2689
2690   /* get selector, this can be NULL when the element is removing the pads
2691    * because it's being disposed. */
2692   selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2693   if (!selector) {
2694     gst_object_unref (peer);
2695     goto no_selector;
2696   }
2697
2698   /* release the pad to the selector, this will make the selector choose a new
2699    * pad. */
2700   gst_element_release_request_pad (selector, peer);
2701   gst_object_unref (peer);
2702
2703   gst_object_unref (selector);
2704   GST_SOURCE_GROUP_UNLOCK (group);
2705
2706   return;
2707
2708   /* ERRORS */
2709 not_linked:
2710   {
2711     GST_DEBUG_OBJECT (playbin, "pad not linked");
2712     GST_SOURCE_GROUP_UNLOCK (group);
2713     return;
2714   }
2715 no_selector:
2716   {
2717     GST_DEBUG_OBJECT (playbin, "selector not found");
2718     GST_SOURCE_GROUP_UNLOCK (group);
2719     return;
2720   }
2721 }
2722
2723 /* we get called when all pads are available and we must connect the sinks to
2724  * them.
2725  * The main purpose of the code is to see if we have video/audio and subtitles
2726  * and pick the right pipelines to display them.
2727  *
2728  * The selectors installed on the group tell us about the presence of
2729  * audio/video and subtitle streams. This allows us to see if we need
2730  * visualisation, video or/and audio.
2731  */
2732 static void
2733 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2734 {
2735   GstPlayBin *playbin;
2736   GstPadLinkReturn res;
2737   gint i;
2738   gboolean configure;
2739
2740   playbin = group->playbin;
2741
2742   GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2743
2744   GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2745
2746   GST_SOURCE_GROUP_LOCK (group);
2747   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2748     GstSourceSelect *select = &group->selector[i];
2749
2750     /* check if the specific media type was detected and thus has a selector
2751      * created for it. If there is the media type, get a sinkpad from the sink
2752      * and link it. We only do this if we have not yet requested the sinkpad
2753      * before. */
2754     if (select->srcpad && select->sinkpad == NULL) {
2755       PlaySinkEventProbeData *data = g_new (PlaySinkEventProbeData, 1);
2756
2757       GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2758       select->sinkpad =
2759           gst_play_sink_request_pad (playbin->playsink, select->type);
2760
2761       /* Install an event probe */
2762       data->playbin = playbin;
2763       data->group = group;
2764       data->type = select->type;
2765       select->sink_event_probe_id =
2766           gst_pad_add_event_probe_full (select->sinkpad,
2767           G_CALLBACK (_playsink_sink_event_probe_cb), data,
2768           (GDestroyNotify) g_free);
2769
2770       res = gst_pad_link (select->srcpad, select->sinkpad);
2771       GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2772           select->media_list[0], res);
2773       if (res != GST_PAD_LINK_OK) {
2774         GST_ELEMENT_ERROR (playbin, CORE, PAD,
2775             ("Internal playbin error."),
2776             ("Failed to link selector to sink. Error %d", res));
2777       }
2778     }
2779   }
2780   GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2781       group->pending - 1);
2782
2783   if (group->pending > 0)
2784     group->pending--;
2785
2786   if (group->suburidecodebin == decodebin)
2787     group->sub_pending = FALSE;
2788
2789   if (group->pending == 0) {
2790     /* we are the last group to complete, we will configure the output and then
2791      * signal the other waiters. */
2792     GST_LOG_OBJECT (playbin, "last group complete");
2793     configure = TRUE;
2794   } else {
2795     GST_LOG_OBJECT (playbin, "have more pending groups");
2796     configure = FALSE;
2797   }
2798   GST_SOURCE_GROUP_UNLOCK (group);
2799
2800   if (configure) {
2801     /* if we have custom sinks, configure them now */
2802     GST_SOURCE_GROUP_LOCK (group);
2803     if (group->audio_sink) {
2804       GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2805           group->audio_sink);
2806       gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2807           group->audio_sink);
2808     } else {
2809       GST_INFO_OBJECT (playbin, "setting default audio sink %" GST_PTR_FORMAT,
2810           playbin->audio_sink);
2811       gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2812           playbin->audio_sink);
2813     }
2814     if (group->video_sink) {
2815       GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2816           group->video_sink);
2817       gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2818           group->video_sink);
2819     } else {
2820       GST_INFO_OBJECT (playbin, "setting default video sink %" GST_PTR_FORMAT,
2821           playbin->video_sink);
2822       gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2823           playbin->video_sink);
2824     }
2825     gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2826         playbin->text_sink);
2827     GST_SOURCE_GROUP_UNLOCK (group);
2828
2829     GST_LOG_OBJECT (playbin, "reconfigure sink");
2830     /* we configure the modes if we were the last decodebin to complete. */
2831     gst_play_sink_reconfigure (playbin->playsink);
2832
2833     /* signal the other decodebins that they can continue now. */
2834     GST_SOURCE_GROUP_LOCK (group);
2835     /* unblock all selectors */
2836     for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2837       GstSourceSelect *select = &group->selector[i];
2838
2839       /* Wait for stream-changed messages on all selectors except
2840        * the text selector because of the sparse nature of text streams.
2841        */
2842       if (select->sinkpad && select->type != GST_PLAY_SINK_TYPE_TEXT) {
2843         GstStructure *s;
2844         GstMessage *msg;
2845         GstEvent *event;
2846         guint32 seqnum;
2847
2848         s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2849             group->uri, NULL);
2850         if (group->suburi)
2851           gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2852         msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2853         seqnum = gst_message_get_seqnum (msg);
2854         event = gst_event_new_sink_message (msg);
2855         g_mutex_lock (group->stream_changed_pending_lock);
2856         group->stream_changed_pending =
2857             g_list_prepend (group->stream_changed_pending,
2858             GUINT_TO_POINTER (seqnum));
2859         g_mutex_unlock (group->stream_changed_pending_lock);
2860         gst_pad_send_event (select->sinkpad, event);
2861         gst_message_unref (msg);
2862       }
2863
2864       if (select->srcpad) {
2865         GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2866             select->srcpad);
2867         gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2868             NULL);
2869       }
2870     }
2871     GST_SOURCE_GROUP_UNLOCK (group);
2872   }
2873
2874   GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2875
2876   return;
2877
2878 shutdown:
2879   {
2880     GST_DEBUG ("ignoring, we are shutting down");
2881     /* Request a flushing pad from playsink that we then link to the selector.
2882      * Then we unblock the selectors so that they stop with a WRONG_STATE
2883      * instead of a NOT_LINKED error.
2884      */
2885     GST_SOURCE_GROUP_LOCK (group);
2886     for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2887       GstSourceSelect *select = &group->selector[i];
2888
2889       if (select->srcpad) {
2890         if (select->sinkpad == NULL) {
2891           GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2892           select->sinkpad =
2893               gst_play_sink_request_pad (playbin->playsink,
2894               GST_PLAY_SINK_TYPE_FLUSHING);
2895           res = gst_pad_link (select->srcpad, select->sinkpad);
2896           GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2897         }
2898         GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2899             select->srcpad);
2900         gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2901             NULL);
2902       }
2903     }
2904     GST_SOURCE_GROUP_UNLOCK (group);
2905     return;
2906   }
2907 }
2908
2909 static void
2910 drained_cb (GstElement * decodebin, GstSourceGroup * group)
2911 {
2912   GstPlayBin *playbin;
2913
2914   playbin = group->playbin;
2915
2916   GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
2917
2918   /* after this call, we should have a next group to activate or we EOS */
2919   g_signal_emit (G_OBJECT (playbin),
2920       gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
2921
2922   /* now activate the next group. If the app did not set a uri, this will
2923    * fail and we can do EOS */
2924   setup_next_source (playbin, GST_STATE_PAUSED);
2925 }
2926
2927 /* Called when we must provide a list of factories to plug to @pad with @caps.
2928  * We first check if we have a sink that can handle the format and if we do, we
2929  * return NULL, to expose the pad. If we have no sink (or the sink does not
2930  * work), we return the list of elements that can connect. */
2931 static GValueArray *
2932 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
2933     GstCaps * caps, GstSourceGroup * group)
2934 {
2935   GstPlayBin *playbin;
2936   GValueArray *result;
2937
2938   playbin = group->playbin;
2939
2940   GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
2941       group, GST_DEBUG_PAD_NAME (pad), caps);
2942
2943   /* filter out the elements based on the caps. */
2944   g_mutex_lock (playbin->elements_lock);
2945   gst_play_bin_update_elements_list (playbin);
2946   result = gst_factory_list_filter (playbin->elements, caps);
2947   g_mutex_unlock (playbin->elements_lock);
2948
2949   GST_DEBUG_OBJECT (playbin, "found factories %p", result);
2950   GST_FACTORY_LIST_DEBUG (result);
2951
2952   return result;
2953 }
2954
2955 /* autoplug-continue decides, if a pad has raw caps that can be exposed
2956  * directly or if further decoding is necessary. We use this to expose
2957  * supported subtitles directly */
2958 static gboolean
2959 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
2960     GstSourceGroup * group)
2961 {
2962   GstCaps *subcaps;
2963   gboolean ret = FALSE;
2964
2965   subcaps = gst_subtitle_overlay_create_factory_caps ();
2966   ret = !gst_caps_can_intersect (subcaps, caps);
2967   gst_caps_unref (subcaps);
2968
2969   GST_DEBUG_OBJECT (group->playbin,
2970       "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
2971       group, GST_DEBUG_PAD_NAME (pad), caps, ret);
2972
2973   return ret;
2974 }
2975
2976 /* We are asked to select an element. See if the next element to check
2977  * is a sink. If this is the case, we see if the sink works by setting it to
2978  * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
2979  * expose the raw pad so that we can setup the mixers. */
2980 static GstAutoplugSelectResult
2981 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
2982     GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
2983 {
2984   GstPlayBin *playbin;
2985   GstElement *element;
2986   const gchar *klass;
2987   GstPlaySinkType type;
2988   GstElement **sinkp;
2989
2990   playbin = group->playbin;
2991
2992   GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
2993       group, GST_DEBUG_PAD_NAME (pad), caps);
2994
2995   GST_DEBUG_OBJECT (playbin, "checking factory %s",
2996       GST_PLUGIN_FEATURE_NAME (factory));
2997
2998   /* if it's not a sink, we just make decodebin try it */
2999   if (!gst_factory_list_is_type (factory, GST_FACTORY_LIST_SINK))
3000     return GST_AUTOPLUG_SELECT_TRY;
3001
3002   /* it's a sink, see if an instance of it actually works */
3003   GST_DEBUG_OBJECT (playbin, "we found a sink");
3004
3005   klass = gst_element_factory_get_klass (factory);
3006
3007   /* figure out the klass */
3008   if (strstr (klass, "Audio")) {
3009     GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3010     type = GST_PLAY_SINK_TYPE_AUDIO;
3011     sinkp = &group->audio_sink;
3012   } else if (strstr (klass, "Video")) {
3013     GST_DEBUG_OBJECT (playbin, "we found a video sink");
3014     type = GST_PLAY_SINK_TYPE_VIDEO;
3015     sinkp = &group->video_sink;
3016   } else {
3017     /* unknown klass, skip this element */
3018     GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3019     return GST_AUTOPLUG_SELECT_SKIP;
3020   }
3021
3022   /* if we are asked to do visualisations and it's an audio sink, skip the
3023    * element. We can only do visualisations with raw sinks */
3024   if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3025     if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3026       GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3027       return GST_AUTOPLUG_SELECT_SKIP;
3028     }
3029   }
3030
3031   /* now see if we already have a sink element */
3032   GST_SOURCE_GROUP_LOCK (group);
3033   if (*sinkp) {
3034     GST_DEBUG_OBJECT (playbin, "we already have a pending sink, expose pad");
3035     /* for now, just assume that we can link the pad to this same sink. FIXME,
3036      * check that we can link this new pad to this sink as well. */
3037     GST_SOURCE_GROUP_UNLOCK (group);
3038     return GST_AUTOPLUG_SELECT_EXPOSE;
3039   }
3040   GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3041   GST_SOURCE_GROUP_UNLOCK (group);
3042
3043   if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3044     GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3045         gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3046     return GST_AUTOPLUG_SELECT_SKIP;
3047   }
3048
3049   /* ... activate it ... We do this before adding it to the bin so that we
3050    * don't accidentally make it post error messages that will stop
3051    * everything. */
3052   if ((gst_element_set_state (element,
3053               GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
3054     GST_WARNING_OBJECT (playbin, "Couldn't set %s to READY",
3055         GST_ELEMENT_NAME (element));
3056     gst_object_unref (element);
3057     return GST_AUTOPLUG_SELECT_SKIP;
3058   }
3059
3060   /* remember the sink in the group now, the element is floating, we take
3061    * ownership now */
3062   GST_SOURCE_GROUP_LOCK (group);
3063   if (*sinkp == NULL) {
3064     /* store the sink in the group, we will configure it later when we
3065      * reconfigure the sink */
3066     GST_DEBUG_OBJECT (playbin, "remember sink");
3067     gst_object_ref_sink (element);
3068     *sinkp = element;
3069   } else {
3070     /* some other thread configured a sink while we were testing the sink, set
3071      * the sink back to NULL and assume we can use the other sink */
3072     GST_DEBUG_OBJECT (playbin, "another sink was found, expose pad");
3073     gst_element_set_state (element, GST_STATE_NULL);
3074     gst_object_unref (element);
3075   }
3076   GST_SOURCE_GROUP_UNLOCK (group);
3077
3078   /* tell decodebin to expose the pad because we are going to use this
3079    * sink */
3080   GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3081
3082   return GST_AUTOPLUG_SELECT_EXPOSE;
3083 }
3084
3085 static void
3086 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3087     GstSourceGroup * group)
3088 {
3089   GstPlayBin *playbin;
3090   GstElement *source;
3091
3092   playbin = group->playbin;
3093
3094   g_object_get (group->uridecodebin, "source", &source, NULL);
3095
3096   GST_OBJECT_LOCK (playbin);
3097   if (playbin->source)
3098     gst_object_unref (playbin->source);
3099   playbin->source = source;
3100   GST_OBJECT_UNLOCK (playbin);
3101
3102   g_object_notify (G_OBJECT (playbin), "source");
3103 }
3104
3105 /* must be called with the group lock */
3106 static gboolean
3107 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3108     gboolean locked)
3109 {
3110   GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3111
3112   if (group->uridecodebin)
3113     gst_element_set_locked_state (group->uridecodebin, locked);
3114   if (group->suburidecodebin)
3115     gst_element_set_locked_state (group->suburidecodebin, locked);
3116
3117   return TRUE;
3118 }
3119
3120 /* must be called with PLAY_BIN_LOCK */
3121 static gboolean
3122 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3123 {
3124   GstElement *uridecodebin;
3125   GstElement *suburidecodebin = NULL;
3126   GstPlayFlags flags;
3127
3128   g_return_val_if_fail (group->valid, FALSE);
3129   g_return_val_if_fail (!group->active, FALSE);
3130
3131   GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3132
3133   GST_SOURCE_GROUP_LOCK (group);
3134
3135   g_list_free (group->stream_changed_pending);
3136   group->stream_changed_pending = NULL;
3137   if (!group->stream_changed_pending_lock)
3138     group->stream_changed_pending_lock = g_mutex_new ();
3139
3140   if (group->uridecodebin) {
3141     GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3142     uridecodebin = group->uridecodebin;
3143     gst_element_set_state (uridecodebin, GST_STATE_READY);
3144     gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3145   } else {
3146     GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3147     uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3148     if (!uridecodebin)
3149       goto no_decodebin;
3150     gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3151     group->uridecodebin = gst_object_ref (uridecodebin);
3152   }
3153
3154   /* configure connection speed */
3155   g_object_set (uridecodebin, "connection-speed",
3156       playbin->connection_speed / 1000, NULL);
3157
3158   flags = gst_play_sink_get_flags (playbin->playsink);
3159
3160   /* configure download buffering */
3161   if (flags & GST_PLAY_FLAG_DOWNLOAD)
3162     g_object_set (uridecodebin, "download", TRUE, NULL);
3163   else
3164     g_object_set (uridecodebin, "download", FALSE, NULL);
3165
3166   /* configure uri */
3167   g_object_set (uridecodebin, "uri", group->uri, NULL);
3168   /* configure buffering of demuxed/parsed data */
3169   if (flags & GST_PLAY_FLAG_BUFFERING)
3170     g_object_set (uridecodebin, "use-buffering", TRUE, NULL);
3171   else
3172     g_object_set (uridecodebin, "use-buffering", FALSE, NULL);
3173   /* configure buffering parameters */
3174   g_object_set (uridecodebin, "buffer-duration", playbin->buffer_duration,
3175       NULL);
3176   g_object_set (uridecodebin, "buffer-size", playbin->buffer_size, NULL);
3177
3178   /* connect pads and other things */
3179   group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3180       G_CALLBACK (pad_added_cb), group);
3181   group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3182       G_CALLBACK (pad_removed_cb), group);
3183   group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3184       G_CALLBACK (no_more_pads_cb), group);
3185   group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3186       G_CALLBACK (notify_source_cb), group);
3187
3188   /* we have 1 pending no-more-pads */
3189   group->pending = 1;
3190
3191   /* is called when the uridecodebin is out of data and we can switch to the
3192    * next uri */
3193   group->drained_id =
3194       g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3195       group);
3196
3197   /* will be called when a new media type is found. We return a list of decoders
3198    * including sinks for decodebin to try */
3199   group->autoplug_factories_id =
3200       g_signal_connect (uridecodebin, "autoplug-factories",
3201       G_CALLBACK (autoplug_factories_cb), group);
3202   group->autoplug_select_id =
3203       g_signal_connect (uridecodebin, "autoplug-select",
3204       G_CALLBACK (autoplug_select_cb), group);
3205   group->autoplug_continue_id =
3206       g_signal_connect (uridecodebin, "autoplug-continue",
3207       G_CALLBACK (autoplug_continue_cb), group);
3208
3209   if (group->suburi) {
3210     /* subtitles */
3211     if (group->suburidecodebin) {
3212       GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3213       suburidecodebin = group->suburidecodebin;
3214       gst_element_set_state (suburidecodebin, GST_STATE_READY);
3215       gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3216     } else {
3217       GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3218       suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3219       if (!suburidecodebin)
3220         goto no_decodebin;
3221
3222       gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3223       group->suburidecodebin = gst_object_ref (suburidecodebin);
3224     }
3225
3226     /* configure connection speed */
3227     g_object_set (suburidecodebin, "connection-speed",
3228         playbin->connection_speed, NULL);
3229     /* configure uri */
3230     g_object_set (suburidecodebin, "uri", group->suburi, NULL);
3231
3232     /* connect pads and other things */
3233     group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3234         G_CALLBACK (pad_added_cb), group);
3235     group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3236         "pad-removed", G_CALLBACK (pad_removed_cb), group);
3237     group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3238         "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3239
3240     group->sub_autoplug_continue_id =
3241         g_signal_connect (suburidecodebin, "autoplug-continue",
3242         G_CALLBACK (autoplug_continue_cb), group);
3243
3244     /* we have 2 pending no-more-pads */
3245     group->pending = 2;
3246     group->sub_pending = TRUE;
3247   } else {
3248     group->sub_pending = FALSE;
3249   }
3250
3251   /* release the group lock before setting the state of the decodebins, they
3252    * might fire signals in this thread that we need to handle with the
3253    * group_lock taken. */
3254   GST_SOURCE_GROUP_UNLOCK (group);
3255
3256   if (suburidecodebin) {
3257     if (gst_element_set_state (suburidecodebin,
3258             target) == GST_STATE_CHANGE_FAILURE) {
3259       GST_DEBUG_OBJECT (playbin,
3260           "failed state change of subtitle uridecodebin");
3261       GST_SOURCE_GROUP_LOCK (group);
3262
3263       REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3264       REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3265       REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3266       REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3267       /* Might already be removed because of an error message */
3268       if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3269         gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3270       if (group->sub_pending) {
3271         group->pending--;
3272         group->sub_pending = FALSE;
3273       }
3274       gst_element_set_state (suburidecodebin, GST_STATE_READY);
3275       GST_SOURCE_GROUP_UNLOCK (group);
3276     }
3277   }
3278   if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3279     goto uridecodebin_failure;
3280
3281   GST_SOURCE_GROUP_LOCK (group);
3282   /* alow state changes of the playbin2 affect the group elements now */
3283   group_set_locked_state_unlocked (playbin, group, FALSE);
3284   group->active = TRUE;
3285   GST_SOURCE_GROUP_UNLOCK (group);
3286
3287   return TRUE;
3288
3289   /* ERRORS */
3290 no_decodebin:
3291   {
3292     GstMessage *msg;
3293
3294     GST_SOURCE_GROUP_UNLOCK (group);
3295     msg =
3296         gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3297         "uridecodebin");
3298     gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3299
3300     GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3301         (_("Could not create \"uridecodebin\" element.")), (NULL));
3302     return FALSE;
3303   }
3304 uridecodebin_failure:
3305   {
3306     GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3307     return FALSE;
3308   }
3309 }
3310
3311 /* unlink a group of uridecodebins from the sink.
3312  * must be called with PLAY_BIN_LOCK */
3313 static gboolean
3314 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3315 {
3316   gint i;
3317
3318   g_return_val_if_fail (group->valid, FALSE);
3319   g_return_val_if_fail (group->active, FALSE);
3320
3321   GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3322
3323   GST_SOURCE_GROUP_LOCK (group);
3324   group->active = FALSE;
3325   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
3326     GstSourceSelect *select = &group->selector[i];
3327
3328     GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3329
3330     if (select->srcpad) {
3331       if (select->sinkpad) {
3332         GST_LOG_OBJECT (playbin, "unlinking from sink");
3333         gst_pad_unlink (select->srcpad, select->sinkpad);
3334
3335         if (select->sink_event_probe_id)
3336           gst_pad_remove_event_probe (select->sinkpad,
3337               select->sink_event_probe_id);
3338         select->sink_event_probe_id = 0;
3339
3340         /* release back */
3341         GST_LOG_OBJECT (playbin, "release sink pad");
3342         gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3343         select->sinkpad = NULL;
3344       }
3345
3346       if (select->src_event_probe_id)
3347         gst_pad_remove_event_probe (select->srcpad, select->src_event_probe_id);
3348       select->src_event_probe_id = 0;
3349
3350       gst_object_unref (select->srcpad);
3351       select->srcpad = NULL;
3352     }
3353
3354     if (select->selector) {
3355       gint n;
3356
3357       /* release and unref requests pad from the selector */
3358       for (n = 0; n < select->channels->len; n++) {
3359         GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3360
3361         gst_element_release_request_pad (select->selector, sinkpad);
3362         gst_object_unref (sinkpad);
3363       }
3364       g_ptr_array_set_size (select->channels, 0);
3365
3366       gst_element_set_state (select->selector, GST_STATE_NULL);
3367       gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3368       select->selector = NULL;
3369     }
3370   }
3371   /* delete any custom sinks we might have */
3372   if (group->audio_sink)
3373     gst_object_unref (group->audio_sink);
3374   group->audio_sink = NULL;
3375   if (group->video_sink)
3376     gst_object_unref (group->video_sink);
3377   group->video_sink = NULL;
3378
3379   if (group->uridecodebin) {
3380     REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3381     REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3382     REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3383     REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3384     REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3385     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3386     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3387     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3388     gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3389   }
3390
3391   if (group->suburidecodebin) {
3392     REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3393     REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3394     REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3395     REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3396
3397     /* Might already be removed because of errors */
3398     if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3399       gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3400   }
3401
3402   GST_SOURCE_GROUP_UNLOCK (group);
3403
3404   return TRUE;
3405 }
3406
3407 /* setup the next group to play, this assumes the next_group is valid and
3408  * configured. It swaps out the current_group and activates the valid 
3409  * next_group. */
3410 static gboolean
3411 setup_next_source (GstPlayBin * playbin, GstState target)
3412 {
3413   GstSourceGroup *new_group, *old_group;
3414
3415   GST_DEBUG_OBJECT (playbin, "setup sources");
3416
3417   /* see if there is a next group */
3418   GST_PLAY_BIN_LOCK (playbin);
3419   new_group = playbin->next_group;
3420   if (!new_group || !new_group->valid)
3421     goto no_next_group;
3422
3423   /* first unlink the current source, if any */
3424   old_group = playbin->curr_group;
3425   if (old_group && old_group->valid) {
3426     gst_play_bin_update_cached_duration (playbin);
3427     /* unlink our pads with the sink */
3428     deactivate_group (playbin, old_group);
3429     old_group->valid = FALSE;
3430   }
3431
3432   /* swap old and new */
3433   playbin->curr_group = new_group;
3434   playbin->next_group = old_group;
3435
3436   /* activate the new group */
3437   if (!activate_group (playbin, new_group, target))
3438     goto activate_failed;
3439
3440   GST_PLAY_BIN_UNLOCK (playbin);
3441
3442   return TRUE;
3443
3444   /* ERRORS */
3445 no_next_group:
3446   {
3447     GST_DEBUG_OBJECT (playbin, "no next group");
3448     if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3449       GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3450     GST_PLAY_BIN_UNLOCK (playbin);
3451     return FALSE;
3452   }
3453 activate_failed:
3454   {
3455     GST_DEBUG_OBJECT (playbin, "activate failed");
3456     GST_PLAY_BIN_UNLOCK (playbin);
3457     return FALSE;
3458   }
3459 }
3460
3461 /* The group that is currently playing is copied again to the
3462  * next_group so that it will start playing the next time.
3463  */
3464 static gboolean
3465 save_current_group (GstPlayBin * playbin)
3466 {
3467   GstSourceGroup *curr_group;
3468
3469   GST_DEBUG_OBJECT (playbin, "save current group");
3470
3471   /* see if there is a current group */
3472   GST_PLAY_BIN_LOCK (playbin);
3473   curr_group = playbin->curr_group;
3474   if (curr_group && curr_group->valid) {
3475     /* unlink our pads with the sink */
3476     deactivate_group (playbin, curr_group);
3477   }
3478   /* swap old and new */
3479   playbin->curr_group = playbin->next_group;
3480   playbin->next_group = curr_group;
3481   GST_PLAY_BIN_UNLOCK (playbin);
3482
3483   return TRUE;
3484 }
3485
3486 /* clear the locked state from all groups. This function is called before a
3487  * state change to NULL is performed on them. */
3488 static gboolean
3489 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3490 {
3491   GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3492       locked);
3493
3494   GST_PLAY_BIN_LOCK (playbin);
3495   GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3496   group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3497   GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3498   GST_SOURCE_GROUP_LOCK (playbin->next_group);
3499   group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3500   GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3501   GST_PLAY_BIN_UNLOCK (playbin);
3502
3503   return TRUE;
3504 }
3505
3506 static GstStateChangeReturn
3507 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3508 {
3509   GstStateChangeReturn ret;
3510   GstPlayBin *playbin;
3511
3512   playbin = GST_PLAY_BIN (element);
3513
3514   switch (transition) {
3515     case GST_STATE_CHANGE_NULL_TO_READY:
3516       g_mutex_lock (playbin->elements_lock);
3517       gst_play_bin_update_elements_list (playbin);
3518       g_mutex_unlock (playbin->elements_lock);
3519       memset (&playbin->duration, 0, sizeof (playbin->duration));
3520       break;
3521     case GST_STATE_CHANGE_READY_TO_PAUSED:{
3522       guint i;
3523
3524       GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3525       memset (&playbin->duration, 0, sizeof (playbin->duration));
3526       g_atomic_int_set (&playbin->shutdown, 0);
3527
3528       for (i = 0; i < 3; i++)
3529         gst_segment_init (&playbin->segments[i], GST_FORMAT_UNDEFINED);
3530
3531       if (!setup_next_source (playbin, GST_STATE_READY))
3532         goto source_failed;
3533       break;
3534     }
3535     case GST_STATE_CHANGE_PAUSED_TO_READY:
3536       /* FIXME unlock our waiting groups */
3537       GST_LOG_OBJECT (playbin, "setting shutdown flag");
3538       g_atomic_int_set (&playbin->shutdown, 1);
3539       memset (&playbin->duration, 0, sizeof (playbin->duration));
3540
3541       /* wait for all callbacks to end by taking the lock.
3542        * No dynamic (critical) new callbacks will
3543        * be able to happen as we set the shutdown flag. */
3544       GST_PLAY_BIN_DYN_LOCK (playbin);
3545       GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3546       GST_PLAY_BIN_DYN_UNLOCK (playbin);
3547       break;
3548     case GST_STATE_CHANGE_READY_TO_NULL:{
3549       guint i;
3550
3551       memset (&playbin->duration, 0, sizeof (playbin->duration));
3552
3553       /* unlock so that all groups go to NULL */
3554       groups_set_locked_state (playbin, FALSE);
3555
3556       for (i = 0; i < 2; i++) {
3557         if (playbin->groups[i].uridecodebin) {
3558           gst_element_set_state (playbin->groups[i].uridecodebin,
3559               GST_STATE_NULL);
3560           gst_object_unref (playbin->groups[i].uridecodebin);
3561           playbin->groups[i].uridecodebin = NULL;
3562         }
3563         if (playbin->groups[i].suburidecodebin) {
3564           gst_element_set_state (playbin->groups[i].suburidecodebin,
3565               GST_STATE_NULL);
3566           gst_object_unref (playbin->groups[i].suburidecodebin);
3567           playbin->groups[i].suburidecodebin = NULL;
3568         }
3569       }
3570       break;
3571     }
3572     default:
3573       break;
3574   }
3575
3576   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3577   if (ret == GST_STATE_CHANGE_FAILURE) {
3578     if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
3579       GstSourceGroup *curr_group;
3580
3581       curr_group = playbin->curr_group;
3582       if (curr_group && curr_group->valid) {
3583         /* unlink our pads with the sink */
3584         deactivate_group (playbin, curr_group);
3585       }
3586
3587       /* Swap current and next group back */
3588       playbin->curr_group = playbin->next_group;
3589       playbin->next_group = curr_group;
3590     }
3591     return ret;
3592   }
3593
3594   switch (transition) {
3595     case GST_STATE_CHANGE_READY_TO_PAUSED:
3596       break;
3597     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3598       /* FIXME Release audio device when we implement that */
3599       break;
3600     case GST_STATE_CHANGE_PAUSED_TO_READY:
3601       save_current_group (playbin);
3602       break;
3603     case GST_STATE_CHANGE_READY_TO_NULL:
3604       /* make sure the groups don't perform a state change anymore until we
3605        * enable them again */
3606       groups_set_locked_state (playbin, TRUE);
3607       break;
3608     default:
3609       break;
3610   }
3611
3612   return ret;
3613
3614   /* ERRORS */
3615 source_failed:
3616   {
3617     return GST_STATE_CHANGE_FAILURE;
3618   }
3619 }
3620
3621 gboolean
3622 gst_play_bin2_plugin_init (GstPlugin * plugin)
3623 {
3624   GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
3625
3626   g_type_class_ref (gst_input_selector_get_type ());
3627   g_type_class_ref (gst_selector_pad_get_type ());
3628
3629   return gst_element_register (plugin, "playbin2", GST_RANK_NONE,
3630       GST_TYPE_PLAY_BIN);
3631 }