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