00743948a01f84f153d567547715cb79ee5d7588
[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_PLAY_BIN_LOCK (group->playbin);
3183   GST_SOURCE_GROUP_LOCK (group);
3184
3185   if ((sink = group->playbin->text_sink))
3186     sinkpad = gst_element_get_static_pad (sink, "sink");
3187   if (sinkpad) {
3188     GstCaps *sinkcaps;
3189
3190     /* Ignore errors here, if a custom sink fails to go
3191      * to READY things are wrong and will error out later
3192      */
3193     if (GST_STATE (sink) < GST_STATE_READY)
3194       gst_element_set_state (sink, GST_STATE_READY);
3195
3196     sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3197     if (!gst_caps_is_any (sinkcaps))
3198       ret = !gst_pad_accept_caps (sinkpad, caps);
3199     gst_caps_unref (sinkcaps);
3200     gst_object_unref (sinkpad);
3201   } else {
3202     GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3203     ret = !gst_caps_is_subset (caps, subcaps);
3204     gst_caps_unref (subcaps);
3205   }
3206   /* If autoplugging can stop don't do additional checks */
3207   if (!ret)
3208     goto done;
3209
3210   /* If this is from the subtitle uridecodebin we don't need to
3211    * check the audio and video sink */
3212   if (group->suburidecodebin
3213       && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3214           GST_OBJECT_CAST (group->suburidecodebin)))
3215     goto done;
3216
3217   if ((sink = group->audio_sink)) {
3218     sinkpad = gst_element_get_static_pad (sink, "sink");
3219     if (sinkpad) {
3220       GstCaps *sinkcaps;
3221
3222       /* Ignore errors here, if a custom sink fails to go
3223        * to READY things are wrong and will error out later
3224        */
3225       if (GST_STATE (sink) < GST_STATE_READY)
3226         gst_element_set_state (sink, GST_STATE_READY);
3227
3228       sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3229       if (!gst_caps_is_any (sinkcaps))
3230         ret = !gst_pad_accept_caps (sinkpad, caps);
3231       gst_caps_unref (sinkcaps);
3232       gst_object_unref (sinkpad);
3233     }
3234   }
3235   if (!ret)
3236     goto done;
3237
3238   if ((sink = group->video_sink)) {
3239     sinkpad = gst_element_get_static_pad (sink, "sink");
3240     if (sinkpad) {
3241       GstCaps *sinkcaps;
3242
3243       /* Ignore errors here, if a custom sink fails to go
3244        * to READY things are wrong and will error out later
3245        */
3246       if (GST_STATE (sink) < GST_STATE_READY)
3247         gst_element_set_state (sink, GST_STATE_READY);
3248
3249       sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3250       if (!gst_caps_is_any (sinkcaps))
3251         ret = !gst_pad_accept_caps (sinkpad, caps);
3252       gst_caps_unref (sinkcaps);
3253       gst_object_unref (sinkpad);
3254     }
3255   }
3256
3257 done:
3258   GST_SOURCE_GROUP_UNLOCK (group);
3259   GST_PLAY_BIN_UNLOCK (group->playbin);
3260
3261   GST_DEBUG_OBJECT (group->playbin,
3262       "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3263       group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3264
3265   return ret;
3266 }
3267
3268 static gboolean
3269 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3270 {
3271   GstPad *sinkpad;
3272
3273   /* ... activate it ... We do this before adding it to the bin so that we
3274    * don't accidentally make it post error messages that will stop
3275    * everything. */
3276   if (GST_STATE (sink) < GST_STATE_READY &&
3277       gst_element_set_state (sink,
3278           GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3279     return FALSE;
3280   }
3281
3282   if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3283     /* Got the sink pad, now let's see if the element actually does accept the
3284      * caps that we have */
3285     if (!gst_pad_accept_caps (sinkpad, caps)) {
3286       gst_object_unref (sinkpad);
3287       return FALSE;
3288     }
3289     gst_object_unref (sinkpad);
3290   }
3291
3292   return TRUE;
3293 }
3294
3295 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw-int; "
3296     "audio/x-raw-float");
3297 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw-rgb; "
3298     "video/x-raw-yuv; " "video/x-raw-gray");
3299
3300 /* We are asked to select an element. See if the next element to check
3301  * is a sink. If this is the case, we see if the sink works by setting it to
3302  * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3303  * expose the raw pad so that we can setup the mixers. */
3304 static GstAutoplugSelectResult
3305 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3306     GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3307 {
3308   GstPlayBin *playbin;
3309   GstElement *element;
3310   const gchar *klass;
3311   GstPlaySinkType type;
3312   GstElement **sinkp;
3313
3314   playbin = group->playbin;
3315
3316   GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3317       group, GST_DEBUG_PAD_NAME (pad), caps);
3318
3319   GST_DEBUG_OBJECT (playbin, "checking factory %s",
3320       GST_PLUGIN_FEATURE_NAME (factory));
3321
3322   /* if it's not a sink, we make sure the element is compatible with
3323    * the fixed sink */
3324   if (!gst_element_factory_list_is_type (factory,
3325           GST_ELEMENT_FACTORY_TYPE_SINK)) {
3326     gboolean isvideodec = gst_element_factory_list_is_type (factory,
3327         GST_ELEMENT_FACTORY_TYPE_DECODER |
3328         GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
3329         GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
3330     gboolean isaudiodec = gst_element_factory_list_is_type (factory,
3331         GST_ELEMENT_FACTORY_TYPE_DECODER |
3332         GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
3333
3334     /* If it is a decoder and we have a fixed sink for the media
3335      * type it outputs, check that the decoder is compatible with this sink */
3336     if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) {
3337       gboolean compatible = TRUE;
3338       GstPad *sinkpad;
3339       GstCaps *caps;
3340       GstElement *sink;
3341
3342       if (isaudiodec)
3343         sink = group->audio_sink;
3344       else
3345         sink = group->video_sink;
3346
3347       if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3348         GstPlayFlags flags = gst_play_bin_get_flags (playbin);
3349         GstCaps *raw_caps =
3350             (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) :
3351             gst_static_caps_get (&raw_video_caps);
3352
3353         caps = gst_pad_get_caps_reffed (sinkpad);
3354
3355         /* If the sink supports raw audio/video, we first check
3356          * if the decoder could output any raw audio/video format
3357          * and assume it is compatible with the sink then. We don't
3358          * do a complete compatibility check here if converters
3359          * are plugged between the decoder and the sink because
3360          * the converters will convert between raw formats and
3361          * even if the decoder format is not supported by the decoder
3362          * a converter will convert it.
3363          *
3364          * We assume here that the converters can convert between
3365          * any raw format.
3366          */
3367         if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO)
3368                 && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec
3369                 && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO)
3370                 && gst_caps_can_intersect (caps, raw_caps))) {
3371           compatible = gst_element_factory_can_src_any_caps (factory, raw_caps)
3372               || gst_element_factory_can_src_any_caps (factory, caps);
3373         } else {
3374           compatible = gst_element_factory_can_src_any_caps (factory, caps);
3375         }
3376
3377         gst_object_unref (sinkpad);
3378         gst_caps_unref (caps);
3379       }
3380
3381       if (compatible)
3382         return GST_AUTOPLUG_SELECT_TRY;
3383
3384       GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink",
3385           GST_PLUGIN_FEATURE_NAME (factory));
3386
3387       return GST_AUTOPLUG_SELECT_SKIP;
3388     } else
3389       return GST_AUTOPLUG_SELECT_TRY;
3390   }
3391
3392   /* it's a sink, see if an instance of it actually works */
3393   GST_DEBUG_OBJECT (playbin, "we found a sink");
3394
3395   klass = gst_element_factory_get_klass (factory);
3396
3397   /* figure out the klass */
3398   if (strstr (klass, "Audio")) {
3399     GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3400     type = GST_PLAY_SINK_TYPE_AUDIO;
3401     sinkp = &group->audio_sink;
3402   } else if (strstr (klass, "Video")) {
3403     GST_DEBUG_OBJECT (playbin, "we found a video sink");
3404     type = GST_PLAY_SINK_TYPE_VIDEO;
3405     sinkp = &group->video_sink;
3406   } else {
3407     /* unknown klass, skip this element */
3408     GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3409     return GST_AUTOPLUG_SELECT_SKIP;
3410   }
3411
3412   /* if we are asked to do visualisations and it's an audio sink, skip the
3413    * element. We can only do visualisations with raw sinks */
3414   if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3415     if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3416       GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3417       return GST_AUTOPLUG_SELECT_SKIP;
3418     }
3419   }
3420
3421   /* now see if we already have a sink element */
3422   GST_SOURCE_GROUP_LOCK (group);
3423   if (*sinkp) {
3424     GstElement *sink = gst_object_ref (*sinkp);
3425
3426     if (sink_accepts_caps (sink, caps)) {
3427       GST_DEBUG_OBJECT (playbin,
3428           "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3429           GST_ELEMENT_NAME (sink), caps);
3430       gst_object_unref (sink);
3431       GST_SOURCE_GROUP_UNLOCK (group);
3432       return GST_AUTOPLUG_SELECT_EXPOSE;
3433     } else {
3434       GST_DEBUG_OBJECT (playbin,
3435           "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3436           GST_ELEMENT_NAME (sink), caps);
3437       gst_object_unref (sink);
3438       GST_SOURCE_GROUP_UNLOCK (group);
3439       return GST_AUTOPLUG_SELECT_SKIP;
3440     }
3441   }
3442   GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3443
3444   if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3445     GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3446         gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3447     GST_SOURCE_GROUP_UNLOCK (group);
3448     return GST_AUTOPLUG_SELECT_SKIP;
3449   }
3450
3451   /* Check if the selected sink actually supports the
3452    * caps and can be set to READY*/
3453   if (!sink_accepts_caps (element, caps)) {
3454     gst_element_set_state (element, GST_STATE_NULL);
3455     gst_object_unref (element);
3456     GST_SOURCE_GROUP_UNLOCK (group);
3457     return GST_AUTOPLUG_SELECT_SKIP;
3458   }
3459
3460   /* remember the sink in the group now, the element is floating, we take
3461    * ownership now 
3462    *
3463    * store the sink in the group, we will configure it later when we
3464    * reconfigure the sink */
3465   GST_DEBUG_OBJECT (playbin, "remember sink");
3466   gst_object_ref_sink (element);
3467   *sinkp = element;
3468   GST_SOURCE_GROUP_UNLOCK (group);
3469
3470   /* tell decodebin to expose the pad because we are going to use this
3471    * sink */
3472   GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3473
3474   return GST_AUTOPLUG_SELECT_EXPOSE;
3475 }
3476
3477 static void
3478 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3479     GstSourceGroup * group)
3480 {
3481   GstPlayBin *playbin;
3482   GstElement *source;
3483
3484   playbin = group->playbin;
3485
3486   g_object_get (group->uridecodebin, "source", &source, NULL);
3487
3488   GST_OBJECT_LOCK (playbin);
3489   if (playbin->source)
3490     gst_object_unref (playbin->source);
3491   playbin->source = source;
3492   GST_OBJECT_UNLOCK (playbin);
3493
3494   g_object_notify (G_OBJECT (playbin), "source");
3495
3496   g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3497       0, playbin->source);
3498 }
3499
3500 /* must be called with the group lock */
3501 static gboolean
3502 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3503     gboolean locked)
3504 {
3505   GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3506
3507   if (group->uridecodebin)
3508     gst_element_set_locked_state (group->uridecodebin, locked);
3509   if (group->suburidecodebin)
3510     gst_element_set_locked_state (group->suburidecodebin, locked);
3511
3512   return TRUE;
3513 }
3514
3515 /* must be called with PLAY_BIN_LOCK */
3516 static gboolean
3517 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3518 {
3519   GstElement *uridecodebin;
3520   GstElement *suburidecodebin = NULL;
3521   GstPlayFlags flags;
3522
3523   g_return_val_if_fail (group->valid, FALSE);
3524   g_return_val_if_fail (!group->active, FALSE);
3525
3526   GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3527
3528   GST_SOURCE_GROUP_LOCK (group);
3529
3530   /* First set up the custom sources */
3531   if (playbin->audio_sink)
3532     group->audio_sink = gst_object_ref (playbin->audio_sink);
3533   if (playbin->video_sink)
3534     group->video_sink = gst_object_ref (playbin->video_sink);
3535
3536   g_list_free (group->stream_changed_pending);
3537   group->stream_changed_pending = NULL;
3538   if (!group->stream_changed_pending_lock)
3539     group->stream_changed_pending_lock = g_mutex_new ();
3540
3541   if (group->uridecodebin) {
3542     GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3543     uridecodebin = group->uridecodebin;
3544     gst_element_set_state (uridecodebin, GST_STATE_READY);
3545     /* no need to take extra ref, we already have one
3546      * and the bin will add one since it is no longer floating,
3547      * as it was at least added once before (below) */
3548     gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3549   } else {
3550     GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3551     uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3552     if (!uridecodebin)
3553       goto no_decodebin;
3554     gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3555     group->uridecodebin = gst_object_ref (uridecodebin);
3556   }
3557
3558   flags = gst_play_sink_get_flags (playbin->playsink);
3559
3560   g_object_set (uridecodebin,
3561       /* configure connection speed */
3562       "connection-speed", playbin->connection_speed / 1000,
3563       /* configure uri */
3564       "uri", group->uri,
3565       /* configure download buffering */
3566       "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3567       /* configure buffering of demuxed/parsed data */
3568       "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3569       /* configure buffering parameters */
3570       "buffer-duration", playbin->buffer_duration,
3571       "buffer-size", playbin->buffer_size,
3572       "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3573
3574   /* connect pads and other things */
3575   group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3576       G_CALLBACK (pad_added_cb), group);
3577   group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3578       G_CALLBACK (pad_removed_cb), group);
3579   group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3580       G_CALLBACK (no_more_pads_cb), group);
3581   group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3582       G_CALLBACK (notify_source_cb), group);
3583
3584   /* we have 1 pending no-more-pads */
3585   group->pending = 1;
3586
3587   /* is called when the uridecodebin is out of data and we can switch to the
3588    * next uri */
3589   group->drained_id =
3590       g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3591       group);
3592
3593   /* will be called when a new media type is found. We return a list of decoders
3594    * including sinks for decodebin to try */
3595   group->autoplug_factories_id =
3596       g_signal_connect (uridecodebin, "autoplug-factories",
3597       G_CALLBACK (autoplug_factories_cb), group);
3598   group->autoplug_select_id =
3599       g_signal_connect (uridecodebin, "autoplug-select",
3600       G_CALLBACK (autoplug_select_cb), group);
3601   group->autoplug_continue_id =
3602       g_signal_connect (uridecodebin, "autoplug-continue",
3603       G_CALLBACK (autoplug_continue_cb), group);
3604
3605   if (group->suburi) {
3606     /* subtitles */
3607     if (group->suburidecodebin) {
3608       GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3609       suburidecodebin = group->suburidecodebin;
3610       gst_element_set_state (suburidecodebin, GST_STATE_READY);
3611       /* no need to take extra ref, we already have one
3612        * and the bin will add one since it is no longer floating,
3613        * as it was at least added once before (below) */
3614       gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3615     } else {
3616       GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3617       suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3618       if (!suburidecodebin)
3619         goto no_decodebin;
3620
3621       gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3622       group->suburidecodebin = gst_object_ref (suburidecodebin);
3623     }
3624
3625     g_object_set (suburidecodebin,
3626         /* configure connection speed */
3627         "connection-speed", playbin->connection_speed,
3628         /* configure uri */
3629         "uri", group->suburi, NULL);
3630
3631     /* connect pads and other things */
3632     group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3633         G_CALLBACK (pad_added_cb), group);
3634     group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3635         "pad-removed", G_CALLBACK (pad_removed_cb), group);
3636     group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3637         "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3638
3639     group->sub_autoplug_continue_id =
3640         g_signal_connect (suburidecodebin, "autoplug-continue",
3641         G_CALLBACK (autoplug_continue_cb), group);
3642
3643     /* we have 2 pending no-more-pads */
3644     group->pending = 2;
3645     group->sub_pending = TRUE;
3646   } else {
3647     group->sub_pending = FALSE;
3648   }
3649
3650   /* release the group lock before setting the state of the decodebins, they
3651    * might fire signals in this thread that we need to handle with the
3652    * group_lock taken. */
3653   GST_SOURCE_GROUP_UNLOCK (group);
3654
3655   if (suburidecodebin) {
3656     if (gst_element_set_state (suburidecodebin,
3657             target) == GST_STATE_CHANGE_FAILURE) {
3658       GST_DEBUG_OBJECT (playbin,
3659           "failed state change of subtitle uridecodebin");
3660       GST_SOURCE_GROUP_LOCK (group);
3661
3662       REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3663       REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3664       REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3665       REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3666       /* Might already be removed because of an error message */
3667       if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3668         gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3669       if (group->sub_pending) {
3670         group->pending--;
3671         group->sub_pending = FALSE;
3672       }
3673       gst_element_set_state (suburidecodebin, GST_STATE_READY);
3674       GST_SOURCE_GROUP_UNLOCK (group);
3675     }
3676   }
3677   if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3678     goto uridecodebin_failure;
3679
3680   GST_SOURCE_GROUP_LOCK (group);
3681   /* alow state changes of the playbin2 affect the group elements now */
3682   group_set_locked_state_unlocked (playbin, group, FALSE);
3683   group->active = TRUE;
3684   GST_SOURCE_GROUP_UNLOCK (group);
3685
3686   return TRUE;
3687
3688   /* ERRORS */
3689 no_decodebin:
3690   {
3691     GstMessage *msg;
3692
3693     /* delete any custom sinks we might have */
3694     if (group->audio_sink) {
3695       /* If this is a automatically created sink set it to NULL */
3696       if (group->audio_sink != playbin->audio_sink)
3697         gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3698       gst_object_unref (group->audio_sink);
3699     }
3700     group->audio_sink = NULL;
3701     if (group->video_sink) {
3702       /* If this is a automatically created sink set it to NULL */
3703       if (group->video_sink != playbin->video_sink)
3704         gst_element_set_state (group->video_sink, GST_STATE_NULL);
3705       gst_object_unref (group->video_sink);
3706     }
3707     group->video_sink = NULL;
3708
3709     GST_SOURCE_GROUP_UNLOCK (group);
3710     msg =
3711         gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3712         "uridecodebin");
3713     gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3714
3715     GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3716         (_("Could not create \"uridecodebin\" element.")), (NULL));
3717     return FALSE;
3718   }
3719 uridecodebin_failure:
3720   {
3721     /* delete any custom sinks we might have */
3722     if (group->audio_sink) {
3723       /* If this is a automatically created sink set it to NULL */
3724       if (group->audio_sink != playbin->audio_sink)
3725         gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3726       gst_object_unref (group->audio_sink);
3727     }
3728     group->audio_sink = NULL;
3729     if (group->video_sink) {
3730       /* If this is a automatically created sink set it to NULL */
3731       if (group->video_sink != playbin->video_sink)
3732         gst_element_set_state (group->video_sink, GST_STATE_NULL);
3733       gst_object_unref (group->video_sink);
3734     }
3735     group->video_sink = NULL;
3736
3737     GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3738     return FALSE;
3739   }
3740 }
3741
3742 /* unlink a group of uridecodebins from the sink.
3743  * must be called with PLAY_BIN_LOCK */
3744 static gboolean
3745 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3746 {
3747   gint i;
3748
3749   g_return_val_if_fail (group->valid, FALSE);
3750   g_return_val_if_fail (group->active, FALSE);
3751
3752   GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3753
3754   GST_SOURCE_GROUP_LOCK (group);
3755   group->active = FALSE;
3756   for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3757     GstSourceSelect *select = &group->selector[i];
3758
3759     GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3760
3761     if (select->srcpad) {
3762       if (select->sinkpad) {
3763         GST_LOG_OBJECT (playbin, "unlinking from sink");
3764         gst_pad_unlink (select->srcpad, select->sinkpad);
3765
3766         /* release back */
3767         GST_LOG_OBJECT (playbin, "release sink pad");
3768         gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3769         select->sinkpad = NULL;
3770       }
3771
3772       gst_object_unref (select->srcpad);
3773       select->srcpad = NULL;
3774     }
3775
3776     if (select->selector) {
3777       gint n;
3778
3779       /* release and unref requests pad from the selector */
3780       for (n = 0; n < select->channels->len; n++) {
3781         GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3782
3783         gst_element_release_request_pad (select->selector, sinkpad);
3784         gst_object_unref (sinkpad);
3785       }
3786       g_ptr_array_set_size (select->channels, 0);
3787
3788       gst_element_set_state (select->selector, GST_STATE_NULL);
3789       gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3790       select->selector = NULL;
3791     }
3792   }
3793   /* delete any custom sinks we might have */
3794   if (group->audio_sink) {
3795     /* If this is a automatically created sink set it to NULL */
3796     if (group->audio_sink != playbin->audio_sink)
3797       gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3798     gst_object_unref (group->audio_sink);
3799   }
3800   group->audio_sink = NULL;
3801   if (group->video_sink) {
3802     /* If this is a automatically created sink set it to NULL */
3803     if (group->video_sink != playbin->video_sink)
3804       gst_element_set_state (group->video_sink, GST_STATE_NULL);
3805     gst_object_unref (group->video_sink);
3806   }
3807   group->video_sink = NULL;
3808
3809   if (group->uridecodebin) {
3810     REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3811     REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3812     REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3813     REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3814     REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3815     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3816     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3817     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3818     gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3819   }
3820
3821   if (group->suburidecodebin) {
3822     REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3823     REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3824     REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3825     REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3826
3827     /* Might already be removed because of errors */
3828     if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3829       gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3830   }
3831
3832   GST_SOURCE_GROUP_UNLOCK (group);
3833
3834   return TRUE;
3835 }
3836
3837 /* setup the next group to play, this assumes the next_group is valid and
3838  * configured. It swaps out the current_group and activates the valid
3839  * next_group. */
3840 static gboolean
3841 setup_next_source (GstPlayBin * playbin, GstState target)
3842 {
3843   GstSourceGroup *new_group, *old_group;
3844
3845   GST_DEBUG_OBJECT (playbin, "setup sources");
3846
3847   /* see if there is a next group */
3848   GST_PLAY_BIN_LOCK (playbin);
3849   new_group = playbin->next_group;
3850   if (!new_group || !new_group->valid)
3851     goto no_next_group;
3852
3853   /* first unlink the current source, if any */
3854   old_group = playbin->curr_group;
3855   if (old_group && old_group->valid && old_group->active) {
3856     gst_play_bin_update_cached_duration (playbin);
3857     /* unlink our pads with the sink */
3858     deactivate_group (playbin, old_group);
3859     old_group->valid = FALSE;
3860   }
3861
3862   /* swap old and new */
3863   playbin->curr_group = new_group;
3864   playbin->next_group = old_group;
3865
3866   /* activate the new group */
3867   if (!activate_group (playbin, new_group, target))
3868     goto activate_failed;
3869
3870   GST_PLAY_BIN_UNLOCK (playbin);
3871
3872   return TRUE;
3873
3874   /* ERRORS */
3875 no_next_group:
3876   {
3877     GST_DEBUG_OBJECT (playbin, "no next group");
3878     if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3879       GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3880     GST_PLAY_BIN_UNLOCK (playbin);
3881     return FALSE;
3882   }
3883 activate_failed:
3884   {
3885     GST_DEBUG_OBJECT (playbin, "activate failed");
3886     GST_PLAY_BIN_UNLOCK (playbin);
3887     return FALSE;
3888   }
3889 }
3890
3891 /* The group that is currently playing is copied again to the
3892  * next_group so that it will start playing the next time.
3893  */
3894 static gboolean
3895 save_current_group (GstPlayBin * playbin)
3896 {
3897   GstSourceGroup *curr_group;
3898
3899   GST_DEBUG_OBJECT (playbin, "save current group");
3900
3901   /* see if there is a current group */
3902   GST_PLAY_BIN_LOCK (playbin);
3903   curr_group = playbin->curr_group;
3904   if (curr_group && curr_group->valid && curr_group->active) {
3905     /* unlink our pads with the sink */
3906     deactivate_group (playbin, curr_group);
3907   }
3908   /* swap old and new */
3909   playbin->curr_group = playbin->next_group;
3910   playbin->next_group = curr_group;
3911   GST_PLAY_BIN_UNLOCK (playbin);
3912
3913   return TRUE;
3914 }
3915
3916 /* clear the locked state from all groups. This function is called before a
3917  * state change to NULL is performed on them. */
3918 static gboolean
3919 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3920 {
3921   GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3922       locked);
3923
3924   GST_PLAY_BIN_LOCK (playbin);
3925   GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3926   group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3927   GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3928   GST_SOURCE_GROUP_LOCK (playbin->next_group);
3929   group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3930   GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3931   GST_PLAY_BIN_UNLOCK (playbin);
3932
3933   return TRUE;
3934 }
3935
3936 static GstStateChangeReturn
3937 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3938 {
3939   GstStateChangeReturn ret;
3940   GstPlayBin *playbin;
3941   gboolean do_save = FALSE;
3942
3943   playbin = GST_PLAY_BIN (element);
3944
3945   switch (transition) {
3946     case GST_STATE_CHANGE_NULL_TO_READY:
3947       memset (&playbin->duration, 0, sizeof (playbin->duration));
3948       break;
3949     case GST_STATE_CHANGE_READY_TO_PAUSED:
3950       GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3951       memset (&playbin->duration, 0, sizeof (playbin->duration));
3952       g_atomic_int_set (&playbin->shutdown, 0);
3953
3954       if (!setup_next_source (playbin, GST_STATE_READY)) {
3955         ret = GST_STATE_CHANGE_FAILURE;
3956         goto failure;
3957       }
3958       break;
3959     case GST_STATE_CHANGE_PAUSED_TO_READY:
3960     async_down:
3961       /* FIXME unlock our waiting groups */
3962       GST_LOG_OBJECT (playbin, "setting shutdown flag");
3963       g_atomic_int_set (&playbin->shutdown, 1);
3964       memset (&playbin->duration, 0, sizeof (playbin->duration));
3965
3966       /* wait for all callbacks to end by taking the lock.
3967        * No dynamic (critical) new callbacks will
3968        * be able to happen as we set the shutdown flag. */
3969       GST_PLAY_BIN_DYN_LOCK (playbin);
3970       GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3971       GST_PLAY_BIN_DYN_UNLOCK (playbin);
3972       if (!do_save)
3973         break;
3974     case GST_STATE_CHANGE_READY_TO_NULL:
3975       /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3976        * an no state change PAUSED to READY passes here,
3977        * though it is a nice-to-have ... */
3978       if (!g_atomic_int_get (&playbin->shutdown)) {
3979         do_save = TRUE;
3980         goto async_down;
3981       }
3982       memset (&playbin->duration, 0, sizeof (playbin->duration));
3983
3984       /* unlock so that all groups go to NULL */
3985       groups_set_locked_state (playbin, FALSE);
3986       break;
3987     default:
3988       break;
3989   }
3990
3991   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3992   if (ret == GST_STATE_CHANGE_FAILURE)
3993     goto failure;
3994
3995   switch (transition) {
3996     case GST_STATE_CHANGE_READY_TO_PAUSED:
3997       break;
3998     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3999       /* FIXME Release audio device when we implement that */
4000       break;
4001     case GST_STATE_CHANGE_PAUSED_TO_READY:
4002       save_current_group (playbin);
4003       break;
4004     case GST_STATE_CHANGE_READY_TO_NULL:
4005     {
4006       guint i;
4007
4008       /* also do missed state change down to READY */
4009       if (do_save)
4010         save_current_group (playbin);
4011       /* Deactive the groups, set the uridecodebins to NULL
4012        * and unref them.
4013        */
4014       for (i = 0; i < 2; i++) {
4015         if (playbin->groups[i].active && playbin->groups[i].valid) {
4016           deactivate_group (playbin, &playbin->groups[i]);
4017           playbin->groups[i].valid = FALSE;
4018         }
4019
4020         if (playbin->groups[i].uridecodebin) {
4021           gst_element_set_state (playbin->groups[i].uridecodebin,
4022               GST_STATE_NULL);
4023           gst_object_unref (playbin->groups[i].uridecodebin);
4024           playbin->groups[i].uridecodebin = NULL;
4025         }
4026
4027         if (playbin->groups[i].suburidecodebin) {
4028           gst_element_set_state (playbin->groups[i].suburidecodebin,
4029               GST_STATE_NULL);
4030           gst_object_unref (playbin->groups[i].suburidecodebin);
4031           playbin->groups[i].suburidecodebin = NULL;
4032         }
4033       }
4034
4035       /* Set our sinks back to NULL, they might not be child of playbin */
4036       if (playbin->audio_sink)
4037         gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
4038       if (playbin->video_sink)
4039         gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
4040       if (playbin->text_sink)
4041         gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
4042
4043       /* make sure the groups don't perform a state change anymore until we
4044        * enable them again */
4045       groups_set_locked_state (playbin, TRUE);
4046       break;
4047     }
4048     default:
4049       break;
4050   }
4051
4052   return ret;
4053
4054   /* ERRORS */
4055 failure:
4056   {
4057     if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
4058       GstSourceGroup *curr_group;
4059
4060       curr_group = playbin->curr_group;
4061       if (curr_group && curr_group->active && curr_group->valid) {
4062         /* unlink our pads with the sink */
4063         deactivate_group (playbin, curr_group);
4064         curr_group->valid = FALSE;
4065       }
4066
4067       /* Swap current and next group back */
4068       playbin->curr_group = playbin->next_group;
4069       playbin->next_group = curr_group;
4070     }
4071     return ret;
4072   }
4073 }
4074
4075 static void
4076 gst_play_bin_xoverlay_expose (GstXOverlay * overlay)
4077 {
4078   GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4079
4080   gst_x_overlay_expose (GST_X_OVERLAY (playbin->playsink));
4081 }
4082
4083 static void
4084 gst_play_bin_xoverlay_handle_events (GstXOverlay * overlay,
4085     gboolean handle_events)
4086 {
4087   GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4088
4089   gst_x_overlay_handle_events (GST_X_OVERLAY (playbin->playsink),
4090       handle_events);
4091 }
4092
4093 static void
4094 gst_play_bin_xoverlay_set_render_rectangle (GstXOverlay * overlay, gint x,
4095     gint y, gint width, gint height)
4096 {
4097   GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4098
4099   gst_x_overlay_set_render_rectangle (GST_X_OVERLAY (playbin->playsink), x, y,
4100       width, height);
4101 }
4102
4103 static void
4104 gst_play_bin_xoverlay_set_window_handle (GstXOverlay * overlay, guintptr handle)
4105 {
4106   GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4107
4108   gst_x_overlay_set_window_handle (GST_X_OVERLAY (playbin->playsink), handle);
4109 }
4110
4111 static void
4112 gst_play_bin_xoverlay_init (gpointer g_iface, gpointer g_iface_data)
4113 {
4114   GstXOverlayClass *iface = (GstXOverlayClass *) g_iface;
4115   iface->expose = gst_play_bin_xoverlay_expose;
4116   iface->handle_events = gst_play_bin_xoverlay_handle_events;
4117   iface->set_render_rectangle = gst_play_bin_xoverlay_set_render_rectangle;
4118   iface->set_window_handle = gst_play_bin_xoverlay_set_window_handle;
4119 }
4120
4121 static gboolean
4122 gst_play_bin_implements_interface_supported (GstImplementsInterface * iface,
4123     GType type)
4124 {
4125   if (type == GST_TYPE_X_OVERLAY || type == GST_TYPE_STREAM_VOLUME ||
4126       type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE)
4127     return TRUE;
4128   else
4129     return FALSE;
4130 }
4131
4132 static void
4133 gst_play_bin_implements_interface_init (gpointer g_iface, gpointer g_iface_data)
4134 {
4135   GstImplementsInterfaceClass *iface = (GstImplementsInterfaceClass *) g_iface;
4136   iface->supported = gst_play_bin_implements_interface_supported;
4137 }
4138
4139 static void
4140 gst_play_bin_navigation_send_event (GstNavigation * navigation,
4141     GstStructure * structure)
4142 {
4143   GstPlayBin *playbin = GST_PLAY_BIN (navigation);
4144
4145   gst_navigation_send_event (GST_NAVIGATION (playbin->playsink), structure);
4146 }
4147
4148 static void
4149 gst_play_bin_navigation_init (gpointer g_iface, gpointer g_iface_data)
4150 {
4151   GstNavigationInterface *iface = (GstNavigationInterface *) g_iface;
4152
4153   iface->send_event = gst_play_bin_navigation_send_event;
4154 }
4155
4156 static const GList *
4157 gst_play_bin_colorbalance_list_channels (GstColorBalance * balance)
4158 {
4159   GstPlayBin *playbin = GST_PLAY_BIN (balance);
4160
4161   return
4162       gst_color_balance_list_channels (GST_COLOR_BALANCE (playbin->playsink));
4163 }
4164
4165 static void
4166 gst_play_bin_colorbalance_set_value (GstColorBalance * balance,
4167     GstColorBalanceChannel * channel, gint value)
4168 {
4169   GstPlayBin *playbin = GST_PLAY_BIN (balance);
4170
4171   gst_color_balance_set_value (GST_COLOR_BALANCE (playbin->playsink), channel,
4172       value);
4173 }
4174
4175 static gint
4176 gst_play_bin_colorbalance_get_value (GstColorBalance * balance,
4177     GstColorBalanceChannel * channel)
4178 {
4179   GstPlayBin *playbin = GST_PLAY_BIN (balance);
4180
4181   return gst_color_balance_get_value (GST_COLOR_BALANCE (playbin->playsink),
4182       channel);
4183 }
4184
4185 static GstColorBalanceType
4186 gst_play_bin_colorbalance_get_balance_type (GstColorBalance * balance)
4187 {
4188   GstPlayBin *playbin = GST_PLAY_BIN (balance);
4189
4190   return
4191       gst_color_balance_get_balance_type (GST_COLOR_BALANCE
4192       (playbin->playsink));
4193 }
4194
4195 static void
4196 gst_play_bin_colorbalance_init (gpointer g_iface, gpointer g_iface_data)
4197 {
4198   GstColorBalanceClass *iface = (GstColorBalanceClass *) g_iface;
4199
4200   iface->list_channels = gst_play_bin_colorbalance_list_channels;
4201   iface->set_value = gst_play_bin_colorbalance_set_value;
4202   iface->get_value = gst_play_bin_colorbalance_get_value;
4203   iface->get_balance_type = gst_play_bin_colorbalance_get_balance_type;
4204 }
4205
4206 gboolean
4207 gst_play_bin2_plugin_init (GstPlugin * plugin)
4208 {
4209   GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
4210
4211   return gst_element_register (plugin, "playbin2", GST_RANK_NONE,
4212       GST_TYPE_PLAY_BIN);
4213 }