Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / gst / playback / gstplaybin2.c
1 /* GStreamer
2  * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:element-playbin2
22  *
23  * Playbin2 provides a stand-alone everything-in-one abstraction for an
24  * audio and/or video player.
25  *
26  * playbin2 is considered stable now. It is the prefered playback API now,
27  * and replaces the old #playbin element, which is no longer supported.
28  *
29  * It can handle both audio and video files and features
30  * <itemizedlist>
31  * <listitem>
32  * automatic file type recognition and based on that automatic
33  * selection and usage of the right audio/video/subtitle demuxers/decoders
34  * </listitem>
35  * <listitem>
36  * visualisations for audio files
37  * </listitem>
38  * <listitem>
39  * subtitle support for video files. Subtitles can be store in external
40  * files.
41  * </listitem>
42  * <listitem>
43  * stream selection between different video/audio/subtitles streams
44  * </listitem>
45  * <listitem>
46  * meta info (tag) extraction
47  * </listitem>
48  * <listitem>
49  * easy access to the last video frame
50  * </listitem>
51  * <listitem>
52  * buffering when playing streams over a network
53  * </listitem>
54  * <listitem>
55  * volume control with mute option
56  * </listitem>
57  * </itemizedlist>
58  *
59  * <refsect2>
60  * <title>Usage</title>
61  * <para>
62  * A playbin2 element can be created just like any other element using
63  * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin2:uri
64  * property. This must be an absolute URI, relative file paths are not allowed.
65  * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
66  *
67  * Playbin is a #GstPipeline. It will notify the application of everything
68  * that's happening (errors, end of stream, tags found, state changes, etc.)
69  * by posting messages on its #GstBus. The application needs to watch the
70  * bus.
71  *
72  * Playback can be initiated by setting the element to PLAYING state using
73  * gst_element_set_state(). Note that the state change will take place in
74  * the background in a separate thread, when the function returns playback
75  * is probably not happening yet and any errors might not have occured yet.
76  * Applications using playbin should ideally be written to deal with things
77  * completely asynchroneous.
78  *
79  * When playback has finished (an EOS message has been received on the bus)
80  * or an error has occured (an ERROR message has been received on the bus) or
81  * the user wants to play a different track, playbin should be set back to
82  * READY or NULL state, then the #GstPlayBin2:uri property should be set to the
83  * new location and then playbin be set to PLAYING state again.
84  *
85  * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
86  * on the playbin element. Again, the seek will not be executed
87  * instantaneously, but will be done in a background thread. When the seek
88  * call returns the seek will most likely still be in process. An application
89  * may wait for the seek to finish (or fail) using gst_element_get_state() with
90  * -1 as the timeout, but this will block the user interface and is not
91  * recommended at all.
92  *
93  * Applications may query the current position and duration of the stream
94  * via gst_element_query_position() and gst_element_query_duration() and
95  * setting the format passed to GST_FORMAT_TIME. If the query was successful,
96  * the duration or position will have been returned in units of nanoseconds.
97  * </para>
98  * </refsect2>
99  * <refsect2>
100  * <title>Advanced Usage: specifying the audio and video sink</title>
101  * <para>
102  * By default, if no audio sink or video sink has been specified via the
103  * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property, playbin will use the autoaudiosink
104  * and autovideosink elements to find the first-best available output method.
105  * This should work in most cases, but is not always desirable. Often either
106  * the user or application might want to specify more explicitly what to use
107  * for audio and video output.
108  *
109  * If the application wants more control over how audio or video should be
110  * output, it may create the audio/video sink elements itself (for example
111  * using gst_element_factory_make()) and provide them to playbin using the
112  * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property.
113  *
114  * GNOME-based applications, for example, will usually want to create
115  * gconfaudiosink and gconfvideosink elements and make playbin use those,
116  * so that output happens to whatever the user has configured in the GNOME
117  * Multimedia System Selector configuration dialog.
118  *
119  * The sink elements do not necessarily need to be ready-made sinks. It is
120  * possible to create container elements that look like a sink to playbin,
121  * but in reality contain a number of custom elements linked together. This
122  * can be achieved by creating a #GstBin and putting elements in there and
123  * linking them, and then creating a sink #GstGhostPad for the bin and pointing
124  * it to the sink pad of the first element within the bin. This can be used
125  * for a number of purposes, for example to force output to a particular
126  * format or to modify or observe the data before it is output.
127  *
128  * It is also possible to 'suppress' audio and/or video output by using
129  * 'fakesink' elements (or capture it from there using the fakesink element's
130  * "handoff" signal, which, nota bene, is fired from the streaming thread!).
131  * </para>
132  * </refsect2>
133  * <refsect2>
134  * <title>Retrieving Tags and Other Meta Data</title>
135  * <para>
136  * Most of the common meta data (artist, title, etc.) can be retrieved by
137  * watching for TAG messages on the pipeline's bus (see above).
138  *
139  * Other more specific meta information like width/height/framerate of video
140  * streams or samplerate/number of channels of audio streams can be obtained
141  * from the negotiated caps on the sink pads of the sinks.
142  * </para>
143  * </refsect2>
144  * <refsect2>
145  * <title>Buffering</title>
146  * Playbin handles buffering automatically for the most part, but applications
147  * need to handle parts of the buffering process as well. Whenever playbin is
148  * buffering, it will post BUFFERING messages on the bus with a percentage
149  * value that shows the progress of the buffering process. Applications need
150  * to set playbin to PLAYING or PAUSED state in response to these messages.
151  * They may also want to convey the buffering progress to the user in some
152  * way. Here is how to extract the percentage information from the message
153  * (requires GStreamer >= 0.10.11):
154  * |[
155  * switch (GST_MESSAGE_TYPE (msg)) {
156  *   case GST_MESSAGE_BUFFERING: {
157  *     gint percent = 0;
158  *     gst_message_parse_buffering (msg, &amp;percent);
159  *     g_print ("Buffering (%%u percent done)", percent);
160  *     break;
161  *   }
162  *   ...
163  * }
164  * ]|
165  * Note that applications should keep/set the pipeline in the PAUSED state when
166  * a BUFFERING message is received with a buffer percent value < 100 and set
167  * the pipeline back to PLAYING state when a BUFFERING message with a value
168  * of 100 percent is received (if PLAYING is the desired state, that is).
169  * </refsect2>
170  * <refsect2>
171  * <title>Embedding the video window in your application</title>
172  * By default, playbin (or rather the video sinks used) will create their own
173  * window. Applications will usually want to force output to a window of their
174  * own, however. This can be done using the #GstXOverlay interface, which most
175  * video sinks implement. See the documentation there for more details.
176  * </refsect2>
177  * <refsect2>
178  * <title>Specifying which CD/DVD device to use</title>
179  * The device to use for CDs/DVDs needs to be set on the source element
180  * playbin creates before it is opened. The only way to do this at the moment
181  * is to connect to playbin's "notify::source" signal, which will be emitted
182  * by playbin when it has created the source element for a particular URI.
183  * In the signal callback you can check if the source element has a "device"
184  * property and set it appropriately. In future ways might be added to specify
185  * the device as part of the URI, but at the time of writing this is not
186  * possible yet.
187  * </refsect2>
188  * <refsect2>
189  * <title>Handling redirects</title>
190  * <para>
191  * Some elements may post 'redirect' messages on the bus to tell the
192  * application to open another location. These are element messages containing
193  * a structure named 'redirect' along with a 'new-location' field of string
194  * type. The new location may be a relative or an absolute URI. Examples
195  * for such redirects can be found in many quicktime movie trailers.
196  * </para>
197  * </refsect2>
198  * <refsect2>
199  * <title>Examples</title>
200  * |[
201  * gst-launch -v playbin uri=file:///path/to/somefile.avi
202  * ]| This will play back the given AVI video file, given that the video and
203  * audio decoders required to decode the content are installed. Since no
204  * special audio sink or video sink is supplied (not possible via gst-launch),
205  * playbin will try to find a suitable audio and video sink automatically
206  * using the autoaudiosink and autovideosink elements.
207  * |[
208  * gst-launch -v playbin uri=cdda://4
209  * ]| This will play back track 4 on an audio CD in your disc drive (assuming
210  * the drive is detected automatically by the plugin).
211  * |[
212  * gst-launch -v playbin uri=dvd://1
213  * ]| This will play back title 1 of a DVD in your disc drive (assuming
214  * the drive is detected automatically by the plugin).
215  * </refsect2>
216  */
217
218 #ifdef HAVE_CONFIG_H
219 #include "config.h"
220 #endif
221
222 #include <string.h>
223 #include <gst/gst.h>
224
225 #include <gst/gst-i18n-plugin.h>
226 #include <gst/pbutils/pbutils.h>
227 #include <gst/interfaces/streamvolume.h>
228
229 #include "gstplay-enum.h"
230 #include "gstplay-marshal.h"
231 #include "gstplayback.h"
232 #include "gstplaysink.h"
233 #include "gstsubtitleoverlay.h"
234
235 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
236 #define GST_CAT_DEFAULT gst_play_bin_debug
237
238 #define GST_TYPE_PLAY_BIN               (gst_play_bin_get_type())
239 #define GST_PLAY_BIN(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
240 #define GST_PLAY_BIN_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
241 #define GST_IS_PLAY_BIN(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
242 #define GST_IS_PLAY_BIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
243
244 #define VOLUME_MAX_DOUBLE 10.0
245
246 typedef struct _GstPlayBin GstPlayBin;
247 typedef struct _GstPlayBinClass GstPlayBinClass;
248 typedef struct _GstSourceGroup GstSourceGroup;
249 typedef struct _GstSourceSelect GstSourceSelect;
250
251 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
252
253 /* has the info for a selector and provides the link to the sink */
254 struct _GstSourceSelect
255 {
256   const gchar *media_list[8];   /* the media types for the selector */
257   SourceSelectGetMediaCapsFunc get_media_caps;  /* more complex caps for the selector */
258   GstPlaySinkType type;         /* the sink pad type of the selector */
259
260   GstElement *selector;         /* the selector */
261   GPtrArray *channels;
262   GstPad *srcpad;               /* the source pad of the selector */
263   GstPad *sinkpad;              /* the sinkpad of the sink when the selector
264                                  * is linked
265                                  */
266   GstEvent *sinkpad_delayed_event;
267   gulong sinkpad_data_probe;
268 };
269
270 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
271 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
272 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
273
274 /* a structure to hold the objects for decoding a uri and the subtitle uri
275  */
276 struct _GstSourceGroup
277 {
278   GstPlayBin *playbin;
279
280   GMutex *lock;
281
282   gboolean valid;               /* the group has valid info to start playback */
283   gboolean active;              /* the group is active */
284
285   /* properties */
286   gchar *uri;
287   gchar *suburi;
288   GValueArray *streaminfo;
289   GstElement *source;
290
291   GPtrArray *video_channels;    /* links to selector pads */
292   GPtrArray *audio_channels;    /* links to selector pads */
293   GPtrArray *text_channels;     /* links to selector pads */
294
295   GstElement *audio_sink;       /* autoplugged audio and video sinks */
296   GstElement *video_sink;
297
298   /* uridecodebins for uri and subtitle uri */
299   GstElement *uridecodebin;
300   GstElement *suburidecodebin;
301   gint pending;
302   gboolean sub_pending;
303
304   gulong pad_added_id;
305   gulong pad_removed_id;
306   gulong no_more_pads_id;
307   gulong notify_source_id;
308   gulong drained_id;
309   gulong autoplug_factories_id;
310   gulong autoplug_select_id;
311   gulong autoplug_continue_id;
312
313   gulong sub_pad_added_id;
314   gulong sub_pad_removed_id;
315   gulong sub_no_more_pads_id;
316   gulong sub_autoplug_continue_id;
317
318   GMutex *stream_changed_pending_lock;
319   GList *stream_changed_pending;
320
321   /* selectors for different streams */
322   GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST];
323 };
324
325 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
326 #define GST_PLAY_BIN_LOCK(bin) (g_static_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
327 #define GST_PLAY_BIN_UNLOCK(bin) (g_static_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
328
329 /* lock to protect dynamic callbacks, like no-more-pads */
330 #define GST_PLAY_BIN_DYN_LOCK(bin)    g_mutex_lock ((bin)->dyn_lock)
331 #define GST_PLAY_BIN_DYN_UNLOCK(bin)  g_mutex_unlock ((bin)->dyn_lock)
332
333 /* lock for shutdown */
334 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label)           \
335 G_STMT_START {                                          \
336   if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown)))   \
337     goto label;                                         \
338   GST_PLAY_BIN_DYN_LOCK (bin);                          \
339   if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
340     GST_PLAY_BIN_DYN_UNLOCK (bin);                      \
341     goto label;                                         \
342   }                                                     \
343 } G_STMT_END
344
345 /* unlock for shutdown */
346 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin)         \
347   GST_PLAY_BIN_DYN_UNLOCK (bin);                  \
348
349 /**
350  * GstPlayBin2:
351  *
352  * playbin element structure
353  */
354 struct _GstPlayBin
355 {
356   GstPipeline parent;
357
358   GStaticRecMutex lock;         /* to protect group switching */
359
360   /* the groups, we use a double buffer to switch between current and next */
361   GstSourceGroup groups[2];     /* array with group info */
362   GstSourceGroup *curr_group;   /* pointer to the currently playing group */
363   GstSourceGroup *next_group;   /* pointer to the next group */
364
365   /* properties */
366   guint connection_speed;       /* connection speed in bits/sec (0 = unknown) */
367   gint current_video;           /* the currently selected stream */
368   gint current_audio;           /* the currently selected stream */
369   gint current_text;            /* the currently selected stream */
370
371   guint64 buffer_duration;      /* When buffering, the max buffer duration (ns) */
372   guint buffer_size;            /* When buffering, the max buffer size (bytes) */
373
374   /* our play sink */
375   GstPlaySink *playsink;
376
377   /* the last activated source */
378   GstElement *source;
379
380   /* lock protecting dynamic adding/removing */
381   GMutex *dyn_lock;
382   /* if we are shutting down or not */
383   gint shutdown;
384
385   GMutex *elements_lock;
386   guint32 elements_cookie;
387   GList *elements;              /* factories we can use for selecting elements */
388
389   gboolean have_selector;       /* set to FALSE when we fail to create an
390                                  * input-selector, so that we only post a
391                                  * warning once */
392
393   GstElement *audio_sink;       /* configured audio sink, or NULL      */
394   GstElement *video_sink;       /* configured video sink, or NULL      */
395   GstElement *text_sink;        /* configured text sink, or NULL       */
396
397   struct
398   {
399     gboolean valid;
400     GstFormat format;
401     gint64 duration;
402   } duration[5];                /* cached durations */
403
404   guint64 ring_buffer_max_size; /* 0 means disabled */
405 };
406
407 struct _GstPlayBinClass
408 {
409   GstPipelineClass parent_class;
410
411   /* notify app that the current uri finished decoding and it is possible to
412    * queue a new one for gapless playback */
413   void (*about_to_finish) (GstPlayBin * playbin);
414
415   /* notify app that number of audio/video/text streams changed */
416   void (*video_changed) (GstPlayBin * playbin);
417   void (*audio_changed) (GstPlayBin * playbin);
418   void (*text_changed) (GstPlayBin * playbin);
419
420   /* notify app that the tags of audio/video/text streams changed */
421   void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
422   void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
423   void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
424
425   /* get audio/video/text tags for a stream */
426   GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
427   GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
428   GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
429
430   /* get the last video frame and convert it to the given caps */
431   GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
432
433   /* get audio/video/text pad for a stream */
434   GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
435   GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
436   GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
437 };
438
439 /* props */
440 #define DEFAULT_URI               NULL
441 #define DEFAULT_SUBURI            NULL
442 #define DEFAULT_SOURCE            NULL
443 #define DEFAULT_FLAGS             GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
444                                   GST_PLAY_FLAG_SOFT_VOLUME
445 #define DEFAULT_N_VIDEO           0
446 #define DEFAULT_CURRENT_VIDEO     -1
447 #define DEFAULT_N_AUDIO           0
448 #define DEFAULT_CURRENT_AUDIO     -1
449 #define DEFAULT_N_TEXT            0
450 #define DEFAULT_CURRENT_TEXT      -1
451 #define DEFAULT_SUBTITLE_ENCODING NULL
452 #define DEFAULT_AUDIO_SINK        NULL
453 #define DEFAULT_VIDEO_SINK        NULL
454 #define DEFAULT_VIS_PLUGIN        NULL
455 #define DEFAULT_TEXT_SINK         NULL
456 #define DEFAULT_VOLUME            1.0
457 #define DEFAULT_MUTE              FALSE
458 #define DEFAULT_FRAME             NULL
459 #define DEFAULT_FONT_DESC         NULL
460 #define DEFAULT_CONNECTION_SPEED  0
461 #define DEFAULT_BUFFER_DURATION   -1
462 #define DEFAULT_BUFFER_SIZE       -1
463 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
464
465 enum
466 {
467   PROP_0,
468   PROP_URI,
469   PROP_SUBURI,
470   PROP_SOURCE,
471   PROP_FLAGS,
472   PROP_N_VIDEO,
473   PROP_CURRENT_VIDEO,
474   PROP_N_AUDIO,
475   PROP_CURRENT_AUDIO,
476   PROP_N_TEXT,
477   PROP_CURRENT_TEXT,
478   PROP_SUBTITLE_ENCODING,
479   PROP_AUDIO_SINK,
480   PROP_VIDEO_SINK,
481   PROP_VIS_PLUGIN,
482   PROP_TEXT_SINK,
483   PROP_VOLUME,
484   PROP_MUTE,
485   PROP_FRAME,
486   PROP_FONT_DESC,
487   PROP_CONNECTION_SPEED,
488   PROP_BUFFER_SIZE,
489   PROP_BUFFER_DURATION,
490   PROP_AV_OFFSET,
491   PROP_RING_BUFFER_MAX_SIZE,
492   PROP_LAST
493 };
494
495 /* signals */
496 enum
497 {
498   SIGNAL_ABOUT_TO_FINISH,
499   SIGNAL_CONVERT_FRAME,
500   SIGNAL_VIDEO_CHANGED,
501   SIGNAL_AUDIO_CHANGED,
502   SIGNAL_TEXT_CHANGED,
503   SIGNAL_VIDEO_TAGS_CHANGED,
504   SIGNAL_AUDIO_TAGS_CHANGED,
505   SIGNAL_TEXT_TAGS_CHANGED,
506   SIGNAL_GET_VIDEO_TAGS,
507   SIGNAL_GET_AUDIO_TAGS,
508   SIGNAL_GET_TEXT_TAGS,
509   SIGNAL_GET_VIDEO_PAD,
510   SIGNAL_GET_AUDIO_PAD,
511   SIGNAL_GET_TEXT_PAD,
512   SIGNAL_SOURCE_SETUP,
513   LAST_SIGNAL
514 };
515
516 static void gst_play_bin_class_init (GstPlayBinClass * klass);
517 static void gst_play_bin_init (GstPlayBin * playbin);
518 static void gst_play_bin_finalize (GObject * object);
519
520 static void gst_play_bin_set_property (GObject * object, guint prop_id,
521     const GValue * value, GParamSpec * spec);
522 static void gst_play_bin_get_property (GObject * object, guint prop_id,
523     GValue * value, GParamSpec * spec);
524
525 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
526     GstStateChange transition);
527
528 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
529 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
530
531 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
532     gint stream);
533 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
534     gint stream);
535 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
536     gint stream);
537
538 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
539     GstCaps * caps);
540
541 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
542 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
543 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
544
545 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
546
547 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
548 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
549     GstSourceGroup * group);
550
551 static void gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
552     gboolean block);
553 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
554     suburidecodebin);
555
556 static GstElementClass *parent_class;
557
558 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
559
560 #define REMOVE_SIGNAL(obj,id)            \
561 if (id) {                                \
562   g_signal_handler_disconnect (obj, id); \
563   id = 0;                                \
564 }
565
566 static GType
567 gst_play_bin_get_type (void)
568 {
569   static GType gst_play_bin_type = 0;
570
571   if (!gst_play_bin_type) {
572     static const GTypeInfo gst_play_bin_info = {
573       sizeof (GstPlayBinClass),
574       NULL,
575       NULL,
576       (GClassInitFunc) gst_play_bin_class_init,
577       NULL,
578       NULL,
579       sizeof (GstPlayBin),
580       0,
581       (GInstanceInitFunc) gst_play_bin_init,
582       NULL
583     };
584     static const GInterfaceInfo svol_info = {
585       NULL, NULL, NULL
586     };
587
588     gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
589         "GstPlayBin2", &gst_play_bin_info, 0);
590
591     g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
592         &svol_info);
593   }
594
595   return gst_play_bin_type;
596 }
597
598 static void
599 gst_play_bin_class_init (GstPlayBinClass * klass)
600 {
601   GObjectClass *gobject_klass;
602   GstElementClass *gstelement_klass;
603   GstBinClass *gstbin_klass;
604
605   gobject_klass = (GObjectClass *) klass;
606   gstelement_klass = (GstElementClass *) klass;
607   gstbin_klass = (GstBinClass *) klass;
608
609   parent_class = g_type_class_peek_parent (klass);
610
611   gobject_klass->set_property = gst_play_bin_set_property;
612   gobject_klass->get_property = gst_play_bin_get_property;
613
614   gobject_klass->finalize = gst_play_bin_finalize;
615
616   /**
617    * GstPlayBin2:uri
618    *
619    * Set the next URI that playbin will play. This property can be set from the
620    * about-to-finish signal to queue the next media file.
621    */
622   g_object_class_install_property (gobject_klass, PROP_URI,
623       g_param_spec_string ("uri", "URI", "URI of the media to play",
624           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
625
626   /**
627    * GstPlayBin2:suburi
628    *
629    * Set the next subtitle URI that playbin will play. This property can be
630    * set from the about-to-finish signal to queue the next subtitle media file.
631    */
632   g_object_class_install_property (gobject_klass, PROP_SUBURI,
633       g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
634           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
635
636   g_object_class_install_property (gobject_klass, PROP_SOURCE,
637       g_param_spec_object ("source", "Source", "Source element",
638           GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
639
640   /**
641    * GstPlayBin2:flags
642    *
643    * Control the behaviour of playbin.
644    */
645   g_object_class_install_property (gobject_klass, PROP_FLAGS,
646       g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
647           GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
648           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
649
650   /**
651    * GstPlayBin2:n-video
652    *
653    * Get the total number of available video streams.
654    */
655   g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
656       g_param_spec_int ("n-video", "Number Video",
657           "Total number of video streams", 0, G_MAXINT, 0,
658           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
659   /**
660    * GstPlayBin2:current-video
661    *
662    * Get or set the currently playing video stream. By default the first video
663    * stream with data is played.
664    */
665   g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
666       g_param_spec_int ("current-video", "Current Video",
667           "Currently playing video stream (-1 = auto)",
668           -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
669   /**
670    * GstPlayBin2:n-audio
671    *
672    * Get the total number of available audio streams.
673    */
674   g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
675       g_param_spec_int ("n-audio", "Number Audio",
676           "Total number of audio streams", 0, G_MAXINT, 0,
677           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
678   /**
679    * GstPlayBin2:current-audio
680    *
681    * Get or set the currently playing audio stream. By default the first audio
682    * stream with data is played.
683    */
684   g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
685       g_param_spec_int ("current-audio", "Current audio",
686           "Currently playing audio stream (-1 = auto)",
687           -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
688   /**
689    * GstPlayBin2:n-text
690    *
691    * Get the total number of available subtitle streams.
692    */
693   g_object_class_install_property (gobject_klass, PROP_N_TEXT,
694       g_param_spec_int ("n-text", "Number Text",
695           "Total number of text streams", 0, G_MAXINT, 0,
696           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
697   /**
698    * GstPlayBin2:current-text:
699    *
700    * Get or set the currently playing subtitle stream. By default the first
701    * subtitle stream with data is played.
702    */
703   g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
704       g_param_spec_int ("current-text", "Current Text",
705           "Currently playing text stream (-1 = auto)",
706           -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
707
708   g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
709       g_param_spec_string ("subtitle-encoding", "subtitle encoding",
710           "Encoding to assume if input subtitles are not in UTF-8 encoding. "
711           "If not set, the GST_SUBTITLE_ENCODING environment variable will "
712           "be checked for an encoding to use. If that is not set either, "
713           "ISO-8859-15 will be assumed.", NULL,
714           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
715
716   g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
717       g_param_spec_object ("video-sink", "Video Sink",
718           "the video output element to use (NULL = default sink)",
719           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
720   g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
721       g_param_spec_object ("audio-sink", "Audio Sink",
722           "the audio output element to use (NULL = default sink)",
723           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
724   g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
725       g_param_spec_object ("vis-plugin", "Vis plugin",
726           "the visualization element to use (NULL = default)",
727           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
728   g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
729       g_param_spec_object ("text-sink", "Text plugin",
730           "the text output element to use (NULL = default textoverlay)",
731           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
732
733   /**
734    * GstPlayBin2:volume:
735    *
736    * Get or set the current audio stream volume. 1.0 means 100%,
737    * 0.0 means mute. This uses a linear volume scale.
738    *
739    */
740   g_object_class_install_property (gobject_klass, PROP_VOLUME,
741       g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
742           0.0, VOLUME_MAX_DOUBLE, 1.0,
743           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
744   g_object_class_install_property (gobject_klass, PROP_MUTE,
745       g_param_spec_boolean ("mute", "Mute",
746           "Mute the audio channel without changing the volume", FALSE,
747           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
748
749   /**
750    * GstPlayBin2:frame:
751    * @playbin: a #GstPlayBin2
752    *
753    * Get the currently rendered or prerolled frame in the video sink.
754    * The #GstCaps on the buffer will describe the format of the buffer.
755    */
756   g_object_class_install_property (gobject_klass, PROP_FRAME,
757       g_param_spec_boxed ("frame", "Frame",
758           "The last frame (NULL = no video available)",
759           GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
760   g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
761       g_param_spec_string ("subtitle-font-desc",
762           "Subtitle font description",
763           "Pango font description of font "
764           "to be used for subtitle rendering", NULL,
765           G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
766
767   g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
768       g_param_spec_uint ("connection-speed", "Connection Speed",
769           "Network connection speed in kbps (0 = unknown)",
770           0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
771           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
772
773   g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
774       g_param_spec_int ("buffer-size", "Buffer size (bytes)",
775           "Buffer size when buffering network streams",
776           -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
777           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
778   g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
779       g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
780           "Buffer duration when buffering network streams",
781           -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
782           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
783   /**
784    * GstPlayBin2:av-offset:
785    *
786    * Control the synchronisation offset between the audio and video streams.
787    * Positive values make the audio ahead of the video and negative values make
788    * the audio go behind the video.
789    *
790    * Since: 0.10.30
791    */
792   g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
793       g_param_spec_int64 ("av-offset", "AV Offset",
794           "The synchronisation offset between audio and video in nanoseconds",
795           G_MININT64, G_MAXINT64, 0,
796           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
797
798   /**
799    * GstQueue2:ring-buffer-max-size
800    *
801    * The maximum size of the ring buffer in bytes. If set to 0, the ring
802    * buffer is disabled. Default 0.
803    *
804    * Since: 0.10.31
805    */
806   g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
807       g_param_spec_uint64 ("ring-buffer-max-size",
808           "Max. ring buffer size (bytes)",
809           "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
810           0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
811           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
812
813   /**
814    * GstPlayBin2::about-to-finish
815    * @playbin: a #GstPlayBin2
816    *
817    * This signal is emitted when the current uri is about to finish. You can
818    * set the uri and suburi to make sure that playback continues.
819    */
820   gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
821       g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
822       G_SIGNAL_RUN_LAST,
823       G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
824       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
825
826   /**
827    * GstPlayBin2::video-changed
828    * @playbin: a #GstPlayBin2
829    *
830    * This signal is emitted whenever the number or order of the video
831    * streams has changed. The application will most likely want to select
832    * a new video stream.
833    */
834   gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
835       g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
836       G_SIGNAL_RUN_LAST,
837       G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
838       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
839   /**
840    * GstPlayBin2::audio-changed
841    * @playbin: a #GstPlayBin2
842    *
843    * This signal is emitted whenever the number or order of the audio
844    * streams has changed. The application will most likely want to select
845    * a new audio stream.
846    */
847   gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
848       g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
849       G_SIGNAL_RUN_LAST,
850       G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
851       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
852   /**
853    * GstPlayBin2::text-changed
854    * @playbin: a #GstPlayBin2
855    *
856    * This signal is emitted whenever the number or order of the text
857    * streams has changed. The application will most likely want to select
858    * a new text stream.
859    */
860   gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
861       g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
862       G_SIGNAL_RUN_LAST,
863       G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
864       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
865
866   /**
867    * GstPlayBin2::video-tags-changed
868    * @playbin: a #GstPlayBin2
869    * @stream: stream index with changed tags
870    *
871    * This signal is emitted whenever the tags of a video stream have changed.
872    * The application will most likely want to get the new tags.
873    *
874    * Since: 0.10.24
875    */
876   gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
877       g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
878       G_SIGNAL_RUN_LAST,
879       G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
880       gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
881
882   /**
883    * GstPlayBin2::audio-tags-changed
884    * @playbin: a #GstPlayBin2
885    * @stream: stream index with changed tags
886    *
887    * This signal is emitted whenever the tags of an audio stream have changed.
888    * The application will most likely want to get the new tags.
889    *
890    * Since: 0.10.24
891    */
892   gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
893       g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
894       G_SIGNAL_RUN_LAST,
895       G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
896       gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
897
898   /**
899    * GstPlayBin2::text-tags-changed
900    * @playbin: a #GstPlayBin2
901    * @stream: stream index with changed tags
902    *
903    * This signal is emitted whenever the tags of a text stream have changed.
904    * The application will most likely want to get the new tags.
905    *
906    * Since: 0.10.24
907    */
908   gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
909       g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
910       G_SIGNAL_RUN_LAST,
911       G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
912       gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
913
914   /**
915    * GstPlayBin2::source-setup:
916    * @playbin: a #GstPlayBin2
917    * @source: source element
918    *
919    * This signal is emitted after the source element has been created, so
920    * it can be configured by setting additional properties (e.g. set a
921    * proxy server for an http source, or set the device and read speed for
922    * an audio cd source). This is functionally equivalent to connecting to
923    * the notify::source signal, but more convenient.
924    *
925    * Since: 0.10.33
926    */
927   gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
928       g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
929       G_SIGNAL_RUN_LAST, 0, NULL, NULL,
930       gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
931
932   /**
933    * GstPlayBin2::get-video-tags
934    * @playbin: a #GstPlayBin2
935    * @stream: a video stream number
936    *
937    * Action signal to retrieve the tags of a specific video stream number.
938    * This information can be used to select a stream.
939    *
940    * Returns: a GstTagList with tags or NULL when the stream number does not
941    * exist.
942    */
943   gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
944       g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
945       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
946       G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
947       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
948   /**
949    * GstPlayBin2::get-audio-tags
950    * @playbin: a #GstPlayBin2
951    * @stream: an audio stream number
952    *
953    * Action signal to retrieve the tags of a specific audio stream number.
954    * This information can be used to select a stream.
955    *
956    * Returns: a GstTagList with tags or NULL when the stream number does not
957    * exist.
958    */
959   gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
960       g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
961       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
962       G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
963       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
964   /**
965    * GstPlayBin2::get-text-tags
966    * @playbin: a #GstPlayBin2
967    * @stream: a text stream number
968    *
969    * Action signal to retrieve the tags of a specific text stream number.
970    * This information can be used to select a stream.
971    *
972    * Returns: a GstTagList with tags or NULL when the stream number does not
973    * exist.
974    */
975   gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
976       g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
977       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
978       G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
979       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
980   /**
981    * GstPlayBin2::convert-frame
982    * @playbin: a #GstPlayBin2
983    * @caps: the target format of the frame
984    *
985    * Action signal to retrieve the currently playing video frame in the format
986    * specified by @caps.
987    * If @caps is %NULL, no conversion will be performed and this function is
988    * equivalent to the #GstPlayBin::frame property.
989    *
990    * Returns: a #GstBuffer of the current video frame converted to #caps.
991    * The caps on the buffer will describe the final layout of the buffer data.
992    * %NULL is returned when no current buffer can be retrieved or when the
993    * conversion failed.
994    */
995   gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
996       g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
997       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
998       G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
999       gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
1000
1001   /**
1002    * GstPlayBin2::get-video-pad
1003    * @playbin: a #GstPlayBin2
1004    * @stream: a video stream number
1005    *
1006    * Action signal to retrieve the stream-selector sinkpad for a specific
1007    * video stream.
1008    * This pad can be used for notifications of caps changes, stream-specific
1009    * queries, etc.
1010    *
1011    * Returns: a #GstPad, or NULL when the stream number does not exist.
1012    */
1013   gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1014       g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1015       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1016       G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1017       gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1018   /**
1019    * GstPlayBin2::get-audio-pad
1020    * @playbin: a #GstPlayBin2
1021    * @stream: an audio stream number
1022    *
1023    * Action signal to retrieve the stream-selector sinkpad for a specific
1024    * audio stream.
1025    * This pad can be used for notifications of caps changes, stream-specific
1026    * queries, etc.
1027    *
1028    * Returns: a #GstPad, or NULL when the stream number does not exist.
1029    */
1030   gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1031       g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1032       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1033       G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1034       gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1035   /**
1036    * GstPlayBin2::get-text-pad
1037    * @playbin: a #GstPlayBin2
1038    * @stream: a text stream number
1039    *
1040    * Action signal to retrieve the stream-selector sinkpad for a specific
1041    * text stream.
1042    * This pad can be used for notifications of caps changes, stream-specific
1043    * queries, etc.
1044    *
1045    * Returns: a #GstPad, or NULL when the stream number does not exist.
1046    */
1047   gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1048       g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1049       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1050       G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1051       gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1052
1053   klass->get_video_tags = gst_play_bin_get_video_tags;
1054   klass->get_audio_tags = gst_play_bin_get_audio_tags;
1055   klass->get_text_tags = gst_play_bin_get_text_tags;
1056
1057   klass->convert_frame = gst_play_bin_convert_frame;
1058
1059   klass->get_video_pad = gst_play_bin_get_video_pad;
1060   klass->get_audio_pad = gst_play_bin_get_audio_pad;
1061   klass->get_text_pad = gst_play_bin_get_text_pad;
1062
1063   gst_element_class_set_details_simple (gstelement_klass,
1064       "Player Bin 2", "Generic/Bin/Player",
1065       "Autoplug and play media from an uri",
1066       "Wim Taymans <wim.taymans@gmail.com>");
1067
1068   gstelement_klass->change_state =
1069       GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1070   gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1071
1072   gstbin_klass->handle_message =
1073       GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1074 }
1075
1076 static void
1077 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1078 {
1079   int n;
1080
1081   /* store the array for the different channels */
1082   group->video_channels = g_ptr_array_new ();
1083   group->audio_channels = g_ptr_array_new ();
1084   group->text_channels = g_ptr_array_new ();
1085   group->lock = g_mutex_new ();
1086   /* init selectors. The selector is found by finding the first prefix that
1087    * matches the media. */
1088   group->playbin = playbin;
1089   /* If you add any items to these lists, check that media_list[] is defined
1090    * above to be large enough to hold MAX(items)+1, so as to accomodate a
1091    * NULL terminator (set when the memory is zeroed on allocation) */
1092   group->selector[0].media_list[0] = "audio/x-raw-";
1093   group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
1094   group->selector[0].channels = group->audio_channels;
1095   group->selector[1].media_list[0] = "audio/";
1096   group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO;
1097   group->selector[1].channels = group->audio_channels;
1098   group->selector[2].media_list[0] = "text/";
1099   group->selector[2].media_list[1] = "application/x-subtitle";
1100   group->selector[2].media_list[2] = "application/x-ssa";
1101   group->selector[2].media_list[3] = "application/x-ass";
1102   group->selector[2].media_list[4] = "video/x-dvd-subpicture";
1103   group->selector[2].media_list[5] = "subpicture/";
1104   group->selector[2].media_list[6] = "subtitle/";
1105   group->selector[2].get_media_caps = gst_subtitle_overlay_create_factory_caps;
1106   group->selector[2].type = GST_PLAY_SINK_TYPE_TEXT;
1107   group->selector[2].channels = group->text_channels;
1108   group->selector[3].media_list[0] = "video/x-raw-";
1109   group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
1110   group->selector[3].channels = group->video_channels;
1111   group->selector[4].media_list[0] = "video/";
1112   group->selector[4].type = GST_PLAY_SINK_TYPE_VIDEO;
1113   group->selector[4].channels = group->video_channels;
1114
1115   for (n = 0; n < GST_PLAY_SINK_TYPE_LAST; n++) {
1116     GstSourceSelect *select = &group->selector[n];
1117     select->sinkpad_delayed_event = NULL;
1118     select->sinkpad_data_probe = 0;
1119   }
1120 }
1121
1122 static void
1123 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1124 {
1125   int n;
1126
1127   for (n = 0; n < GST_PLAY_SINK_TYPE_LAST; n++) {
1128     GstSourceSelect *select = &group->selector[n];
1129     if (select->sinkpad && select->sinkpad_data_probe)
1130       gst_pad_remove_data_probe (select->sinkpad, select->sinkpad_data_probe);
1131     if (select->sinkpad_delayed_event)
1132       gst_event_unref (select->sinkpad_delayed_event);
1133   }
1134
1135   g_free (group->uri);
1136   g_free (group->suburi);
1137   g_ptr_array_free (group->video_channels, TRUE);
1138   g_ptr_array_free (group->audio_channels, TRUE);
1139   g_ptr_array_free (group->text_channels, TRUE);
1140
1141   g_mutex_free (group->lock);
1142   if (group->audio_sink) {
1143     if (group->audio_sink != playbin->audio_sink)
1144       gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1145     gst_object_unref (group->audio_sink);
1146   }
1147   group->audio_sink = NULL;
1148   if (group->video_sink) {
1149     if (group->video_sink != playbin->video_sink)
1150       gst_element_set_state (group->video_sink, GST_STATE_NULL);
1151     gst_object_unref (group->video_sink);
1152   }
1153   group->video_sink = NULL;
1154
1155   g_list_free (group->stream_changed_pending);
1156   group->stream_changed_pending = NULL;
1157
1158   if (group->stream_changed_pending_lock)
1159     g_mutex_free (group->stream_changed_pending_lock);
1160   group->stream_changed_pending_lock = NULL;
1161 }
1162
1163 static void
1164 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1165 {
1166   g_object_notify (G_OBJECT (playbin), "volume");
1167 }
1168
1169 static void
1170 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1171 {
1172   g_object_notify (G_OBJECT (playbin), "mute");
1173 }
1174
1175 /* Must be called with elements lock! */
1176 static void
1177 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1178 {
1179   GList *res, *tmp;
1180
1181   if (!playbin->elements ||
1182       playbin->elements_cookie !=
1183       gst_default_registry_get_feature_list_cookie ()) {
1184     if (playbin->elements)
1185       gst_plugin_feature_list_free (playbin->elements);
1186     res =
1187         gst_element_factory_list_get_elements
1188         (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1189     tmp =
1190         gst_element_factory_list_get_elements
1191         (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1192     playbin->elements = g_list_concat (res, tmp);
1193     playbin->elements =
1194         g_list_sort (playbin->elements, gst_plugin_feature_rank_compare_func);
1195     playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1196   }
1197 }
1198
1199 static void
1200 gst_play_bin_init (GstPlayBin * playbin)
1201 {
1202   g_static_rec_mutex_init (&playbin->lock);
1203   playbin->dyn_lock = g_mutex_new ();
1204
1205   /* assume we can create a selector */
1206   playbin->have_selector = TRUE;
1207
1208   /* init groups */
1209   playbin->curr_group = &playbin->groups[0];
1210   playbin->next_group = &playbin->groups[1];
1211   init_group (playbin, &playbin->groups[0]);
1212   init_group (playbin, &playbin->groups[1]);
1213
1214   /* first filter out the interesting element factories */
1215   playbin->elements_lock = g_mutex_new ();
1216
1217   /* add sink */
1218   playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1219   gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1220   gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1221   /* Connect to notify::volume and notify::mute signals for proxying */
1222   g_signal_connect (playbin->playsink, "notify::volume",
1223       G_CALLBACK (notify_volume_cb), playbin);
1224   g_signal_connect (playbin->playsink, "notify::mute",
1225       G_CALLBACK (notify_mute_cb), playbin);
1226
1227   playbin->current_video = DEFAULT_CURRENT_VIDEO;
1228   playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1229   playbin->current_text = DEFAULT_CURRENT_TEXT;
1230
1231   playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1232   playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1233   playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1234 }
1235
1236 static void
1237 gst_play_bin_finalize (GObject * object)
1238 {
1239   GstPlayBin *playbin;
1240
1241   playbin = GST_PLAY_BIN (object);
1242
1243   free_group (playbin, &playbin->groups[0]);
1244   free_group (playbin, &playbin->groups[1]);
1245
1246   if (playbin->source)
1247     gst_object_unref (playbin->source);
1248   if (playbin->video_sink) {
1249     gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1250     gst_object_unref (playbin->video_sink);
1251   }
1252   if (playbin->audio_sink) {
1253     gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1254     gst_object_unref (playbin->audio_sink);
1255   }
1256   if (playbin->text_sink) {
1257     gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1258     gst_object_unref (playbin->text_sink);
1259   }
1260
1261   if (playbin->elements)
1262     gst_plugin_feature_list_free (playbin->elements);
1263
1264   g_static_rec_mutex_free (&playbin->lock);
1265   g_mutex_free (playbin->dyn_lock);
1266   g_mutex_free (playbin->elements_lock);
1267
1268   G_OBJECT_CLASS (parent_class)->finalize (object);
1269 }
1270
1271 static void
1272 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1273 {
1274   GstSourceGroup *group;
1275
1276   if (uri == NULL) {
1277     g_warning ("cannot set NULL uri");
1278     return;
1279   }
1280
1281   GST_PLAY_BIN_LOCK (playbin);
1282   group = playbin->next_group;
1283
1284   GST_SOURCE_GROUP_LOCK (group);
1285   /* store the uri in the next group we will play */
1286   g_free (group->uri);
1287   group->uri = g_strdup (uri);
1288   group->valid = TRUE;
1289   GST_SOURCE_GROUP_UNLOCK (group);
1290
1291   GST_DEBUG ("set new uri to %s", uri);
1292   GST_PLAY_BIN_UNLOCK (playbin);
1293 }
1294
1295 static void
1296 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1297 {
1298   GstSourceGroup *group;
1299
1300   GST_PLAY_BIN_LOCK (playbin);
1301   group = playbin->next_group;
1302
1303   GST_SOURCE_GROUP_LOCK (group);
1304   g_free (group->suburi);
1305   group->suburi = g_strdup (suburi);
1306   GST_SOURCE_GROUP_UNLOCK (group);
1307
1308   GST_DEBUG ("setting new .sub uri to %s", suburi);
1309
1310   GST_PLAY_BIN_UNLOCK (playbin);
1311 }
1312
1313 static void
1314 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1315 {
1316   gst_play_sink_set_flags (playbin->playsink, flags);
1317   gst_play_sink_reconfigure (playbin->playsink);
1318 }
1319
1320 static GstPlayFlags
1321 gst_play_bin_get_flags (GstPlayBin * playbin)
1322 {
1323   GstPlayFlags flags;
1324
1325   flags = gst_play_sink_get_flags (playbin->playsink);
1326
1327   return flags;
1328 }
1329
1330 /* get the currently playing group or if nothing is playing, the next
1331  * group. Must be called with the PLAY_BIN_LOCK. */
1332 static GstSourceGroup *
1333 get_group (GstPlayBin * playbin)
1334 {
1335   GstSourceGroup *result;
1336
1337   if (!(result = playbin->curr_group))
1338     result = playbin->next_group;
1339
1340   return result;
1341 }
1342
1343 static GstPad *
1344 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1345 {
1346   GstPad *sinkpad = NULL;
1347   GstSourceGroup *group;
1348
1349   GST_PLAY_BIN_LOCK (playbin);
1350   group = get_group (playbin);
1351   if (stream < group->video_channels->len) {
1352     sinkpad = g_ptr_array_index (group->video_channels, stream);
1353     gst_object_ref (sinkpad);
1354   }
1355   GST_PLAY_BIN_UNLOCK (playbin);
1356
1357   return sinkpad;
1358 }
1359
1360 static GstPad *
1361 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1362 {
1363   GstPad *sinkpad = NULL;
1364   GstSourceGroup *group;
1365
1366   GST_PLAY_BIN_LOCK (playbin);
1367   group = get_group (playbin);
1368   if (stream < group->audio_channels->len) {
1369     sinkpad = g_ptr_array_index (group->audio_channels, stream);
1370     gst_object_ref (sinkpad);
1371   }
1372   GST_PLAY_BIN_UNLOCK (playbin);
1373
1374   return sinkpad;
1375 }
1376
1377 static GstPad *
1378 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1379 {
1380   GstPad *sinkpad = NULL;
1381   GstSourceGroup *group;
1382
1383   GST_PLAY_BIN_LOCK (playbin);
1384   group = get_group (playbin);
1385   if (stream < group->text_channels->len) {
1386     sinkpad = g_ptr_array_index (group->text_channels, stream);
1387     gst_object_ref (sinkpad);
1388   }
1389   GST_PLAY_BIN_UNLOCK (playbin);
1390
1391   return sinkpad;
1392 }
1393
1394
1395 static GstTagList *
1396 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1397 {
1398   GstTagList *result;
1399   GstPad *sinkpad;
1400
1401   if (!channels || stream >= channels->len)
1402     return NULL;
1403
1404   sinkpad = g_ptr_array_index (channels, stream);
1405   g_object_get (sinkpad, "tags", &result, NULL);
1406
1407   return result;
1408 }
1409
1410 static GstTagList *
1411 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1412 {
1413   GstTagList *result;
1414   GstSourceGroup *group;
1415
1416   GST_PLAY_BIN_LOCK (playbin);
1417   group = get_group (playbin);
1418   result = get_tags (playbin, group->video_channels, stream);
1419   GST_PLAY_BIN_UNLOCK (playbin);
1420
1421   return result;
1422 }
1423
1424 static GstTagList *
1425 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1426 {
1427   GstTagList *result;
1428   GstSourceGroup *group;
1429
1430   GST_PLAY_BIN_LOCK (playbin);
1431   group = get_group (playbin);
1432   result = get_tags (playbin, group->audio_channels, stream);
1433   GST_PLAY_BIN_UNLOCK (playbin);
1434
1435   return result;
1436 }
1437
1438 static GstTagList *
1439 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1440 {
1441   GstTagList *result;
1442   GstSourceGroup *group;
1443
1444   GST_PLAY_BIN_LOCK (playbin);
1445   group = get_group (playbin);
1446   result = get_tags (playbin, group->text_channels, stream);
1447   GST_PLAY_BIN_UNLOCK (playbin);
1448
1449   return result;
1450 }
1451
1452 static GstBuffer *
1453 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1454 {
1455   return gst_play_sink_convert_frame (playbin->playsink, caps);
1456 }
1457
1458 /* Returns current stream number, or -1 if none has been selected yet */
1459 static int
1460 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1461 {
1462   /* Internal API cleanup would make this easier... */
1463   int i;
1464   GstPad *pad, *current;
1465   GstObject *selector = NULL;
1466   int ret = -1;
1467
1468   for (i = 0; i < channels->len; i++) {
1469     pad = g_ptr_array_index (channels, i);
1470     if ((selector = gst_pad_get_parent (pad))) {
1471       g_object_get (selector, "active-pad", &current, NULL);
1472       gst_object_unref (selector);
1473
1474       if (pad == current) {
1475         gst_object_unref (current);
1476         ret = i;
1477         break;
1478       }
1479
1480       if (current)
1481         gst_object_unref (current);
1482     }
1483   }
1484
1485   return ret;
1486 }
1487
1488 static gboolean
1489 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1490 {
1491   GstSourceGroup *group;
1492   GPtrArray *channels;
1493   GstPad *sinkpad;
1494
1495   GST_PLAY_BIN_LOCK (playbin);
1496   group = get_group (playbin);
1497   if (!(channels = group->video_channels))
1498     goto no_channels;
1499
1500   if (stream == -1 || channels->len <= stream) {
1501     sinkpad = NULL;
1502   } else {
1503     /* take channel from selected stream */
1504     sinkpad = g_ptr_array_index (channels, stream);
1505   }
1506
1507   if (sinkpad)
1508     gst_object_ref (sinkpad);
1509   GST_PLAY_BIN_UNLOCK (playbin);
1510
1511   if (sinkpad) {
1512     GstObject *selector;
1513
1514     if ((selector = gst_pad_get_parent (sinkpad))) {
1515       /* activate the selected pad */
1516       g_object_set (selector, "active-pad", sinkpad, NULL);
1517       gst_object_unref (selector);
1518     }
1519     gst_object_unref (sinkpad);
1520   }
1521   return TRUE;
1522
1523 no_channels:
1524   {
1525     GST_PLAY_BIN_UNLOCK (playbin);
1526     GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1527     return FALSE;
1528   }
1529 }
1530
1531 static gboolean
1532 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1533 {
1534   GstSourceGroup *group;
1535   GPtrArray *channels;
1536   GstPad *sinkpad;
1537
1538   GST_PLAY_BIN_LOCK (playbin);
1539   group = get_group (playbin);
1540   if (!(channels = group->audio_channels))
1541     goto no_channels;
1542
1543   if (stream == -1 || channels->len <= stream) {
1544     sinkpad = NULL;
1545   } else {
1546     /* take channel from selected stream */
1547     sinkpad = g_ptr_array_index (channels, stream);
1548   }
1549
1550   if (sinkpad)
1551     gst_object_ref (sinkpad);
1552   GST_PLAY_BIN_UNLOCK (playbin);
1553
1554   if (sinkpad) {
1555     GstObject *selector;
1556
1557     if ((selector = gst_pad_get_parent (sinkpad))) {
1558       /* activate the selected pad */
1559       g_object_set (selector, "active-pad", sinkpad, NULL);
1560       gst_object_unref (selector);
1561     }
1562     gst_object_unref (sinkpad);
1563   }
1564   return TRUE;
1565
1566 no_channels:
1567   {
1568     GST_PLAY_BIN_UNLOCK (playbin);
1569     GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1570     return FALSE;
1571   }
1572 }
1573
1574 static void
1575 _suburidecodebin_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
1576 {
1577   GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
1578 }
1579
1580 static void
1581 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1582 {
1583   GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1584   GstPad *sinkpad;
1585
1586   if (it && gst_iterator_next (it, (gpointer) & sinkpad) == GST_ITERATOR_OK
1587       && sinkpad) {
1588     GstEvent *event;
1589
1590     event =
1591         gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1592         GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1593     if (!gst_pad_send_event (sinkpad, event)) {
1594       event =
1595           gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1596           GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1597       if (!gst_pad_send_event (sinkpad, event))
1598         GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1599     }
1600
1601     gst_object_unref (sinkpad);
1602   }
1603
1604   if (it)
1605     gst_iterator_free (it);
1606 }
1607
1608 static void
1609 gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
1610     gboolean block)
1611 {
1612   GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1613   gboolean done = FALSE;
1614
1615   GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1616
1617   if (!it)
1618     return;
1619   while (!done) {
1620     GstPad *sinkpad;
1621
1622     switch (gst_iterator_next (it, (gpointer) & sinkpad)) {
1623       case GST_ITERATOR_OK:
1624         gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
1625             NULL);
1626         gst_object_unref (sinkpad);
1627         break;
1628       case GST_ITERATOR_DONE:
1629         done = TRUE;
1630         break;
1631       case GST_ITERATOR_RESYNC:
1632         gst_iterator_resync (it);
1633         break;
1634       case GST_ITERATOR_ERROR:
1635         done = TRUE;
1636         break;
1637     }
1638   }
1639   gst_iterator_free (it);
1640 }
1641
1642 static gboolean
1643 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1644 {
1645   GstSourceGroup *group;
1646   GPtrArray *channels;
1647   GstPad *sinkpad;
1648
1649   GST_PLAY_BIN_LOCK (playbin);
1650   group = get_group (playbin);
1651   if (!(channels = group->text_channels))
1652     goto no_channels;
1653
1654   if (stream == -1 || channels->len <= stream) {
1655     sinkpad = NULL;
1656   } else {
1657     /* take channel from selected stream */
1658     sinkpad = g_ptr_array_index (channels, stream);
1659   }
1660
1661   if (sinkpad)
1662     gst_object_ref (sinkpad);
1663   GST_PLAY_BIN_UNLOCK (playbin);
1664
1665   if (sinkpad) {
1666     GstObject *selector;
1667
1668     if ((selector = gst_pad_get_parent (sinkpad))) {
1669       GstPad *old_sinkpad;
1670
1671       g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1672
1673       if (old_sinkpad != sinkpad) {
1674         gboolean need_unblock, need_block, need_seek;
1675         GstPad *src, *peer = NULL, *oldpeer = NULL;
1676         GstElement *parent_element = NULL, *old_parent_element = NULL;
1677
1678         /* Now check if we need to seek the suburidecodebin to the beginning
1679          * or if we need to block all suburidecodebin sinkpads or if we need
1680          * to unblock all suburidecodebin sinkpads
1681          */
1682         if (sinkpad)
1683           peer = gst_pad_get_peer (sinkpad);
1684         if (old_sinkpad)
1685           oldpeer = gst_pad_get_peer (old_sinkpad);
1686
1687         if (peer)
1688           parent_element = gst_pad_get_parent_element (peer);
1689         if (oldpeer)
1690           old_parent_element = gst_pad_get_parent_element (oldpeer);
1691
1692         need_block = (old_parent_element == group->suburidecodebin
1693             && parent_element != old_parent_element);
1694         need_unblock = (parent_element == group->suburidecodebin
1695             && parent_element != old_parent_element);
1696         need_seek = (parent_element == group->suburidecodebin);
1697
1698         if (peer)
1699           gst_object_unref (peer);
1700         if (oldpeer)
1701           gst_object_unref (oldpeer);
1702         if (parent_element)
1703           gst_object_unref (parent_element);
1704         if (old_parent_element)
1705           gst_object_unref (old_parent_element);
1706
1707         /* Block all suburidecodebin sinkpads */
1708         if (need_block)
1709           gst_play_bin_suburidecodebin_block (group->suburidecodebin, TRUE);
1710
1711         /* activate the selected pad */
1712         g_object_set (selector, "active-pad", sinkpad, NULL);
1713
1714         src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1715         peer = gst_pad_get_peer (src);
1716         if (peer) {
1717           GstStructure *s;
1718           GstEvent *event;
1719           /* Flush the subtitle renderer to remove any
1720            * currently displayed subtitles. This event will
1721            * never travel outside subtitleoverlay!
1722            */
1723           s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1724           event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1725           gst_pad_send_event (peer, event);
1726           gst_object_unref (peer);
1727         }
1728         gst_object_unref (src);
1729
1730         /* Unblock pads if necessary */
1731         if (need_unblock)
1732           gst_play_bin_suburidecodebin_block (group->suburidecodebin, FALSE);
1733
1734         /* seek to the beginning */
1735         if (need_seek)
1736           gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1737       }
1738       gst_object_unref (selector);
1739
1740       if (old_sinkpad)
1741         gst_object_unref (old_sinkpad);
1742     }
1743     gst_object_unref (sinkpad);
1744   }
1745   return TRUE;
1746
1747 no_channels:
1748   {
1749     GST_PLAY_BIN_UNLOCK (playbin);
1750     return FALSE;
1751   }
1752 }
1753
1754 static void
1755 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1756     const gchar * dbg, GstElement * sink)
1757 {
1758   GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1759
1760   GST_PLAY_BIN_LOCK (playbin);
1761   if (*elem != sink) {
1762     GstElement *old;
1763
1764     old = *elem;
1765     if (sink)
1766       gst_object_ref_sink (sink);
1767
1768     *elem = sink;
1769     if (old)
1770       gst_object_unref (old);
1771   }
1772   GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1773   GST_PLAY_BIN_UNLOCK (playbin);
1774 }
1775
1776 static void
1777 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1778 {
1779   GstElement *elem;
1780
1781   GST_PLAY_BIN_LOCK (playbin);
1782
1783   /* set subtitles on all current and next decodebins. */
1784   if ((elem = playbin->groups[0].uridecodebin))
1785     g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1786   if ((elem = playbin->groups[0].suburidecodebin))
1787     g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1788   if ((elem = playbin->groups[1].uridecodebin))
1789     g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1790   if ((elem = playbin->groups[1].suburidecodebin))
1791     g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1792
1793   gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1794   GST_PLAY_BIN_UNLOCK (playbin);
1795 }
1796
1797 static void
1798 gst_play_bin_set_property (GObject * object, guint prop_id,
1799     const GValue * value, GParamSpec * pspec)
1800 {
1801   GstPlayBin *playbin = GST_PLAY_BIN (object);
1802
1803   switch (prop_id) {
1804     case PROP_URI:
1805       gst_play_bin_set_uri (playbin, g_value_get_string (value));
1806       break;
1807     case PROP_SUBURI:
1808       gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1809       break;
1810     case PROP_FLAGS:
1811       gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1812       break;
1813     case PROP_CURRENT_VIDEO:
1814       gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1815       break;
1816     case PROP_CURRENT_AUDIO:
1817       gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1818       break;
1819     case PROP_CURRENT_TEXT:
1820       gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1821       break;
1822     case PROP_SUBTITLE_ENCODING:
1823       gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1824       break;
1825     case PROP_VIDEO_SINK:
1826       gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1827           g_value_get_object (value));
1828       break;
1829     case PROP_AUDIO_SINK:
1830       gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1831           g_value_get_object (value));
1832       break;
1833     case PROP_VIS_PLUGIN:
1834       gst_play_sink_set_vis_plugin (playbin->playsink,
1835           g_value_get_object (value));
1836       break;
1837     case PROP_TEXT_SINK:
1838       gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1839           g_value_get_object (value));
1840       break;
1841     case PROP_VOLUME:
1842       gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1843       break;
1844     case PROP_MUTE:
1845       gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1846       break;
1847     case PROP_FONT_DESC:
1848       gst_play_sink_set_font_desc (playbin->playsink,
1849           g_value_get_string (value));
1850       break;
1851     case PROP_CONNECTION_SPEED:
1852       GST_PLAY_BIN_LOCK (playbin);
1853       playbin->connection_speed = g_value_get_uint (value) * 1000;
1854       GST_PLAY_BIN_UNLOCK (playbin);
1855       break;
1856     case PROP_BUFFER_SIZE:
1857       playbin->buffer_size = g_value_get_int (value);
1858       break;
1859     case PROP_BUFFER_DURATION:
1860       playbin->buffer_duration = g_value_get_int64 (value);
1861       break;
1862     case PROP_AV_OFFSET:
1863       gst_play_sink_set_av_offset (playbin->playsink,
1864           g_value_get_int64 (value));
1865       break;
1866     case PROP_RING_BUFFER_MAX_SIZE:
1867       playbin->ring_buffer_max_size = g_value_get_uint64 (value);
1868       break;
1869     default:
1870       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1871       break;
1872   }
1873 }
1874
1875 static GstElement *
1876 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1877     const gchar * dbg, GstPlaySinkType type)
1878 {
1879   GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
1880
1881   GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1882       GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1883       dbg, sink, dbg, *elem);
1884
1885   if (sink == NULL) {
1886     GST_PLAY_BIN_LOCK (playbin);
1887     if ((sink = *elem))
1888       gst_object_ref (sink);
1889     GST_PLAY_BIN_UNLOCK (playbin);
1890   }
1891
1892   return sink;
1893 }
1894
1895 static void
1896 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1897     GParamSpec * pspec)
1898 {
1899   GstPlayBin *playbin = GST_PLAY_BIN (object);
1900
1901   switch (prop_id) {
1902     case PROP_URI:
1903     {
1904       GstSourceGroup *group;
1905
1906       GST_PLAY_BIN_LOCK (playbin);
1907       group = get_group (playbin);
1908       g_value_set_string (value, group->uri);
1909       GST_PLAY_BIN_UNLOCK (playbin);
1910       break;
1911     }
1912     case PROP_SUBURI:
1913     {
1914       GstSourceGroup *group;
1915
1916       GST_PLAY_BIN_LOCK (playbin);
1917       group = get_group (playbin);
1918       g_value_set_string (value, group->suburi);
1919       GST_PLAY_BIN_UNLOCK (playbin);
1920       break;
1921     }
1922     case PROP_SOURCE:
1923     {
1924       GST_OBJECT_LOCK (playbin);
1925       g_value_set_object (value, playbin->source);
1926       GST_OBJECT_UNLOCK (playbin);
1927       break;
1928     }
1929     case PROP_FLAGS:
1930       g_value_set_flags (value, gst_play_bin_get_flags (playbin));
1931       break;
1932     case PROP_N_VIDEO:
1933     {
1934       GstSourceGroup *group;
1935       gint n_video;
1936
1937       GST_PLAY_BIN_LOCK (playbin);
1938       group = get_group (playbin);
1939       n_video = (group->video_channels ? group->video_channels->len : 0);
1940       g_value_set_int (value, n_video);
1941       GST_PLAY_BIN_UNLOCK (playbin);
1942       break;
1943     }
1944     case PROP_CURRENT_VIDEO:
1945       GST_PLAY_BIN_LOCK (playbin);
1946       g_value_set_int (value, playbin->current_video);
1947       GST_PLAY_BIN_UNLOCK (playbin);
1948       break;
1949     case PROP_N_AUDIO:
1950     {
1951       GstSourceGroup *group;
1952       gint n_audio;
1953
1954       GST_PLAY_BIN_LOCK (playbin);
1955       group = get_group (playbin);
1956       n_audio = (group->audio_channels ? group->audio_channels->len : 0);
1957       g_value_set_int (value, n_audio);
1958       GST_PLAY_BIN_UNLOCK (playbin);
1959       break;
1960     }
1961     case PROP_CURRENT_AUDIO:
1962       GST_PLAY_BIN_LOCK (playbin);
1963       g_value_set_int (value, playbin->current_audio);
1964       GST_PLAY_BIN_UNLOCK (playbin);
1965       break;
1966     case PROP_N_TEXT:
1967     {
1968       GstSourceGroup *group;
1969       gint n_text;
1970
1971       GST_PLAY_BIN_LOCK (playbin);
1972       group = get_group (playbin);
1973       n_text = (group->text_channels ? group->text_channels->len : 0);
1974       g_value_set_int (value, n_text);
1975       GST_PLAY_BIN_UNLOCK (playbin);
1976       break;
1977     }
1978     case PROP_CURRENT_TEXT:
1979       GST_PLAY_BIN_LOCK (playbin);
1980       g_value_set_int (value, playbin->current_text);
1981       GST_PLAY_BIN_UNLOCK (playbin);
1982       break;
1983     case PROP_SUBTITLE_ENCODING:
1984       GST_PLAY_BIN_LOCK (playbin);
1985       g_value_take_string (value,
1986           gst_play_sink_get_subtitle_encoding (playbin->playsink));
1987       GST_PLAY_BIN_UNLOCK (playbin);
1988       break;
1989     case PROP_VIDEO_SINK:
1990       g_value_take_object (value,
1991           gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
1992               "video", GST_PLAY_SINK_TYPE_VIDEO));
1993       break;
1994     case PROP_AUDIO_SINK:
1995       g_value_take_object (value,
1996           gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
1997               "audio", GST_PLAY_SINK_TYPE_AUDIO));
1998       break;
1999     case PROP_VIS_PLUGIN:
2000       g_value_take_object (value,
2001           gst_play_sink_get_vis_plugin (playbin->playsink));
2002       break;
2003     case PROP_TEXT_SINK:
2004       g_value_take_object (value,
2005           gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2006               "text", GST_PLAY_SINK_TYPE_TEXT));
2007       break;
2008     case PROP_VOLUME:
2009       g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2010       break;
2011     case PROP_MUTE:
2012       g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2013       break;
2014     case PROP_FRAME:
2015       gst_value_take_buffer (value,
2016           gst_play_sink_get_last_frame (playbin->playsink));
2017       break;
2018     case PROP_FONT_DESC:
2019       g_value_take_string (value,
2020           gst_play_sink_get_font_desc (playbin->playsink));
2021       break;
2022     case PROP_CONNECTION_SPEED:
2023       GST_PLAY_BIN_LOCK (playbin);
2024       g_value_set_uint (value, playbin->connection_speed / 1000);
2025       GST_PLAY_BIN_UNLOCK (playbin);
2026       break;
2027     case PROP_BUFFER_SIZE:
2028       GST_OBJECT_LOCK (playbin);
2029       g_value_set_int (value, playbin->buffer_size);
2030       GST_OBJECT_UNLOCK (playbin);
2031       break;
2032     case PROP_BUFFER_DURATION:
2033       GST_OBJECT_LOCK (playbin);
2034       g_value_set_int64 (value, playbin->buffer_duration);
2035       GST_OBJECT_UNLOCK (playbin);
2036       break;
2037     case PROP_AV_OFFSET:
2038       g_value_set_int64 (value,
2039           gst_play_sink_get_av_offset (playbin->playsink));
2040       break;
2041     case PROP_RING_BUFFER_MAX_SIZE:
2042       g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2043       break;
2044     default:
2045       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2046       break;
2047   }
2048 }
2049
2050 static void
2051 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2052     gboolean valid, GstQuery * query)
2053 {
2054   GstFormat fmt;
2055   gint64 duration;
2056   gint i;
2057
2058   GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2059   gst_query_parse_duration (query, &fmt, &duration);
2060
2061   for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2062     if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2063       playbin->duration[i].valid = valid;
2064       playbin->duration[i].format = fmt;
2065       playbin->duration[i].duration = valid ? duration : -1;
2066       break;
2067     }
2068   }
2069 }
2070
2071 static void
2072 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2073 {
2074   const GstFormat formats[] =
2075       { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2076   gboolean ret;
2077   GstQuery *query;
2078   gint i;
2079
2080   GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2081   for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2082     query = gst_query_new_duration (formats[i]);
2083     ret =
2084         GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2085         query);
2086     gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2087     gst_query_unref (query);
2088   }
2089 }
2090
2091 static gboolean
2092 gst_play_bin_query (GstElement * element, GstQuery * query)
2093 {
2094   GstPlayBin *playbin = GST_PLAY_BIN (element);
2095   gboolean ret;
2096
2097   /* During a group switch we shouldn't allow duration queries
2098    * because it's not clear if the old or new group's duration
2099    * is returned and if the sinks are already playing new data
2100    * or old data. See bug #585969
2101    *
2102    * While we're at it, also don't do any other queries during
2103    * a group switch or any other event that causes topology changes
2104    * by taking the playbin lock in any case.
2105    */
2106   GST_PLAY_BIN_LOCK (playbin);
2107
2108   if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2109     GstSourceGroup *group = playbin->curr_group;
2110     gboolean pending;
2111
2112     GST_SOURCE_GROUP_LOCK (group);
2113     if (group->stream_changed_pending_lock) {
2114       g_mutex_lock (group->stream_changed_pending_lock);
2115       pending = group->pending || group->stream_changed_pending;
2116       g_mutex_unlock (group->stream_changed_pending_lock);
2117     } else {
2118       pending = group->pending;
2119     }
2120     if (pending) {
2121       GstFormat fmt;
2122       gint i;
2123
2124       ret = FALSE;
2125       gst_query_parse_duration (query, &fmt, NULL);
2126       for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2127         if (fmt == playbin->duration[i].format) {
2128           ret = playbin->duration[i].valid;
2129           gst_query_set_duration (query, fmt,
2130               (ret ? playbin->duration[i].duration : -1));
2131           break;
2132         }
2133       }
2134       /* if nothing cached yet, we might as well request duration,
2135        * such as during initial startup */
2136       if (ret) {
2137         GST_DEBUG_OBJECT (playbin,
2138             "Taking cached duration because of pending group switch: %d", ret);
2139         GST_SOURCE_GROUP_UNLOCK (group);
2140         GST_PLAY_BIN_UNLOCK (playbin);
2141         return ret;
2142       }
2143     }
2144     GST_SOURCE_GROUP_UNLOCK (group);
2145   }
2146
2147   ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2148
2149   if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2150     gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2151   GST_PLAY_BIN_UNLOCK (playbin);
2152
2153   return ret;
2154 }
2155
2156 /* mime types we are not handling on purpose right now, don't post a
2157  * missing-plugin message for these */
2158 static const gchar *blacklisted_mimes[] = {
2159   NULL
2160 };
2161
2162 static void
2163 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2164 {
2165   GstPlayBin *playbin = GST_PLAY_BIN (bin);
2166   GstSourceGroup *group;
2167
2168   if (gst_is_missing_plugin_message (msg)) {
2169     gchar *detail;
2170     guint i;
2171
2172     detail = gst_missing_plugin_message_get_installer_detail (msg);
2173     for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2174       if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2175         GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2176         gst_message_unref (msg);
2177         g_free (detail);
2178         return;
2179       }
2180     }
2181     g_free (detail);
2182   } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2183     const GstStructure *s = gst_message_get_structure (msg);
2184
2185     /* Drop all stream-changed messages except the last one */
2186     if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2187       guint32 seqnum = gst_message_get_seqnum (msg);
2188       GList *l, *l_prev;
2189
2190       group = playbin->curr_group;
2191       g_mutex_lock (group->stream_changed_pending_lock);
2192       for (l = group->stream_changed_pending; l;) {
2193         guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2194
2195         if (l_seqnum == seqnum) {
2196           l_prev = l;
2197           l = l->next;
2198           group->stream_changed_pending =
2199               g_list_delete_link (group->stream_changed_pending, l_prev);
2200           if (group->stream_changed_pending) {
2201             gst_message_unref (msg);
2202             msg = NULL;
2203             break;
2204           }
2205         } else {
2206           l = l->next;
2207         }
2208       }
2209       g_mutex_unlock (group->stream_changed_pending_lock);
2210     }
2211   } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2212       GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2213     GstObject *src = GST_OBJECT_CAST (msg->src);
2214
2215     /* Ignore async state changes from the uridecodebin children,
2216      * see bug #602000. */
2217     group = playbin->curr_group;
2218     if (src && (group = playbin->curr_group) &&
2219         ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2220             || (group->suburidecodebin
2221                 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2222       GST_DEBUG_OBJECT (playbin,
2223           "Ignoring async state change of uridecodebin: %s",
2224           GST_OBJECT_NAME (src));
2225       gst_message_unref (msg);
2226       msg = NULL;
2227     }
2228   } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2229     /* If we get an error of the subtitle uridecodebin transform
2230      * them into warnings and disable the subtitles */
2231     group = playbin->curr_group;
2232     if (group && group->suburidecodebin) {
2233       if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2234                   (group->suburidecodebin)))) {
2235         GError *err;
2236         gchar *debug = NULL;
2237         GstMessage *new_msg;
2238         GstIterator *it;
2239         gboolean done = FALSE;
2240
2241         gst_message_parse_error (msg, &err, &debug);
2242         new_msg = gst_message_new_warning (msg->src, err, debug);
2243
2244         gst_message_unref (msg);
2245         g_error_free (err);
2246         g_free (debug);
2247         msg = new_msg;
2248
2249         REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2250         REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2251         REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2252         REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2253
2254         it = gst_element_iterate_src_pads (group->suburidecodebin);
2255         while (it && !done) {
2256           GstPad *p = NULL;
2257           GstIteratorResult res;
2258
2259           res = gst_iterator_next (it, (gpointer) & p);
2260
2261           switch (res) {
2262             case GST_ITERATOR_DONE:
2263               done = TRUE;
2264               break;
2265             case GST_ITERATOR_OK:
2266               pad_removed_cb (NULL, p, group);
2267               gst_object_unref (p);
2268               break;
2269
2270             case GST_ITERATOR_RESYNC:
2271               gst_iterator_resync (it);
2272               break;
2273             case GST_ITERATOR_ERROR:
2274               done = TRUE;
2275               break;
2276           }
2277         }
2278         if (it)
2279           gst_iterator_free (it);
2280
2281         gst_object_ref (group->suburidecodebin);
2282         gst_bin_remove (bin, group->suburidecodebin);
2283         gst_element_set_locked_state (group->suburidecodebin, FALSE);
2284
2285         if (group->sub_pending) {
2286           group->sub_pending = FALSE;
2287           no_more_pads_cb (NULL, group);
2288         }
2289       }
2290     }
2291   }
2292
2293   if (msg)
2294     GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2295 }
2296
2297 static void
2298 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2299     GstPlayBin * playbin)
2300 {
2301   const gchar *property;
2302   GstSourceGroup *group;
2303   GstSourceSelect *select = NULL;
2304   int i;
2305
2306   GST_PLAY_BIN_LOCK (playbin);
2307   group = get_group (playbin);
2308
2309   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2310     if (selector == G_OBJECT (group->selector[i].selector)) {
2311       select = &group->selector[i];
2312     }
2313   }
2314
2315   /* We got a pad-change after our group got switched out; no need to notify */
2316   if (!select) {
2317     GST_PLAY_BIN_UNLOCK (playbin);
2318     return;
2319   }
2320
2321   switch (select->type) {
2322     case GST_PLAY_SINK_TYPE_VIDEO:
2323     case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2324       property = "current-video";
2325       playbin->current_video = get_current_stream_number (playbin,
2326           group->video_channels);
2327       break;
2328     case GST_PLAY_SINK_TYPE_AUDIO:
2329     case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2330       property = "current-audio";
2331       playbin->current_audio = get_current_stream_number (playbin,
2332           group->audio_channels);
2333       break;
2334     case GST_PLAY_SINK_TYPE_TEXT:
2335       property = "current-text";
2336       playbin->current_text = get_current_stream_number (playbin,
2337           group->text_channels);
2338       break;
2339     default:
2340       property = NULL;
2341   }
2342   GST_PLAY_BIN_UNLOCK (playbin);
2343
2344   if (property)
2345     g_object_notify (G_OBJECT (playbin), property);
2346 }
2347
2348 static void
2349 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
2350 {
2351   /* no nothing */
2352   GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
2353 }
2354
2355 /* this callback sends a delayed event once the pad becomes unblocked */
2356 static gboolean
2357 stream_changed_data_probe (GstPad * pad, GstMiniObject * object, gpointer data)
2358 {
2359   GstSourceSelect *select = (GstSourceSelect *) data;
2360   GstEvent *e;
2361
2362   /* we need do this just once, so cleanup first */
2363   gst_pad_remove_data_probe (pad, select->sinkpad_data_probe);
2364   select->sinkpad_data_probe = 0;
2365   e = select->sinkpad_delayed_event;
2366   select->sinkpad_delayed_event = NULL;
2367
2368   /* really, this should not happen */
2369   if (!e) {
2370     GST_WARNING ("Data probed called, but no delayed event");
2371     return TRUE;
2372   }
2373
2374   if (GST_IS_EVENT (object)
2375       && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_NEWSEGMENT) {
2376     /* push the event first, then send the delayed one */
2377     gst_event_ref (GST_EVENT_CAST (object));
2378     gst_pad_send_event (pad, GST_EVENT_CAST (object));
2379     gst_pad_send_event (pad, e);
2380     return FALSE;
2381   } else {
2382     /* send delayed event, then allow the caller to go on */
2383     gst_pad_send_event (pad, e);
2384     return TRUE;
2385   }
2386 }
2387
2388 /* helper function to lookup stuff in lists */
2389 static gboolean
2390 array_has_value (const gchar * values[], const gchar * value)
2391 {
2392   gint i;
2393
2394   for (i = 0; values[i]; i++) {
2395     if (g_str_has_prefix (value, values[i]))
2396       return TRUE;
2397   }
2398   return FALSE;
2399 }
2400
2401 typedef struct
2402 {
2403   GstPlayBin *playbin;
2404   gint stream_id;
2405   GstPlaySinkType type;
2406 } NotifyTagsData;
2407
2408 static void
2409 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2410 {
2411   NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2412   gint signal;
2413
2414   GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2415       " with stream id %d and type %d have changed",
2416       object, ntdata->stream_id, ntdata->type);
2417
2418   switch (ntdata->type) {
2419     case GST_PLAY_SINK_TYPE_VIDEO:
2420     case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2421       signal = SIGNAL_VIDEO_TAGS_CHANGED;
2422       break;
2423     case GST_PLAY_SINK_TYPE_AUDIO:
2424     case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2425       signal = SIGNAL_AUDIO_TAGS_CHANGED;
2426       break;
2427     case GST_PLAY_SINK_TYPE_TEXT:
2428       signal = SIGNAL_TEXT_TAGS_CHANGED;
2429       break;
2430     default:
2431       signal = -1;
2432       break;
2433   }
2434
2435   if (signal >= 0)
2436     g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2437         ntdata->stream_id);
2438 }
2439
2440 /* this function is called when a new pad is added to decodebin. We check the
2441  * type of the pad and add it to the selector element of the group.
2442  */
2443 static void
2444 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2445 {
2446   GstPlayBin *playbin;
2447   GstCaps *caps;
2448   const GstStructure *s;
2449   const gchar *name;
2450   GstPad *sinkpad;
2451   GstPadLinkReturn res;
2452   GstSourceSelect *select = NULL;
2453   gint i;
2454   gboolean changed = FALSE;
2455
2456   playbin = group->playbin;
2457
2458   caps = gst_pad_get_caps_reffed (pad);
2459   s = gst_caps_get_structure (caps, 0);
2460   name = gst_structure_get_name (s);
2461
2462   GST_DEBUG_OBJECT (playbin,
2463       "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2464       GST_DEBUG_PAD_NAME (pad), caps, group);
2465
2466   /* major type of the pad, this determines the selector to use */
2467   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2468     if (array_has_value (group->selector[i].media_list, name)) {
2469       select = &group->selector[i];
2470       break;
2471     } else if (group->selector[i].get_media_caps) {
2472       GstCaps *media_caps = group->selector[i].get_media_caps ();
2473
2474       if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2475         select = &group->selector[i];
2476         gst_caps_unref (media_caps);
2477         break;
2478       }
2479       gst_caps_unref (media_caps);
2480     }
2481   }
2482   /* no selector found for the media type, don't bother linking it to a
2483    * selector. This will leave the pad unlinked and thus ignored. */
2484   if (select == NULL)
2485     goto unknown_type;
2486
2487   GST_SOURCE_GROUP_LOCK (group);
2488   if (select->selector == NULL && playbin->have_selector) {
2489     /* no selector, create one */
2490     GST_DEBUG_OBJECT (playbin, "creating new input selector");
2491     select->selector = gst_element_factory_make ("input-selector", NULL);
2492     if (select->selector == NULL) {
2493       /* post the missing selector message only once */
2494       playbin->have_selector = FALSE;
2495       gst_element_post_message (GST_ELEMENT_CAST (playbin),
2496           gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2497               "input-selector"));
2498       GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2499           (_("Missing element '%s' - check your GStreamer installation."),
2500               "input-selector"), (NULL));
2501     } else {
2502       g_signal_connect (select->selector, "notify::active-pad",
2503           G_CALLBACK (selector_active_pad_changed), playbin);
2504
2505       GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2506       gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2507       gst_element_set_state (select->selector, GST_STATE_PAUSED);
2508     }
2509   }
2510
2511   if (select->srcpad == NULL) {
2512     if (select->selector) {
2513       /* save source pad of the selector */
2514       select->srcpad = gst_element_get_static_pad (select->selector, "src");
2515     } else {
2516       /* no selector, use the pad as the source pad then */
2517       select->srcpad = gst_object_ref (pad);
2518     }
2519
2520     /* block the selector srcpad. It's possible that multiple decodebins start
2521      * pushing data into the selectors before we have a chance to collect all
2522      * streams and connect the sinks, resulting in not-linked errors. After we
2523      * configured the sinks we will unblock them all. */
2524     GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2525     gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
2526   }
2527
2528   /* get sinkpad for the new stream */
2529   if (select->selector) {
2530     if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2531       gulong notify_tags_handler = 0;
2532       NotifyTagsData *ntdata;
2533
2534       GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2535           GST_DEBUG_PAD_NAME (sinkpad));
2536
2537       /* store the selector for the pad */
2538       g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2539
2540       /* connect to the notify::tags signal for our
2541        * own *-tags-changed signals
2542        */
2543       ntdata = g_new0 (NotifyTagsData, 1);
2544       ntdata->playbin = playbin;
2545       ntdata->stream_id = select->channels->len;
2546       ntdata->type = select->type;
2547
2548       notify_tags_handler =
2549           g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2550           G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2551           (GConnectFlags) 0);
2552       g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2553           (gpointer) notify_tags_handler);
2554
2555       /* store the pad in the array */
2556       GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2557       g_ptr_array_add (select->channels, sinkpad);
2558
2559       res = gst_pad_link (pad, sinkpad);
2560       if (GST_PAD_LINK_FAILED (res))
2561         goto link_failed;
2562
2563       /* store selector pad so we can release it */
2564       g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2565
2566       changed = TRUE;
2567       GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2568           GST_DEBUG_PAD_NAME (pad), select->selector);
2569     }
2570   } else {
2571     /* no selector, don't configure anything, we'll link the new pad directly to
2572      * the sink. */
2573     changed = FALSE;
2574     sinkpad = NULL;
2575   }
2576   GST_SOURCE_GROUP_UNLOCK (group);
2577
2578   if (changed) {
2579     int signal;
2580     gboolean always_ok = (decodebin == group->suburidecodebin);
2581
2582     switch (select->type) {
2583       case GST_PLAY_SINK_TYPE_VIDEO:
2584       case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2585         /* we want to return NOT_LINKED for unselected pads but only for pads
2586          * from the normal uridecodebin. This makes sure that subtitle streams
2587          * are not raced past audio/video from decodebin2's multiqueue.
2588          * For pads from suburidecodebin OK should always be returned, otherwise
2589          * it will most likely stop. */
2590         g_object_set (sinkpad, "always-ok", always_ok, NULL);
2591         signal = SIGNAL_VIDEO_CHANGED;
2592         break;
2593       case GST_PLAY_SINK_TYPE_AUDIO:
2594       case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2595         g_object_set (sinkpad, "always-ok", always_ok, NULL);
2596         signal = SIGNAL_AUDIO_CHANGED;
2597         break;
2598       case GST_PLAY_SINK_TYPE_TEXT:
2599         g_object_set (sinkpad, "always-ok", always_ok, NULL);
2600         signal = SIGNAL_TEXT_CHANGED;
2601         break;
2602       default:
2603         signal = -1;
2604     }
2605
2606     if (signal >= 0)
2607       g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2608   }
2609
2610 done:
2611   gst_caps_unref (caps);
2612   return;
2613
2614   /* ERRORS */
2615 unknown_type:
2616   {
2617     GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2618         name, GST_DEBUG_PAD_NAME (pad));
2619     goto done;
2620   }
2621 link_failed:
2622   {
2623     GST_ERROR_OBJECT (playbin,
2624         "failed to link pad %s:%s to selector, reason %d",
2625         GST_DEBUG_PAD_NAME (pad), res);
2626     GST_SOURCE_GROUP_UNLOCK (group);
2627     goto done;
2628   }
2629 }
2630
2631 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2632  * the selector. This will make the selector select a new pad. */
2633 static void
2634 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2635 {
2636   GstPlayBin *playbin;
2637   GstPad *peer;
2638   GstElement *selector;
2639   GstSourceSelect *select;
2640
2641   playbin = group->playbin;
2642
2643   GST_DEBUG_OBJECT (playbin,
2644       "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2645
2646   GST_SOURCE_GROUP_LOCK (group);
2647   /* get the selector sinkpad */
2648   if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2649     goto not_linked;
2650
2651   if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2652     gulong notify_tags_handler;
2653
2654     notify_tags_handler =
2655         (gulong) g_object_get_data (G_OBJECT (peer),
2656         "playbin2.notify_tags_handler");
2657     if (notify_tags_handler != 0)
2658       g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2659     g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2660
2661     /* remove the pad from the array */
2662     g_ptr_array_remove (select->channels, peer);
2663     GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2664   }
2665
2666   /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2667   gst_pad_unlink (pad, peer);
2668
2669   /* get selector, this can be NULL when the element is removing the pads
2670    * because it's being disposed. */
2671   selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2672   if (!selector) {
2673     gst_object_unref (peer);
2674     goto no_selector;
2675   }
2676
2677   /* release the pad to the selector, this will make the selector choose a new
2678    * pad. */
2679   gst_element_release_request_pad (selector, peer);
2680   gst_object_unref (peer);
2681
2682   gst_object_unref (selector);
2683   GST_SOURCE_GROUP_UNLOCK (group);
2684
2685   return;
2686
2687   /* ERRORS */
2688 not_linked:
2689   {
2690     GST_DEBUG_OBJECT (playbin, "pad not linked");
2691     GST_SOURCE_GROUP_UNLOCK (group);
2692     return;
2693   }
2694 no_selector:
2695   {
2696     GST_DEBUG_OBJECT (playbin, "selector not found");
2697     GST_SOURCE_GROUP_UNLOCK (group);
2698     return;
2699   }
2700 }
2701
2702 /* we get called when all pads are available and we must connect the sinks to
2703  * them.
2704  * The main purpose of the code is to see if we have video/audio and subtitles
2705  * and pick the right pipelines to display them.
2706  *
2707  * The selectors installed on the group tell us about the presence of
2708  * audio/video and subtitle streams. This allows us to see if we need
2709  * visualisation, video or/and audio.
2710  */
2711 static void
2712 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2713 {
2714   GstPlayBin *playbin;
2715   GstPadLinkReturn res;
2716   gint i;
2717   gboolean configure;
2718
2719   playbin = group->playbin;
2720
2721   GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2722
2723   GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2724
2725   GST_SOURCE_GROUP_LOCK (group);
2726   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2727     GstSourceSelect *select = &group->selector[i];
2728
2729     /* check if the specific media type was detected and thus has a selector
2730      * created for it. If there is the media type, get a sinkpad from the sink
2731      * and link it. We only do this if we have not yet requested the sinkpad
2732      * before. */
2733     if (select->srcpad && select->sinkpad == NULL) {
2734       GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2735       select->sinkpad =
2736           gst_play_sink_request_pad (playbin->playsink, select->type);
2737
2738       res = gst_pad_link (select->srcpad, select->sinkpad);
2739       GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2740           select->media_list[0], res);
2741       if (res != GST_PAD_LINK_OK) {
2742         GST_ELEMENT_ERROR (playbin, CORE, PAD,
2743             ("Internal playbin error."),
2744             ("Failed to link selector to sink. Error %d", res));
2745       }
2746     }
2747   }
2748   GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2749       group->pending - 1);
2750
2751   if (group->pending > 0)
2752     group->pending--;
2753
2754   if (group->suburidecodebin == decodebin)
2755     group->sub_pending = FALSE;
2756
2757   if (group->pending == 0) {
2758     /* we are the last group to complete, we will configure the output and then
2759      * signal the other waiters. */
2760     GST_LOG_OBJECT (playbin, "last group complete");
2761     configure = TRUE;
2762   } else {
2763     GST_LOG_OBJECT (playbin, "have more pending groups");
2764     configure = FALSE;
2765   }
2766   GST_SOURCE_GROUP_UNLOCK (group);
2767
2768   if (configure) {
2769     /* if we have custom sinks, configure them now */
2770     GST_SOURCE_GROUP_LOCK (group);
2771
2772     GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2773         group->audio_sink);
2774     gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2775         group->audio_sink);
2776
2777     GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2778         group->video_sink);
2779     gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2780         group->video_sink);
2781
2782     GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
2783         playbin->text_sink);
2784     gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2785         playbin->text_sink);
2786
2787     GST_SOURCE_GROUP_UNLOCK (group);
2788
2789     GST_LOG_OBJECT (playbin, "reconfigure sink");
2790     /* we configure the modes if we were the last decodebin to complete. */
2791     gst_play_sink_reconfigure (playbin->playsink);
2792
2793     /* signal the other decodebins that they can continue now. */
2794     GST_SOURCE_GROUP_LOCK (group);
2795     /* unblock all selectors */
2796     for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2797       GstSourceSelect *select = &group->selector[i];
2798
2799       /* All streamsynchronizer streams should see stream-changed message,
2800        * to arrange for blocking unblocking. */
2801       if (select->sinkpad) {
2802         GstStructure *s;
2803         GstMessage *msg;
2804         GstEvent *event;
2805         guint32 seqnum;
2806
2807         s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2808             group->uri, NULL);
2809         if (group->suburi)
2810           gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2811         msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2812         seqnum = gst_message_get_seqnum (msg);
2813         event = gst_event_new_sink_message (msg);
2814         g_mutex_lock (group->stream_changed_pending_lock);
2815         group->stream_changed_pending =
2816             g_list_prepend (group->stream_changed_pending,
2817             GUINT_TO_POINTER (seqnum));
2818
2819         /* remove any data probe we might have, and replace */
2820         if (select->sinkpad_delayed_event)
2821           gst_event_unref (select->sinkpad_delayed_event);
2822         select->sinkpad_delayed_event = event;
2823         if (select->sinkpad_data_probe)
2824           gst_pad_remove_data_probe (select->sinkpad,
2825               select->sinkpad_data_probe);
2826
2827         /* we go to the trouble of setting a probe on the pad to send
2828            the playbin2-stream-changed event as sending it here might
2829            find that the pad is blocked, so we'd block here, and the
2830            pad might not be linked yet. Additionally, sending it here
2831            apparently would be on the wrong thread */
2832         select->sinkpad_data_probe =
2833             gst_pad_add_data_probe (select->sinkpad,
2834             (GCallback) stream_changed_data_probe, (gpointer) select);
2835
2836         g_mutex_unlock (group->stream_changed_pending_lock);
2837         gst_message_unref (msg);
2838       }
2839
2840       if (select->srcpad) {
2841         GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2842             select->srcpad);
2843         gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2844             NULL);
2845       }
2846     }
2847     GST_SOURCE_GROUP_UNLOCK (group);
2848   }
2849
2850   GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2851
2852   return;
2853
2854 shutdown:
2855   {
2856     GST_DEBUG ("ignoring, we are shutting down");
2857     /* Request a flushing pad from playsink that we then link to the selector.
2858      * Then we unblock the selectors so that they stop with a WRONG_STATE
2859      * instead of a NOT_LINKED error.
2860      */
2861     GST_SOURCE_GROUP_LOCK (group);
2862     for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2863       GstSourceSelect *select = &group->selector[i];
2864
2865       if (select->srcpad) {
2866         if (select->sinkpad == NULL) {
2867           GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2868           select->sinkpad =
2869               gst_play_sink_request_pad (playbin->playsink,
2870               GST_PLAY_SINK_TYPE_FLUSHING);
2871           res = gst_pad_link (select->srcpad, select->sinkpad);
2872           GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2873         }
2874         GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2875             select->srcpad);
2876         gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2877             NULL);
2878       }
2879     }
2880     GST_SOURCE_GROUP_UNLOCK (group);
2881     return;
2882   }
2883 }
2884
2885 static void
2886 drained_cb (GstElement * decodebin, GstSourceGroup * group)
2887 {
2888   GstPlayBin *playbin;
2889
2890   playbin = group->playbin;
2891
2892   GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
2893
2894   /* after this call, we should have a next group to activate or we EOS */
2895   g_signal_emit (G_OBJECT (playbin),
2896       gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
2897
2898   /* now activate the next group. If the app did not set a uri, this will
2899    * fail and we can do EOS */
2900   setup_next_source (playbin, GST_STATE_PAUSED);
2901 }
2902
2903 /* Called when we must provide a list of factories to plug to @pad with @caps.
2904  * We first check if we have a sink that can handle the format and if we do, we
2905  * return NULL, to expose the pad. If we have no sink (or the sink does not
2906  * work), we return the list of elements that can connect. */
2907 static GValueArray *
2908 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
2909     GstCaps * caps, GstSourceGroup * group)
2910 {
2911   GstPlayBin *playbin;
2912   GList *mylist, *tmp;
2913   GValueArray *result;
2914
2915   playbin = group->playbin;
2916
2917   GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
2918       group, GST_DEBUG_PAD_NAME (pad), caps);
2919
2920   /* filter out the elements based on the caps. */
2921   g_mutex_lock (playbin->elements_lock);
2922   gst_play_bin_update_elements_list (playbin);
2923   mylist =
2924       gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
2925       FALSE);
2926   g_mutex_unlock (playbin->elements_lock);
2927
2928   GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
2929   GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
2930
2931   result = g_value_array_new (g_list_length (mylist));
2932
2933   for (tmp = mylist; tmp; tmp = tmp->next) {
2934     GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
2935     GValue val = { 0, };
2936
2937     g_value_init (&val, G_TYPE_OBJECT);
2938     g_value_set_object (&val, factory);
2939     g_value_array_append (result, &val);
2940     g_value_unset (&val);
2941   }
2942   gst_plugin_feature_list_free (mylist);
2943
2944   return result;
2945 }
2946
2947 /* autoplug-continue decides, if a pad has raw caps that can be exposed
2948  * directly or if further decoding is necessary. We use this to expose
2949  * supported subtitles directly */
2950
2951 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
2952  * explicitely the caps it supports and if it claims to support ANY
2953  * caps it really should support everything */
2954 static gboolean
2955 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
2956     GstSourceGroup * group)
2957 {
2958   gboolean ret = TRUE;
2959   GstElement *sink;
2960   GstPad *sinkpad = NULL;
2961
2962   GST_PLAY_BIN_LOCK (group->playbin);
2963   GST_SOURCE_GROUP_LOCK (group);
2964
2965   if ((sink = group->playbin->text_sink))
2966     sinkpad = gst_element_get_static_pad (sink, "sink");
2967   if (sinkpad) {
2968     GstCaps *sinkcaps;
2969
2970     /* Ignore errors here, if a custom sink fails to go
2971      * to READY things are wrong and will error out later
2972      */
2973     if (GST_STATE (sink) < GST_STATE_READY)
2974       gst_element_set_state (sink, GST_STATE_READY);
2975
2976     sinkcaps = gst_pad_get_caps_reffed (sinkpad);
2977     if (!gst_caps_is_any (sinkcaps))
2978       ret = !gst_pad_accept_caps (sinkpad, caps);
2979     gst_caps_unref (sinkcaps);
2980     gst_object_unref (sinkpad);
2981   } else {
2982     GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
2983     ret = !gst_caps_can_intersect (caps, subcaps);
2984     gst_caps_unref (subcaps);
2985   }
2986   /* If autoplugging can stop don't do additional checks */
2987   if (!ret)
2988     goto done;
2989
2990   /* If this is from the subtitle uridecodebin we don't need to
2991    * check the audio and video sink */
2992   if (group->suburidecodebin
2993       && gst_object_has_ancestor (GST_OBJECT_CAST (element),
2994           GST_OBJECT_CAST (group->suburidecodebin)))
2995     goto done;
2996
2997   if ((sink = group->audio_sink)) {
2998     sinkpad = gst_element_get_static_pad (sink, "sink");
2999     if (sinkpad) {
3000       GstCaps *sinkcaps;
3001
3002       /* Ignore errors here, if a custom sink fails to go
3003        * to READY things are wrong and will error out later
3004        */
3005       if (GST_STATE (sink) < GST_STATE_READY)
3006         gst_element_set_state (sink, GST_STATE_READY);
3007
3008       sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3009       if (!gst_caps_is_any (sinkcaps))
3010         ret = !gst_pad_accept_caps (sinkpad, caps);
3011       gst_caps_unref (sinkcaps);
3012       gst_object_unref (sinkpad);
3013     }
3014   }
3015   if (!ret)
3016     goto done;
3017
3018   if ((sink = group->video_sink)) {
3019     sinkpad = gst_element_get_static_pad (sink, "sink");
3020     if (sinkpad) {
3021       GstCaps *sinkcaps;
3022
3023       /* Ignore errors here, if a custom sink fails to go
3024        * to READY things are wrong and will error out later
3025        */
3026       if (GST_STATE (sink) < GST_STATE_READY)
3027         gst_element_set_state (sink, GST_STATE_READY);
3028
3029       sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3030       if (!gst_caps_is_any (sinkcaps))
3031         ret = !gst_pad_accept_caps (sinkpad, caps);
3032       gst_caps_unref (sinkcaps);
3033       gst_object_unref (sinkpad);
3034     }
3035   }
3036
3037 done:
3038   GST_SOURCE_GROUP_UNLOCK (group);
3039   GST_PLAY_BIN_UNLOCK (group->playbin);
3040
3041   GST_DEBUG_OBJECT (group->playbin,
3042       "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3043       group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3044
3045   return ret;
3046 }
3047
3048 static gboolean
3049 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3050 {
3051   GstPad *sinkpad;
3052
3053   /* ... activate it ... We do this before adding it to the bin so that we
3054    * don't accidentally make it post error messages that will stop
3055    * everything. */
3056   if (GST_STATE (sink) < GST_STATE_READY &&
3057       gst_element_set_state (sink,
3058           GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3059     return FALSE;
3060   }
3061
3062   if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3063     /* Got the sink pad, now let's see if the element actually does accept the
3064      * caps that we have */
3065     if (!gst_pad_accept_caps (sinkpad, caps)) {
3066       gst_object_unref (sinkpad);
3067       return FALSE;
3068     }
3069     gst_object_unref (sinkpad);
3070   }
3071
3072   return TRUE;
3073 }
3074
3075 /* We are asked to select an element. See if the next element to check
3076  * is a sink. If this is the case, we see if the sink works by setting it to
3077  * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3078  * expose the raw pad so that we can setup the mixers. */
3079 static GstAutoplugSelectResult
3080 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3081     GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3082 {
3083   GstPlayBin *playbin;
3084   GstElement *element;
3085   const gchar *klass;
3086   GstPlaySinkType type;
3087   GstElement **sinkp;
3088
3089   playbin = group->playbin;
3090
3091   GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3092       group, GST_DEBUG_PAD_NAME (pad), caps);
3093
3094   GST_DEBUG_OBJECT (playbin, "checking factory %s",
3095       GST_PLUGIN_FEATURE_NAME (factory));
3096
3097   /* if it's not a sink, we just make decodebin try it */
3098   if (!gst_element_factory_list_is_type (factory,
3099           GST_ELEMENT_FACTORY_TYPE_SINK))
3100     return GST_AUTOPLUG_SELECT_TRY;
3101
3102   /* it's a sink, see if an instance of it actually works */
3103   GST_DEBUG_OBJECT (playbin, "we found a sink");
3104
3105   klass = gst_element_factory_get_klass (factory);
3106
3107   /* figure out the klass */
3108   if (strstr (klass, "Audio")) {
3109     GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3110     type = GST_PLAY_SINK_TYPE_AUDIO;
3111     sinkp = &group->audio_sink;
3112   } else if (strstr (klass, "Video")) {
3113     GST_DEBUG_OBJECT (playbin, "we found a video sink");
3114     type = GST_PLAY_SINK_TYPE_VIDEO;
3115     sinkp = &group->video_sink;
3116   } else {
3117     /* unknown klass, skip this element */
3118     GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3119     return GST_AUTOPLUG_SELECT_SKIP;
3120   }
3121
3122   /* if we are asked to do visualisations and it's an audio sink, skip the
3123    * element. We can only do visualisations with raw sinks */
3124   if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3125     if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3126       GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3127       return GST_AUTOPLUG_SELECT_SKIP;
3128     }
3129   }
3130
3131   /* now see if we already have a sink element */
3132   GST_SOURCE_GROUP_LOCK (group);
3133   if (*sinkp) {
3134     GstElement *sink = gst_object_ref (*sinkp);
3135
3136     if (sink_accepts_caps (sink, caps)) {
3137       GST_DEBUG_OBJECT (playbin,
3138           "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3139           GST_ELEMENT_NAME (sink), caps);
3140       gst_object_unref (sink);
3141       GST_SOURCE_GROUP_UNLOCK (group);
3142       return GST_AUTOPLUG_SELECT_EXPOSE;
3143     } else {
3144       GST_DEBUG_OBJECT (playbin,
3145           "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3146           GST_ELEMENT_NAME (sink), caps);
3147       gst_object_unref (sink);
3148       GST_SOURCE_GROUP_UNLOCK (group);
3149       return GST_AUTOPLUG_SELECT_SKIP;
3150     }
3151   }
3152   GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3153
3154   if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3155     GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3156         gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3157     GST_SOURCE_GROUP_UNLOCK (group);
3158     return GST_AUTOPLUG_SELECT_SKIP;
3159   }
3160
3161   /* Check if the selected sink actually supports the
3162    * caps and can be set to READY*/
3163   if (!sink_accepts_caps (element, caps)) {
3164     gst_element_set_state (element, GST_STATE_NULL);
3165     gst_object_unref (element);
3166     GST_SOURCE_GROUP_UNLOCK (group);
3167     return GST_AUTOPLUG_SELECT_SKIP;
3168   }
3169
3170   /* remember the sink in the group now, the element is floating, we take
3171    * ownership now 
3172    *
3173    * store the sink in the group, we will configure it later when we
3174    * reconfigure the sink */
3175   GST_DEBUG_OBJECT (playbin, "remember sink");
3176   gst_object_ref_sink (element);
3177   *sinkp = element;
3178   GST_SOURCE_GROUP_UNLOCK (group);
3179
3180   /* tell decodebin to expose the pad because we are going to use this
3181    * sink */
3182   GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3183
3184   return GST_AUTOPLUG_SELECT_EXPOSE;
3185 }
3186
3187 static void
3188 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3189     GstSourceGroup * group)
3190 {
3191   GstPlayBin *playbin;
3192   GstElement *source;
3193
3194   playbin = group->playbin;
3195
3196   g_object_get (group->uridecodebin, "source", &source, NULL);
3197
3198   GST_OBJECT_LOCK (playbin);
3199   if (playbin->source)
3200     gst_object_unref (playbin->source);
3201   playbin->source = source;
3202   GST_OBJECT_UNLOCK (playbin);
3203
3204   g_object_notify (G_OBJECT (playbin), "source");
3205
3206   g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3207       0, playbin->source);
3208 }
3209
3210 /* must be called with the group lock */
3211 static gboolean
3212 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3213     gboolean locked)
3214 {
3215   GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3216
3217   if (group->uridecodebin)
3218     gst_element_set_locked_state (group->uridecodebin, locked);
3219   if (group->suburidecodebin)
3220     gst_element_set_locked_state (group->suburidecodebin, locked);
3221
3222   return TRUE;
3223 }
3224
3225 /* must be called with PLAY_BIN_LOCK */
3226 static gboolean
3227 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3228 {
3229   GstElement *uridecodebin;
3230   GstElement *suburidecodebin = NULL;
3231   GstPlayFlags flags;
3232
3233   g_return_val_if_fail (group->valid, FALSE);
3234   g_return_val_if_fail (!group->active, FALSE);
3235
3236   GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3237
3238   GST_SOURCE_GROUP_LOCK (group);
3239
3240   /* First set up the custom sources */
3241   if (playbin->audio_sink)
3242     group->audio_sink = gst_object_ref (playbin->audio_sink);
3243   if (playbin->video_sink)
3244     group->video_sink = gst_object_ref (playbin->video_sink);
3245
3246   g_list_free (group->stream_changed_pending);
3247   group->stream_changed_pending = NULL;
3248   if (!group->stream_changed_pending_lock)
3249     group->stream_changed_pending_lock = g_mutex_new ();
3250
3251   if (group->uridecodebin) {
3252     GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3253     uridecodebin = group->uridecodebin;
3254     gst_element_set_state (uridecodebin, GST_STATE_READY);
3255     gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3256   } else {
3257     GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3258     uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3259     if (!uridecodebin)
3260       goto no_decodebin;
3261     gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3262     group->uridecodebin = gst_object_ref (uridecodebin);
3263   }
3264
3265   flags = gst_play_sink_get_flags (playbin->playsink);
3266
3267   g_object_set (uridecodebin,
3268       /* configure connection speed */
3269       "connection-speed", playbin->connection_speed / 1000,
3270       /* configure uri */
3271       "uri", group->uri,
3272       /* configure download buffering */
3273       "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3274       /* configure buffering of demuxed/parsed data */
3275       "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3276       /* configure buffering parameters */
3277       "buffer-duration", playbin->buffer_duration,
3278       "buffer-size", playbin->buffer_size,
3279       "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3280
3281   /* connect pads and other things */
3282   group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3283       G_CALLBACK (pad_added_cb), group);
3284   group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3285       G_CALLBACK (pad_removed_cb), group);
3286   group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3287       G_CALLBACK (no_more_pads_cb), group);
3288   group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3289       G_CALLBACK (notify_source_cb), group);
3290
3291   /* we have 1 pending no-more-pads */
3292   group->pending = 1;
3293
3294   /* is called when the uridecodebin is out of data and we can switch to the
3295    * next uri */
3296   group->drained_id =
3297       g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3298       group);
3299
3300   /* will be called when a new media type is found. We return a list of decoders
3301    * including sinks for decodebin to try */
3302   group->autoplug_factories_id =
3303       g_signal_connect (uridecodebin, "autoplug-factories",
3304       G_CALLBACK (autoplug_factories_cb), group);
3305   group->autoplug_select_id =
3306       g_signal_connect (uridecodebin, "autoplug-select",
3307       G_CALLBACK (autoplug_select_cb), group);
3308   group->autoplug_continue_id =
3309       g_signal_connect (uridecodebin, "autoplug-continue",
3310       G_CALLBACK (autoplug_continue_cb), group);
3311
3312   if (group->suburi) {
3313     /* subtitles */
3314     if (group->suburidecodebin) {
3315       GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3316       suburidecodebin = group->suburidecodebin;
3317       gst_element_set_state (suburidecodebin, GST_STATE_READY);
3318       gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3319     } else {
3320       GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3321       suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3322       if (!suburidecodebin)
3323         goto no_decodebin;
3324
3325       gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3326       group->suburidecodebin = gst_object_ref (suburidecodebin);
3327     }
3328
3329     g_object_set (suburidecodebin,
3330         /* configure connection speed */
3331         "connection-speed", playbin->connection_speed,
3332         /* configure uri */
3333         "uri", group->suburi, NULL);
3334
3335     /* connect pads and other things */
3336     group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3337         G_CALLBACK (pad_added_cb), group);
3338     group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3339         "pad-removed", G_CALLBACK (pad_removed_cb), group);
3340     group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3341         "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3342
3343     group->sub_autoplug_continue_id =
3344         g_signal_connect (suburidecodebin, "autoplug-continue",
3345         G_CALLBACK (autoplug_continue_cb), group);
3346
3347     /* we have 2 pending no-more-pads */
3348     group->pending = 2;
3349     group->sub_pending = TRUE;
3350   } else {
3351     group->sub_pending = FALSE;
3352   }
3353
3354   /* release the group lock before setting the state of the decodebins, they
3355    * might fire signals in this thread that we need to handle with the
3356    * group_lock taken. */
3357   GST_SOURCE_GROUP_UNLOCK (group);
3358
3359   if (suburidecodebin) {
3360     if (gst_element_set_state (suburidecodebin,
3361             target) == GST_STATE_CHANGE_FAILURE) {
3362       GST_DEBUG_OBJECT (playbin,
3363           "failed state change of subtitle uridecodebin");
3364       GST_SOURCE_GROUP_LOCK (group);
3365
3366       REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3367       REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3368       REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3369       REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3370       /* Might already be removed because of an error message */
3371       if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3372         gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3373       if (group->sub_pending) {
3374         group->pending--;
3375         group->sub_pending = FALSE;
3376       }
3377       gst_element_set_state (suburidecodebin, GST_STATE_READY);
3378       GST_SOURCE_GROUP_UNLOCK (group);
3379     }
3380   }
3381   if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3382     goto uridecodebin_failure;
3383
3384   GST_SOURCE_GROUP_LOCK (group);
3385   /* alow state changes of the playbin2 affect the group elements now */
3386   group_set_locked_state_unlocked (playbin, group, FALSE);
3387   group->active = TRUE;
3388   GST_SOURCE_GROUP_UNLOCK (group);
3389
3390   return TRUE;
3391
3392   /* ERRORS */
3393 no_decodebin:
3394   {
3395     GstMessage *msg;
3396
3397     /* delete any custom sinks we might have */
3398     if (group->audio_sink) {
3399       /* If this is a automatically created sink set it to NULL */
3400       if (group->audio_sink != playbin->audio_sink)
3401         gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3402       gst_object_unref (group->audio_sink);
3403     }
3404     group->audio_sink = NULL;
3405     if (group->video_sink) {
3406       /* If this is a automatically created sink set it to NULL */
3407       if (group->video_sink != playbin->video_sink)
3408         gst_element_set_state (group->video_sink, GST_STATE_NULL);
3409       gst_object_unref (group->video_sink);
3410     }
3411     group->video_sink = NULL;
3412
3413     GST_SOURCE_GROUP_UNLOCK (group);
3414     msg =
3415         gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3416         "uridecodebin");
3417     gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3418
3419     GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3420         (_("Could not create \"uridecodebin\" element.")), (NULL));
3421     return FALSE;
3422   }
3423 uridecodebin_failure:
3424   {
3425     /* delete any custom sinks we might have */
3426     if (group->audio_sink) {
3427       /* If this is a automatically created sink set it to NULL */
3428       if (group->audio_sink != playbin->audio_sink)
3429         gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3430       gst_object_unref (group->audio_sink);
3431     }
3432     group->audio_sink = NULL;
3433     if (group->video_sink) {
3434       /* If this is a automatically created sink set it to NULL */
3435       if (group->video_sink != playbin->video_sink)
3436         gst_element_set_state (group->video_sink, GST_STATE_NULL);
3437       gst_object_unref (group->video_sink);
3438     }
3439     group->video_sink = NULL;
3440
3441     GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3442     return FALSE;
3443   }
3444 }
3445
3446 /* unlink a group of uridecodebins from the sink.
3447  * must be called with PLAY_BIN_LOCK */
3448 static gboolean
3449 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3450 {
3451   gint i;
3452
3453   g_return_val_if_fail (group->valid, FALSE);
3454   g_return_val_if_fail (group->active, FALSE);
3455
3456   GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3457
3458   GST_SOURCE_GROUP_LOCK (group);
3459   group->active = FALSE;
3460   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
3461     GstSourceSelect *select = &group->selector[i];
3462
3463     GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3464
3465     if (select->srcpad) {
3466       if (select->sinkpad) {
3467         GST_LOG_OBJECT (playbin, "unlinking from sink");
3468         gst_pad_unlink (select->srcpad, select->sinkpad);
3469
3470         /* release back */
3471         GST_LOG_OBJECT (playbin, "release sink pad");
3472         gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3473         select->sinkpad = NULL;
3474       }
3475
3476       gst_object_unref (select->srcpad);
3477       select->srcpad = NULL;
3478     }
3479
3480     if (select->selector) {
3481       gint n;
3482
3483       /* release and unref requests pad from the selector */
3484       for (n = 0; n < select->channels->len; n++) {
3485         GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3486
3487         gst_element_release_request_pad (select->selector, sinkpad);
3488         gst_object_unref (sinkpad);
3489       }
3490       g_ptr_array_set_size (select->channels, 0);
3491
3492       gst_element_set_state (select->selector, GST_STATE_NULL);
3493       gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3494       select->selector = NULL;
3495     }
3496   }
3497   /* delete any custom sinks we might have */
3498   if (group->audio_sink) {
3499     /* If this is a automatically created sink set it to NULL */
3500     if (group->audio_sink != playbin->audio_sink)
3501       gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3502     gst_object_unref (group->audio_sink);
3503   }
3504   group->audio_sink = NULL;
3505   if (group->video_sink) {
3506     /* If this is a automatically created sink set it to NULL */
3507     if (group->video_sink != playbin->video_sink)
3508       gst_element_set_state (group->video_sink, GST_STATE_NULL);
3509     gst_object_unref (group->video_sink);
3510   }
3511   group->video_sink = NULL;
3512
3513   if (group->uridecodebin) {
3514     REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3515     REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3516     REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3517     REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3518     REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3519     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3520     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3521     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3522     gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3523   }
3524
3525   if (group->suburidecodebin) {
3526     REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3527     REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3528     REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3529     REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3530
3531     /* Might already be removed because of errors */
3532     if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3533       gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3534   }
3535
3536   GST_SOURCE_GROUP_UNLOCK (group);
3537
3538   return TRUE;
3539 }
3540
3541 /* setup the next group to play, this assumes the next_group is valid and
3542  * configured. It swaps out the current_group and activates the valid
3543  * next_group. */
3544 static gboolean
3545 setup_next_source (GstPlayBin * playbin, GstState target)
3546 {
3547   GstSourceGroup *new_group, *old_group;
3548
3549   GST_DEBUG_OBJECT (playbin, "setup sources");
3550
3551   /* see if there is a next group */
3552   GST_PLAY_BIN_LOCK (playbin);
3553   new_group = playbin->next_group;
3554   if (!new_group || !new_group->valid)
3555     goto no_next_group;
3556
3557   /* first unlink the current source, if any */
3558   old_group = playbin->curr_group;
3559   if (old_group && old_group->valid && old_group->active) {
3560     gst_play_bin_update_cached_duration (playbin);
3561     /* unlink our pads with the sink */
3562     deactivate_group (playbin, old_group);
3563     old_group->valid = FALSE;
3564   }
3565
3566   /* swap old and new */
3567   playbin->curr_group = new_group;
3568   playbin->next_group = old_group;
3569
3570   /* activate the new group */
3571   if (!activate_group (playbin, new_group, target))
3572     goto activate_failed;
3573
3574   GST_PLAY_BIN_UNLOCK (playbin);
3575
3576   return TRUE;
3577
3578   /* ERRORS */
3579 no_next_group:
3580   {
3581     GST_DEBUG_OBJECT (playbin, "no next group");
3582     if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3583       GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3584     GST_PLAY_BIN_UNLOCK (playbin);
3585     return FALSE;
3586   }
3587 activate_failed:
3588   {
3589     GST_DEBUG_OBJECT (playbin, "activate failed");
3590     GST_PLAY_BIN_UNLOCK (playbin);
3591     return FALSE;
3592   }
3593 }
3594
3595 /* The group that is currently playing is copied again to the
3596  * next_group so that it will start playing the next time.
3597  */
3598 static gboolean
3599 save_current_group (GstPlayBin * playbin)
3600 {
3601   GstSourceGroup *curr_group;
3602
3603   GST_DEBUG_OBJECT (playbin, "save current group");
3604
3605   /* see if there is a current group */
3606   GST_PLAY_BIN_LOCK (playbin);
3607   curr_group = playbin->curr_group;
3608   if (curr_group && curr_group->valid) {
3609     /* unlink our pads with the sink */
3610     deactivate_group (playbin, curr_group);
3611   }
3612   /* swap old and new */
3613   playbin->curr_group = playbin->next_group;
3614   playbin->next_group = curr_group;
3615   GST_PLAY_BIN_UNLOCK (playbin);
3616
3617   return TRUE;
3618 }
3619
3620 /* clear the locked state from all groups. This function is called before a
3621  * state change to NULL is performed on them. */
3622 static gboolean
3623 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3624 {
3625   GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3626       locked);
3627
3628   GST_PLAY_BIN_LOCK (playbin);
3629   GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3630   group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3631   GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3632   GST_SOURCE_GROUP_LOCK (playbin->next_group);
3633   group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3634   GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3635   GST_PLAY_BIN_UNLOCK (playbin);
3636
3637   return TRUE;
3638 }
3639
3640 static GstStateChangeReturn
3641 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3642 {
3643   GstStateChangeReturn ret;
3644   GstPlayBin *playbin;
3645   gboolean do_save = FALSE;
3646
3647   playbin = GST_PLAY_BIN (element);
3648
3649   switch (transition) {
3650     case GST_STATE_CHANGE_NULL_TO_READY:
3651       memset (&playbin->duration, 0, sizeof (playbin->duration));
3652       break;
3653     case GST_STATE_CHANGE_READY_TO_PAUSED:
3654       GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3655       memset (&playbin->duration, 0, sizeof (playbin->duration));
3656       g_atomic_int_set (&playbin->shutdown, 0);
3657
3658       if (!setup_next_source (playbin, GST_STATE_READY)) {
3659         ret = GST_STATE_CHANGE_FAILURE;
3660         goto failure;
3661       }
3662       break;
3663     case GST_STATE_CHANGE_PAUSED_TO_READY:
3664     async_down:
3665       /* FIXME unlock our waiting groups */
3666       GST_LOG_OBJECT (playbin, "setting shutdown flag");
3667       g_atomic_int_set (&playbin->shutdown, 1);
3668       memset (&playbin->duration, 0, sizeof (playbin->duration));
3669
3670       /* wait for all callbacks to end by taking the lock.
3671        * No dynamic (critical) new callbacks will
3672        * be able to happen as we set the shutdown flag. */
3673       GST_PLAY_BIN_DYN_LOCK (playbin);
3674       GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3675       GST_PLAY_BIN_DYN_UNLOCK (playbin);
3676       if (!do_save)
3677         break;
3678     case GST_STATE_CHANGE_READY_TO_NULL:
3679       /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3680        * an no state change PAUSED to READY passes here,
3681        * though it is a nice-to-have ... */
3682       if (!g_atomic_int_get (&playbin->shutdown)) {
3683         do_save = TRUE;
3684         goto async_down;
3685       }
3686       memset (&playbin->duration, 0, sizeof (playbin->duration));
3687
3688       /* unlock so that all groups go to NULL */
3689       groups_set_locked_state (playbin, FALSE);
3690       break;
3691     default:
3692       break;
3693   }
3694
3695   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3696   if (ret == GST_STATE_CHANGE_FAILURE)
3697     goto failure;
3698
3699   switch (transition) {
3700     case GST_STATE_CHANGE_READY_TO_PAUSED:
3701       break;
3702     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3703       /* FIXME Release audio device when we implement that */
3704       break;
3705     case GST_STATE_CHANGE_PAUSED_TO_READY:
3706       save_current_group (playbin);
3707       break;
3708     case GST_STATE_CHANGE_READY_TO_NULL:
3709     {
3710       guint i;
3711
3712       /* also do missed state change down to READY */
3713       if (do_save)
3714         save_current_group (playbin);
3715       /* Deactive the groups, set the uridecodebins to NULL
3716        * and unref them.
3717        */
3718       for (i = 0; i < 2; i++) {
3719         if (playbin->groups[i].active && playbin->groups[i].valid) {
3720           deactivate_group (playbin, &playbin->groups[i]);
3721           playbin->groups[i].valid = FALSE;
3722         }
3723
3724         if (playbin->groups[i].uridecodebin) {
3725           gst_element_set_state (playbin->groups[i].uridecodebin,
3726               GST_STATE_NULL);
3727           gst_object_unref (playbin->groups[i].uridecodebin);
3728           playbin->groups[i].uridecodebin = NULL;
3729         }
3730
3731         if (playbin->groups[i].suburidecodebin) {
3732           gst_element_set_state (playbin->groups[i].suburidecodebin,
3733               GST_STATE_NULL);
3734           gst_object_unref (playbin->groups[i].suburidecodebin);
3735           playbin->groups[i].suburidecodebin = NULL;
3736         }
3737       }
3738
3739       /* Set our sinks back to NULL, they might not be child of playbin */
3740       if (playbin->audio_sink)
3741         gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
3742       if (playbin->video_sink)
3743         gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
3744       if (playbin->text_sink)
3745         gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
3746
3747       /* make sure the groups don't perform a state change anymore until we
3748        * enable them again */
3749       groups_set_locked_state (playbin, TRUE);
3750       break;
3751     }
3752     default:
3753       break;
3754   }
3755
3756   return ret;
3757
3758   /* ERRORS */
3759 failure:
3760   {
3761     if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
3762       GstSourceGroup *curr_group;
3763
3764       curr_group = playbin->curr_group;
3765       if (curr_group && curr_group->active && curr_group->valid) {
3766         /* unlink our pads with the sink */
3767         deactivate_group (playbin, curr_group);
3768         curr_group->valid = FALSE;
3769       }
3770
3771       /* Swap current and next group back */
3772       playbin->curr_group = playbin->next_group;
3773       playbin->next_group = curr_group;
3774     }
3775     return ret;
3776   }
3777 }
3778
3779 gboolean
3780 gst_play_bin2_plugin_init (GstPlugin * plugin)
3781 {
3782   GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
3783
3784   return gst_element_register (plugin, "playbin2", GST_RANK_NONE,
3785       GST_TYPE_PLAY_BIN);
3786 }