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