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