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