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