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