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