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