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