playbin2: Send flush events when changing subtitle tracks and use new input-selector...
[platform/upstream/gstreamer.git] / gst / playback / gstplaybin2.c
1 /* GStreamer
2  * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
3  * Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * SECTION:element-playbin
23  *
24  * Playbin provides a stand-alone everything-in-one abstraction for an
25  * audio and/or video player.
26  *
27  * Playbin can handle both audio and video files and features
28  * <itemizedlist>
29  * <listitem>
30  * automatic file type recognition and based on that automatic
31  * selection and usage of the right audio/video/subtitle demuxers/decoders
32  * </listitem>
33  * <listitem>
34  * visualisations for audio files
35  * </listitem>
36  * <listitem>
37  * subtitle support for video files. Subtitles can be store in external
38  * files.
39  * </listitem>
40  * <listitem>
41  * stream selection between different video/audio/subtitles streams
42  * </listitem>
43  * <listitem>
44  * meta info (tag) extraction
45  * </listitem>
46  * <listitem>
47  * easy access to the last video sample
48  * </listitem>
49  * <listitem>
50  * buffering when playing streams over a network
51  * </listitem>
52  * <listitem>
53  * volume control with mute option
54  * </listitem>
55  * </itemizedlist>
56  *
57  * <refsect2>
58  * <title>Usage</title>
59  * <para>
60  * A playbin element can be created just like any other element using
61  * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin:uri
62  * property. This must be an absolute URI, relative file paths are not allowed.
63  * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
64  *
65  * Playbin is a #GstPipeline. It will notify the application of everything
66  * that's happening (errors, end of stream, tags found, state changes, etc.)
67  * by posting messages on its #GstBus. The application needs to watch the
68  * bus.
69  *
70  * Playback can be initiated by setting the element to PLAYING state using
71  * gst_element_set_state(). Note that the state change will take place in
72  * the background in a separate thread, when the function returns playback
73  * is probably not happening yet and any errors might not have occured yet.
74  * Applications using playbin should ideally be written to deal with things
75  * completely asynchroneous.
76  *
77  * When playback has finished (an EOS message has been received on the bus)
78  * or an error has occured (an ERROR message has been received on the bus) or
79  * the user wants to play a different track, playbin should be set back to
80  * READY or NULL state, then the #GstPlayBin:uri property should be set to the
81  * new location and then playbin be set to PLAYING state again.
82  *
83  * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
84  * on the playbin element. Again, the seek will not be executed
85  * instantaneously, but will be done in a background thread. When the seek
86  * call returns the seek will most likely still be in process. An application
87  * may wait for the seek to finish (or fail) using gst_element_get_state() with
88  * -1 as the timeout, but this will block the user interface and is not
89  * recommended at all.
90  *
91  * Applications may query the current position and duration of the stream
92  * via gst_element_query_position() and gst_element_query_duration() and
93  * setting the format passed to GST_FORMAT_TIME. If the query was successful,
94  * the duration or position will have been returned in units of nanoseconds.
95  * </para>
96  * </refsect2>
97  * <refsect2>
98  * <title>Advanced Usage: specifying the audio and video sink</title>
99  * <para>
100  * By default, if no audio sink or video sink has been specified via the
101  * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property, playbin will use the autoaudiosink
102  * and autovideosink elements to find the first-best available output method.
103  * This should work in most cases, but is not always desirable. Often either
104  * the user or application might want to specify more explicitly what to use
105  * for audio and video output.
106  *
107  * If the application wants more control over how audio or video should be
108  * output, it may create the audio/video sink elements itself (for example
109  * using gst_element_factory_make()) and provide them to playbin using the
110  * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property.
111  *
112  * GNOME-based applications, for example, will usually want to create
113  * gconfaudiosink and gconfvideosink elements and make playbin use those,
114  * so that output happens to whatever the user has configured in the GNOME
115  * Multimedia System Selector configuration dialog.
116  *
117  * The sink elements do not necessarily need to be ready-made sinks. It is
118  * possible to create container elements that look like a sink to playbin,
119  * but in reality contain a number of custom elements linked together. This
120  * can be achieved by creating a #GstBin and putting elements in there and
121  * linking them, and then creating a sink #GstGhostPad for the bin and pointing
122  * it to the sink pad of the first element within the bin. This can be used
123  * for a number of purposes, for example to force output to a particular
124  * format or to modify or observe the data before it is output.
125  *
126  * It is also possible to 'suppress' audio and/or video output by using
127  * 'fakesink' elements (or capture it from there using the fakesink element's
128  * "handoff" signal, which, nota bene, is fired from the streaming thread!).
129  * </para>
130  * </refsect2>
131  * <refsect2>
132  * <title>Retrieving Tags and Other Meta Data</title>
133  * <para>
134  * Most of the common meta data (artist, title, etc.) can be retrieved by
135  * watching for TAG messages on the pipeline's bus (see above).
136  *
137  * Other more specific meta information like width/height/framerate of video
138  * streams or samplerate/number of channels of audio streams can be obtained
139  * from the negotiated caps on the sink pads of the sinks.
140  * </para>
141  * </refsect2>
142  * <refsect2>
143  * <title>Buffering</title>
144  * Playbin handles buffering automatically for the most part, but applications
145  * need to handle parts of the buffering process as well. Whenever playbin is
146  * buffering, it will post BUFFERING messages on the bus with a percentage
147  * value that shows the progress of the buffering process. Applications need
148  * to set playbin to PLAYING or PAUSED state in response to these messages.
149  * They may also want to convey the buffering progress to the user in some
150  * way. Here is how to extract the percentage information from the message
151  * (requires GStreamer >= 0.10.11):
152  * |[
153  * switch (GST_MESSAGE_TYPE (msg)) {
154  *   case GST_MESSAGE_BUFFERING: {
155  *     gint percent = 0;
156  *     gst_message_parse_buffering (msg, &amp;percent);
157  *     g_print ("Buffering (%%u percent done)", percent);
158  *     break;
159  *   }
160  *   ...
161  * }
162  * ]|
163  * Note that applications should keep/set the pipeline in the PAUSED state when
164  * a BUFFERING message is received with a buffer percent value < 100 and set
165  * the pipeline back to PLAYING state when a BUFFERING message with a value
166  * of 100 percent is received (if PLAYING is the desired state, that is).
167  * </refsect2>
168  * <refsect2>
169  * <title>Embedding the video window in your application</title>
170  * By default, playbin (or rather the video sinks used) will create their own
171  * window. Applications will usually want to force output to a window of their
172  * own, however. This can be done using the #GstVideoOverlay interface, which most
173  * video sinks implement. See the documentation there for more details.
174  * </refsect2>
175  * <refsect2>
176  * <title>Specifying which CD/DVD device to use</title>
177  * The device to use for CDs/DVDs needs to be set on the source element
178  * playbin creates before it is opened. The most generic way of doing this
179  * is to connect to playbin's "source-setup" (or "notify::source") signal,
180  * which will be emitted by playbin2 when it has created the source element
181  * for a particular URI. In the signal callback you can check if the source
182  * element has a "device" property and set it appropriately. In some cases
183  * the device can also be set as part of the URI, but it depends on the
184  * elements involved if this will work or not. For example, for DVD menu
185  * playback, the following syntax might work (if the resindvd plugin is used):
186  * dvd://[/path/to/device]
187  * </refsect2>
188  * <refsect2>
189  * <title>Handling redirects</title>
190  * <para>
191  * Some elements may post 'redirect' messages on the bus to tell the
192  * application to open another location. These are element messages containing
193  * a structure named 'redirect' along with a 'new-location' field of string
194  * type. The new location may be a relative or an absolute URI. Examples
195  * for such redirects can be found in many quicktime movie trailers.
196  * </para>
197  * </refsect2>
198  * <refsect2>
199  * <title>Examples</title>
200  * |[
201  * gst-launch -v playbin2 uri=file:///path/to/somefile.avi
202  * ]| This will play back the given AVI video file, given that the video and
203  * audio decoders required to decode the content are installed. Since no
204  * special audio sink or video sink is supplied (not possible via gst-launch),
205  * playbin will try to find a suitable audio and video sink automatically
206  * using the autoaudiosink and autovideosink elements.
207  * |[
208  * gst-launch -v playbin2 uri=cdda://4
209  * ]| This will play back track 4 on an audio CD in your disc drive (assuming
210  * the drive is detected automatically by the plugin).
211  * |[
212  * gst-launch -v playbin2 uri=dvd://
213  * ]| This will play back the DVD in your disc drive (assuming
214  * the drive is detected automatically by the plugin).
215  * </refsect2>
216  */
217
218 /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
219  * with newer GLib versions (>= 2.31.0) */
220 #define GLIB_DISABLE_DEPRECATION_WARNINGS
221
222 #ifdef HAVE_CONFIG_H
223 #include "config.h"
224 #endif
225
226 #include <string.h>
227 #include <gst/gst.h>
228
229 #include <gst/gst-i18n-plugin.h>
230 #include <gst/pbutils/pbutils.h>
231 #include <gst/audio/streamvolume.h>
232 #include <gst/video/videooverlay.h>
233 #include <gst/video/navigation.h>
234 #include <gst/video/colorbalance.h>
235 #include "gstplay-enum.h"
236 #include "gstplayback.h"
237 #include "gstplaysink.h"
238 #include "gstsubtitleoverlay.h"
239 #include "gst/glib-compat-private.h"
240 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
241 #define GST_CAT_DEFAULT gst_play_bin_debug
242
243 #define GST_TYPE_PLAY_BIN               (gst_play_bin_get_type())
244 #define GST_PLAY_BIN(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
245 #define GST_PLAY_BIN_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
246 #define GST_IS_PLAY_BIN(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
247 #define GST_IS_PLAY_BIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
248
249 #define VOLUME_MAX_DOUBLE 10.0
250
251 typedef struct _GstPlayBin GstPlayBin;
252 typedef struct _GstPlayBinClass GstPlayBinClass;
253 typedef struct _GstSourceGroup GstSourceGroup;
254 typedef struct _GstSourceSelect GstSourceSelect;
255
256 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
257
258 /* has the info for a selector and provides the link to the sink */
259 struct _GstSourceSelect
260 {
261   const gchar *media_list[8];   /* the media types for the selector */
262   SourceSelectGetMediaCapsFunc get_media_caps;  /* more complex caps for the selector */
263   GstPlaySinkType type;         /* the sink pad type of the selector */
264
265   GstElement *selector;         /* the selector */
266   GPtrArray *channels;
267   GstPad *srcpad;               /* the source pad of the selector */
268   GstPad *sinkpad;              /* the sinkpad of the sink when the selector
269                                  * is linked
270                                  */
271   GstEvent *sinkpad_delayed_event;
272   gulong sinkpad_data_probe;
273   gulong block_id;
274 };
275
276 #define GST_SOURCE_GROUP_GET_LOCK(group) (&((GstSourceGroup*)(group))->lock)
277 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
278 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
279
280 enum
281 {
282   PLAYBIN_STREAM_AUDIO = 0,
283   PLAYBIN_STREAM_VIDEO,
284   PLAYBIN_STREAM_TEXT,
285   PLAYBIN_STREAM_LAST
286 };
287
288 /* a structure to hold the objects for decoding a uri and the subtitle uri
289  */
290 struct _GstSourceGroup
291 {
292   GstPlayBin *playbin;
293
294   GMutex lock;
295
296   gboolean valid;               /* the group has valid info to start playback */
297   gboolean active;              /* the group is active */
298
299   /* properties */
300   gchar *uri;
301   gchar *suburi;
302   GValueArray *streaminfo;
303   GstElement *source;
304
305   GPtrArray *video_channels;    /* links to selector pads */
306   GPtrArray *audio_channels;    /* links to selector pads */
307   GPtrArray *text_channels;     /* links to selector pads */
308
309   GstElement *audio_sink;       /* autoplugged audio and video sinks */
310   GstElement *video_sink;
311
312   /* uridecodebins for uri and subtitle uri */
313   GstElement *uridecodebin;
314   GstElement *suburidecodebin;
315   gint pending;
316   gboolean sub_pending;
317
318   gulong pad_added_id;
319   gulong pad_removed_id;
320   gulong no_more_pads_id;
321   gulong notify_source_id;
322   gulong drained_id;
323   gulong autoplug_factories_id;
324   gulong autoplug_select_id;
325   gulong autoplug_continue_id;
326
327   gulong sub_pad_added_id;
328   gulong sub_pad_removed_id;
329   gulong sub_no_more_pads_id;
330   gulong sub_autoplug_continue_id;
331
332   gulong block_id;
333
334   GMutex stream_changed_pending_lock;
335   GList *stream_changed_pending;
336
337   /* to prevent that suburidecodebin seek flushes disrupt playback */
338   GMutex suburi_flushes_to_drop_lock;
339   GSList *suburi_flushes_to_drop;
340
341   /* selectors for different streams */
342   GstSourceSelect selector[PLAYBIN_STREAM_LAST];
343 };
344
345 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
346 #define GST_PLAY_BIN_LOCK(bin) (g_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
347 #define GST_PLAY_BIN_UNLOCK(bin) (g_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
348
349 /* lock to protect dynamic callbacks, like no-more-pads */
350 #define GST_PLAY_BIN_DYN_LOCK(bin)    g_mutex_lock (&(bin)->dyn_lock)
351 #define GST_PLAY_BIN_DYN_UNLOCK(bin)  g_mutex_unlock (&(bin)->dyn_lock)
352
353 /* lock for shutdown */
354 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label)           \
355 G_STMT_START {                                          \
356   if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown)))   \
357     goto label;                                         \
358   GST_PLAY_BIN_DYN_LOCK (bin);                          \
359   if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
360     GST_PLAY_BIN_DYN_UNLOCK (bin);                      \
361     goto label;                                         \
362   }                                                     \
363 } G_STMT_END
364
365 /* unlock for shutdown */
366 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin)         \
367   GST_PLAY_BIN_DYN_UNLOCK (bin);                  \
368
369 /**
370  * GstPlayBin:
371  *
372  * playbin element structure
373  */
374 struct _GstPlayBin
375 {
376   GstPipeline parent;
377
378   GRecMutex lock;               /* to protect group switching */
379
380   /* the groups, we use a double buffer to switch between current and next */
381   GstSourceGroup groups[2];     /* array with group info */
382   GstSourceGroup *curr_group;   /* pointer to the currently playing group */
383   GstSourceGroup *next_group;   /* pointer to the next group */
384
385   /* properties */
386   guint64 connection_speed;     /* connection speed in bits/sec (0 = unknown) */
387   gint current_video;           /* the currently selected stream */
388   gint current_audio;           /* the currently selected stream */
389   gint current_text;            /* the currently selected stream */
390
391   guint64 buffer_duration;      /* When buffering, the max buffer duration (ns) */
392   guint buffer_size;            /* When buffering, the max buffer size (bytes) */
393
394   /* our play sink */
395   GstPlaySink *playsink;
396
397   /* the last activated source */
398   GstElement *source;
399
400   /* lock protecting dynamic adding/removing */
401   GMutex dyn_lock;
402   /* if we are shutting down or not */
403   gint shutdown;
404
405   GMutex elements_lock;
406   guint32 elements_cookie;
407   GList *elements;              /* factories we can use for selecting elements */
408
409   gboolean have_selector;       /* set to FALSE when we fail to create an
410                                  * input-selector, so that we only post a
411                                  * warning once */
412
413   gboolean video_pending_flush_finish;  /* whether we are pending to send a custom
414                                          * custom-video-flush-finish event
415                                          * on pad activation */
416   gboolean audio_pending_flush_finish;  /* whether we are pending to send a custom
417                                          * custom-audio-flush-finish event
418                                          * on pad activation */
419   gboolean text_pending_flush_finish;   /* whether we are pending to send a custom
420                                          * custom-subtitle-flush-finish event
421                                          * on pad activation */
422
423   GstElement *audio_sink;       /* configured audio sink, or NULL      */
424   GstElement *video_sink;       /* configured video sink, or NULL      */
425   GstElement *text_sink;        /* configured text sink, or NULL       */
426
427   struct
428   {
429     gboolean valid;
430     GstFormat format;
431     gint64 duration;
432   } duration[5];                /* cached durations */
433
434   guint64 ring_buffer_max_size; /* 0 means disabled */
435 };
436
437 struct _GstPlayBinClass
438 {
439   GstPipelineClass parent_class;
440
441   /* notify app that the current uri finished decoding and it is possible to
442    * queue a new one for gapless playback */
443   void (*about_to_finish) (GstPlayBin * playbin);
444
445   /* notify app that number of audio/video/text streams changed */
446   void (*video_changed) (GstPlayBin * playbin);
447   void (*audio_changed) (GstPlayBin * playbin);
448   void (*text_changed) (GstPlayBin * playbin);
449
450   /* notify app that the tags of audio/video/text streams changed */
451   void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
452   void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
453   void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
454
455   /* get audio/video/text tags for a stream */
456   GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
457   GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
458   GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
459
460   /* get the last video sample and convert it to the given caps */
461   GstSample *(*convert_sample) (GstPlayBin * playbin, GstCaps * caps);
462
463   /* get audio/video/text pad for a stream */
464   GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
465   GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
466   GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
467 };
468
469 /* props */
470 #define DEFAULT_URI               NULL
471 #define DEFAULT_SUBURI            NULL
472 #define DEFAULT_SOURCE            NULL
473 #define DEFAULT_FLAGS             GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
474                                   GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_SOFT_COLORBALANCE
475 #define DEFAULT_N_VIDEO           0
476 #define DEFAULT_CURRENT_VIDEO     -1
477 #define DEFAULT_N_AUDIO           0
478 #define DEFAULT_CURRENT_AUDIO     -1
479 #define DEFAULT_N_TEXT            0
480 #define DEFAULT_CURRENT_TEXT      -1
481 #define DEFAULT_SUBTITLE_ENCODING NULL
482 #define DEFAULT_AUDIO_SINK        NULL
483 #define DEFAULT_VIDEO_SINK        NULL
484 #define DEFAULT_VIS_PLUGIN        NULL
485 #define DEFAULT_TEXT_SINK         NULL
486 #define DEFAULT_VOLUME            1.0
487 #define DEFAULT_MUTE              FALSE
488 #define DEFAULT_FRAME             NULL
489 #define DEFAULT_FONT_DESC         NULL
490 #define DEFAULT_CONNECTION_SPEED  0
491 #define DEFAULT_BUFFER_DURATION   -1
492 #define DEFAULT_BUFFER_SIZE       -1
493 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
494
495 enum
496 {
497   PROP_0,
498   PROP_URI,
499   PROP_CURRENT_URI,
500   PROP_SUBURI,
501   PROP_CURRENT_SUBURI,
502   PROP_SOURCE,
503   PROP_FLAGS,
504   PROP_N_VIDEO,
505   PROP_CURRENT_VIDEO,
506   PROP_N_AUDIO,
507   PROP_CURRENT_AUDIO,
508   PROP_N_TEXT,
509   PROP_CURRENT_TEXT,
510   PROP_SUBTITLE_ENCODING,
511   PROP_AUDIO_SINK,
512   PROP_VIDEO_SINK,
513   PROP_VIS_PLUGIN,
514   PROP_TEXT_SINK,
515   PROP_VOLUME,
516   PROP_MUTE,
517   PROP_SAMPLE,
518   PROP_FONT_DESC,
519   PROP_CONNECTION_SPEED,
520   PROP_BUFFER_SIZE,
521   PROP_BUFFER_DURATION,
522   PROP_AV_OFFSET,
523   PROP_RING_BUFFER_MAX_SIZE,
524   PROP_LAST
525 };
526
527 /* signals */
528 enum
529 {
530   SIGNAL_ABOUT_TO_FINISH,
531   SIGNAL_CONVERT_SAMPLE,
532   SIGNAL_VIDEO_CHANGED,
533   SIGNAL_AUDIO_CHANGED,
534   SIGNAL_TEXT_CHANGED,
535   SIGNAL_VIDEO_TAGS_CHANGED,
536   SIGNAL_AUDIO_TAGS_CHANGED,
537   SIGNAL_TEXT_TAGS_CHANGED,
538   SIGNAL_GET_VIDEO_TAGS,
539   SIGNAL_GET_AUDIO_TAGS,
540   SIGNAL_GET_TEXT_TAGS,
541   SIGNAL_GET_VIDEO_PAD,
542   SIGNAL_GET_AUDIO_PAD,
543   SIGNAL_GET_TEXT_PAD,
544   SIGNAL_SOURCE_SETUP,
545   LAST_SIGNAL
546 };
547
548 static void gst_play_bin_class_init (GstPlayBinClass * klass);
549 static void gst_play_bin_init (GstPlayBin * playbin);
550 static void gst_play_bin_finalize (GObject * object);
551
552 static void gst_play_bin_set_property (GObject * object, guint prop_id,
553     const GValue * value, GParamSpec * spec);
554 static void gst_play_bin_get_property (GObject * object, guint prop_id,
555     GValue * value, GParamSpec * spec);
556
557 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
558     GstStateChange transition);
559
560 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
561 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
562
563 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
564     gint stream);
565 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
566     gint stream);
567 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
568     gint stream);
569
570 static GstSample *gst_play_bin_convert_sample (GstPlayBin * playbin,
571     GstCaps * caps);
572
573 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
574 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
575 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
576
577 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
578
579 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
580 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
581     GstSourceGroup * group);
582
583 static void gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
584     GstElement * suburidecodebin, gboolean block);
585 static void gst_play_bin_suburidecodebin_seek_to_start (GstSourceGroup * group);
586
587 static GstElementClass *parent_class;
588
589 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
590
591 #define REMOVE_SIGNAL(obj,id)            \
592 if (id) {                                \
593   g_signal_handler_disconnect (obj, id); \
594   id = 0;                                \
595 }
596
597 static void gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data);
598 static void gst_play_bin_navigation_init (gpointer g_iface,
599     gpointer g_iface_data);
600 static void gst_play_bin_colorbalance_init (gpointer g_iface,
601     gpointer g_iface_data);
602
603 static GType
604 gst_play_bin_get_type (void)
605 {
606   static GType gst_play_bin_type = 0;
607
608   if (!gst_play_bin_type) {
609     static const GTypeInfo gst_play_bin_info = {
610       sizeof (GstPlayBinClass),
611       NULL,
612       NULL,
613       (GClassInitFunc) gst_play_bin_class_init,
614       NULL,
615       NULL,
616       sizeof (GstPlayBin),
617       0,
618       (GInstanceInitFunc) gst_play_bin_init,
619       NULL
620     };
621     static const GInterfaceInfo svol_info = {
622       NULL, NULL, NULL
623     };
624     static const GInterfaceInfo ov_info = {
625       gst_play_bin_overlay_init,
626       NULL, NULL
627     };
628     static const GInterfaceInfo nav_info = {
629       gst_play_bin_navigation_init,
630       NULL, NULL
631     };
632     static const GInterfaceInfo col_info = {
633       gst_play_bin_colorbalance_init,
634       NULL, NULL
635     };
636
637     gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
638         "GstPlayBin", &gst_play_bin_info, 0);
639
640     g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
641         &svol_info);
642     g_type_add_interface_static (gst_play_bin_type, GST_TYPE_VIDEO_OVERLAY,
643         &ov_info);
644     g_type_add_interface_static (gst_play_bin_type, GST_TYPE_NAVIGATION,
645         &nav_info);
646     g_type_add_interface_static (gst_play_bin_type, GST_TYPE_COLOR_BALANCE,
647         &col_info);
648   }
649
650   return gst_play_bin_type;
651 }
652
653 static void
654 gst_play_bin_class_init (GstPlayBinClass * klass)
655 {
656   GObjectClass *gobject_klass;
657   GstElementClass *gstelement_klass;
658   GstBinClass *gstbin_klass;
659
660   gobject_klass = (GObjectClass *) klass;
661   gstelement_klass = (GstElementClass *) klass;
662   gstbin_klass = (GstBinClass *) klass;
663
664   parent_class = g_type_class_peek_parent (klass);
665
666   gobject_klass->set_property = gst_play_bin_set_property;
667   gobject_klass->get_property = gst_play_bin_get_property;
668
669   gobject_klass->finalize = gst_play_bin_finalize;
670
671   /**
672    * GstPlayBin:uri
673    *
674    * Set the next URI that playbin will play. This property can be set from the
675    * about-to-finish signal to queue the next media file.
676    */
677   g_object_class_install_property (gobject_klass, PROP_URI,
678       g_param_spec_string ("uri", "URI", "URI of the media to play",
679           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
680
681    /**
682    * GstPlayBin:current-uri
683    *
684    * The currently playing uri.
685    */
686   g_object_class_install_property (gobject_klass, PROP_CURRENT_URI,
687       g_param_spec_string ("current-uri", "Current URI",
688           "The currently playing URI", NULL,
689           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
690
691   /**
692    * GstPlayBin:suburi
693    *
694    * Set the next subtitle URI that playbin will play. This property can be
695    * set from the about-to-finish signal to queue the next subtitle media file.
696    */
697   g_object_class_install_property (gobject_klass, PROP_SUBURI,
698       g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
699           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
700
701   /**
702    * GstPlayBin:current-suburi
703    *
704    * The currently playing subtitle uri.
705    */
706   g_object_class_install_property (gobject_klass, PROP_CURRENT_SUBURI,
707       g_param_spec_string ("current-suburi", "Current .sub-URI",
708           "The currently playing URI of a subtitle",
709           NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
710
711   g_object_class_install_property (gobject_klass, PROP_SOURCE,
712       g_param_spec_object ("source", "Source", "Source element",
713           GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
714
715   /**
716    * GstPlayBin:flags
717    *
718    * Control the behaviour of playbin.
719    */
720   g_object_class_install_property (gobject_klass, PROP_FLAGS,
721       g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
722           GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
723           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
724
725   /**
726    * GstPlayBin:n-video
727    *
728    * Get the total number of available video streams.
729    */
730   g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
731       g_param_spec_int ("n-video", "Number Video",
732           "Total number of video streams", 0, G_MAXINT, 0,
733           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
734   /**
735    * GstPlayBin:current-video
736    *
737    * Get or set the currently playing video stream. By default the first video
738    * stream with data is played.
739    */
740   g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
741       g_param_spec_int ("current-video", "Current Video",
742           "Currently playing video stream (-1 = auto)",
743           -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
744   /**
745    * GstPlayBin:n-audio
746    *
747    * Get the total number of available audio streams.
748    */
749   g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
750       g_param_spec_int ("n-audio", "Number Audio",
751           "Total number of audio streams", 0, G_MAXINT, 0,
752           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
753   /**
754    * GstPlayBin:current-audio
755    *
756    * Get or set the currently playing audio stream. By default the first audio
757    * stream with data is played.
758    */
759   g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
760       g_param_spec_int ("current-audio", "Current audio",
761           "Currently playing audio stream (-1 = auto)",
762           -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
763   /**
764    * GstPlayBin:n-text
765    *
766    * Get the total number of available subtitle streams.
767    */
768   g_object_class_install_property (gobject_klass, PROP_N_TEXT,
769       g_param_spec_int ("n-text", "Number Text",
770           "Total number of text streams", 0, G_MAXINT, 0,
771           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
772   /**
773    * GstPlayBin:current-text:
774    *
775    * Get or set the currently playing subtitle stream. By default the first
776    * subtitle stream with data is played.
777    */
778   g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
779       g_param_spec_int ("current-text", "Current Text",
780           "Currently playing text stream (-1 = auto)",
781           -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
782
783   g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
784       g_param_spec_string ("subtitle-encoding", "subtitle encoding",
785           "Encoding to assume if input subtitles are not in UTF-8 encoding. "
786           "If not set, the GST_SUBTITLE_ENCODING environment variable will "
787           "be checked for an encoding to use. If that is not set either, "
788           "ISO-8859-15 will be assumed.", NULL,
789           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
790
791   g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
792       g_param_spec_object ("video-sink", "Video Sink",
793           "the video output element to use (NULL = default sink)",
794           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
795   g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
796       g_param_spec_object ("audio-sink", "Audio Sink",
797           "the audio output element to use (NULL = default sink)",
798           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
799   g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
800       g_param_spec_object ("vis-plugin", "Vis plugin",
801           "the visualization element to use (NULL = default)",
802           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
803   g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
804       g_param_spec_object ("text-sink", "Text plugin",
805           "the text output element to use (NULL = default subtitleoverlay)",
806           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
807
808   /**
809    * GstPlayBin:volume:
810    *
811    * Get or set the current audio stream volume. 1.0 means 100%,
812    * 0.0 means mute. This uses a linear volume scale.
813    *
814    */
815   g_object_class_install_property (gobject_klass, PROP_VOLUME,
816       g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
817           0.0, VOLUME_MAX_DOUBLE, 1.0,
818           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
819   g_object_class_install_property (gobject_klass, PROP_MUTE,
820       g_param_spec_boolean ("mute", "Mute",
821           "Mute the audio channel without changing the volume", FALSE,
822           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
823
824   /**
825    * GstPlayBin:sample:
826    * @playbin: a #GstPlayBin
827    *
828    * Get the currently rendered or prerolled sample in the video sink.
829    * The #GstCaps in the sample will describe the format of the buffer.
830    */
831   g_object_class_install_property (gobject_klass, PROP_SAMPLE,
832       g_param_spec_boxed ("sample", "Sample",
833           "The last sample (NULL = no video available)",
834           GST_TYPE_SAMPLE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
835
836   g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
837       g_param_spec_string ("subtitle-font-desc",
838           "Subtitle font description",
839           "Pango font description of font "
840           "to be used for subtitle rendering", NULL,
841           G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
842
843   g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
844       g_param_spec_uint64 ("connection-speed", "Connection Speed",
845           "Network connection speed in kbps (0 = unknown)",
846           0, G_MAXUINT64 / 1000, DEFAULT_CONNECTION_SPEED,
847           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
848
849   g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
850       g_param_spec_int ("buffer-size", "Buffer size (bytes)",
851           "Buffer size when buffering network streams",
852           -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
853           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
854   g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
855       g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
856           "Buffer duration when buffering network streams",
857           -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
858           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
859   /**
860    * GstPlayBin:av-offset:
861    *
862    * Control the synchronisation offset between the audio and video streams.
863    * Positive values make the audio ahead of the video and negative values make
864    * the audio go behind the video.
865    *
866    * Since: 0.10.30
867    */
868   g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
869       g_param_spec_int64 ("av-offset", "AV Offset",
870           "The synchronisation offset between audio and video in nanoseconds",
871           G_MININT64, G_MAXINT64, 0,
872           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
873
874   /**
875    * GstQueue2:ring-buffer-max-size
876    *
877    * The maximum size of the ring buffer in bytes. If set to 0, the ring
878    * buffer is disabled. Default 0.
879    *
880    * Since: 0.10.31
881    */
882   g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
883       g_param_spec_uint64 ("ring-buffer-max-size",
884           "Max. ring buffer size (bytes)",
885           "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
886           0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
887           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
888
889   /**
890    * GstPlayBin::about-to-finish
891    * @playbin: a #GstPlayBin
892    *
893    * This signal is emitted when the current uri is about to finish. You can
894    * set the uri and suburi to make sure that playback continues.
895    *
896    * This signal is emitted from the context of a GStreamer streaming thread.
897    */
898   gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
899       g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
900       G_SIGNAL_RUN_LAST,
901       G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
902       g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
903
904   /**
905    * GstPlayBin::video-changed
906    * @playbin: a #GstPlayBin
907    *
908    * This signal is emitted whenever the number or order of the video
909    * streams has changed. The application will most likely want to select
910    * a new video stream.
911    *
912    * This signal is usually emitted from the context of a GStreamer streaming
913    * thread. You can use gst_message_new_application() and
914    * gst_element_post_message() to notify your application's main thread.
915    */
916   /* FIXME 0.11: turn video-changed signal into message? */
917   gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
918       g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
919       G_SIGNAL_RUN_LAST,
920       G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
921       g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
922   /**
923    * GstPlayBin::audio-changed
924    * @playbin: a #GstPlayBin
925    *
926    * This signal is emitted whenever the number or order of the audio
927    * streams has changed. The application will most likely want to select
928    * a new audio stream.
929    *
930    * This signal may be emitted from the context of a GStreamer streaming thread.
931    * You can use gst_message_new_application() and gst_element_post_message()
932    * to notify your application's main thread.
933    */
934   /* FIXME 0.11: turn audio-changed signal into message? */
935   gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
936       g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
937       G_SIGNAL_RUN_LAST,
938       G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
939       g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
940   /**
941    * GstPlayBin::text-changed
942    * @playbin: a #GstPlayBin
943    *
944    * This signal is emitted whenever the number or order of the text
945    * streams has changed. The application will most likely want to select
946    * a new text stream.
947    *
948    * This signal may be emitted from the context of a GStreamer streaming thread.
949    * You can use gst_message_new_application() and gst_element_post_message()
950    * to notify your application's main thread.
951    */
952   /* FIXME 0.11: turn text-changed signal into message? */
953   gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
954       g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
955       G_SIGNAL_RUN_LAST,
956       G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
957       g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
958
959   /**
960    * GstPlayBin::video-tags-changed
961    * @playbin: a #GstPlayBin
962    * @stream: stream index with changed tags
963    *
964    * This signal is emitted whenever the tags of a video stream have changed.
965    * The application will most likely want to get the new tags.
966    *
967    * This signal may be emitted from the context of a GStreamer streaming thread.
968    * You can use gst_message_new_application() and gst_element_post_message()
969    * to notify your application's main thread.
970    *
971    * Since: 0.10.24
972    */
973   gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
974       g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
975       G_SIGNAL_RUN_LAST,
976       G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
977       g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
978
979   /**
980    * GstPlayBin::audio-tags-changed
981    * @playbin: a #GstPlayBin
982    * @stream: stream index with changed tags
983    *
984    * This signal is emitted whenever the tags of an audio stream have changed.
985    * The application will most likely want to get the new tags.
986    *
987    * This signal may be emitted from the context of a GStreamer streaming thread.
988    * You can use gst_message_new_application() and gst_element_post_message()
989    * to notify your application's main thread.
990    *
991    * Since: 0.10.24
992    */
993   gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
994       g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
995       G_SIGNAL_RUN_LAST,
996       G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
997       g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
998
999   /**
1000    * GstPlayBin::text-tags-changed
1001    * @playbin: a #GstPlayBin
1002    * @stream: stream index with changed tags
1003    *
1004    * This signal is emitted whenever the tags of a text stream have changed.
1005    * The application will most likely want to get the new tags.
1006    *
1007    * This signal may be emitted from the context of a GStreamer streaming thread.
1008    * You can use gst_message_new_application() and gst_element_post_message()
1009    * to notify your application's main thread.
1010    *
1011    * Since: 0.10.24
1012    */
1013   gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
1014       g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
1015       G_SIGNAL_RUN_LAST,
1016       G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
1017       g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
1018
1019   /**
1020    * GstPlayBin::source-setup:
1021    * @playbin: a #GstPlayBin
1022    * @source: source element
1023    *
1024    * This signal is emitted after the source element has been created, so
1025    * it can be configured by setting additional properties (e.g. set a
1026    * proxy server for an http source, or set the device and read speed for
1027    * an audio cd source). This is functionally equivalent to connecting to
1028    * the notify::source signal, but more convenient.
1029    *
1030    * This signal is usually emitted from the context of a GStreamer streaming
1031    * thread.
1032    *
1033    * Since: 0.10.33
1034    */
1035   gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
1036       g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
1037       G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1038       g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
1039
1040   /**
1041    * GstPlayBin::get-video-tags
1042    * @playbin: a #GstPlayBin
1043    * @stream: a video stream number
1044    *
1045    * Action signal to retrieve the tags of a specific video stream number.
1046    * This information can be used to select a stream.
1047    *
1048    * Returns: a GstTagList with tags or NULL when the stream number does not
1049    * exist.
1050    */
1051   gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
1052       g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
1053       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1054       G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
1055       g_cclosure_marshal_generic, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1056   /**
1057    * GstPlayBin::get-audio-tags
1058    * @playbin: a #GstPlayBin
1059    * @stream: an audio stream number
1060    *
1061    * Action signal to retrieve the tags of a specific audio stream number.
1062    * This information can be used to select a stream.
1063    *
1064    * Returns: a GstTagList with tags or NULL when the stream number does not
1065    * exist.
1066    */
1067   gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
1068       g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
1069       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1070       G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
1071       g_cclosure_marshal_generic, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1072   /**
1073    * GstPlayBin::get-text-tags
1074    * @playbin: a #GstPlayBin
1075    * @stream: a text stream number
1076    *
1077    * Action signal to retrieve the tags of a specific text stream number.
1078    * This information can be used to select a stream.
1079    *
1080    * Returns: a GstTagList with tags or NULL when the stream number does not
1081    * exist.
1082    */
1083   gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
1084       g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
1085       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1086       G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
1087       g_cclosure_marshal_generic, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1088   /**
1089    * GstPlayBin::convert-sample
1090    * @playbin: a #GstPlayBin
1091    * @caps: the target format of the frame
1092    *
1093    * Action signal to retrieve the currently playing video frame in the format
1094    * specified by @caps.
1095    * If @caps is %NULL, no conversion will be performed and this function is
1096    * equivalent to the #GstPlayBin::frame property.
1097    *
1098    * Returns: a #GstBuffer of the current video frame converted to #caps.
1099    * The caps on the buffer will describe the final layout of the buffer data.
1100    * %NULL is returned when no current buffer can be retrieved or when the
1101    * conversion failed.
1102    */
1103   gst_play_bin_signals[SIGNAL_CONVERT_SAMPLE] =
1104       g_signal_new ("convert-sample", G_TYPE_FROM_CLASS (klass),
1105       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1106       G_STRUCT_OFFSET (GstPlayBinClass, convert_sample), NULL, NULL,
1107       g_cclosure_marshal_generic, GST_TYPE_SAMPLE, 1, GST_TYPE_CAPS);
1108
1109   /**
1110    * GstPlayBin::get-video-pad
1111    * @playbin: a #GstPlayBin
1112    * @stream: a video stream number
1113    *
1114    * Action signal to retrieve the stream-selector sinkpad for a specific
1115    * video stream.
1116    * This pad can be used for notifications of caps changes, stream-specific
1117    * queries, etc.
1118    *
1119    * Returns: a #GstPad, or NULL when the stream number does not exist.
1120    */
1121   gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1122       g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1123       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1124       G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1125       g_cclosure_marshal_generic, GST_TYPE_PAD, 1, G_TYPE_INT);
1126   /**
1127    * GstPlayBin::get-audio-pad
1128    * @playbin: a #GstPlayBin
1129    * @stream: an audio stream number
1130    *
1131    * Action signal to retrieve the stream-selector sinkpad for a specific
1132    * audio stream.
1133    * This pad can be used for notifications of caps changes, stream-specific
1134    * queries, etc.
1135    *
1136    * Returns: a #GstPad, or NULL when the stream number does not exist.
1137    */
1138   gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1139       g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1140       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1141       G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1142       g_cclosure_marshal_generic, GST_TYPE_PAD, 1, G_TYPE_INT);
1143   /**
1144    * GstPlayBin::get-text-pad
1145    * @playbin: a #GstPlayBin
1146    * @stream: a text stream number
1147    *
1148    * Action signal to retrieve the stream-selector sinkpad for a specific
1149    * text stream.
1150    * This pad can be used for notifications of caps changes, stream-specific
1151    * queries, etc.
1152    *
1153    * Returns: a #GstPad, or NULL when the stream number does not exist.
1154    */
1155   gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1156       g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1157       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1158       G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1159       g_cclosure_marshal_generic, GST_TYPE_PAD, 1, G_TYPE_INT);
1160
1161   klass->get_video_tags = gst_play_bin_get_video_tags;
1162   klass->get_audio_tags = gst_play_bin_get_audio_tags;
1163   klass->get_text_tags = gst_play_bin_get_text_tags;
1164
1165   klass->convert_sample = gst_play_bin_convert_sample;
1166
1167   klass->get_video_pad = gst_play_bin_get_video_pad;
1168   klass->get_audio_pad = gst_play_bin_get_audio_pad;
1169   klass->get_text_pad = gst_play_bin_get_text_pad;
1170
1171   gst_element_class_set_static_metadata (gstelement_klass,
1172       "Player Bin 2", "Generic/Bin/Player",
1173       "Autoplug and play media from an uri",
1174       "Wim Taymans <wim.taymans@gmail.com>");
1175
1176   gstelement_klass->change_state =
1177       GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1178   gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1179
1180   gstbin_klass->handle_message =
1181       GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1182 }
1183
1184 static void
1185 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1186 {
1187   int n;
1188
1189   /* store the array for the different channels */
1190   group->video_channels = g_ptr_array_new ();
1191   group->audio_channels = g_ptr_array_new ();
1192   group->text_channels = g_ptr_array_new ();
1193   g_mutex_init (&group->lock);
1194   /* init selectors. The selector is found by finding the first prefix that
1195    * matches the media. */
1196   group->playbin = playbin;
1197   /* If you add any items to these lists, check that media_list[] is defined
1198    * above to be large enough to hold MAX(items)+1, so as to accommodate a
1199    * NULL terminator (set when the memory is zeroed on allocation) */
1200   group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
1201   group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
1202   group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
1203   group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
1204   group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
1205   group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
1206   group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
1207   group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
1208   group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
1209   group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
1210   group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
1211   group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
1212   group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
1213   group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
1214       gst_subtitle_overlay_create_factory_caps;
1215   group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
1216   group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
1217
1218   for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1219     GstSourceSelect *select = &group->selector[n];
1220     select->sinkpad_delayed_event = NULL;
1221     select->sinkpad_data_probe = 0;
1222   }
1223 }
1224
1225 static void
1226 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1227 {
1228   int n;
1229
1230   for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1231     GstSourceSelect *select = &group->selector[n];
1232     if (select->sinkpad && select->sinkpad_data_probe)
1233       gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
1234     if (select->sinkpad_delayed_event)
1235       gst_event_unref (select->sinkpad_delayed_event);
1236   }
1237
1238   g_free (group->uri);
1239   g_free (group->suburi);
1240   g_ptr_array_free (group->video_channels, TRUE);
1241   g_ptr_array_free (group->audio_channels, TRUE);
1242   g_ptr_array_free (group->text_channels, TRUE);
1243
1244   g_mutex_clear (&group->lock);
1245   if (group->audio_sink) {
1246     if (group->audio_sink != playbin->audio_sink)
1247       gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1248     gst_object_unref (group->audio_sink);
1249   }
1250   group->audio_sink = NULL;
1251   if (group->video_sink) {
1252     if (group->video_sink != playbin->video_sink)
1253       gst_element_set_state (group->video_sink, GST_STATE_NULL);
1254     gst_object_unref (group->video_sink);
1255   }
1256   group->video_sink = NULL;
1257
1258   g_list_free (group->stream_changed_pending);
1259   group->stream_changed_pending = NULL;
1260
1261   if (group->stream_changed_pending_lock.p)
1262     g_mutex_clear (&group->stream_changed_pending_lock);
1263   group->stream_changed_pending_lock.p = NULL;
1264
1265   g_slist_free (group->suburi_flushes_to_drop);
1266   group->suburi_flushes_to_drop = NULL;
1267
1268   if (group->suburi_flushes_to_drop_lock.p)
1269     g_mutex_clear (&group->suburi_flushes_to_drop_lock);
1270   group->suburi_flushes_to_drop_lock.p = NULL;
1271 }
1272
1273 static void
1274 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1275 {
1276   g_object_notify (G_OBJECT (playbin), "volume");
1277 }
1278
1279 static void
1280 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1281 {
1282   g_object_notify (G_OBJECT (playbin), "mute");
1283 }
1284
1285 static void
1286 colorbalance_value_changed_cb (GstColorBalance * balance,
1287     GstColorBalanceChannel * channel, gint value, GstPlayBin * playbin)
1288 {
1289   gst_color_balance_value_changed (GST_COLOR_BALANCE (playbin), channel, value);
1290 }
1291
1292 static gint
1293 compare_factories_func (gconstpointer p1, gconstpointer p2)
1294 {
1295   GstPluginFeature *f1, *f2;
1296   gint diff;
1297   gboolean s1, s2;
1298
1299   f1 = (GstPluginFeature *) p1;
1300   f2 = (GstPluginFeature *) p2;
1301
1302   s1 = gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (f1),
1303       GST_ELEMENT_FACTORY_TYPE_SINK);
1304   s2 = gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (f2),
1305       GST_ELEMENT_FACTORY_TYPE_SINK);
1306
1307   if (s1 && !s2)
1308     return -1;
1309   else if (!s1 && s2)
1310     return 1;
1311
1312   diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
1313   if (diff != 0)
1314     return diff;
1315
1316   diff = strcmp (GST_OBJECT_NAME (f2), GST_OBJECT_NAME (f1));
1317
1318   return diff;
1319 }
1320
1321 /* Must be called with elements lock! */
1322 static void
1323 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1324 {
1325   GList *res, *tmp;
1326   guint cookie;
1327
1328   cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
1329   if (!playbin->elements || playbin->elements_cookie != cookie) {
1330     if (playbin->elements)
1331       gst_plugin_feature_list_free (playbin->elements);
1332     res =
1333         gst_element_factory_list_get_elements
1334         (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1335     tmp =
1336         gst_element_factory_list_get_elements
1337         (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1338     playbin->elements = g_list_concat (res, tmp);
1339     playbin->elements = g_list_sort (playbin->elements, compare_factories_func);
1340     playbin->elements_cookie = cookie;
1341   }
1342 }
1343
1344 static void
1345 gst_play_bin_init (GstPlayBin * playbin)
1346 {
1347   g_rec_mutex_init (&playbin->lock);
1348   g_mutex_init (&playbin->dyn_lock);
1349
1350   /* assume we can create a selector */
1351   playbin->have_selector = TRUE;
1352
1353   /* init groups */
1354   playbin->curr_group = &playbin->groups[0];
1355   playbin->next_group = &playbin->groups[1];
1356   init_group (playbin, &playbin->groups[0]);
1357   init_group (playbin, &playbin->groups[1]);
1358
1359   /* first filter out the interesting element factories */
1360   g_mutex_init (&playbin->elements_lock);
1361
1362   /* add sink */
1363   playbin->playsink =
1364       g_object_new (GST_TYPE_PLAY_SINK, "name", "playsink", "send-event-mode",
1365       1, NULL);
1366   gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1367   gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1368   /* Connect to notify::volume and notify::mute signals for proxying */
1369   g_signal_connect (playbin->playsink, "notify::volume",
1370       G_CALLBACK (notify_volume_cb), playbin);
1371   g_signal_connect (playbin->playsink, "notify::mute",
1372       G_CALLBACK (notify_mute_cb), playbin);
1373   g_signal_connect (playbin->playsink, "value-changed",
1374       G_CALLBACK (colorbalance_value_changed_cb), playbin);
1375
1376   playbin->current_video = DEFAULT_CURRENT_VIDEO;
1377   playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1378   playbin->current_text = DEFAULT_CURRENT_TEXT;
1379
1380   playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1381   playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1382   playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1383 }
1384
1385 static void
1386 gst_play_bin_finalize (GObject * object)
1387 {
1388   GstPlayBin *playbin;
1389
1390   playbin = GST_PLAY_BIN (object);
1391
1392   free_group (playbin, &playbin->groups[0]);
1393   free_group (playbin, &playbin->groups[1]);
1394
1395   if (playbin->source)
1396     gst_object_unref (playbin->source);
1397   if (playbin->video_sink) {
1398     gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1399     gst_object_unref (playbin->video_sink);
1400   }
1401   if (playbin->audio_sink) {
1402     gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1403     gst_object_unref (playbin->audio_sink);
1404   }
1405   if (playbin->text_sink) {
1406     gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1407     gst_object_unref (playbin->text_sink);
1408   }
1409
1410   if (playbin->elements)
1411     gst_plugin_feature_list_free (playbin->elements);
1412
1413   g_rec_mutex_clear (&playbin->lock);
1414   g_mutex_clear (&playbin->dyn_lock);
1415   g_mutex_clear (&playbin->elements_lock);
1416
1417   G_OBJECT_CLASS (parent_class)->finalize (object);
1418 }
1419
1420 static gboolean
1421 gst_playbin_uri_is_valid (GstPlayBin * playbin, const gchar * uri)
1422 {
1423   const gchar *c;
1424
1425   GST_LOG_OBJECT (playbin, "checking uri '%s'", uri);
1426
1427   /* this just checks the protocol */
1428   if (!gst_uri_is_valid (uri))
1429     return FALSE;
1430
1431   for (c = uri; *c != '\0'; ++c) {
1432     if (!g_ascii_isprint (*c))
1433       goto invalid;
1434     if (*c == ' ')
1435       goto invalid;
1436   }
1437
1438   return TRUE;
1439
1440 invalid:
1441   {
1442     GST_WARNING_OBJECT (playbin, "uri '%s' not valid, character #%u",
1443         uri, (guint) ((guintptr) c - (guintptr) uri));
1444     return FALSE;
1445   }
1446 }
1447
1448 static void
1449 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1450 {
1451   GstSourceGroup *group;
1452
1453   if (uri == NULL) {
1454     g_warning ("cannot set NULL uri");
1455     return;
1456   }
1457
1458   if (!gst_playbin_uri_is_valid (playbin, uri)) {
1459     if (g_str_has_prefix (uri, "file:")) {
1460       GST_WARNING_OBJECT (playbin, "not entirely correct file URI '%s' - make "
1461           "sure to escape spaces and non-ASCII characters properly and specify "
1462           "an absolute path. Use gst_filename_to_uri() to convert filenames "
1463           "to URIs", uri);
1464     } else {
1465       /* GST_ERROR_OBJECT (playbin, "malformed URI '%s'", uri); */
1466     }
1467   }
1468
1469   GST_PLAY_BIN_LOCK (playbin);
1470   group = playbin->next_group;
1471
1472   GST_SOURCE_GROUP_LOCK (group);
1473   /* store the uri in the next group we will play */
1474   g_free (group->uri);
1475   group->uri = g_strdup (uri);
1476   group->valid = TRUE;
1477   GST_SOURCE_GROUP_UNLOCK (group);
1478
1479   GST_DEBUG ("set new uri to %s", uri);
1480   GST_PLAY_BIN_UNLOCK (playbin);
1481 }
1482
1483 static void
1484 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1485 {
1486   GstSourceGroup *group;
1487
1488   GST_PLAY_BIN_LOCK (playbin);
1489   group = playbin->next_group;
1490
1491   GST_SOURCE_GROUP_LOCK (group);
1492   g_free (group->suburi);
1493   group->suburi = g_strdup (suburi);
1494   GST_SOURCE_GROUP_UNLOCK (group);
1495
1496   GST_DEBUG ("setting new .sub uri to %s", suburi);
1497
1498   GST_PLAY_BIN_UNLOCK (playbin);
1499 }
1500
1501 static void
1502 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1503 {
1504   gst_play_sink_set_flags (playbin->playsink, flags);
1505   gst_play_sink_reconfigure (playbin->playsink);
1506 }
1507
1508 static GstPlayFlags
1509 gst_play_bin_get_flags (GstPlayBin * playbin)
1510 {
1511   GstPlayFlags flags;
1512
1513   flags = gst_play_sink_get_flags (playbin->playsink);
1514
1515   return flags;
1516 }
1517
1518 /* get the currently playing group or if nothing is playing, the next
1519  * group. Must be called with the PLAY_BIN_LOCK. */
1520 static GstSourceGroup *
1521 get_group (GstPlayBin * playbin)
1522 {
1523   GstSourceGroup *result;
1524
1525   if (!(result = playbin->curr_group))
1526     result = playbin->next_group;
1527
1528   return result;
1529 }
1530
1531 static GstPad *
1532 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1533 {
1534   GstPad *sinkpad = NULL;
1535   GstSourceGroup *group;
1536
1537   GST_PLAY_BIN_LOCK (playbin);
1538   group = get_group (playbin);
1539   if (stream < group->video_channels->len) {
1540     sinkpad = g_ptr_array_index (group->video_channels, stream);
1541     gst_object_ref (sinkpad);
1542   }
1543   GST_PLAY_BIN_UNLOCK (playbin);
1544
1545   return sinkpad;
1546 }
1547
1548 static GstPad *
1549 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1550 {
1551   GstPad *sinkpad = NULL;
1552   GstSourceGroup *group;
1553
1554   GST_PLAY_BIN_LOCK (playbin);
1555   group = get_group (playbin);
1556   if (stream < group->audio_channels->len) {
1557     sinkpad = g_ptr_array_index (group->audio_channels, stream);
1558     gst_object_ref (sinkpad);
1559   }
1560   GST_PLAY_BIN_UNLOCK (playbin);
1561
1562   return sinkpad;
1563 }
1564
1565 static GstPad *
1566 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1567 {
1568   GstPad *sinkpad = NULL;
1569   GstSourceGroup *group;
1570
1571   GST_PLAY_BIN_LOCK (playbin);
1572   group = get_group (playbin);
1573   if (stream < group->text_channels->len) {
1574     sinkpad = g_ptr_array_index (group->text_channels, stream);
1575     gst_object_ref (sinkpad);
1576   }
1577   GST_PLAY_BIN_UNLOCK (playbin);
1578
1579   return sinkpad;
1580 }
1581
1582
1583 static GstTagList *
1584 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1585 {
1586   GstTagList *result;
1587   GstPad *sinkpad;
1588
1589   if (!channels || stream >= channels->len)
1590     return NULL;
1591
1592   sinkpad = g_ptr_array_index (channels, stream);
1593   g_object_get (sinkpad, "tags", &result, NULL);
1594
1595   return result;
1596 }
1597
1598 static GstTagList *
1599 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1600 {
1601   GstTagList *result;
1602   GstSourceGroup *group;
1603
1604   GST_PLAY_BIN_LOCK (playbin);
1605   group = get_group (playbin);
1606   result = get_tags (playbin, group->video_channels, stream);
1607   GST_PLAY_BIN_UNLOCK (playbin);
1608
1609   return result;
1610 }
1611
1612 static GstTagList *
1613 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1614 {
1615   GstTagList *result;
1616   GstSourceGroup *group;
1617
1618   GST_PLAY_BIN_LOCK (playbin);
1619   group = get_group (playbin);
1620   result = get_tags (playbin, group->audio_channels, stream);
1621   GST_PLAY_BIN_UNLOCK (playbin);
1622
1623   return result;
1624 }
1625
1626 static GstTagList *
1627 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1628 {
1629   GstTagList *result;
1630   GstSourceGroup *group;
1631
1632   GST_PLAY_BIN_LOCK (playbin);
1633   group = get_group (playbin);
1634   result = get_tags (playbin, group->text_channels, stream);
1635   GST_PLAY_BIN_UNLOCK (playbin);
1636
1637   return result;
1638 }
1639
1640 static GstSample *
1641 gst_play_bin_convert_sample (GstPlayBin * playbin, GstCaps * caps)
1642 {
1643   return gst_play_sink_convert_sample (playbin->playsink, caps);
1644 }
1645
1646 /* Returns current stream number, or -1 if none has been selected yet */
1647 static int
1648 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1649 {
1650   /* Internal API cleanup would make this easier... */
1651   int i;
1652   GstPad *pad, *current;
1653   GstObject *selector = NULL;
1654   int ret = -1;
1655
1656   for (i = 0; i < channels->len; i++) {
1657     pad = g_ptr_array_index (channels, i);
1658     if ((selector = gst_pad_get_parent (pad))) {
1659       g_object_get (selector, "active-pad", &current, NULL);
1660       gst_object_unref (selector);
1661
1662       if (pad == current) {
1663         gst_object_unref (current);
1664         ret = i;
1665         break;
1666       }
1667
1668       if (current)
1669         gst_object_unref (current);
1670     }
1671   }
1672
1673   return ret;
1674 }
1675
1676 static gboolean
1677 gst_playbin2_send_custom_event (GstObject * selector, const gchar * event_name)
1678 {
1679   GstPad *src;
1680   GstPad *peer;
1681   GstStructure *s;
1682   GstEvent *event;
1683   gboolean ret = FALSE;
1684
1685   src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1686   peer = gst_pad_get_peer (src);
1687   if (peer) {
1688     s = gst_structure_new_empty (event_name);
1689     event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1690     gst_pad_send_event (peer, event);
1691     gst_object_unref (peer);
1692     ret = TRUE;
1693   }
1694   gst_object_unref (src);
1695   return ret;
1696 }
1697
1698 static gboolean
1699 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1700 {
1701   GstSourceGroup *group;
1702   GPtrArray *channels;
1703   GstPad *sinkpad;
1704
1705   GST_PLAY_BIN_LOCK (playbin);
1706
1707   GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1708       playbin->current_video, stream);
1709
1710   group = get_group (playbin);
1711   if (!(channels = group->video_channels))
1712     goto no_channels;
1713
1714   if (stream == -1 || channels->len <= stream) {
1715     sinkpad = NULL;
1716   } else {
1717     /* take channel from selected stream */
1718     sinkpad = g_ptr_array_index (channels, stream);
1719   }
1720
1721   if (sinkpad)
1722     gst_object_ref (sinkpad);
1723   GST_PLAY_BIN_UNLOCK (playbin);
1724
1725   if (sinkpad) {
1726     GstObject *selector;
1727
1728     if ((selector = gst_pad_get_parent (sinkpad))) {
1729       GstPad *old_sinkpad;
1730
1731       g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1732
1733       if (old_sinkpad != sinkpad) {
1734         if (gst_playbin2_send_custom_event (selector,
1735                 "playsink-custom-video-flush"))
1736           playbin->video_pending_flush_finish = TRUE;
1737
1738         /* activate the selected pad */
1739         g_object_set (selector, "active-pad", sinkpad, NULL);
1740       }
1741
1742       gst_object_unref (selector);
1743     }
1744     gst_object_unref (sinkpad);
1745   }
1746   return TRUE;
1747
1748 no_channels:
1749   {
1750     GST_PLAY_BIN_UNLOCK (playbin);
1751     GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1752     return FALSE;
1753   }
1754 }
1755
1756 static gboolean
1757 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1758 {
1759   GstSourceGroup *group;
1760   GPtrArray *channels;
1761   GstPad *sinkpad;
1762
1763   GST_PLAY_BIN_LOCK (playbin);
1764
1765   GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1766       playbin->current_audio, stream);
1767
1768   group = get_group (playbin);
1769   if (!(channels = group->audio_channels))
1770     goto no_channels;
1771
1772   if (stream == -1 || channels->len <= stream) {
1773     sinkpad = NULL;
1774   } else {
1775     /* take channel from selected stream */
1776     sinkpad = g_ptr_array_index (channels, stream);
1777   }
1778
1779   if (sinkpad)
1780     gst_object_ref (sinkpad);
1781   GST_PLAY_BIN_UNLOCK (playbin);
1782
1783   if (sinkpad) {
1784     GstObject *selector;
1785
1786     if ((selector = gst_pad_get_parent (sinkpad))) {
1787       GstPad *old_sinkpad;
1788
1789       g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1790
1791       if (old_sinkpad != sinkpad) {
1792         if (gst_playbin2_send_custom_event (selector,
1793                 "playsink-custom-audio-flush"))
1794           playbin->audio_pending_flush_finish = TRUE;
1795
1796         /* activate the selected pad */
1797         g_object_set (selector, "active-pad", sinkpad, NULL);
1798       }
1799       gst_object_unref (selector);
1800     }
1801     gst_object_unref (sinkpad);
1802   }
1803   return TRUE;
1804
1805 no_channels:
1806   {
1807     GST_PLAY_BIN_UNLOCK (playbin);
1808     GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1809     return FALSE;
1810   }
1811 }
1812
1813 static void
1814 gst_play_bin_suburidecodebin_seek_to_start (GstSourceGroup * group)
1815 {
1816   GstElement *suburidecodebin = group->suburidecodebin;
1817   GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1818   GstPad *sinkpad;
1819   GValue item = { 0, };
1820
1821   if (it && gst_iterator_next (it, &item) == GST_ITERATOR_OK
1822       && ((sinkpad = g_value_get_object (&item)) != NULL)) {
1823     GstEvent *event;
1824     guint32 seqnum;
1825
1826     event =
1827         gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_FLUSH,
1828         GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1829     seqnum = gst_event_get_seqnum (event);
1830
1831     /* store the seqnum to drop flushes from this seek later */
1832     g_mutex_lock (&group->suburi_flushes_to_drop_lock);
1833     group->suburi_flushes_to_drop =
1834         g_slist_append (group->suburi_flushes_to_drop,
1835         GUINT_TO_POINTER (seqnum));
1836     g_mutex_unlock (&group->suburi_flushes_to_drop_lock);
1837
1838     if (!gst_pad_send_event (sinkpad, event)) {
1839       event =
1840           gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1841           GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1842       gst_event_set_seqnum (event, seqnum);
1843       if (!gst_pad_send_event (sinkpad, event)) {
1844         GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1845
1846         g_mutex_lock (&group->suburi_flushes_to_drop_lock);
1847         group->suburi_flushes_to_drop =
1848             g_slist_remove (group->suburi_flushes_to_drop,
1849             GUINT_TO_POINTER (seqnum));
1850         g_mutex_unlock (&group->suburi_flushes_to_drop_lock);
1851       }
1852     }
1853
1854     g_value_unset (&item);
1855   }
1856
1857   if (it)
1858     gst_iterator_free (it);
1859 }
1860
1861 static void
1862 gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
1863     GstElement * suburidecodebin, gboolean block)
1864 {
1865   GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1866   gboolean done = FALSE;
1867   GValue item = { 0, };
1868
1869   GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1870
1871   if (!it)
1872     return;
1873   while (!done) {
1874     GstPad *sinkpad;
1875
1876     switch (gst_iterator_next (it, &item)) {
1877       case GST_ITERATOR_OK:
1878         sinkpad = g_value_get_object (&item);
1879         if (block) {
1880           group->block_id =
1881               gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1882               NULL, NULL, NULL);
1883         } else if (group->block_id) {
1884           gst_pad_remove_probe (sinkpad, group->block_id);
1885           group->block_id = 0;
1886         }
1887         g_value_reset (&item);
1888         break;
1889       case GST_ITERATOR_DONE:
1890         done = TRUE;
1891         break;
1892       case GST_ITERATOR_RESYNC:
1893         gst_iterator_resync (it);
1894         break;
1895       case GST_ITERATOR_ERROR:
1896         done = TRUE;
1897         break;
1898     }
1899   }
1900   g_value_unset (&item);
1901   gst_iterator_free (it);
1902 }
1903
1904 static gboolean
1905 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1906 {
1907   GstSourceGroup *group;
1908   GPtrArray *channels;
1909   GstPad *sinkpad;
1910
1911   GST_PLAY_BIN_LOCK (playbin);
1912
1913   GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1914       playbin->current_text, stream);
1915
1916   group = get_group (playbin);
1917   if (!(channels = group->text_channels))
1918     goto no_channels;
1919
1920   if (stream == -1 || channels->len <= stream) {
1921     sinkpad = NULL;
1922   } else {
1923     /* take channel from selected stream */
1924     sinkpad = g_ptr_array_index (channels, stream);
1925   }
1926
1927   if (sinkpad)
1928     gst_object_ref (sinkpad);
1929   GST_PLAY_BIN_UNLOCK (playbin);
1930
1931   if (sinkpad) {
1932     GstObject *selector;
1933
1934     if ((selector = gst_pad_get_parent (sinkpad))) {
1935       GstPad *old_sinkpad;
1936
1937       g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1938
1939       if (old_sinkpad != sinkpad) {
1940         gboolean need_unblock, need_block, need_seek;
1941         GstPad *peer = NULL, *oldpeer = NULL;
1942         GstElement *parent_element = NULL, *old_parent_element = NULL;
1943
1944         /* Now check if we need to seek the suburidecodebin to the beginning
1945          * or if we need to block all suburidecodebin sinkpads or if we need
1946          * to unblock all suburidecodebin sinkpads
1947          */
1948         if (sinkpad)
1949           peer = gst_pad_get_peer (sinkpad);
1950         if (old_sinkpad)
1951           oldpeer = gst_pad_get_peer (old_sinkpad);
1952
1953         if (peer)
1954           parent_element = gst_pad_get_parent_element (peer);
1955         if (oldpeer)
1956           old_parent_element = gst_pad_get_parent_element (oldpeer);
1957
1958         need_block = (old_parent_element == group->suburidecodebin
1959             && parent_element != old_parent_element);
1960         need_unblock = (parent_element == group->suburidecodebin
1961             && parent_element != old_parent_element);
1962         need_seek = (parent_element == group->suburidecodebin);
1963
1964         if (peer)
1965           gst_object_unref (peer);
1966         if (oldpeer)
1967           gst_object_unref (oldpeer);
1968         if (parent_element)
1969           gst_object_unref (parent_element);
1970         if (old_parent_element)
1971           gst_object_unref (old_parent_element);
1972
1973         /* Block all suburidecodebin sinkpads */
1974         if (need_block)
1975           gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1976               TRUE);
1977
1978         if (gst_playbin2_send_custom_event (selector,
1979                 "playsink-custom-subtitle-flush"))
1980           playbin->text_pending_flush_finish = TRUE;
1981
1982         /* activate the selected pad */
1983         g_object_set (selector, "active-pad", sinkpad, NULL);
1984
1985         /* Unblock pads if necessary */
1986         if (need_unblock)
1987           gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1988               FALSE);
1989
1990         /* seek to the beginning */
1991         if (need_seek)
1992           gst_play_bin_suburidecodebin_seek_to_start (group);
1993       }
1994       gst_object_unref (selector);
1995
1996       if (old_sinkpad)
1997         gst_object_unref (old_sinkpad);
1998     }
1999     gst_object_unref (sinkpad);
2000   }
2001   return TRUE;
2002
2003 no_channels:
2004   {
2005     GST_PLAY_BIN_UNLOCK (playbin);
2006     return FALSE;
2007   }
2008 }
2009
2010 static void
2011 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
2012     const gchar * dbg, GstElement * sink)
2013 {
2014   GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
2015
2016   GST_PLAY_BIN_LOCK (playbin);
2017   if (*elem != sink) {
2018     GstElement *old;
2019
2020     old = *elem;
2021     if (sink)
2022       gst_object_ref_sink (sink);
2023
2024     *elem = sink;
2025     if (old)
2026       gst_object_unref (old);
2027   }
2028   GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
2029   GST_PLAY_BIN_UNLOCK (playbin);
2030 }
2031
2032 static void
2033 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
2034 {
2035   GstElement *elem;
2036
2037   GST_PLAY_BIN_LOCK (playbin);
2038
2039   /* set subtitles on all current and next decodebins. */
2040   if ((elem = playbin->groups[0].uridecodebin))
2041     g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
2042   if ((elem = playbin->groups[0].suburidecodebin))
2043     g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
2044   if ((elem = playbin->groups[1].uridecodebin))
2045     g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
2046   if ((elem = playbin->groups[1].suburidecodebin))
2047     g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
2048
2049   gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
2050   GST_PLAY_BIN_UNLOCK (playbin);
2051 }
2052
2053 static void
2054 gst_play_bin_set_property (GObject * object, guint prop_id,
2055     const GValue * value, GParamSpec * pspec)
2056 {
2057   GstPlayBin *playbin = GST_PLAY_BIN (object);
2058
2059   switch (prop_id) {
2060     case PROP_URI:
2061       gst_play_bin_set_uri (playbin, g_value_get_string (value));
2062       break;
2063     case PROP_SUBURI:
2064       gst_play_bin_set_suburi (playbin, g_value_get_string (value));
2065       break;
2066     case PROP_FLAGS:
2067       gst_play_bin_set_flags (playbin, g_value_get_flags (value));
2068       break;
2069     case PROP_CURRENT_VIDEO:
2070       gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
2071       break;
2072     case PROP_CURRENT_AUDIO:
2073       gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
2074       break;
2075     case PROP_CURRENT_TEXT:
2076       gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
2077       break;
2078     case PROP_SUBTITLE_ENCODING:
2079       gst_play_bin_set_encoding (playbin, g_value_get_string (value));
2080       break;
2081     case PROP_VIDEO_SINK:
2082       gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
2083           g_value_get_object (value));
2084       break;
2085     case PROP_AUDIO_SINK:
2086       gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
2087           g_value_get_object (value));
2088       break;
2089     case PROP_VIS_PLUGIN:
2090       gst_play_sink_set_vis_plugin (playbin->playsink,
2091           g_value_get_object (value));
2092       break;
2093     case PROP_TEXT_SINK:
2094       gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
2095           g_value_get_object (value));
2096       break;
2097     case PROP_VOLUME:
2098       gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
2099       break;
2100     case PROP_MUTE:
2101       gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
2102       break;
2103     case PROP_FONT_DESC:
2104       gst_play_sink_set_font_desc (playbin->playsink,
2105           g_value_get_string (value));
2106       break;
2107     case PROP_CONNECTION_SPEED:
2108       GST_PLAY_BIN_LOCK (playbin);
2109       playbin->connection_speed = g_value_get_uint64 (value) * 1000;
2110       GST_PLAY_BIN_UNLOCK (playbin);
2111       break;
2112     case PROP_BUFFER_SIZE:
2113       playbin->buffer_size = g_value_get_int (value);
2114       break;
2115     case PROP_BUFFER_DURATION:
2116       playbin->buffer_duration = g_value_get_int64 (value);
2117       break;
2118     case PROP_AV_OFFSET:
2119       gst_play_sink_set_av_offset (playbin->playsink,
2120           g_value_get_int64 (value));
2121       break;
2122     case PROP_RING_BUFFER_MAX_SIZE:
2123       playbin->ring_buffer_max_size = g_value_get_uint64 (value);
2124       break;
2125     default:
2126       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2127       break;
2128   }
2129 }
2130
2131 static GstElement *
2132 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
2133     const gchar * dbg, GstPlaySinkType type)
2134 {
2135   GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
2136
2137   GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
2138       GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
2139       dbg, sink, dbg, *elem);
2140
2141   if (sink == NULL) {
2142     GST_PLAY_BIN_LOCK (playbin);
2143     if ((sink = *elem))
2144       gst_object_ref (sink);
2145     GST_PLAY_BIN_UNLOCK (playbin);
2146   }
2147
2148   return sink;
2149 }
2150
2151 static void
2152 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
2153     GParamSpec * pspec)
2154 {
2155   GstPlayBin *playbin = GST_PLAY_BIN (object);
2156
2157   switch (prop_id) {
2158     case PROP_URI:
2159     {
2160       GstSourceGroup *group;
2161
2162       GST_PLAY_BIN_LOCK (playbin);
2163       group = playbin->next_group;
2164       g_value_set_string (value, group->uri);
2165       GST_PLAY_BIN_UNLOCK (playbin);
2166       break;
2167       break;
2168     }
2169     case PROP_CURRENT_URI:
2170     {
2171       GstSourceGroup *group;
2172
2173       GST_PLAY_BIN_LOCK (playbin);
2174       group = get_group (playbin);
2175       g_value_set_string (value, group->uri);
2176       GST_PLAY_BIN_UNLOCK (playbin);
2177       break;
2178     }
2179     case PROP_SUBURI:
2180     {
2181       GstSourceGroup *group;
2182
2183       GST_PLAY_BIN_LOCK (playbin);
2184       group = playbin->next_group;
2185       g_value_set_string (value, group->suburi);
2186       GST_PLAY_BIN_UNLOCK (playbin);
2187       break;
2188     }
2189     case PROP_CURRENT_SUBURI:
2190     {
2191       GstSourceGroup *group;
2192
2193       GST_PLAY_BIN_LOCK (playbin);
2194       group = get_group (playbin);
2195       g_value_set_string (value, group->suburi);
2196       GST_PLAY_BIN_UNLOCK (playbin);
2197       break;
2198     }
2199     case PROP_SOURCE:
2200     {
2201       GST_OBJECT_LOCK (playbin);
2202       g_value_set_object (value, playbin->source);
2203       GST_OBJECT_UNLOCK (playbin);
2204       break;
2205     }
2206     case PROP_FLAGS:
2207       g_value_set_flags (value, gst_play_bin_get_flags (playbin));
2208       break;
2209     case PROP_N_VIDEO:
2210     {
2211       GstSourceGroup *group;
2212       gint n_video;
2213
2214       GST_PLAY_BIN_LOCK (playbin);
2215       group = get_group (playbin);
2216       n_video = (group->video_channels ? group->video_channels->len : 0);
2217       g_value_set_int (value, n_video);
2218       GST_PLAY_BIN_UNLOCK (playbin);
2219       break;
2220     }
2221     case PROP_CURRENT_VIDEO:
2222       GST_PLAY_BIN_LOCK (playbin);
2223       g_value_set_int (value, playbin->current_video);
2224       GST_PLAY_BIN_UNLOCK (playbin);
2225       break;
2226     case PROP_N_AUDIO:
2227     {
2228       GstSourceGroup *group;
2229       gint n_audio;
2230
2231       GST_PLAY_BIN_LOCK (playbin);
2232       group = get_group (playbin);
2233       n_audio = (group->audio_channels ? group->audio_channels->len : 0);
2234       g_value_set_int (value, n_audio);
2235       GST_PLAY_BIN_UNLOCK (playbin);
2236       break;
2237     }
2238     case PROP_CURRENT_AUDIO:
2239       GST_PLAY_BIN_LOCK (playbin);
2240       g_value_set_int (value, playbin->current_audio);
2241       GST_PLAY_BIN_UNLOCK (playbin);
2242       break;
2243     case PROP_N_TEXT:
2244     {
2245       GstSourceGroup *group;
2246       gint n_text;
2247
2248       GST_PLAY_BIN_LOCK (playbin);
2249       group = get_group (playbin);
2250       n_text = (group->text_channels ? group->text_channels->len : 0);
2251       g_value_set_int (value, n_text);
2252       GST_PLAY_BIN_UNLOCK (playbin);
2253       break;
2254     }
2255     case PROP_CURRENT_TEXT:
2256       GST_PLAY_BIN_LOCK (playbin);
2257       g_value_set_int (value, playbin->current_text);
2258       GST_PLAY_BIN_UNLOCK (playbin);
2259       break;
2260     case PROP_SUBTITLE_ENCODING:
2261       GST_PLAY_BIN_LOCK (playbin);
2262       g_value_take_string (value,
2263           gst_play_sink_get_subtitle_encoding (playbin->playsink));
2264       GST_PLAY_BIN_UNLOCK (playbin);
2265       break;
2266     case PROP_VIDEO_SINK:
2267       g_value_take_object (value,
2268           gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2269               "video", GST_PLAY_SINK_TYPE_VIDEO));
2270       break;
2271     case PROP_AUDIO_SINK:
2272       g_value_take_object (value,
2273           gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2274               "audio", GST_PLAY_SINK_TYPE_AUDIO));
2275       break;
2276     case PROP_VIS_PLUGIN:
2277       g_value_take_object (value,
2278           gst_play_sink_get_vis_plugin (playbin->playsink));
2279       break;
2280     case PROP_TEXT_SINK:
2281       g_value_take_object (value,
2282           gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2283               "text", GST_PLAY_SINK_TYPE_TEXT));
2284       break;
2285     case PROP_VOLUME:
2286       g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2287       break;
2288     case PROP_MUTE:
2289       g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2290       break;
2291     case PROP_SAMPLE:
2292       gst_value_take_sample (value,
2293           gst_play_sink_get_last_sample (playbin->playsink));
2294       break;
2295     case PROP_FONT_DESC:
2296       g_value_take_string (value,
2297           gst_play_sink_get_font_desc (playbin->playsink));
2298       break;
2299     case PROP_CONNECTION_SPEED:
2300       GST_PLAY_BIN_LOCK (playbin);
2301       g_value_set_uint64 (value, playbin->connection_speed / 1000);
2302       GST_PLAY_BIN_UNLOCK (playbin);
2303       break;
2304     case PROP_BUFFER_SIZE:
2305       GST_OBJECT_LOCK (playbin);
2306       g_value_set_int (value, playbin->buffer_size);
2307       GST_OBJECT_UNLOCK (playbin);
2308       break;
2309     case PROP_BUFFER_DURATION:
2310       GST_OBJECT_LOCK (playbin);
2311       g_value_set_int64 (value, playbin->buffer_duration);
2312       GST_OBJECT_UNLOCK (playbin);
2313       break;
2314     case PROP_AV_OFFSET:
2315       g_value_set_int64 (value,
2316           gst_play_sink_get_av_offset (playbin->playsink));
2317       break;
2318     case PROP_RING_BUFFER_MAX_SIZE:
2319       g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2320       break;
2321     default:
2322       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2323       break;
2324   }
2325 }
2326
2327 static void
2328 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2329     gboolean valid, GstQuery * query)
2330 {
2331   GstFormat fmt;
2332   gint64 duration;
2333   gint i;
2334
2335   GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2336   gst_query_parse_duration (query, &fmt, &duration);
2337
2338   for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2339     if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2340       playbin->duration[i].valid = valid;
2341       playbin->duration[i].format = fmt;
2342       playbin->duration[i].duration = valid ? duration : -1;
2343       break;
2344     }
2345   }
2346 }
2347
2348 static void
2349 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2350 {
2351   const GstFormat formats[] =
2352       { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2353   gboolean ret;
2354   GstQuery *query;
2355   gint i;
2356
2357   GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2358   for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2359     query = gst_query_new_duration (formats[i]);
2360     ret =
2361         GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2362         query);
2363     gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2364     gst_query_unref (query);
2365   }
2366 }
2367
2368 static gboolean
2369 gst_play_bin_query (GstElement * element, GstQuery * query)
2370 {
2371   GstPlayBin *playbin = GST_PLAY_BIN (element);
2372   gboolean ret;
2373
2374   /* During a group switch we shouldn't allow duration queries
2375    * because it's not clear if the old or new group's duration
2376    * is returned and if the sinks are already playing new data
2377    * or old data. See bug #585969
2378    *
2379    * While we're at it, also don't do any other queries during
2380    * a group switch or any other event that causes topology changes
2381    * by taking the playbin lock in any case.
2382    */
2383   GST_PLAY_BIN_LOCK (playbin);
2384
2385   if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2386     GstSourceGroup *group = playbin->curr_group;
2387     gboolean pending;
2388
2389     GST_SOURCE_GROUP_LOCK (group);
2390     if (group->stream_changed_pending_lock.p) {
2391       g_mutex_lock (&group->stream_changed_pending_lock);
2392       pending = group->pending || group->stream_changed_pending;
2393       g_mutex_unlock (&group->stream_changed_pending_lock);
2394     } else {
2395       pending = group->pending;
2396     }
2397     if (pending) {
2398       GstFormat fmt;
2399       gint i;
2400
2401       ret = FALSE;
2402       gst_query_parse_duration (query, &fmt, NULL);
2403       for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2404         if (fmt == playbin->duration[i].format) {
2405           ret = playbin->duration[i].valid;
2406           gst_query_set_duration (query, fmt,
2407               (ret ? playbin->duration[i].duration : -1));
2408           break;
2409         }
2410       }
2411       /* if nothing cached yet, we might as well request duration,
2412        * such as during initial startup */
2413       if (ret) {
2414         GST_DEBUG_OBJECT (playbin,
2415             "Taking cached duration because of pending group switch: %d", ret);
2416         GST_SOURCE_GROUP_UNLOCK (group);
2417         GST_PLAY_BIN_UNLOCK (playbin);
2418         return ret;
2419       }
2420     }
2421     GST_SOURCE_GROUP_UNLOCK (group);
2422   }
2423
2424   ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2425
2426   if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2427     gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2428   GST_PLAY_BIN_UNLOCK (playbin);
2429
2430   return ret;
2431 }
2432
2433 /* mime types we are not handling on purpose right now, don't post a
2434  * missing-plugin message for these */
2435 static const gchar *blacklisted_mimes[] = {
2436   NULL
2437 };
2438
2439 static void
2440 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2441 {
2442   GstPlayBin *playbin = GST_PLAY_BIN (bin);
2443   GstSourceGroup *group;
2444
2445   if (gst_is_missing_plugin_message (msg)) {
2446     gchar *detail;
2447     guint i;
2448
2449     detail = gst_missing_plugin_message_get_installer_detail (msg);
2450     for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2451       if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2452         GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2453         gst_message_unref (msg);
2454         g_free (detail);
2455         return;
2456       }
2457     }
2458     g_free (detail);
2459   } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2460     const GstStructure *s = gst_message_get_structure (msg);
2461
2462     /* Drop all stream-changed messages except the last one */
2463     if (strcmp ("playbin-stream-changed", gst_structure_get_name (s)) == 0) {
2464       guint32 seqnum = gst_message_get_seqnum (msg);
2465       GList *l, *l_prev;
2466
2467       group = playbin->curr_group;
2468       g_mutex_lock (&group->stream_changed_pending_lock);
2469       for (l = group->stream_changed_pending; l;) {
2470         guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2471
2472         if (l_seqnum == seqnum) {
2473           l_prev = l;
2474           l = l->next;
2475           group->stream_changed_pending =
2476               g_list_delete_link (group->stream_changed_pending, l_prev);
2477           if (group->stream_changed_pending) {
2478             gst_message_unref (msg);
2479             msg = NULL;
2480             break;
2481           }
2482         } else {
2483           l = l->next;
2484         }
2485       }
2486       g_mutex_unlock (&group->stream_changed_pending_lock);
2487     }
2488   } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2489       GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2490     GstObject *src = GST_OBJECT_CAST (msg->src);
2491
2492     /* Ignore async state changes from the uridecodebin children,
2493      * see bug #602000. */
2494     group = playbin->curr_group;
2495     if (src && (group = playbin->curr_group) &&
2496         ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2497             || (group->suburidecodebin
2498                 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2499       GST_DEBUG_OBJECT (playbin,
2500           "Ignoring async state change of uridecodebin: %s",
2501           GST_OBJECT_NAME (src));
2502       gst_message_unref (msg);
2503       msg = NULL;
2504     }
2505   } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2506     /* If we get an error of the subtitle uridecodebin transform
2507      * them into warnings and disable the subtitles */
2508     group = playbin->curr_group;
2509     if (group && group->suburidecodebin) {
2510       if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2511                   (group->suburidecodebin)))) {
2512         GError *err;
2513         gchar *debug = NULL;
2514         GstMessage *new_msg;
2515         GstIterator *it;
2516         gboolean done = FALSE;
2517         GValue item = { 0, };
2518
2519         gst_message_parse_error (msg, &err, &debug);
2520         new_msg = gst_message_new_warning (msg->src, err, debug);
2521
2522         gst_message_unref (msg);
2523         g_error_free (err);
2524         g_free (debug);
2525         msg = new_msg;
2526
2527         REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2528         REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2529         REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2530         REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2531
2532         it = gst_element_iterate_src_pads (group->suburidecodebin);
2533         while (it && !done) {
2534           GstPad *p = NULL;
2535           GstIteratorResult res;
2536
2537           res = gst_iterator_next (it, &item);
2538
2539           switch (res) {
2540             case GST_ITERATOR_DONE:
2541               done = TRUE;
2542               break;
2543             case GST_ITERATOR_OK:
2544               p = g_value_get_object (&item);
2545               pad_removed_cb (NULL, p, group);
2546               g_value_reset (&item);
2547               break;
2548
2549             case GST_ITERATOR_RESYNC:
2550               gst_iterator_resync (it);
2551               break;
2552             case GST_ITERATOR_ERROR:
2553               done = TRUE;
2554               break;
2555           }
2556         }
2557         g_value_unset (&item);
2558         if (it)
2559           gst_iterator_free (it);
2560
2561         gst_object_ref (group->suburidecodebin);
2562         gst_bin_remove (bin, group->suburidecodebin);
2563         gst_element_set_locked_state (group->suburidecodebin, FALSE);
2564
2565         if (group->sub_pending) {
2566           group->sub_pending = FALSE;
2567           no_more_pads_cb (NULL, group);
2568         }
2569       }
2570     }
2571   }
2572
2573   if (msg)
2574     GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2575 }
2576
2577 static void
2578 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2579     GstPlayBin * playbin)
2580 {
2581   const gchar *property;
2582   GstSourceGroup *group;
2583   GstSourceSelect *select = NULL;
2584   int i;
2585
2586   GST_PLAY_BIN_LOCK (playbin);
2587   group = get_group (playbin);
2588
2589   for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2590     if (selector == G_OBJECT (group->selector[i].selector)) {
2591       select = &group->selector[i];
2592     }
2593   }
2594
2595   /* We got a pad-change after our group got switched out; no need to notify */
2596   if (!select) {
2597     GST_PLAY_BIN_UNLOCK (playbin);
2598     return;
2599   }
2600
2601   switch (select->type) {
2602     case GST_PLAY_SINK_TYPE_VIDEO:
2603     case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2604       property = "current-video";
2605       playbin->current_video = get_current_stream_number (playbin,
2606           group->video_channels);
2607
2608       if (playbin->video_pending_flush_finish) {
2609         playbin->video_pending_flush_finish = FALSE;
2610         GST_PLAY_BIN_UNLOCK (playbin);
2611         gst_playbin2_send_custom_event (GST_OBJECT (selector),
2612             "playsink-custom-video-flush-finish");
2613         goto notify;
2614       }
2615       break;
2616     case GST_PLAY_SINK_TYPE_AUDIO:
2617     case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2618       property = "current-audio";
2619       playbin->current_audio = get_current_stream_number (playbin,
2620           group->audio_channels);
2621
2622       if (playbin->audio_pending_flush_finish) {
2623         playbin->audio_pending_flush_finish = FALSE;
2624         GST_PLAY_BIN_UNLOCK (playbin);
2625         gst_playbin2_send_custom_event (GST_OBJECT (selector),
2626             "playsink-custom-audio-flush-finish");
2627         goto notify;
2628       }
2629       break;
2630     case GST_PLAY_SINK_TYPE_TEXT:
2631       property = "current-text";
2632       playbin->current_text = get_current_stream_number (playbin,
2633           group->text_channels);
2634
2635       if (playbin->text_pending_flush_finish) {
2636         playbin->text_pending_flush_finish = FALSE;
2637         GST_PLAY_BIN_UNLOCK (playbin);
2638         gst_playbin2_send_custom_event (GST_OBJECT (selector),
2639             "playsink-custom-subtitle-flush-finish");
2640         goto notify;
2641       }
2642       break;
2643     default:
2644       property = NULL;
2645   }
2646   GST_PLAY_BIN_UNLOCK (playbin);
2647
2648 notify:
2649   if (property)
2650     g_object_notify (G_OBJECT (playbin), property);
2651 }
2652
2653 /* this callback sends a delayed event once the pad becomes unblocked */
2654 static GstPadProbeReturn
2655 stream_changed_data_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
2656 {
2657   GstMiniObject *object = GST_PAD_PROBE_INFO_DATA (info);
2658   GstSourceSelect *select = (GstSourceSelect *) data;
2659   GstEvent *e;
2660
2661   /* we need do this just once, so cleanup first */
2662   gst_pad_remove_probe (pad, select->sinkpad_data_probe);
2663   select->sinkpad_data_probe = 0;
2664   e = select->sinkpad_delayed_event;
2665   select->sinkpad_delayed_event = NULL;
2666
2667   /* really, this should not happen */
2668   if (!e) {
2669     GST_WARNING ("Data probed called, but no delayed event");
2670     return GST_PAD_PROBE_OK;
2671   }
2672
2673   if (GST_IS_EVENT (object)
2674       && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_SEGMENT) {
2675     /* push the event first, then send the delayed one */
2676     gst_event_ref (GST_EVENT_CAST (object));
2677     gst_pad_send_event (pad, GST_EVENT_CAST (object));
2678     gst_pad_send_event (pad, e);
2679     return GST_PAD_PROBE_DROP;
2680   } else {
2681     /* send delayed event, then allow the caller to go on */
2682     gst_pad_send_event (pad, e);
2683     return GST_PAD_PROBE_OK;
2684   }
2685 }
2686
2687 static GstPadProbeReturn
2688 _suburidecodebin_event_probe (GstPad * pad, GstPadProbeInfo * info,
2689     gpointer udata)
2690 {
2691   GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2692   GstSourceGroup *group = udata;
2693   GstEvent *event = GST_PAD_PROBE_INFO_DATA (info);
2694
2695   switch (GST_EVENT_TYPE (event)) {
2696     case GST_EVENT_FLUSH_START:
2697     case GST_EVENT_FLUSH_STOP:
2698     {
2699       guint32 seqnum = gst_event_get_seqnum (event);
2700       GSList *item = g_slist_find (group->suburi_flushes_to_drop,
2701           GUINT_TO_POINTER (seqnum));
2702       if (item) {
2703         ret = GST_PAD_PROBE_DROP;       /* this is from subtitle seek only, drop it */
2704         if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2705           group->suburi_flushes_to_drop =
2706               g_slist_delete_link (group->suburi_flushes_to_drop, item);
2707         }
2708       }
2709     }
2710     default:
2711       break;
2712   }
2713   return ret;
2714 }
2715
2716 /* helper function to lookup stuff in lists */
2717 static gboolean
2718 array_has_value (const gchar * values[], const gchar * value, gboolean exact)
2719 {
2720   gint i;
2721
2722   for (i = 0; values[i]; i++) {
2723     if (exact && !strcmp (value, values[i]))
2724       return TRUE;
2725     if (!exact && g_str_has_prefix (value, values[i]))
2726       return TRUE;
2727   }
2728   return FALSE;
2729 }
2730
2731 typedef struct
2732 {
2733   GstPlayBin *playbin;
2734   gint stream_id;
2735   GstPlaySinkType type;
2736 } NotifyTagsData;
2737
2738 static void
2739 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2740 {
2741   NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2742   gint signal;
2743
2744   GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2745       " with stream id %d and type %d have changed",
2746       object, ntdata->stream_id, ntdata->type);
2747
2748   switch (ntdata->type) {
2749     case GST_PLAY_SINK_TYPE_VIDEO:
2750     case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2751       signal = SIGNAL_VIDEO_TAGS_CHANGED;
2752       break;
2753     case GST_PLAY_SINK_TYPE_AUDIO:
2754     case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2755       signal = SIGNAL_AUDIO_TAGS_CHANGED;
2756       break;
2757     case GST_PLAY_SINK_TYPE_TEXT:
2758       signal = SIGNAL_TEXT_TAGS_CHANGED;
2759       break;
2760     default:
2761       signal = -1;
2762       break;
2763   }
2764
2765   if (signal >= 0)
2766     g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2767         ntdata->stream_id);
2768 }
2769
2770 /* this function is called when a new pad is added to decodebin. We check the
2771  * type of the pad and add it to the selector element of the group.
2772  */
2773 static void
2774 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2775 {
2776   GstPlayBin *playbin;
2777   GstCaps *caps;
2778   const GstStructure *s;
2779   const gchar *name;
2780   GstPad *sinkpad;
2781   GstPadLinkReturn res;
2782   GstSourceSelect *select = NULL;
2783   gint i, pass;
2784   gboolean changed = FALSE;
2785
2786   playbin = group->playbin;
2787
2788   caps = gst_pad_query_caps (pad, NULL);
2789   s = gst_caps_get_structure (caps, 0);
2790   name = gst_structure_get_name (s);
2791
2792   GST_DEBUG_OBJECT (playbin,
2793       "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2794       GST_DEBUG_PAD_NAME (pad), caps, group);
2795
2796   /* major type of the pad, this determines the selector to use,
2797      try exact match first so we don't prematurely match video/
2798      for video/x-dvd-subpicture */
2799   for (pass = 0; !select && pass < 2; pass++) {
2800     for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2801       if (array_has_value (group->selector[i].media_list, name, pass == 0)) {
2802         select = &group->selector[i];
2803         break;
2804       } else if (group->selector[i].get_media_caps) {
2805         GstCaps *media_caps = group->selector[i].get_media_caps ();
2806
2807         if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2808           select = &group->selector[i];
2809           gst_caps_unref (media_caps);
2810           break;
2811         }
2812         gst_caps_unref (media_caps);
2813       }
2814     }
2815   }
2816   /* no selector found for the media type, don't bother linking it to a
2817    * selector. This will leave the pad unlinked and thus ignored. */
2818   if (select == NULL)
2819     goto unknown_type;
2820
2821   GST_SOURCE_GROUP_LOCK (group);
2822   if (select->selector == NULL && playbin->have_selector) {
2823     /* no selector, create one */
2824     GST_DEBUG_OBJECT (playbin, "creating new input selector");
2825     select->selector = gst_element_factory_make ("input-selector", NULL);
2826     if (select->selector == NULL) {
2827       /* post the missing selector message only once */
2828       playbin->have_selector = FALSE;
2829       gst_element_post_message (GST_ELEMENT_CAST (playbin),
2830           gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2831               "input-selector"));
2832       GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2833           (_("Missing element '%s' - check your GStreamer installation."),
2834               "input-selector"), (NULL));
2835     } else {
2836       /* sync-mode=1, use clock */
2837       if (select->type == GST_PLAY_SINK_TYPE_TEXT)
2838         g_object_set (select->selector, "sync-streams", TRUE,
2839             "sync-mode", 1, "cache-buffers", TRUE, NULL);
2840       else
2841         g_object_set (select->selector, "sync-streams", TRUE, NULL);
2842
2843       g_signal_connect (select->selector, "notify::active-pad",
2844           G_CALLBACK (selector_active_pad_changed), playbin);
2845
2846       GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2847       gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2848       gst_element_set_state (select->selector, GST_STATE_PAUSED);
2849     }
2850   }
2851
2852   if (select->srcpad == NULL) {
2853     if (select->selector) {
2854       /* save source pad of the selector */
2855       select->srcpad = gst_element_get_static_pad (select->selector, "src");
2856     } else {
2857       /* no selector, use the pad as the source pad then */
2858       select->srcpad = gst_object_ref (pad);
2859     }
2860
2861     /* block the selector srcpad. It's possible that multiple decodebins start
2862      * pushing data into the selectors before we have a chance to collect all
2863      * streams and connect the sinks, resulting in not-linked errors. After we
2864      * configured the sinks we will unblock them all. */
2865     GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2866     select->block_id =
2867         gst_pad_add_probe (select->srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2868         NULL, NULL, NULL);
2869   }
2870
2871   /* get sinkpad for the new stream */
2872   if (select->selector) {
2873     if ((sinkpad = gst_element_get_request_pad (select->selector, "sink_%u"))) {
2874       gulong notify_tags_handler = 0;
2875       NotifyTagsData *ntdata;
2876
2877       GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2878           GST_DEBUG_PAD_NAME (sinkpad));
2879
2880       /* store the selector for the pad */
2881       g_object_set_data (G_OBJECT (sinkpad), "playbin.select", select);
2882
2883       /* connect to the notify::tags signal for our
2884        * own *-tags-changed signals
2885        */
2886       ntdata = g_new0 (NotifyTagsData, 1);
2887       ntdata->playbin = playbin;
2888       ntdata->stream_id = select->channels->len;
2889       ntdata->type = select->type;
2890
2891       notify_tags_handler =
2892           g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2893           G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2894           (GConnectFlags) 0);
2895       g_object_set_data (G_OBJECT (sinkpad), "playbin.notify_tags_handler",
2896           (gpointer) (guintptr) notify_tags_handler);
2897
2898       /* store the pad in the array */
2899       GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2900       g_ptr_array_add (select->channels, sinkpad);
2901
2902       res = gst_pad_link (pad, sinkpad);
2903       if (GST_PAD_LINK_FAILED (res))
2904         goto link_failed;
2905
2906       /* store selector pad so we can release it */
2907       g_object_set_data (G_OBJECT (pad), "playbin.sinkpad", sinkpad);
2908
2909       changed = TRUE;
2910       GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2911           GST_DEBUG_PAD_NAME (pad), select->selector);
2912     }
2913   } else {
2914     /* no selector, don't configure anything, we'll link the new pad directly to
2915      * the sink. */
2916     changed = FALSE;
2917     sinkpad = NULL;
2918
2919     /* store the selector for the pad */
2920     g_object_set_data (G_OBJECT (pad), "playbin2.select", select);
2921   }
2922   GST_SOURCE_GROUP_UNLOCK (group);
2923
2924   if (decodebin == group->suburidecodebin) {
2925     /* TODO store the probe id */
2926     /* to avoid propagating flushes from suburi specific seeks */
2927     gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
2928         _suburidecodebin_event_probe, group, NULL);
2929   }
2930
2931   if (changed) {
2932     int signal;
2933     gboolean always_ok = (decodebin == group->suburidecodebin);
2934
2935     switch (select->type) {
2936       case GST_PLAY_SINK_TYPE_VIDEO:
2937       case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2938         /* we want to return NOT_LINKED for unselected pads but only for pads
2939          * from the normal uridecodebin. This makes sure that subtitle streams
2940          * are not raced past audio/video from decodebin's multiqueue.
2941          * For pads from suburidecodebin OK should always be returned, otherwise
2942          * it will most likely stop. */
2943         g_object_set (sinkpad, "always-ok", always_ok, NULL);
2944         signal = SIGNAL_VIDEO_CHANGED;
2945         break;
2946       case GST_PLAY_SINK_TYPE_AUDIO:
2947       case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2948         g_object_set (sinkpad, "always-ok", always_ok, NULL);
2949         signal = SIGNAL_AUDIO_CHANGED;
2950         break;
2951       case GST_PLAY_SINK_TYPE_TEXT:
2952         g_object_set (sinkpad, "always-ok", always_ok, NULL);
2953         signal = SIGNAL_TEXT_CHANGED;
2954         break;
2955       default:
2956         signal = -1;
2957     }
2958
2959     if (signal >= 0)
2960       g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2961   }
2962
2963 done:
2964   gst_caps_unref (caps);
2965   return;
2966
2967   /* ERRORS */
2968 unknown_type:
2969   {
2970     GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2971         name, GST_DEBUG_PAD_NAME (pad));
2972     goto done;
2973   }
2974 link_failed:
2975   {
2976     GST_ERROR_OBJECT (playbin,
2977         "failed to link pad %s:%s to selector, reason %d",
2978         GST_DEBUG_PAD_NAME (pad), res);
2979     GST_SOURCE_GROUP_UNLOCK (group);
2980     goto done;
2981   }
2982 }
2983
2984 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2985  * the selector. This will make the selector select a new pad. */
2986 static void
2987 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2988 {
2989   GstPlayBin *playbin;
2990   GstPad *peer;
2991   GstElement *selector;
2992   GstSourceSelect *select;
2993
2994   playbin = group->playbin;
2995
2996   GST_DEBUG_OBJECT (playbin,
2997       "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2998
2999   GST_SOURCE_GROUP_LOCK (group);
3000
3001   if ((select = g_object_get_data (G_OBJECT (pad), "playbin2.select"))) {
3002     g_assert (select->selector == NULL);
3003     g_assert (select->srcpad == pad);
3004     gst_object_unref (pad);
3005     select->srcpad = NULL;
3006     goto exit;
3007   }
3008
3009   /* get the selector sinkpad */
3010   if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin.sinkpad")))
3011     goto not_linked;
3012
3013   if ((select = g_object_get_data (G_OBJECT (peer), "playbin.select"))) {
3014     gulong notify_tags_handler;
3015
3016     notify_tags_handler =
3017         (guintptr) g_object_get_data (G_OBJECT (peer),
3018         "playbin.notify_tags_handler");
3019     if (notify_tags_handler != 0)
3020       g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
3021     g_object_set_data (G_OBJECT (peer), "playbin.notify_tags_handler", NULL);
3022
3023     /* remove the pad from the array */
3024     g_ptr_array_remove (select->channels, peer);
3025     GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
3026
3027     if (!select->channels->len && select->selector) {
3028       GST_DEBUG_OBJECT (playbin, "all selector sinkpads removed");
3029       GST_DEBUG_OBJECT (playbin, "removing selector %p", select->selector);
3030       gst_object_unref (select->srcpad);
3031       select->srcpad = NULL;
3032       gst_element_set_state (select->selector, GST_STATE_NULL);
3033       gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3034       select->selector = NULL;
3035     }
3036   }
3037
3038   /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
3039   gst_pad_unlink (pad, peer);
3040
3041   /* get selector, this can be NULL when the element is removing the pads
3042    * because it's being disposed. */
3043   selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
3044   if (!selector) {
3045     gst_object_unref (peer);
3046     goto no_selector;
3047   }
3048
3049   /* release the pad to the selector, this will make the selector choose a new
3050    * pad. */
3051   gst_element_release_request_pad (selector, peer);
3052   gst_object_unref (peer);
3053
3054   gst_object_unref (selector);
3055 exit:
3056   GST_SOURCE_GROUP_UNLOCK (group);
3057
3058   return;
3059
3060   /* ERRORS */
3061 not_linked:
3062   {
3063     GST_DEBUG_OBJECT (playbin, "pad not linked");
3064     GST_SOURCE_GROUP_UNLOCK (group);
3065     return;
3066   }
3067 no_selector:
3068   {
3069     GST_DEBUG_OBJECT (playbin, "selector not found");
3070     GST_SOURCE_GROUP_UNLOCK (group);
3071     return;
3072   }
3073 }
3074
3075 /* we get called when all pads are available and we must connect the sinks to
3076  * them.
3077  * The main purpose of the code is to see if we have video/audio and subtitles
3078  * and pick the right pipelines to display them.
3079  *
3080  * The selectors installed on the group tell us about the presence of
3081  * audio/video and subtitle streams. This allows us to see if we need
3082  * visualisation, video or/and audio.
3083  */
3084 static void
3085 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
3086 {
3087   GstPlayBin *playbin;
3088   GstPadLinkReturn res;
3089   gint i;
3090   gboolean configure;
3091
3092   playbin = group->playbin;
3093
3094   GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
3095
3096   GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
3097
3098   GST_SOURCE_GROUP_LOCK (group);
3099   for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3100     GstSourceSelect *select = &group->selector[i];
3101
3102     /* check if the specific media type was detected and thus has a selector
3103      * created for it. If there is the media type, get a sinkpad from the sink
3104      * and link it. We only do this if we have not yet requested the sinkpad
3105      * before. */
3106     if (select->srcpad && select->sinkpad == NULL) {
3107       GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
3108       select->sinkpad =
3109           gst_play_sink_request_pad (playbin->playsink, select->type);
3110     } else if (select->srcpad && select->sinkpad) {
3111       GST_DEBUG_OBJECT (playbin, "refreshing new sink pad %d", select->type);
3112       gst_play_sink_refresh_pad (playbin->playsink, select->sinkpad,
3113           select->type);
3114     } else if (select->sinkpad && select->srcpad == NULL) {
3115       GST_DEBUG_OBJECT (playbin, "releasing sink pad %d", select->type);
3116       gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3117       select->sinkpad = NULL;
3118     }
3119     if (select->sinkpad && select->srcpad &&
3120         !gst_pad_is_linked (select->srcpad)) {
3121       res = gst_pad_link (select->srcpad, select->sinkpad);
3122       GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
3123           select->media_list[0], res);
3124       if (res != GST_PAD_LINK_OK) {
3125         GST_ELEMENT_ERROR (playbin, CORE, PAD,
3126             ("Internal playbin error."),
3127             ("Failed to link selector to sink. Error %d", res));
3128       }
3129     }
3130   }
3131   GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
3132       group->pending - 1);
3133
3134   if (group->pending > 0)
3135     group->pending--;
3136
3137   if (group->suburidecodebin == decodebin)
3138     group->sub_pending = FALSE;
3139
3140   if (group->pending == 0) {
3141     /* we are the last group to complete, we will configure the output and then
3142      * signal the other waiters. */
3143     GST_LOG_OBJECT (playbin, "last group complete");
3144     configure = TRUE;
3145   } else {
3146     GST_LOG_OBJECT (playbin, "have more pending groups");
3147     configure = FALSE;
3148   }
3149   GST_SOURCE_GROUP_UNLOCK (group);
3150
3151   if (configure) {
3152     /* if we have custom sinks, configure them now */
3153     GST_SOURCE_GROUP_LOCK (group);
3154
3155     if (group->audio_sink) {
3156       GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
3157           group->audio_sink);
3158       gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
3159           group->audio_sink);
3160     }
3161
3162     if (group->video_sink) {
3163       GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
3164           group->video_sink);
3165       gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
3166           group->video_sink);
3167     }
3168
3169     if (playbin->text_sink) {
3170       GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
3171           playbin->text_sink);
3172       gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
3173           playbin->text_sink);
3174     }
3175
3176     GST_SOURCE_GROUP_UNLOCK (group);
3177
3178     /* signal the other decodebins that they can continue now. */
3179     GST_SOURCE_GROUP_LOCK (group);
3180     /* unblock all selectors */
3181     for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3182       GstSourceSelect *select = &group->selector[i];
3183
3184       /* All streamsynchronizer streams should see stream-changed message,
3185        * to arrange for blocking unblocking. */
3186       if (select->sinkpad) {
3187         GstStructure *s;
3188         GstMessage *msg;
3189         GstEvent *event;
3190         guint32 seqnum;
3191
3192         s = gst_structure_new ("playbin-stream-changed", "uri", G_TYPE_STRING,
3193             group->uri, NULL);
3194         if (group->suburi)
3195           gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
3196         msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
3197         seqnum = gst_message_get_seqnum (msg);
3198         event = gst_event_new_sink_message ("GstPlaybin", msg);
3199         g_mutex_lock (&group->stream_changed_pending_lock);
3200         group->stream_changed_pending =
3201             g_list_prepend (group->stream_changed_pending,
3202             GUINT_TO_POINTER (seqnum));
3203
3204         /* remove any data probe we might have, and replace */
3205         if (select->sinkpad_delayed_event)
3206           gst_event_unref (select->sinkpad_delayed_event);
3207         select->sinkpad_delayed_event = event;
3208         if (select->sinkpad_data_probe)
3209           gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
3210
3211         /* we go to the trouble of setting a probe on the pad to send
3212            the playbin-stream-changed event as sending it here might
3213            find that the pad is blocked, so we'd block here, and the
3214            pad might not be linked yet. Additionally, sending it here
3215            apparently would be on the wrong thread */
3216         select->sinkpad_data_probe =
3217             gst_pad_add_probe (select->sinkpad,
3218             GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
3219             stream_changed_data_probe, (gpointer) select, NULL);
3220
3221         g_mutex_unlock (&group->stream_changed_pending_lock);
3222         gst_message_unref (msg);
3223       }
3224
3225       if (select->srcpad) {
3226         GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
3227             select->srcpad);
3228         if (select->block_id) {
3229           gst_pad_remove_probe (select->srcpad, select->block_id);
3230           select->block_id = 0;
3231         }
3232       }
3233     }
3234     GST_SOURCE_GROUP_UNLOCK (group);
3235   }
3236
3237   GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
3238
3239   return;
3240
3241 shutdown:
3242   {
3243     GST_DEBUG ("ignoring, we are shutting down");
3244     /* Request a flushing pad from playsink that we then link to the selector.
3245      * Then we unblock the selectors so that they stop with a WRONG_STATE
3246      * instead of a NOT_LINKED error.
3247      */
3248     GST_SOURCE_GROUP_LOCK (group);
3249     for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3250       GstSourceSelect *select = &group->selector[i];
3251
3252       if (select->srcpad) {
3253         if (select->sinkpad == NULL) {
3254           GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
3255           select->sinkpad =
3256               gst_play_sink_request_pad (playbin->playsink,
3257               GST_PLAY_SINK_TYPE_FLUSHING);
3258           res = gst_pad_link (select->srcpad, select->sinkpad);
3259           GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
3260         }
3261         GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
3262             select->srcpad);
3263         if (select->block_id) {
3264           gst_pad_remove_probe (select->srcpad, select->block_id);
3265           select->block_id = 0;
3266         }
3267       }
3268     }
3269     GST_SOURCE_GROUP_UNLOCK (group);
3270     return;
3271   }
3272 }
3273
3274 static void
3275 drained_cb (GstElement * decodebin, GstSourceGroup * group)
3276 {
3277   GstPlayBin *playbin;
3278
3279   playbin = group->playbin;
3280
3281   GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
3282
3283   /* after this call, we should have a next group to activate or we EOS */
3284   g_signal_emit (G_OBJECT (playbin),
3285       gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
3286
3287   /* now activate the next group. If the app did not set a uri, this will
3288    * fail and we can do EOS */
3289   setup_next_source (playbin, GST_STATE_PAUSED);
3290 }
3291
3292 /* Like gst_element_factory_can_sink_any_caps() but doesn't
3293  * allow ANY caps on the sinkpad template */
3294 static gboolean
3295 _factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps)
3296 {
3297   const GList *templs;
3298
3299   templs = gst_element_factory_get_static_pad_templates (factory);
3300
3301   while (templs) {
3302     GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
3303
3304     if (templ->direction == GST_PAD_SINK) {
3305       GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
3306
3307       if (!gst_caps_is_any (templcaps)
3308           && gst_caps_can_intersect (templcaps, caps)) {
3309         gst_caps_unref (templcaps);
3310         return TRUE;
3311       }
3312       gst_caps_unref (templcaps);
3313     }
3314     templs = g_list_next (templs);
3315   }
3316
3317   return FALSE;
3318 }
3319
3320 /* Called when we must provide a list of factories to plug to @pad with @caps.
3321  * We first check if we have a sink that can handle the format and if we do, we
3322  * return NULL, to expose the pad. If we have no sink (or the sink does not
3323  * work), we return the list of elements that can connect. */
3324 static GValueArray *
3325 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
3326     GstCaps * caps, GstSourceGroup * group)
3327 {
3328   GstPlayBin *playbin;
3329   GList *mylist, *tmp;
3330   GValueArray *result;
3331
3332   playbin = group->playbin;
3333
3334   GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
3335       group, GST_DEBUG_PAD_NAME (pad), caps);
3336
3337   /* filter out the elements based on the caps. */
3338   g_mutex_lock (&playbin->elements_lock);
3339   gst_play_bin_update_elements_list (playbin);
3340   mylist =
3341       gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
3342       FALSE);
3343   g_mutex_unlock (&playbin->elements_lock);
3344
3345   GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
3346   GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
3347
3348   /* 2 additional elements for the already set audio/video sinks */
3349   result = g_value_array_new (g_list_length (mylist) + 2);
3350
3351   /* Check if we already have an audio/video sink and if this is the case
3352    * put it as the first element of the array */
3353   if (group->audio_sink) {
3354     GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
3355
3356     if (factory && _factory_can_sink_caps (factory, caps)) {
3357       GValue val = { 0, };
3358
3359       g_value_init (&val, G_TYPE_OBJECT);
3360       g_value_set_object (&val, factory);
3361       result = g_value_array_append (result, &val);
3362       g_value_unset (&val);
3363     }
3364   }
3365
3366   if (group->video_sink) {
3367     GstElementFactory *factory = gst_element_get_factory (group->video_sink);
3368
3369     if (factory && _factory_can_sink_caps (factory, caps)) {
3370       GValue val = { 0, };
3371
3372       g_value_init (&val, G_TYPE_OBJECT);
3373       g_value_set_object (&val, factory);
3374       result = g_value_array_append (result, &val);
3375       g_value_unset (&val);
3376     }
3377   }
3378
3379   for (tmp = mylist; tmp; tmp = tmp->next) {
3380     GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
3381     GValue val = { 0, };
3382
3383     if (group->audio_sink && gst_element_factory_list_is_type (factory,
3384             GST_ELEMENT_FACTORY_TYPE_SINK |
3385             GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
3386       continue;
3387     }
3388     if (group->video_sink && gst_element_factory_list_is_type (factory,
3389             GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
3390             | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
3391       continue;
3392     }
3393
3394     g_value_init (&val, G_TYPE_OBJECT);
3395     g_value_set_object (&val, factory);
3396     g_value_array_append (result, &val);
3397     g_value_unset (&val);
3398   }
3399   gst_plugin_feature_list_free (mylist);
3400
3401   return result;
3402 }
3403
3404 /* autoplug-continue decides, if a pad has raw caps that can be exposed
3405  * directly or if further decoding is necessary. We use this to expose
3406  * supported subtitles directly */
3407
3408 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
3409  * explicitly the caps it supports and if it claims to support ANY
3410  * caps it really should support everything */
3411 static gboolean
3412 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
3413     GstSourceGroup * group)
3414 {
3415   gboolean ret = TRUE;
3416   GstElement *sink;
3417   GstPad *sinkpad = NULL;
3418
3419   GST_SOURCE_GROUP_LOCK (group);
3420
3421   if ((sink = group->playbin->text_sink))
3422     sinkpad = gst_element_get_static_pad (sink, "sink");
3423   if (sinkpad) {
3424     GstCaps *sinkcaps;
3425
3426     /* Ignore errors here, if a custom sink fails to go
3427      * to READY things are wrong and will error out later
3428      */
3429     if (GST_STATE (sink) < GST_STATE_READY)
3430       gst_element_set_state (sink, GST_STATE_READY);
3431
3432     sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3433     if (!gst_caps_is_any (sinkcaps))
3434       ret = !gst_pad_query_accept_caps (sinkpad, caps);
3435     gst_caps_unref (sinkcaps);
3436     gst_object_unref (sinkpad);
3437   } else {
3438     GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3439     ret = !gst_caps_is_subset (caps, subcaps);
3440     gst_caps_unref (subcaps);
3441   }
3442   /* If autoplugging can stop don't do additional checks */
3443   if (!ret)
3444     goto done;
3445
3446   /* If this is from the subtitle uridecodebin we don't need to
3447    * check the audio and video sink */
3448   if (group->suburidecodebin
3449       && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3450           GST_OBJECT_CAST (group->suburidecodebin)))
3451     goto done;
3452
3453   if ((sink = group->audio_sink)) {
3454     sinkpad = gst_element_get_static_pad (sink, "sink");
3455     if (sinkpad) {
3456       GstCaps *sinkcaps;
3457
3458       /* Ignore errors here, if a custom sink fails to go
3459        * to READY things are wrong and will error out later
3460        */
3461       if (GST_STATE (sink) < GST_STATE_READY)
3462         gst_element_set_state (sink, GST_STATE_READY);
3463
3464       sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3465       if (!gst_caps_is_any (sinkcaps))
3466         ret = !gst_pad_query_accept_caps (sinkpad, caps);
3467       gst_caps_unref (sinkcaps);
3468       gst_object_unref (sinkpad);
3469     }
3470   }
3471   if (!ret)
3472     goto done;
3473
3474   if ((sink = group->video_sink)) {
3475     sinkpad = gst_element_get_static_pad (sink, "sink");
3476     if (sinkpad) {
3477       GstCaps *sinkcaps;
3478
3479       /* Ignore errors here, if a custom sink fails to go
3480        * to READY things are wrong and will error out later
3481        */
3482       if (GST_STATE (sink) < GST_STATE_READY)
3483         gst_element_set_state (sink, GST_STATE_READY);
3484
3485       sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3486       if (!gst_caps_is_any (sinkcaps))
3487         ret = !gst_pad_query_accept_caps (sinkpad, caps);
3488       gst_caps_unref (sinkcaps);
3489       gst_object_unref (sinkpad);
3490     }
3491   }
3492
3493 done:
3494   GST_SOURCE_GROUP_UNLOCK (group);
3495
3496   GST_DEBUG_OBJECT (group->playbin,
3497       "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3498       group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3499
3500   return ret;
3501 }
3502
3503 static gboolean
3504 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3505 {
3506   GstPad *sinkpad;
3507
3508   /* ... activate it ... We do this before adding it to the bin so that we
3509    * don't accidentally make it post error messages that will stop
3510    * everything. */
3511   if (GST_STATE (sink) < GST_STATE_READY &&
3512       gst_element_set_state (sink,
3513           GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3514     return FALSE;
3515   }
3516
3517   if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3518     /* Got the sink pad, now let's see if the element actually does accept the
3519      * caps that we have */
3520     if (!gst_pad_query_accept_caps (sinkpad, caps)) {
3521       gst_object_unref (sinkpad);
3522       return FALSE;
3523     }
3524     gst_object_unref (sinkpad);
3525   }
3526
3527   return TRUE;
3528 }
3529
3530 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw");
3531 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw");
3532
3533 /* We are asked to select an element. See if the next element to check
3534  * is a sink. If this is the case, we see if the sink works by setting it to
3535  * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3536  * expose the raw pad so that we can setup the mixers. */
3537 static GstAutoplugSelectResult
3538 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3539     GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3540 {
3541   GstPlayBin *playbin;
3542   GstElement *element;
3543   const gchar *klass;
3544   GstPlaySinkType type;
3545   GstElement **sinkp;
3546
3547   playbin = group->playbin;
3548
3549   GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3550       group, GST_DEBUG_PAD_NAME (pad), caps);
3551
3552   GST_DEBUG_OBJECT (playbin, "checking factory %s", GST_OBJECT_NAME (factory));
3553
3554   /* if it's not a sink, we make sure the element is compatible with
3555    * the fixed sink */
3556   if (!gst_element_factory_list_is_type (factory,
3557           GST_ELEMENT_FACTORY_TYPE_SINK)) {
3558     gboolean isvideodec = gst_element_factory_list_is_type (factory,
3559         GST_ELEMENT_FACTORY_TYPE_DECODER |
3560         GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
3561         GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
3562     gboolean isaudiodec = gst_element_factory_list_is_type (factory,
3563         GST_ELEMENT_FACTORY_TYPE_DECODER |
3564         GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
3565
3566     /* If it is a decoder and we have a fixed sink for the media
3567      * type it outputs, check that the decoder is compatible with this sink */
3568     if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) {
3569       gboolean compatible = TRUE;
3570       GstPad *sinkpad;
3571       GstCaps *caps;
3572       GstElement *sink;
3573
3574       if (isaudiodec)
3575         sink = group->audio_sink;
3576       else
3577         sink = group->video_sink;
3578
3579       if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3580         GstPlayFlags flags = gst_play_bin_get_flags (playbin);
3581         GstCaps *raw_caps =
3582             (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) :
3583             gst_static_caps_get (&raw_video_caps);
3584
3585         caps = gst_pad_query_caps (sinkpad, NULL);
3586
3587         /* If the sink supports raw audio/video, we first check
3588          * if the decoder could output any raw audio/video format
3589          * and assume it is compatible with the sink then. We don't
3590          * do a complete compatibility check here if converters
3591          * are plugged between the decoder and the sink because
3592          * the converters will convert between raw formats and
3593          * even if the decoder format is not supported by the decoder
3594          * a converter will convert it.
3595          *
3596          * We assume here that the converters can convert between
3597          * any raw format.
3598          */
3599         if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO)
3600                 && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec
3601                 && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO)
3602                 && gst_caps_can_intersect (caps, raw_caps))) {
3603           compatible = gst_element_factory_can_src_any_caps (factory, raw_caps)
3604               || gst_element_factory_can_src_any_caps (factory, caps);
3605         } else {
3606           compatible = gst_element_factory_can_src_any_caps (factory, caps);
3607         }
3608
3609         gst_object_unref (sinkpad);
3610         gst_caps_unref (caps);
3611       }
3612
3613       if (compatible)
3614         return GST_AUTOPLUG_SELECT_TRY;
3615
3616       GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink",
3617           GST_OBJECT_NAME (factory));
3618
3619       return GST_AUTOPLUG_SELECT_SKIP;
3620     } else
3621       return GST_AUTOPLUG_SELECT_TRY;
3622   }
3623
3624   /* it's a sink, see if an instance of it actually works */
3625   GST_DEBUG_OBJECT (playbin, "we found a sink");
3626
3627   klass = gst_element_factory_get_klass (factory);
3628
3629   /* figure out the klass */
3630   if (strstr (klass, "Audio")) {
3631     GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3632     type = GST_PLAY_SINK_TYPE_AUDIO;
3633     sinkp = &group->audio_sink;
3634   } else if (strstr (klass, "Video")) {
3635     GST_DEBUG_OBJECT (playbin, "we found a video sink");
3636     type = GST_PLAY_SINK_TYPE_VIDEO;
3637     sinkp = &group->video_sink;
3638   } else {
3639     /* unknown klass, skip this element */
3640     GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3641     return GST_AUTOPLUG_SELECT_SKIP;
3642   }
3643
3644   /* if we are asked to do visualisations and it's an audio sink, skip the
3645    * element. We can only do visualisations with raw sinks */
3646   if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3647     if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3648       GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3649       return GST_AUTOPLUG_SELECT_SKIP;
3650     }
3651   }
3652
3653   /* now see if we already have a sink element */
3654   GST_SOURCE_GROUP_LOCK (group);
3655   if (*sinkp) {
3656     GstElement *sink = gst_object_ref (*sinkp);
3657
3658     if (sink_accepts_caps (sink, caps)) {
3659       GST_DEBUG_OBJECT (playbin,
3660           "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3661           GST_ELEMENT_NAME (sink), caps);
3662       gst_object_unref (sink);
3663       GST_SOURCE_GROUP_UNLOCK (group);
3664       return GST_AUTOPLUG_SELECT_EXPOSE;
3665     } else {
3666       GST_DEBUG_OBJECT (playbin,
3667           "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3668           GST_ELEMENT_NAME (sink), caps);
3669       gst_object_unref (sink);
3670       GST_SOURCE_GROUP_UNLOCK (group);
3671       return GST_AUTOPLUG_SELECT_SKIP;
3672     }
3673   }
3674   GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3675
3676   if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3677     GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3678         gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3679     GST_SOURCE_GROUP_UNLOCK (group);
3680     return GST_AUTOPLUG_SELECT_SKIP;
3681   }
3682
3683   /* Check if the selected sink actually supports the
3684    * caps and can be set to READY*/
3685   if (!sink_accepts_caps (element, caps)) {
3686     gst_element_set_state (element, GST_STATE_NULL);
3687     gst_object_unref (element);
3688     GST_SOURCE_GROUP_UNLOCK (group);
3689     return GST_AUTOPLUG_SELECT_SKIP;
3690   }
3691
3692   /* remember the sink in the group now, the element is floating, we take
3693    * ownership now 
3694    *
3695    * store the sink in the group, we will configure it later when we
3696    * reconfigure the sink */
3697   GST_DEBUG_OBJECT (playbin, "remember sink");
3698   gst_object_ref_sink (element);
3699   *sinkp = element;
3700   GST_SOURCE_GROUP_UNLOCK (group);
3701
3702   /* tell decodebin to expose the pad because we are going to use this
3703    * sink */
3704   GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3705
3706   return GST_AUTOPLUG_SELECT_EXPOSE;
3707 }
3708
3709 static void
3710 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3711     GstSourceGroup * group)
3712 {
3713   GstPlayBin *playbin;
3714   GstElement *source;
3715
3716   playbin = group->playbin;
3717
3718   g_object_get (group->uridecodebin, "source", &source, NULL);
3719
3720   GST_OBJECT_LOCK (playbin);
3721   if (playbin->source)
3722     gst_object_unref (playbin->source);
3723   playbin->source = source;
3724   GST_OBJECT_UNLOCK (playbin);
3725
3726   g_object_notify (G_OBJECT (playbin), "source");
3727
3728   g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3729       0, playbin->source);
3730 }
3731
3732 /* must be called with the group lock */
3733 static gboolean
3734 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3735     gboolean locked)
3736 {
3737   GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3738
3739   if (group->uridecodebin)
3740     gst_element_set_locked_state (group->uridecodebin, locked);
3741   if (group->suburidecodebin)
3742     gst_element_set_locked_state (group->suburidecodebin, locked);
3743
3744   return TRUE;
3745 }
3746
3747 /* must be called with PLAY_BIN_LOCK */
3748 static gboolean
3749 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3750 {
3751   GstElement *uridecodebin;
3752   GstElement *suburidecodebin = NULL;
3753   GstPlayFlags flags;
3754
3755   g_return_val_if_fail (group->valid, FALSE);
3756   g_return_val_if_fail (!group->active, FALSE);
3757
3758   GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3759
3760   GST_SOURCE_GROUP_LOCK (group);
3761
3762   /* First set up the custom sources */
3763   if (playbin->audio_sink)
3764     group->audio_sink = gst_object_ref (playbin->audio_sink);
3765   if (playbin->video_sink)
3766     group->video_sink = gst_object_ref (playbin->video_sink);
3767
3768   g_list_free (group->stream_changed_pending);
3769   group->stream_changed_pending = NULL;
3770   if (!group->stream_changed_pending_lock.p)
3771     g_mutex_init (&group->stream_changed_pending_lock);
3772
3773   g_slist_free (group->suburi_flushes_to_drop);
3774   group->suburi_flushes_to_drop = NULL;
3775   if (!group->suburi_flushes_to_drop_lock.p)
3776     g_mutex_init (&group->suburi_flushes_to_drop_lock);
3777
3778   if (group->uridecodebin) {
3779     GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3780     uridecodebin = group->uridecodebin;
3781     gst_element_set_state (uridecodebin, GST_STATE_READY);
3782     /* no need to take extra ref, we already have one
3783      * and the bin will add one since it is no longer floating,
3784      * as it was at least added once before (below) */
3785     gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3786   } else {
3787     GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3788     uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3789     if (!uridecodebin)
3790       goto no_decodebin;
3791     gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3792     group->uridecodebin = gst_object_ref (uridecodebin);
3793   }
3794
3795   flags = gst_play_sink_get_flags (playbin->playsink);
3796
3797   g_object_set (uridecodebin,
3798       /* configure connection speed */
3799       "connection-speed", playbin->connection_speed / 1000,
3800       /* configure uri */
3801       "uri", group->uri,
3802       /* configure download buffering */
3803       "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3804       /* configure buffering of demuxed/parsed data */
3805       "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3806       /* configure buffering parameters */
3807       "buffer-duration", playbin->buffer_duration,
3808       "buffer-size", playbin->buffer_size,
3809       "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3810
3811   /* connect pads and other things */
3812   group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3813       G_CALLBACK (pad_added_cb), group);
3814   group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3815       G_CALLBACK (pad_removed_cb), group);
3816   group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3817       G_CALLBACK (no_more_pads_cb), group);
3818   group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3819       G_CALLBACK (notify_source_cb), group);
3820
3821   /* we have 1 pending no-more-pads */
3822   group->pending = 1;
3823
3824   /* is called when the uridecodebin is out of data and we can switch to the
3825    * next uri */
3826   group->drained_id =
3827       g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3828       group);
3829
3830   /* will be called when a new media type is found. We return a list of decoders
3831    * including sinks for decodebin to try */
3832   group->autoplug_factories_id =
3833       g_signal_connect (uridecodebin, "autoplug-factories",
3834       G_CALLBACK (autoplug_factories_cb), group);
3835   group->autoplug_select_id =
3836       g_signal_connect (uridecodebin, "autoplug-select",
3837       G_CALLBACK (autoplug_select_cb), group);
3838   group->autoplug_continue_id =
3839       g_signal_connect (uridecodebin, "autoplug-continue",
3840       G_CALLBACK (autoplug_continue_cb), group);
3841
3842   if (group->suburi) {
3843     /* subtitles */
3844     if (group->suburidecodebin) {
3845       GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3846       suburidecodebin = group->suburidecodebin;
3847       gst_element_set_state (suburidecodebin, GST_STATE_READY);
3848       /* no need to take extra ref, we already have one
3849        * and the bin will add one since it is no longer floating,
3850        * as it was at least added once before (below) */
3851       gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3852     } else {
3853       GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3854       suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3855       if (!suburidecodebin)
3856         goto no_decodebin;
3857
3858       gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3859       group->suburidecodebin = gst_object_ref (suburidecodebin);
3860     }
3861
3862     g_object_set (suburidecodebin,
3863         /* configure connection speed */
3864         "connection-speed", playbin->connection_speed,
3865         /* configure uri */
3866         "uri", group->suburi, NULL);
3867
3868     /* connect pads and other things */
3869     group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3870         G_CALLBACK (pad_added_cb), group);
3871     group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3872         "pad-removed", G_CALLBACK (pad_removed_cb), group);
3873     group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3874         "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3875
3876     group->sub_autoplug_continue_id =
3877         g_signal_connect (suburidecodebin, "autoplug-continue",
3878         G_CALLBACK (autoplug_continue_cb), group);
3879
3880     /* we have 2 pending no-more-pads */
3881     group->pending = 2;
3882     group->sub_pending = TRUE;
3883   } else {
3884     group->sub_pending = FALSE;
3885   }
3886
3887   /* release the group lock before setting the state of the decodebins, they
3888    * might fire signals in this thread that we need to handle with the
3889    * group_lock taken. */
3890   GST_SOURCE_GROUP_UNLOCK (group);
3891
3892   if (suburidecodebin) {
3893     if (gst_element_set_state (suburidecodebin,
3894             target) == GST_STATE_CHANGE_FAILURE) {
3895       GST_DEBUG_OBJECT (playbin,
3896           "failed state change of subtitle uridecodebin");
3897       GST_SOURCE_GROUP_LOCK (group);
3898
3899       REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3900       REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3901       REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3902       REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3903       /* Might already be removed because of an error message */
3904       if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3905         gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3906       if (group->sub_pending) {
3907         group->pending--;
3908         group->sub_pending = FALSE;
3909       }
3910       gst_element_set_state (suburidecodebin, GST_STATE_READY);
3911       GST_SOURCE_GROUP_UNLOCK (group);
3912     }
3913   }
3914   if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3915     goto uridecodebin_failure;
3916
3917   GST_SOURCE_GROUP_LOCK (group);
3918   /* alow state changes of the playbin affect the group elements now */
3919   group_set_locked_state_unlocked (playbin, group, FALSE);
3920   group->active = TRUE;
3921   GST_SOURCE_GROUP_UNLOCK (group);
3922
3923   return TRUE;
3924
3925   /* ERRORS */
3926 no_decodebin:
3927   {
3928     GstMessage *msg;
3929
3930     /* delete any custom sinks we might have */
3931     if (group->audio_sink) {
3932       /* If this is a automatically created sink set it to NULL */
3933       if (group->audio_sink != playbin->audio_sink)
3934         gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3935       gst_object_unref (group->audio_sink);
3936     }
3937     group->audio_sink = NULL;
3938     if (group->video_sink) {
3939       /* If this is a automatically created sink set it to NULL */
3940       if (group->video_sink != playbin->video_sink)
3941         gst_element_set_state (group->video_sink, GST_STATE_NULL);
3942       gst_object_unref (group->video_sink);
3943     }
3944     group->video_sink = NULL;
3945
3946     GST_SOURCE_GROUP_UNLOCK (group);
3947     msg =
3948         gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3949         "uridecodebin");
3950     gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3951
3952     GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3953         (_("Could not create \"uridecodebin\" element.")), (NULL));
3954     return FALSE;
3955   }
3956 uridecodebin_failure:
3957   {
3958     /* delete any custom sinks we might have */
3959     if (group->audio_sink) {
3960       /* If this is a automatically created sink set it to NULL */
3961       if (group->audio_sink != playbin->audio_sink)
3962         gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3963       gst_object_unref (group->audio_sink);
3964     }
3965     group->audio_sink = NULL;
3966     if (group->video_sink) {
3967       /* If this is a automatically created sink set it to NULL */
3968       if (group->video_sink != playbin->video_sink)
3969         gst_element_set_state (group->video_sink, GST_STATE_NULL);
3970       gst_object_unref (group->video_sink);
3971     }
3972     group->video_sink = NULL;
3973
3974     GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3975     return FALSE;
3976   }
3977 }
3978
3979 /* unlink a group of uridecodebins from the sink.
3980  * must be called with PLAY_BIN_LOCK */
3981 static gboolean
3982 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3983 {
3984   gint i;
3985
3986   g_return_val_if_fail (group->valid, FALSE);
3987   g_return_val_if_fail (group->active, FALSE);
3988
3989   GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3990
3991   GST_SOURCE_GROUP_LOCK (group);
3992   group->active = FALSE;
3993   for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3994     GstSourceSelect *select = &group->selector[i];
3995
3996     GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3997
3998     if (select->srcpad) {
3999       if (select->sinkpad) {
4000         GST_LOG_OBJECT (playbin, "unlinking from sink");
4001         gst_pad_unlink (select->srcpad, select->sinkpad);
4002
4003         /* release back */
4004         GST_LOG_OBJECT (playbin, "release sink pad");
4005         gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
4006         select->sinkpad = NULL;
4007       }
4008
4009       gst_object_unref (select->srcpad);
4010       select->srcpad = NULL;
4011     }
4012
4013     if (select->selector) {
4014       gint n;
4015
4016       /* release and unref requests pad from the selector */
4017       for (n = 0; n < select->channels->len; n++) {
4018         GstPad *sinkpad = g_ptr_array_index (select->channels, n);
4019
4020         gst_element_release_request_pad (select->selector, sinkpad);
4021         gst_object_unref (sinkpad);
4022       }
4023       g_ptr_array_set_size (select->channels, 0);
4024
4025       gst_element_set_state (select->selector, GST_STATE_NULL);
4026       gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
4027       select->selector = NULL;
4028     }
4029   }
4030   /* delete any custom sinks we might have */
4031   if (group->audio_sink) {
4032     /* If this is a automatically created sink set it to NULL */
4033     if (group->audio_sink != playbin->audio_sink)
4034       gst_element_set_state (group->audio_sink, GST_STATE_NULL);
4035     gst_object_unref (group->audio_sink);
4036   }
4037   group->audio_sink = NULL;
4038   if (group->video_sink) {
4039     /* If this is a automatically created sink set it to NULL */
4040     if (group->video_sink != playbin->video_sink)
4041       gst_element_set_state (group->video_sink, GST_STATE_NULL);
4042     gst_object_unref (group->video_sink);
4043   }
4044   group->video_sink = NULL;
4045
4046   if (group->uridecodebin) {
4047     REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
4048     REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
4049     REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
4050     REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
4051     REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
4052     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
4053     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
4054     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
4055     gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
4056   }
4057
4058   if (group->suburidecodebin) {
4059     REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
4060     REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
4061     REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
4062     REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
4063
4064     /* Might already be removed because of errors */
4065     if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
4066       gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
4067   }
4068
4069   GST_SOURCE_GROUP_UNLOCK (group);
4070
4071   return TRUE;
4072 }
4073
4074 /* setup the next group to play, this assumes the next_group is valid and
4075  * configured. It swaps out the current_group and activates the valid
4076  * next_group. */
4077 static gboolean
4078 setup_next_source (GstPlayBin * playbin, GstState target)
4079 {
4080   GstSourceGroup *new_group, *old_group;
4081
4082   GST_DEBUG_OBJECT (playbin, "setup sources");
4083
4084   /* see if there is a next group */
4085   GST_PLAY_BIN_LOCK (playbin);
4086   new_group = playbin->next_group;
4087   if (!new_group || !new_group->valid)
4088     goto no_next_group;
4089
4090   /* first unlink the current source, if any */
4091   old_group = playbin->curr_group;
4092   if (old_group && old_group->valid && old_group->active) {
4093     gst_play_bin_update_cached_duration (playbin);
4094     /* unlink our pads with the sink */
4095     deactivate_group (playbin, old_group);
4096     old_group->valid = FALSE;
4097   }
4098
4099   /* swap old and new */
4100   playbin->curr_group = new_group;
4101   playbin->next_group = old_group;
4102
4103   /* activate the new group */
4104   if (!activate_group (playbin, new_group, target))
4105     goto activate_failed;
4106
4107   GST_PLAY_BIN_UNLOCK (playbin);
4108
4109   return TRUE;
4110
4111   /* ERRORS */
4112 no_next_group:
4113   {
4114     GST_DEBUG_OBJECT (playbin, "no next group");
4115     if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
4116       GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
4117     GST_PLAY_BIN_UNLOCK (playbin);
4118     return FALSE;
4119   }
4120 activate_failed:
4121   {
4122     GST_DEBUG_OBJECT (playbin, "activate failed");
4123     GST_PLAY_BIN_UNLOCK (playbin);
4124     return FALSE;
4125   }
4126 }
4127
4128 /* The group that is currently playing is copied again to the
4129  * next_group so that it will start playing the next time.
4130  */
4131 static gboolean
4132 save_current_group (GstPlayBin * playbin)
4133 {
4134   GstSourceGroup *curr_group;
4135
4136   GST_DEBUG_OBJECT (playbin, "save current group");
4137
4138   /* see if there is a current group */
4139   GST_PLAY_BIN_LOCK (playbin);
4140   curr_group = playbin->curr_group;
4141   if (curr_group && curr_group->valid && curr_group->active) {
4142     /* unlink our pads with the sink */
4143     deactivate_group (playbin, curr_group);
4144   }
4145   /* swap old and new */
4146   playbin->curr_group = playbin->next_group;
4147   playbin->next_group = curr_group;
4148   GST_PLAY_BIN_UNLOCK (playbin);
4149
4150   return TRUE;
4151 }
4152
4153 /* clear the locked state from all groups. This function is called before a
4154  * state change to NULL is performed on them. */
4155 static gboolean
4156 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
4157 {
4158   GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
4159       locked);
4160
4161   GST_PLAY_BIN_LOCK (playbin);
4162   GST_SOURCE_GROUP_LOCK (playbin->curr_group);
4163   group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
4164   GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
4165   GST_SOURCE_GROUP_LOCK (playbin->next_group);
4166   group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
4167   GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
4168   GST_PLAY_BIN_UNLOCK (playbin);
4169
4170   return TRUE;
4171 }
4172
4173 static GstStateChangeReturn
4174 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
4175 {
4176   GstStateChangeReturn ret;
4177   GstPlayBin *playbin;
4178   gboolean do_save = FALSE;
4179
4180   playbin = GST_PLAY_BIN (element);
4181
4182   switch (transition) {
4183     case GST_STATE_CHANGE_NULL_TO_READY:
4184       memset (&playbin->duration, 0, sizeof (playbin->duration));
4185       break;
4186     case GST_STATE_CHANGE_READY_TO_PAUSED:
4187       GST_LOG_OBJECT (playbin, "clearing shutdown flag");
4188       memset (&playbin->duration, 0, sizeof (playbin->duration));
4189       g_atomic_int_set (&playbin->shutdown, 0);
4190
4191       if (!setup_next_source (playbin, GST_STATE_READY)) {
4192         ret = GST_STATE_CHANGE_FAILURE;
4193         goto failure;
4194       }
4195       break;
4196     case GST_STATE_CHANGE_PAUSED_TO_READY:
4197     async_down:
4198       /* FIXME unlock our waiting groups */
4199       GST_LOG_OBJECT (playbin, "setting shutdown flag");
4200       g_atomic_int_set (&playbin->shutdown, 1);
4201       memset (&playbin->duration, 0, sizeof (playbin->duration));
4202
4203       /* wait for all callbacks to end by taking the lock.
4204        * No dynamic (critical) new callbacks will
4205        * be able to happen as we set the shutdown flag. */
4206       GST_PLAY_BIN_DYN_LOCK (playbin);
4207       GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
4208       GST_PLAY_BIN_DYN_UNLOCK (playbin);
4209       if (!do_save)
4210         break;
4211     case GST_STATE_CHANGE_READY_TO_NULL:
4212       /* we go async to PAUSED, so if that fails, we never make it to PAUSED
4213        * an no state change PAUSED to READY passes here,
4214        * though it is a nice-to-have ... */
4215       if (!g_atomic_int_get (&playbin->shutdown)) {
4216         do_save = TRUE;
4217         goto async_down;
4218       }
4219       memset (&playbin->duration, 0, sizeof (playbin->duration));
4220
4221       /* unlock so that all groups go to NULL */
4222       groups_set_locked_state (playbin, FALSE);
4223       break;
4224     default:
4225       break;
4226   }
4227
4228   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4229   if (ret == GST_STATE_CHANGE_FAILURE)
4230     goto failure;
4231
4232   switch (transition) {
4233     case GST_STATE_CHANGE_READY_TO_PAUSED:
4234       break;
4235     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4236       /* FIXME Release audio device when we implement that */
4237       break;
4238     case GST_STATE_CHANGE_PAUSED_TO_READY:
4239       save_current_group (playbin);
4240       break;
4241     case GST_STATE_CHANGE_READY_TO_NULL:
4242     {
4243       guint i;
4244
4245       /* also do missed state change down to READY */
4246       if (do_save)
4247         save_current_group (playbin);
4248       /* Deactive the groups, set the uridecodebins to NULL
4249        * and unref them.
4250        */
4251       for (i = 0; i < 2; i++) {
4252         if (playbin->groups[i].active && playbin->groups[i].valid) {
4253           deactivate_group (playbin, &playbin->groups[i]);
4254           playbin->groups[i].valid = FALSE;
4255         }
4256
4257         if (playbin->groups[i].uridecodebin) {
4258           gst_element_set_state (playbin->groups[i].uridecodebin,
4259               GST_STATE_NULL);
4260           gst_object_unref (playbin->groups[i].uridecodebin);
4261           playbin->groups[i].uridecodebin = NULL;
4262         }
4263
4264         if (playbin->groups[i].suburidecodebin) {
4265           gst_element_set_state (playbin->groups[i].suburidecodebin,
4266               GST_STATE_NULL);
4267           gst_object_unref (playbin->groups[i].suburidecodebin);
4268           playbin->groups[i].suburidecodebin = NULL;
4269         }
4270       }
4271
4272       /* Set our sinks back to NULL, they might not be child of playbin */
4273       if (playbin->audio_sink)
4274         gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
4275       if (playbin->video_sink)
4276         gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
4277       if (playbin->text_sink)
4278         gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
4279
4280       /* make sure the groups don't perform a state change anymore until we
4281        * enable them again */
4282       groups_set_locked_state (playbin, TRUE);
4283       break;
4284     }
4285     default:
4286       break;
4287   }
4288
4289   return ret;
4290
4291   /* ERRORS */
4292 failure:
4293   {
4294     if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
4295       GstSourceGroup *curr_group;
4296
4297       curr_group = playbin->curr_group;
4298       if (curr_group && curr_group->active && curr_group->valid) {
4299         /* unlink our pads with the sink */
4300         deactivate_group (playbin, curr_group);
4301         curr_group->valid = FALSE;
4302       }
4303
4304       /* Swap current and next group back */
4305       playbin->curr_group = playbin->next_group;
4306       playbin->next_group = curr_group;
4307     }
4308     return ret;
4309   }
4310 }
4311
4312 static void
4313 gst_play_bin_overlay_expose (GstVideoOverlay * overlay)
4314 {
4315   GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4316
4317   gst_video_overlay_expose (GST_VIDEO_OVERLAY (playbin->playsink));
4318 }
4319
4320 static void
4321 gst_play_bin_overlay_handle_events (GstVideoOverlay * overlay,
4322     gboolean handle_events)
4323 {
4324   GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4325
4326   gst_video_overlay_handle_events (GST_VIDEO_OVERLAY (playbin->playsink),
4327       handle_events);
4328 }
4329
4330 static void
4331 gst_play_bin_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x,
4332     gint y, gint width, gint height)
4333 {
4334   GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4335
4336   gst_video_overlay_set_render_rectangle (GST_VIDEO_OVERLAY (playbin->playsink),
4337       x, y, width, height);
4338 }
4339
4340 static void
4341 gst_play_bin_overlay_set_window_handle (GstVideoOverlay * overlay,
4342     guintptr handle)
4343 {
4344   GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4345
4346   gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (playbin->playsink),
4347       handle);
4348 }
4349
4350 static void
4351 gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data)
4352 {
4353   GstVideoOverlayInterface *iface = (GstVideoOverlayInterface *) g_iface;
4354   iface->expose = gst_play_bin_overlay_expose;
4355   iface->handle_events = gst_play_bin_overlay_handle_events;
4356   iface->set_render_rectangle = gst_play_bin_overlay_set_render_rectangle;
4357   iface->set_window_handle = gst_play_bin_overlay_set_window_handle;
4358 }
4359
4360 static void
4361 gst_play_bin_navigation_send_event (GstNavigation * navigation,
4362     GstStructure * structure)
4363 {
4364   GstPlayBin *playbin = GST_PLAY_BIN (navigation);
4365
4366   gst_navigation_send_event (GST_NAVIGATION (playbin->playsink), structure);
4367 }
4368
4369 static void
4370 gst_play_bin_navigation_init (gpointer g_iface, gpointer g_iface_data)
4371 {
4372   GstNavigationInterface *iface = (GstNavigationInterface *) g_iface;
4373
4374   iface->send_event = gst_play_bin_navigation_send_event;
4375 }
4376
4377 static const GList *
4378 gst_play_bin_colorbalance_list_channels (GstColorBalance * balance)
4379 {
4380   GstPlayBin *playbin = GST_PLAY_BIN (balance);
4381
4382   return
4383       gst_color_balance_list_channels (GST_COLOR_BALANCE (playbin->playsink));
4384 }
4385
4386 static void
4387 gst_play_bin_colorbalance_set_value (GstColorBalance * balance,
4388     GstColorBalanceChannel * channel, gint value)
4389 {
4390   GstPlayBin *playbin = GST_PLAY_BIN (balance);
4391
4392   gst_color_balance_set_value (GST_COLOR_BALANCE (playbin->playsink), channel,
4393       value);
4394 }
4395
4396 static gint
4397 gst_play_bin_colorbalance_get_value (GstColorBalance * balance,
4398     GstColorBalanceChannel * channel)
4399 {
4400   GstPlayBin *playbin = GST_PLAY_BIN (balance);
4401
4402   return gst_color_balance_get_value (GST_COLOR_BALANCE (playbin->playsink),
4403       channel);
4404 }
4405
4406 static GstColorBalanceType
4407 gst_play_bin_colorbalance_get_balance_type (GstColorBalance * balance)
4408 {
4409   GstPlayBin *playbin = GST_PLAY_BIN (balance);
4410
4411   return
4412       gst_color_balance_get_balance_type (GST_COLOR_BALANCE
4413       (playbin->playsink));
4414 }
4415
4416 static void
4417 gst_play_bin_colorbalance_init (gpointer g_iface, gpointer g_iface_data)
4418 {
4419   GstColorBalanceInterface *iface = (GstColorBalanceInterface *) g_iface;
4420
4421   iface->list_channels = gst_play_bin_colorbalance_list_channels;
4422   iface->set_value = gst_play_bin_colorbalance_set_value;
4423   iface->get_value = gst_play_bin_colorbalance_get_value;
4424   iface->get_balance_type = gst_play_bin_colorbalance_get_balance_type;
4425 }
4426
4427 gboolean
4428 gst_play_bin2_plugin_init (GstPlugin * plugin)
4429 {
4430   GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin", 0, "play bin");
4431
4432   return gst_element_register (plugin, "playbin", GST_RANK_NONE,
4433       GST_TYPE_PLAY_BIN);
4434 }