c02c078420f3ae404265e2b6485654e72cf73678
[platform/upstream/gst-plugins-base.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 confinguration 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  * using the #GstPlayBin2:stream-info property, which will return a GList of stream info
143  * objects, one for each stream. These are opaque objects that can only be
144  * accessed via the standard GObject property interface, ie. g_object_get().
145  * Each stream info object has the following properties:
146  * <itemizedlist>
147  * <listitem>"object" (GstObject) (the decoder source pad usually)</listitem>
148  * <listitem>"type" (enum) (if this is an audio/video/subtitle stream)</listitem>
149  * <listitem>"decoder" (string) (name of decoder used to decode this stream)</listitem>
150  * <listitem>"mute" (boolean) (to mute or unmute this stream)</listitem>
151  * <listitem>"caps" (GstCaps) (caps of the decoded stream)</listitem>
152  * <listitem>"language-code" (string) (ISO-639 language code for this stream, mostly used for audio/subtitle streams)</listitem>
153  * <listitem>"codec" (string) (format this stream was encoded in)</listitem>
154  * </itemizedlist>
155  * Stream information from the #GstPlayBin2:stream-info property is best queried once
156  * playbin has changed into PAUSED or PLAYING state (which can be detected
157  * via a state-changed message on the bus where old_state=READY and
158  * new_state=PAUSED), since before that the list might not be complete yet or
159  * not contain all available information (like language-codes).
160  * </para>
161  * </refsect2>
162  * <refsect2>
163  * <title>Buffering</title>
164  * Playbin handles buffering automatically for the most part, but applications
165  * need to handle parts of the buffering process as well. Whenever playbin is
166  * buffering, it will post BUFFERING messages on the bus with a percentage
167  * value that shows the progress of the buffering process. Applications need
168  * to set playbin to PLAYING or PAUSED state in response to these messages.
169  * They may also want to convey the buffering progress to the user in some
170  * way. Here is how to extract the percentage information from the message
171  * (requires GStreamer >= 0.10.11):
172  * |[
173  * switch (GST_MESSAGE_TYPE (msg)) {
174  *   case GST_MESSAGE_BUFFERING: {
175  *     gint percent = 0;
176  *     gst_message_parse_buffering (msg, &amp;percent);
177  *     g_print ("Buffering (%%u percent done)", percent);
178  *     break;
179  *   }
180  *   ...
181  * }
182  * ]|
183  * Note that applications should keep/set the pipeline in the PAUSED state when
184  * a BUFFERING message is received with a buffer percent value < 100 and set
185  * the pipeline back to PLAYING state when a BUFFERING message with a value
186  * of 100 percent is received (if PLAYING is the desired state, that is).
187  * </refsect2>
188  * <refsect2>
189  * <title>Embedding the video window in your application</title>
190  * By default, playbin (or rather the video sinks used) will create their own
191  * window. Applications will usually want to force output to a window of their
192  * own, however. This can be done using the #GstXOverlay interface, which most
193  * video sinks implement. See the documentation there for more details.
194  * </refsect2>
195  * <refsect2>
196  * <title>Specifying which CD/DVD device to use</title>
197  * The device to use for CDs/DVDs needs to be set on the source element
198  * playbin creates before it is opened. The only way to do this at the moment
199  * is to connect to playbin's "notify::source" signal, which will be emitted
200  * by playbin when it has created the source element for a particular URI.
201  * In the signal callback you can check if the source element has a "device"
202  * property and set it appropriately. In future ways might be added to specify
203  * the device as part of the URI, but at the time of writing this is not
204  * possible yet.
205  * </refsect2>
206  * <refsect2>
207  * <title>Examples</title>
208  * |[
209  * gst-launch -v playbin uri=file:///path/to/somefile.avi
210  * ]| This will play back the given AVI video file, given that the video and
211  * audio decoders required to decode the content are installed. Since no
212  * special audio sink or video sink is supplied (not possible via gst-launch),
213  * playbin will try to find a suitable audio and video sink automatically
214  * using the autoaudiosink and autovideosink elements.
215  * |[
216  * gst-launch -v playbin uri=cdda://4
217  * ]| This will play back track 4 on an audio CD in your disc drive (assuming
218  * the drive is detected automatically by the plugin).
219  * |[
220  * gst-launch -v playbin uri=dvd://1
221  * ]| This will play back title 1 of a DVD in your disc drive (assuming
222  * the drive is detected automatically by the plugin).
223  * </refsect2>
224  */
225
226 #ifdef HAVE_CONFIG_H
227 #include "config.h"
228 #endif
229
230 #include <string.h>
231 #include <gst/gst.h>
232
233 #include <gst/gst-i18n-plugin.h>
234 #include <gst/pbutils/pbutils.h>
235
236 #include "gstplay-enum.h"
237 #include "gstplay-marshal.h"
238 #include "gstplaysink.h"
239 #include "gstfactorylists.h"
240 #include "gstscreenshot.h"
241
242 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
243 #define GST_CAT_DEFAULT gst_play_bin_debug
244
245 #define GST_TYPE_PLAY_BIN               (gst_play_bin_get_type())
246 #define GST_PLAY_BIN(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
247 #define GST_PLAY_BIN_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
248 #define GST_IS_PLAY_BIN(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
249 #define GST_IS_PLAY_BIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
250
251 #define VOLUME_MAX_DOUBLE 10.0
252
253 typedef struct _GstPlayBin GstPlayBin;
254 typedef struct _GstPlayBinClass GstPlayBinClass;
255 typedef struct _GstSourceGroup GstSourceGroup;
256 typedef struct _GstSourceSelect GstSourceSelect;
257
258 /* has the info for a selector and provides the link to the sink */
259 struct _GstSourceSelect
260 {
261   const gchar *media;           /* the media type of 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 is linked */
268 };
269
270 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
271 #define GST_SOURCE_GROUP_GET_COND(group) (((GstSourceGroup*)(group))->cond)
272 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
273 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
274 #define GST_SOURCE_GROUP_WAIT(group) (g_cond_wait \
275                 (GST_SOURCE_GROUP_GET_COND (group),GST_SOURCE_GROUP_GET_LOCK(group)))
276 #define GST_SOURCE_GROUP_BROADCAST(group) (g_cond_broadcast \
277                 (GST_SOURCE_GROUP_GET_COND (group)))
278
279 /* a structure to hold the objects for decoding a uri and the subtitle uri
280  */
281 struct _GstSourceGroup
282 {
283   GstPlayBin *playbin;
284
285   GMutex *lock;
286   GCond *cond;
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   /* uridecodebins for uri and subtitle uri */
302   GstElement *uridecodebin;
303   GstElement *suburidecodebin;
304   gint pending;
305
306   gulong pad_added_id;
307   gulong pad_removed_id;
308   gulong no_more_pads_id;
309   gulong notify_source_id;
310   gulong drained_id;
311   gulong autoplug_factories_id;
312   gulong autoplug_select_id;
313
314   gulong sub_pad_added_id;
315   gulong sub_pad_removed_id;
316   gulong sub_no_more_pads_id;
317
318   /* selectors for different streams */
319   GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST];
320 };
321
322 #define GST_PLAY_BIN_GET_LOCK(bin) (((GstPlayBin*)(bin))->lock)
323 #define GST_PLAY_BIN_LOCK(bin) (g_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
324 #define GST_PLAY_BIN_UNLOCK(bin) (g_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
325
326 /* lock to protect dynamic callbacks, like no-more-pads */
327 #define GST_PLAY_BIN_DYN_LOCK(bin)    g_mutex_lock ((bin)->dyn_lock)
328 #define GST_PLAY_BIN_DYN_UNLOCK(bin)  g_mutex_unlock ((bin)->dyn_lock)
329
330 /* lock for shutdown */
331 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label)           \
332 G_STMT_START {                                          \
333   if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown)))   \
334     goto label;                                         \
335   GST_PLAY_BIN_DYN_LOCK (bin);                          \
336   if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
337     GST_PLAY_BIN_DYN_UNLOCK (bin);                      \
338     goto label;                                         \
339   }                                                     \
340 } G_STMT_END
341
342 /* unlock for shutdown */
343 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin)         \
344   GST_PLAY_BIN_DYN_UNLOCK (bin);                  \
345
346 /**
347  * GstPlayBin2:
348  *
349  * playbin element structure
350  */
351 struct _GstPlayBin
352 {
353   GstPipeline parent;
354
355   GMutex *lock;                 /* to protect group switching */
356
357   /* the groups, we use a double buffer to switch between current and next */
358   GstSourceGroup groups[2];     /* array with group info */
359   GstSourceGroup *curr_group;   /* pointer to the currently playing group */
360   GstSourceGroup *next_group;   /* pointer to the next group */
361
362   gboolean about_to_finish;     /* the about-to-finish signal is emitted */
363
364   /* properties */
365   guint connection_speed;       /* connection speed in bits/sec (0 = unknown) */
366   gint current_video;           /* the currently selected stream */
367   gint current_audio;           /* the currently selected stream */
368   gint current_text;            /* the currently selected stream */
369   gchar *encoding;              /* subtitle encoding */
370
371   guint64 buffer_duration;      /* When buffering, the max buffer duration (ns) */
372   guint buffer_size;            /* When buffering, the max buffer size (bytes) */
373
374   /* our play sink */
375   GstPlaySink *playsink;
376
377   /* the last activated source */
378   GstElement *source;
379
380   /* lock protecting dynamic adding/removing */
381   GMutex *dyn_lock;
382   /* if we are shutting down or not */
383   gint shutdown;
384
385   GValueArray *elements;        /* factories we can use for selecting elements */
386 };
387
388 struct _GstPlayBinClass
389 {
390   GstPipelineClass parent_class;
391
392   /* notify app that the current uri finished decoding and it is possible to
393    * queue a new one for gapless playback */
394   void (*about_to_finish) (GstPlayBin * playbin);
395
396   /* notify app that number of audio/video/text streams changed */
397   void (*video_changed) (GstPlayBin * playbin);
398   void (*audio_changed) (GstPlayBin * playbin);
399   void (*text_changed) (GstPlayBin * playbin);
400
401   /* get audio/video/text tags for a stream */
402   GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
403   GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
404   GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
405
406   /* get the last video frame and convert it to the given caps */
407   GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
408
409   /* get audio/video/text pad for a stream */
410   GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
411   GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
412   GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
413 };
414
415 /* props */
416 #define DEFAULT_URI               NULL
417 #define DEFAULT_SUBURI            NULL
418 #define DEFAULT_SOURCE            NULL
419 #define DEFAULT_FLAGS             GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
420                                   GST_PLAY_FLAG_SOFT_VOLUME
421 #define DEFAULT_N_VIDEO           0
422 #define DEFAULT_CURRENT_VIDEO     -1
423 #define DEFAULT_N_AUDIO           0
424 #define DEFAULT_CURRENT_AUDIO     -1
425 #define DEFAULT_N_TEXT            0
426 #define DEFAULT_CURRENT_TEXT      -1
427 #define DEFAULT_SUBTITLE_ENCODING NULL
428 #define DEFAULT_AUDIO_SINK        NULL
429 #define DEFAULT_VIDEO_SINK        NULL
430 #define DEFAULT_VIS_PLUGIN        NULL
431 #define DEFAULT_VOLUME            1.0
432 #define DEFAULT_MUTE              FALSE
433 #define DEFAULT_FRAME             NULL
434 #define DEFAULT_FONT_DESC         NULL
435 #define DEFAULT_CONNECTION_SPEED  0
436 #define DEFAULT_BUFFER_DURATION   -1
437 #define DEFAULT_BUFFER_SIZE       -1
438
439 enum
440 {
441   PROP_0,
442   PROP_URI,
443   PROP_SUBURI,
444   PROP_SOURCE,
445   PROP_FLAGS,
446   PROP_N_VIDEO,
447   PROP_CURRENT_VIDEO,
448   PROP_N_AUDIO,
449   PROP_CURRENT_AUDIO,
450   PROP_N_TEXT,
451   PROP_CURRENT_TEXT,
452   PROP_SUBTITLE_ENCODING,
453   PROP_AUDIO_SINK,
454   PROP_VIDEO_SINK,
455   PROP_VIS_PLUGIN,
456   PROP_VOLUME,
457   PROP_MUTE,
458   PROP_FRAME,
459   PROP_FONT_DESC,
460   PROP_CONNECTION_SPEED,
461   PROP_BUFFER_SIZE,
462   PROP_BUFFER_DURATION
463 };
464
465 /* signals */
466 enum
467 {
468   SIGNAL_ABOUT_TO_FINISH,
469   SIGNAL_CONVERT_FRAME,
470   SIGNAL_VIDEO_CHANGED,
471   SIGNAL_AUDIO_CHANGED,
472   SIGNAL_TEXT_CHANGED,
473   SIGNAL_GET_VIDEO_TAGS,
474   SIGNAL_GET_AUDIO_TAGS,
475   SIGNAL_GET_TEXT_TAGS,
476   SIGNAL_GET_VIDEO_PAD,
477   SIGNAL_GET_AUDIO_PAD,
478   SIGNAL_GET_TEXT_PAD,
479   LAST_SIGNAL
480 };
481
482 static void gst_play_bin_class_init (GstPlayBinClass * klass);
483 static void gst_play_bin_init (GstPlayBin * playbin);
484 static void gst_play_bin_finalize (GObject * object);
485
486 static void gst_play_bin_set_property (GObject * object, guint prop_id,
487     const GValue * value, GParamSpec * spec);
488 static void gst_play_bin_get_property (GObject * object, guint prop_id,
489     GValue * value, GParamSpec * spec);
490
491 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
492     GstStateChange transition);
493
494 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
495
496 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
497     gint stream);
498 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
499     gint stream);
500 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
501     gint stream);
502
503 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
504     GstCaps * caps);
505
506 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
507 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
508 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
509
510 static gboolean setup_next_source (GstPlayBin * playbin);
511
512 static GstElementClass *parent_class;
513
514 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
515
516 static const GstElementDetails gst_play_bin_details =
517 GST_ELEMENT_DETAILS ("Player Bin 2",
518     "Generic/Bin/Player",
519     "Autoplug and play media from an uri",
520     "Wim Taymans <wim.taymans@gmail.com>");
521
522 static void
523 gst_play_marshal_BUFFER__BOXED (GClosure * closure,
524     GValue * return_value G_GNUC_UNUSED,
525     guint n_param_values,
526     const GValue * param_values,
527     gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
528 {
529   typedef GstBuffer *(*GMarshalFunc_OBJECT__BOXED) (gpointer data1,
530       gpointer arg_1, gpointer data2);
531   register GMarshalFunc_OBJECT__BOXED callback;
532   register GCClosure *cc = (GCClosure *) closure;
533   register gpointer data1, data2;
534   GstBuffer *v_return;
535
536   g_return_if_fail (return_value != NULL);
537   g_return_if_fail (n_param_values == 2);
538
539   if (G_CCLOSURE_SWAP_DATA (closure)) {
540     data1 = closure->data;
541     data2 = g_value_peek_pointer (param_values + 0);
542   } else {
543     data1 = g_value_peek_pointer (param_values + 0);
544     data2 = closure->data;
545   }
546   callback =
547       (GMarshalFunc_OBJECT__BOXED) (marshal_data ? marshal_data : cc->callback);
548
549   v_return = callback (data1, g_value_get_boxed (param_values + 1), data2);
550
551   gst_value_take_buffer (return_value, v_return);
552 }
553
554 static GType
555 gst_play_bin_get_type (void)
556 {
557   static GType gst_play_bin_type = 0;
558
559   if (!gst_play_bin_type) {
560     static const GTypeInfo gst_play_bin_info = {
561       sizeof (GstPlayBinClass),
562       NULL,
563       NULL,
564       (GClassInitFunc) gst_play_bin_class_init,
565       NULL,
566       NULL,
567       sizeof (GstPlayBin),
568       0,
569       (GInstanceInitFunc) gst_play_bin_init,
570       NULL
571     };
572
573     gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
574         "GstPlayBin2", &gst_play_bin_info, 0);
575   }
576
577   return gst_play_bin_type;
578 }
579
580 static void
581 gst_play_bin_class_init (GstPlayBinClass * klass)
582 {
583   GObjectClass *gobject_klass;
584   GstElementClass *gstelement_klass;
585   GstBinClass *gstbin_klass;
586
587   gobject_klass = (GObjectClass *) klass;
588   gstelement_klass = (GstElementClass *) klass;
589   gstbin_klass = (GstBinClass *) klass;
590
591   parent_class = g_type_class_peek_parent (klass);
592
593   gobject_klass->set_property = gst_play_bin_set_property;
594   gobject_klass->get_property = gst_play_bin_get_property;
595
596   gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_bin_finalize);
597
598   /**
599    * GstPlayBin2:uri
600    *
601    * Set the next URI that playbin will play. This property can be set from the
602    * about-to-finish signal to queue the next media file.
603    */
604   g_object_class_install_property (gobject_klass, PROP_URI,
605       g_param_spec_string ("uri", "URI", "URI of the media to play",
606           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
607
608   /**
609    * GstPlayBin2:suburi
610    *
611    * Set the next subtitle URI that playbin will play. This property can be
612    * set from the about-to-finish signal to queue the next subtitle media file.
613    */
614   g_object_class_install_property (gobject_klass, PROP_SUBURI,
615       g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
616           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
617
618   g_object_class_install_property (gobject_klass, PROP_SOURCE,
619       g_param_spec_object ("source", "Source", "Source element",
620           GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
621
622   /**
623    * GstPlayBin2:flags
624    *
625    * Control the behaviour of playbin.
626    */
627   g_object_class_install_property (gobject_klass, PROP_FLAGS,
628       g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
629           GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
630           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
631
632   /**
633    * GstPlayBin2:n-video
634    *
635    * Get the total number of available video streams. 
636    */
637   g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
638       g_param_spec_int ("n-video", "Number Video",
639           "Total number of video streams", 0, G_MAXINT, 0,
640           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
641   /**
642    * GstPlayBin2:current-video
643    *
644    * Get or set the currently playing video stream. By default the first video
645    * stream with data is played.
646    */
647   g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
648       g_param_spec_int ("current-video", "Current Video",
649           "Currently playing video stream (-1 = auto)",
650           -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
651   /**
652    * GstPlayBin2:n-audio
653    *
654    * Get the total number of available audio streams. 
655    */
656   g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
657       g_param_spec_int ("n-audio", "Number Audio",
658           "Total number of audio streams", 0, G_MAXINT, 0,
659           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
660   /**
661    * GstPlayBin2:current-audio
662    *
663    * Get or set the currently playing audio stream. By default the first audio
664    * stream with data is played.
665    */
666   g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
667       g_param_spec_int ("current-audio", "Current audio",
668           "Currently playing audio stream (-1 = auto)",
669           -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
670   /**
671    * GstPlayBin2:n-text
672    *
673    * Get the total number of available subtitle streams. 
674    */
675   g_object_class_install_property (gobject_klass, PROP_N_TEXT,
676       g_param_spec_int ("n-text", "Number Text",
677           "Total number of text streams", 0, G_MAXINT, 0,
678           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
679   /**
680    * GstPlayBin2:current-text:
681    *
682    * Get or set the currently playing subtitle stream. By default the first
683    * subtitle stream with data is played.
684    */
685   g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
686       g_param_spec_int ("current-text", "Current Text",
687           "Currently playing text stream (-1 = auto)",
688           -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
689
690   g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
691       g_param_spec_string ("subtitle-encoding", "subtitle encoding",
692           "Encoding to assume if input subtitles are not in UTF-8 encoding. "
693           "If not set, the GST_SUBTITLE_ENCODING environment variable will "
694           "be checked for an encoding to use. If that is not set either, "
695           "ISO-8859-15 will be assumed.", NULL,
696           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
697
698   g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
699       g_param_spec_object ("video-sink", "Video Sink",
700           "the video output element to use (NULL = default sink)",
701           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
702   g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
703       g_param_spec_object ("audio-sink", "Audio Sink",
704           "the audio output element to use (NULL = default sink)",
705           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
706   g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
707       g_param_spec_object ("vis-plugin", "Vis plugin",
708           "the visualization element to use (NULL = default)",
709           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
710
711   g_object_class_install_property (gobject_klass, PROP_VOLUME,
712       g_param_spec_double ("volume", "Volume", "The audio volume",
713           0.0, VOLUME_MAX_DOUBLE, 1.0,
714           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
715   g_object_class_install_property (gobject_klass, PROP_MUTE,
716       g_param_spec_boolean ("mute", "Mute",
717           "Mute the audio channel without changing the volume", FALSE,
718           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
719
720   /**
721    * GstPlayBin2:frame:
722    * @playbin: a #GstPlayBin2
723    *
724    * Get the currently rendered or prerolled frame in the sink.
725    * The #GstCaps on the buffer will describe the format of the buffer.
726    */
727   g_object_class_install_property (gobject_klass, PROP_FRAME,
728       gst_param_spec_mini_object ("frame", "Frame",
729           "The last frame (NULL = no video available)",
730           GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
731   g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
732       g_param_spec_string ("subtitle-font-desc",
733           "Subtitle font description",
734           "Pango font description of font "
735           "to be used for subtitle rendering", NULL,
736           G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
737
738   g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
739       g_param_spec_uint ("connection-speed", "Connection Speed",
740           "Network connection speed in kbps (0 = unknown)",
741           0, G_MAXUINT, DEFAULT_CONNECTION_SPEED,
742           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
743
744   g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
745       g_param_spec_int ("buffer-size", "Buffer size (bytes)",
746           "Buffer size when buffering network streams",
747           -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
748           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
749   g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
750       g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
751           "Buffer duration when buffering network streams",
752           -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
753           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
754
755   /**
756    * GstPlayBin2::about-to-finish
757    * @playbin: a #GstPlayBin2
758    *
759    * This signal is emitted when the current uri is about to finish. You can
760    * set the uri and suburi to make sure that playback continues.
761    */
762   gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
763       g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
764       G_SIGNAL_RUN_LAST,
765       G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
766       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
767
768   /**
769    * GstPlayBin2::video-changed
770    * @playbin: a #GstPlayBin2
771    *
772    * This signal is emitted whenever the number or order of the video
773    * streams has changed. The application will most likely want to select
774    * a new video stream.
775    */
776   gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
777       g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
778       G_SIGNAL_RUN_LAST,
779       G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
780       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
781   /**
782    * GstPlayBin2::audio-changed
783    * @playbin: a #GstPlayBin2
784    *
785    * This signal is emitted whenever the number or order of the audio
786    * streams has changed. The application will most likely want to select
787    * a new audio stream.
788    */
789   gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
790       g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
791       G_SIGNAL_RUN_LAST,
792       G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
793       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
794   /**
795    * GstPlayBin2::text-changed
796    * @playbin: a #GstPlayBin2
797    *
798    * This signal is emitted whenever the number or order of the text
799    * streams has changed. The application will most likely want to select
800    * a new text stream.
801    */
802   gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
803       g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
804       G_SIGNAL_RUN_LAST,
805       G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
806       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
807
808   /**
809    * GstPlayBin2::get-video-tags
810    * @playbin: a #GstPlayBin2
811    * @stream: a video stream number
812    *
813    * Action signal to retrieve the tags of a specific video stream number.
814    * This information can be used to select a stream.
815    *
816    * Returns: a GstTagList with tags or NULL when the stream number does not
817    * exist.
818    */
819   gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
820       g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
821       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
822       G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
823       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
824   /**
825    * GstPlayBin2::get-audio-tags
826    * @playbin: a #GstPlayBin2
827    * @stream: an audio stream number
828    *
829    * Action signal to retrieve the tags of a specific audio stream number.
830    * This information can be used to select a stream.
831    *
832    * Returns: a GstTagList with tags or NULL when the stream number does not
833    * exist.
834    */
835   gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
836       g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
837       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
838       G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
839       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
840   /**
841    * GstPlayBin2::get-text-tags
842    * @playbin: a #GstPlayBin2
843    * @stream: a text stream number
844    *
845    * Action signal to retrieve the tags of a specific text stream number.
846    * This information can be used to select a stream.
847    *
848    * Returns: a GstTagList with tags or NULL when the stream number does not
849    * exist.
850    */
851   gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
852       g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
853       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
854       G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
855       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
856   /**
857    * GstPlayBin2::convert-frame
858    * @playbin: a #GstPlayBin2
859    * @caps: the target format of the frame
860    *
861    * Action signal to retrieve the currently playing video frame in the format
862    * specified by @caps.
863    * If @caps is %NULL, no conversion will be performed and this function is
864    * equivalent to the #GstPlayBin::frame property.
865    *
866    * Returns: a #GstBuffer of the current video frame converted to #caps. 
867    * The caps on the buffer will describe the final layout of the buffer data.
868    * %NULL is returned when no current buffer can be retrieved or when the
869    * conversion failed.
870    */
871   gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
872       g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
873       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
874       G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
875       gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
876
877   /**
878    * GstPlayBin2::get-video-pad
879    * @playbin: a #GstPlayBin2
880    * @stream: a video stream number
881    *
882    * Action signal to retrieve the stream-selector sinkpad for a specific 
883    * video stream.
884    * This pad can be used for notifications of caps changes, stream-specific
885    * queries, etc.
886    *
887    * Returns: a #GstPad, or NULL when the stream number does not exist.
888    */
889   gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
890       g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
891       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
892       G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
893       gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
894   /**
895    * GstPlayBin2::get-audio-pad
896    * @playbin: a #GstPlayBin2
897    * @stream: an audio stream number
898    *
899    * Action signal to retrieve the stream-selector sinkpad for a specific 
900    * audio stream.
901    * This pad can be used for notifications of caps changes, stream-specific
902    * queries, etc.
903    *
904    * Returns: a #GstPad, or NULL when the stream number does not exist.
905    */
906   gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
907       g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
908       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
909       G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
910       gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
911   /**
912    * GstPlayBin2::get-text-pad
913    * @playbin: a #GstPlayBin2
914    * @stream: a text stream number
915    *
916    * Action signal to retrieve the stream-selector sinkpad for a specific 
917    * text stream.
918    * This pad can be used for notifications of caps changes, stream-specific
919    * queries, etc.
920    *
921    * Returns: a #GstPad, or NULL when the stream number does not exist.
922    */
923   gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
924       g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
925       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
926       G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
927       gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
928
929   klass->get_video_tags = gst_play_bin_get_video_tags;
930   klass->get_audio_tags = gst_play_bin_get_audio_tags;
931   klass->get_text_tags = gst_play_bin_get_text_tags;
932
933   klass->convert_frame = gst_play_bin_convert_frame;
934
935   klass->get_video_pad = gst_play_bin_get_video_pad;
936   klass->get_audio_pad = gst_play_bin_get_audio_pad;
937   klass->get_text_pad = gst_play_bin_get_text_pad;
938
939   gst_element_class_set_details (gstelement_klass, &gst_play_bin_details);
940
941   gstelement_klass->change_state =
942       GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
943
944   gstbin_klass->handle_message =
945       GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
946 }
947
948 static void
949 init_group (GstPlayBin * playbin, GstSourceGroup * group)
950 {
951   /* store the array for the different channels */
952   group->video_channels = g_ptr_array_new ();
953   group->audio_channels = g_ptr_array_new ();
954   group->text_channels = g_ptr_array_new ();
955   group->lock = g_mutex_new ();
956   group->cond = g_cond_new ();
957   /* init selectors */
958   group->playbin = playbin;
959   group->selector[0].media = "audio/x-raw-";
960   group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
961   group->selector[0].channels = group->audio_channels;
962   group->selector[1].media = "audio/";
963   group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO;
964   group->selector[1].channels = group->audio_channels;
965   group->selector[2].media = "video/x-raw-";
966   group->selector[2].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
967   group->selector[2].channels = group->video_channels;
968   group->selector[3].media = "video/";
969   group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO;
970   group->selector[3].channels = group->video_channels;
971   group->selector[4].media = "text/";
972   group->selector[4].type = GST_PLAY_SINK_TYPE_TEXT;
973   group->selector[4].channels = group->text_channels;
974 }
975
976 static void
977 free_group (GstPlayBin * playbin, GstSourceGroup * group)
978 {
979   g_free (group->uri);
980   g_ptr_array_free (group->video_channels, TRUE);
981   g_ptr_array_free (group->audio_channels, TRUE);
982   g_ptr_array_free (group->text_channels, TRUE);
983   g_mutex_free (group->lock);
984   g_cond_free (group->cond);
985 }
986
987 static void
988 gst_play_bin_init (GstPlayBin * playbin)
989 {
990   GstFactoryListType type;
991
992   playbin->lock = g_mutex_new ();
993   playbin->dyn_lock = g_mutex_new ();
994
995   /* init groups */
996   playbin->curr_group = &playbin->groups[0];
997   playbin->next_group = &playbin->groups[1];
998   init_group (playbin, &playbin->groups[0]);
999   init_group (playbin, &playbin->groups[1]);
1000
1001   /* first filter out the interesting element factories */
1002   type = GST_FACTORY_LIST_DECODER | GST_FACTORY_LIST_SINK;
1003   playbin->elements = gst_factory_list_get_elements (type);
1004   gst_factory_list_debug (playbin->elements);
1005
1006   /* add sink */
1007   playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1008   gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1009   gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1010
1011   playbin->encoding = g_strdup (DEFAULT_SUBTITLE_ENCODING);
1012
1013   playbin->current_video = DEFAULT_CURRENT_VIDEO;
1014   playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1015   playbin->current_text = DEFAULT_CURRENT_TEXT;
1016
1017   playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1018   playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1019 }
1020
1021 static void
1022 gst_play_bin_finalize (GObject * object)
1023 {
1024   GstPlayBin *playbin;
1025
1026   playbin = GST_PLAY_BIN (object);
1027
1028   free_group (playbin, &playbin->groups[0]);
1029   free_group (playbin, &playbin->groups[1]);
1030
1031   if (playbin->source)
1032     gst_object_unref (playbin->source);
1033
1034   g_value_array_free (playbin->elements);
1035   g_free (playbin->encoding);
1036   g_mutex_free (playbin->lock);
1037   g_mutex_free (playbin->dyn_lock);
1038
1039   G_OBJECT_CLASS (parent_class)->finalize (object);
1040 }
1041
1042 static void
1043 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1044 {
1045   GstSourceGroup *group;
1046
1047   if (uri == NULL) {
1048     g_warning ("cannot set NULL uri");
1049     return;
1050   }
1051
1052   GST_PLAY_BIN_LOCK (playbin);
1053   group = playbin->next_group;
1054
1055   GST_SOURCE_GROUP_LOCK (group);
1056   /* store the uri in the next group we will play */
1057   g_free (group->uri);
1058   group->uri = g_strdup (uri);
1059   group->valid = TRUE;
1060   GST_SOURCE_GROUP_UNLOCK (group);
1061
1062   GST_DEBUG ("set new uri to %s", uri);
1063   GST_PLAY_BIN_UNLOCK (playbin);
1064 }
1065
1066 static void
1067 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1068 {
1069   GstSourceGroup *group;
1070
1071   GST_PLAY_BIN_LOCK (playbin);
1072   group = playbin->next_group;
1073
1074   GST_SOURCE_GROUP_LOCK (group);
1075   g_free (group->suburi);
1076   group->suburi = g_strdup (suburi);
1077   GST_SOURCE_GROUP_UNLOCK (group);
1078
1079   GST_DEBUG ("setting new .sub uri to %s", suburi);
1080
1081   GST_PLAY_BIN_UNLOCK (playbin);
1082 }
1083
1084 /* get the currently playing group or if nothing is playing, the next
1085  * group. Must be called with the PLAY_BIN_LOCK. */
1086 static GstSourceGroup *
1087 get_group (GstPlayBin * playbin)
1088 {
1089   GstSourceGroup *result;
1090
1091   if (!(result = playbin->curr_group))
1092     result = playbin->next_group;
1093
1094   return result;
1095 }
1096
1097 static GstPad *
1098 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1099 {
1100   GstPad *sinkpad = NULL;
1101   GstSourceGroup *group;
1102
1103   GST_PLAY_BIN_LOCK (playbin);
1104   group = get_group (playbin);
1105   if (stream < group->video_channels->len) {
1106     sinkpad = g_ptr_array_index (group->video_channels, stream);
1107     gst_object_ref (sinkpad);
1108   }
1109   GST_PLAY_BIN_UNLOCK (playbin);
1110
1111   return sinkpad;
1112 }
1113
1114 static GstPad *
1115 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1116 {
1117   GstPad *sinkpad = NULL;
1118   GstSourceGroup *group;
1119
1120   GST_PLAY_BIN_LOCK (playbin);
1121   group = get_group (playbin);
1122   if (stream < group->audio_channels->len) {
1123     sinkpad = g_ptr_array_index (group->audio_channels, stream);
1124     gst_object_ref (sinkpad);
1125   }
1126   GST_PLAY_BIN_UNLOCK (playbin);
1127
1128   return sinkpad;
1129 }
1130
1131 static GstPad *
1132 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1133 {
1134   GstPad *sinkpad = NULL;
1135   GstSourceGroup *group;
1136
1137   GST_PLAY_BIN_LOCK (playbin);
1138   group = get_group (playbin);
1139   if (stream < group->text_channels->len) {
1140     sinkpad = g_ptr_array_index (group->text_channels, stream);
1141     gst_object_ref (sinkpad);
1142   }
1143   GST_PLAY_BIN_UNLOCK (playbin);
1144
1145   return sinkpad;
1146 }
1147
1148
1149 static GstTagList *
1150 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1151 {
1152   GstTagList *result;
1153   GstPad *sinkpad;
1154
1155   if (!channels || stream >= channels->len)
1156     return NULL;
1157
1158   sinkpad = g_ptr_array_index (channels, stream);
1159   g_object_get (sinkpad, "tags", &result, NULL);
1160
1161   return result;
1162 }
1163
1164 static GstTagList *
1165 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1166 {
1167   GstTagList *result;
1168   GstSourceGroup *group;
1169
1170   GST_PLAY_BIN_LOCK (playbin);
1171   group = get_group (playbin);
1172   result = get_tags (playbin, group->video_channels, stream);
1173   GST_PLAY_BIN_UNLOCK (playbin);
1174
1175   return result;
1176 }
1177
1178 static GstTagList *
1179 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1180 {
1181   GstTagList *result;
1182   GstSourceGroup *group;
1183
1184   GST_PLAY_BIN_LOCK (playbin);
1185   group = get_group (playbin);
1186   result = get_tags (playbin, group->audio_channels, stream);
1187   GST_PLAY_BIN_UNLOCK (playbin);
1188
1189   return result;
1190 }
1191
1192 static GstTagList *
1193 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1194 {
1195   GstTagList *result;
1196   GstSourceGroup *group;
1197
1198   GST_PLAY_BIN_LOCK (playbin);
1199   group = get_group (playbin);
1200   result = get_tags (playbin, group->text_channels, stream);
1201   GST_PLAY_BIN_UNLOCK (playbin);
1202
1203   return result;
1204 }
1205
1206 static GstBuffer *
1207 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1208 {
1209   GstBuffer *result;
1210
1211   result = gst_play_sink_get_last_frame (playbin->playsink);
1212   if (result != NULL && caps != NULL) {
1213     GstBuffer *temp;
1214
1215     temp = gst_play_frame_conv_convert (result, caps);
1216     gst_buffer_unref (result);
1217     result = temp;
1218   }
1219   return result;
1220 }
1221
1222 /* Returns current stream number, or -1 if none has been selected yet */
1223 static int
1224 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1225 {
1226   /* Internal API cleanup would make this easier... */
1227   int i;
1228   GstPad *pad, *current;
1229   GstObject *selector = NULL;
1230   int ret = -1;
1231
1232   for (i = 0; i < channels->len; i++) {
1233     pad = g_ptr_array_index (channels, i);
1234     if ((selector = gst_pad_get_parent (pad))) {
1235       g_object_get (selector, "active-pad", &current, NULL);
1236
1237       if (pad == current) {
1238         gst_object_unref (current);
1239         ret = i;
1240         break;
1241       }
1242
1243       if (current)
1244         gst_object_unref (current);
1245     }
1246   }
1247
1248   if (selector)
1249     gst_object_unref (selector);
1250
1251   return ret;
1252 }
1253
1254 static gboolean
1255 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1256 {
1257   GstSourceGroup *group;
1258   GPtrArray *channels;
1259   GstPad *sinkpad;
1260
1261   GST_PLAY_BIN_LOCK (playbin);
1262   group = get_group (playbin);
1263   if (!(channels = group->video_channels))
1264     goto no_channels;
1265
1266   if (stream == -1 || channels->len < stream) {
1267     sinkpad = NULL;
1268   } else {
1269     /* take channel from selected stream */
1270     sinkpad = g_ptr_array_index (channels, stream);
1271   }
1272
1273   if (sinkpad)
1274     gst_object_ref (sinkpad);
1275   GST_PLAY_BIN_UNLOCK (playbin);
1276
1277   if (sinkpad) {
1278     GstObject *selector;
1279
1280     if ((selector = gst_pad_get_parent (sinkpad))) {
1281       /* activate the selected pad */
1282       g_object_set (selector, "active-pad", sinkpad, NULL);
1283       gst_object_unref (selector);
1284     }
1285     gst_object_unref (sinkpad);
1286   }
1287   return TRUE;
1288
1289 no_channels:
1290   {
1291     GST_PLAY_BIN_UNLOCK (playbin);
1292     return FALSE;
1293   }
1294 }
1295
1296 static gboolean
1297 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1298 {
1299   GstSourceGroup *group;
1300   GPtrArray *channels;
1301   GstPad *sinkpad;
1302
1303   GST_PLAY_BIN_LOCK (playbin);
1304   group = get_group (playbin);
1305   if (!(channels = group->audio_channels))
1306     goto no_channels;
1307
1308   if (stream == -1 || channels->len < stream) {
1309     sinkpad = NULL;
1310   } else {
1311     /* take channel from selected stream */
1312     sinkpad = g_ptr_array_index (channels, stream);
1313   }
1314
1315   if (sinkpad)
1316     gst_object_ref (sinkpad);
1317   GST_PLAY_BIN_UNLOCK (playbin);
1318
1319   if (sinkpad) {
1320     GstObject *selector;
1321
1322     if ((selector = gst_pad_get_parent (sinkpad))) {
1323       /* activate the selected pad */
1324       g_object_set (selector, "active-pad", sinkpad, NULL);
1325       gst_object_unref (selector);
1326     }
1327     gst_object_unref (sinkpad);
1328   }
1329   return TRUE;
1330
1331 no_channels:
1332   {
1333     GST_PLAY_BIN_UNLOCK (playbin);
1334     return FALSE;
1335   }
1336 }
1337
1338 static gboolean
1339 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1340 {
1341   GstSourceGroup *group;
1342   GPtrArray *channels;
1343   GstPad *sinkpad;
1344
1345   GST_PLAY_BIN_LOCK (playbin);
1346   group = get_group (playbin);
1347   if (!(channels = group->text_channels))
1348     goto no_channels;
1349
1350   if (stream == -1 || channels->len < stream) {
1351     sinkpad = NULL;
1352   } else {
1353     /* take channel from selected stream */
1354     sinkpad = g_ptr_array_index (channels, stream);
1355   }
1356
1357   if (sinkpad)
1358     gst_object_ref (sinkpad);
1359   GST_PLAY_BIN_UNLOCK (playbin);
1360
1361   if (sinkpad) {
1362     GstObject *selector;
1363
1364     if ((selector = gst_pad_get_parent (sinkpad))) {
1365       /* activate the selected pad */
1366       g_object_set (selector, "active-pad", sinkpad, NULL);
1367       gst_object_unref (selector);
1368     }
1369     gst_object_unref (sinkpad);
1370   }
1371   return TRUE;
1372
1373 no_channels:
1374   {
1375     GST_PLAY_BIN_UNLOCK (playbin);
1376     return FALSE;
1377   }
1378 }
1379
1380 static void
1381 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1382 {
1383   GstElement *elem;
1384
1385   GST_PLAY_BIN_LOCK (playbin);
1386   g_free (playbin->encoding);
1387   playbin->encoding = g_strdup (encoding);
1388
1389   /* set subtitles on all current and next decodebins. */
1390   if ((elem = playbin->groups[0].uridecodebin))
1391     g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1392   if ((elem = playbin->groups[0].suburidecodebin))
1393     g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1394   if ((elem = playbin->groups[1].uridecodebin))
1395     g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1396   if ((elem = playbin->groups[1].suburidecodebin))
1397     g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1398   GST_PLAY_BIN_UNLOCK (playbin);
1399 }
1400
1401 static void
1402 gst_play_bin_set_property (GObject * object, guint prop_id,
1403     const GValue * value, GParamSpec * pspec)
1404 {
1405   GstPlayBin *playbin;
1406
1407   playbin = GST_PLAY_BIN (object);
1408
1409   switch (prop_id) {
1410     case PROP_URI:
1411       gst_play_bin_set_uri (playbin, g_value_get_string (value));
1412       break;
1413     case PROP_SUBURI:
1414       gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1415       break;
1416     case PROP_FLAGS:
1417       gst_play_sink_set_flags (playbin->playsink, g_value_get_flags (value));
1418       gst_play_sink_reconfigure (playbin->playsink);
1419       break;
1420     case PROP_CURRENT_VIDEO:
1421       gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1422       break;
1423     case PROP_CURRENT_AUDIO:
1424       gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1425       break;
1426     case PROP_CURRENT_TEXT:
1427       gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1428       break;
1429     case PROP_SUBTITLE_ENCODING:
1430       gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1431       break;
1432     case PROP_VIDEO_SINK:
1433       gst_play_sink_set_video_sink (playbin->playsink,
1434           g_value_get_object (value));
1435       break;
1436     case PROP_AUDIO_SINK:
1437       gst_play_sink_set_audio_sink (playbin->playsink,
1438           g_value_get_object (value));
1439       break;
1440     case PROP_VIS_PLUGIN:
1441       gst_play_sink_set_vis_plugin (playbin->playsink,
1442           g_value_get_object (value));
1443       break;
1444     case PROP_VOLUME:
1445       gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1446       break;
1447     case PROP_MUTE:
1448       gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1449       break;
1450     case PROP_FONT_DESC:
1451       gst_play_sink_set_font_desc (playbin->playsink,
1452           g_value_get_string (value));
1453       break;
1454     case PROP_CONNECTION_SPEED:
1455       GST_PLAY_BIN_LOCK (playbin);
1456       playbin->connection_speed = g_value_get_uint (value) * 1000;
1457       GST_PLAY_BIN_UNLOCK (playbin);
1458       break;
1459     case PROP_BUFFER_SIZE:
1460       playbin->buffer_size = g_value_get_int (value);
1461       break;
1462     case PROP_BUFFER_DURATION:
1463       playbin->buffer_duration = g_value_get_int64 (value);
1464       break;
1465     default:
1466       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1467       break;
1468   }
1469 }
1470
1471 static void
1472 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1473     GParamSpec * pspec)
1474 {
1475   GstPlayBin *playbin;
1476
1477   playbin = GST_PLAY_BIN (object);
1478
1479   switch (prop_id) {
1480     case PROP_URI:
1481     {
1482       GstSourceGroup *group;
1483
1484       GST_PLAY_BIN_LOCK (playbin);
1485       group = get_group (playbin);
1486       g_value_set_string (value, group->uri);
1487       GST_PLAY_BIN_UNLOCK (playbin);
1488       break;
1489     }
1490     case PROP_SUBURI:
1491     {
1492       GstSourceGroup *group;
1493
1494       GST_PLAY_BIN_LOCK (playbin);
1495       group = get_group (playbin);
1496       g_value_set_string (value, group->suburi);
1497       GST_PLAY_BIN_UNLOCK (playbin);
1498       break;
1499     }
1500     case PROP_SOURCE:
1501     {
1502       GST_OBJECT_LOCK (playbin);
1503       g_value_set_object (value, playbin->source);
1504       GST_OBJECT_UNLOCK (playbin);
1505       break;
1506     }
1507     case PROP_FLAGS:
1508       g_value_set_flags (value, gst_play_sink_get_flags (playbin->playsink));
1509       break;
1510     case PROP_N_VIDEO:
1511     {
1512       GstSourceGroup *group;
1513       gint n_video;
1514
1515       GST_PLAY_BIN_LOCK (playbin);
1516       group = get_group (playbin);
1517       n_video = (group->video_channels ? group->video_channels->len : 0);
1518       g_value_set_int (value, n_video);
1519       GST_PLAY_BIN_UNLOCK (playbin);
1520       break;
1521     }
1522     case PROP_CURRENT_VIDEO:
1523       GST_PLAY_BIN_LOCK (playbin);
1524       g_value_set_int (value, playbin->current_video);
1525       GST_PLAY_BIN_UNLOCK (playbin);
1526       break;
1527     case PROP_N_AUDIO:
1528     {
1529       GstSourceGroup *group;
1530       gint n_audio;
1531
1532       GST_PLAY_BIN_LOCK (playbin);
1533       group = get_group (playbin);
1534       n_audio = (group->audio_channels ? group->audio_channels->len : 0);
1535       g_value_set_int (value, n_audio);
1536       GST_PLAY_BIN_UNLOCK (playbin);
1537       break;
1538     }
1539     case PROP_CURRENT_AUDIO:
1540       GST_PLAY_BIN_LOCK (playbin);
1541       g_value_set_int (value, playbin->current_audio);
1542       GST_PLAY_BIN_UNLOCK (playbin);
1543       break;
1544     case PROP_N_TEXT:
1545     {
1546       GstSourceGroup *group;
1547       gint n_text;
1548
1549       GST_PLAY_BIN_LOCK (playbin);
1550       group = get_group (playbin);
1551       n_text = (group->text_channels ? group->text_channels->len : 0);
1552       g_value_set_int (value, n_text);
1553       GST_PLAY_BIN_UNLOCK (playbin);
1554       break;
1555     }
1556     case PROP_CURRENT_TEXT:
1557       GST_PLAY_BIN_LOCK (playbin);
1558       g_value_set_int (value, playbin->current_text);
1559       GST_PLAY_BIN_UNLOCK (playbin);
1560       break;
1561     case PROP_SUBTITLE_ENCODING:
1562       GST_PLAY_BIN_LOCK (playbin);
1563       g_value_set_string (value, playbin->encoding);
1564       GST_PLAY_BIN_UNLOCK (playbin);
1565       break;
1566     case PROP_VIDEO_SINK:
1567       g_value_set_object (value,
1568           gst_play_sink_get_video_sink (playbin->playsink));
1569       break;
1570     case PROP_AUDIO_SINK:
1571       g_value_set_object (value,
1572           gst_play_sink_get_audio_sink (playbin->playsink));
1573       break;
1574     case PROP_VIS_PLUGIN:
1575       g_value_set_object (value,
1576           gst_play_sink_get_vis_plugin (playbin->playsink));
1577       break;
1578     case PROP_VOLUME:
1579       g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
1580       break;
1581     case PROP_MUTE:
1582       g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
1583       break;
1584     case PROP_FRAME:
1585       gst_value_take_buffer (value, gst_play_bin_convert_frame (playbin, NULL));
1586       break;
1587     case PROP_FONT_DESC:
1588       g_value_take_string (value,
1589           gst_play_sink_get_font_desc (playbin->playsink));
1590       break;
1591     case PROP_CONNECTION_SPEED:
1592       GST_PLAY_BIN_LOCK (playbin);
1593       g_value_set_uint (value, playbin->connection_speed / 1000);
1594       GST_PLAY_BIN_UNLOCK (playbin);
1595       break;
1596     case PROP_BUFFER_SIZE:
1597       GST_OBJECT_LOCK (playbin);
1598       g_value_set_int (value, playbin->buffer_size);
1599       GST_OBJECT_UNLOCK (playbin);
1600       break;
1601     case PROP_BUFFER_DURATION:
1602       GST_OBJECT_LOCK (playbin);
1603       g_value_set_int64 (value, playbin->buffer_duration);
1604       GST_OBJECT_UNLOCK (playbin);
1605       break;
1606     default:
1607       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1608       break;
1609   }
1610 }
1611
1612 /* mime types we are not handling on purpose right now, don't post a
1613  * missing-plugin message for these */
1614 static const gchar *blacklisted_mimes[] = {
1615   "video/x-dvd-subpicture", NULL
1616 };
1617
1618 static void
1619 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
1620 {
1621   if (gst_is_missing_plugin_message (msg)) {
1622     gchar *detail;
1623     guint i;
1624
1625     detail = gst_missing_plugin_message_get_installer_detail (msg);
1626     for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
1627       if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
1628         GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
1629         gst_message_unref (msg);
1630         g_free (detail);
1631         return;
1632       }
1633     }
1634     g_free (detail);
1635   }
1636   GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
1637 }
1638
1639 static void
1640 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
1641     GstPlayBin * playbin)
1642 {
1643   gchar *property;
1644   GstSourceGroup *group;
1645   GstSourceSelect *select = NULL;
1646   int i;
1647
1648   GST_PLAY_BIN_LOCK (playbin);
1649   group = get_group (playbin);
1650
1651   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
1652     if (selector == G_OBJECT (group->selector[i].selector)) {
1653       select = &group->selector[i];
1654     }
1655   }
1656
1657   /* We got a pad-change after our group got switched out; no need to notify */
1658   if (!select) {
1659     GST_PLAY_BIN_UNLOCK (playbin);
1660     return;
1661   }
1662
1663   switch (select->type) {
1664     case GST_PLAY_SINK_TYPE_VIDEO:
1665     case GST_PLAY_SINK_TYPE_VIDEO_RAW:
1666       property = "current-video";
1667       playbin->current_video = get_current_stream_number (playbin,
1668           group->video_channels);
1669       break;
1670     case GST_PLAY_SINK_TYPE_AUDIO:
1671     case GST_PLAY_SINK_TYPE_AUDIO_RAW:
1672       property = "current-audio";
1673       playbin->current_audio = get_current_stream_number (playbin,
1674           group->audio_channels);
1675       break;
1676     case GST_PLAY_SINK_TYPE_TEXT:
1677       property = "current-text";
1678       playbin->current_text = get_current_stream_number (playbin,
1679           group->text_channels);
1680       break;
1681     default:
1682       property = NULL;
1683   }
1684   GST_PLAY_BIN_UNLOCK (playbin);
1685
1686   if (property)
1687     g_object_notify (G_OBJECT (playbin), property);
1688 }
1689
1690 static void
1691 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
1692 {
1693   /* no nothing */
1694   GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
1695 }
1696
1697 /* this function is called when a new pad is added to decodebin. We check the
1698  * type of the pad and add it to the selector element of the group. 
1699  */
1700 static void
1701 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
1702 {
1703   GstPlayBin *playbin;
1704   GstCaps *caps;
1705   const GstStructure *s;
1706   const gchar *name;
1707   GstPad *sinkpad;
1708   GstPadLinkReturn res;
1709   GstSourceSelect *select = NULL;
1710   gint i;
1711   gboolean changed = FALSE;
1712
1713   playbin = group->playbin;
1714
1715   caps = gst_pad_get_caps (pad);
1716   s = gst_caps_get_structure (caps, 0);
1717   name = gst_structure_get_name (s);
1718
1719   GST_DEBUG_OBJECT (playbin,
1720       "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
1721       GST_DEBUG_PAD_NAME (pad), caps, group);
1722
1723   /* major type of the pad, this determines the selector to use */
1724   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
1725     if (g_str_has_prefix (name, group->selector[i].media)) {
1726       select = &group->selector[i];
1727       break;
1728     }
1729   }
1730   /* no selector found for the media type, don't bother linking it to a
1731    * selector. This will leave the pad unlinked and thus ignored. */
1732   if (select == NULL)
1733     goto unknown_type;
1734
1735   GST_SOURCE_GROUP_LOCK (group);
1736   if (select->selector == NULL) {
1737     /* no selector, create one */
1738     GST_DEBUG_OBJECT (playbin, "creating new selector");
1739     select->selector = gst_element_factory_make ("input-selector", NULL);
1740     if (select->selector == NULL)
1741       goto no_selector;
1742
1743     g_signal_connect (select->selector, "notify::active-pad",
1744         G_CALLBACK (selector_active_pad_changed), playbin);
1745
1746     GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
1747     gst_bin_add (GST_BIN_CAST (playbin), select->selector);
1748     gst_element_set_state (select->selector, GST_STATE_PAUSED);
1749
1750     /* save source pad */
1751     select->srcpad = gst_element_get_static_pad (select->selector, "src");
1752     /* block the selector srcpad. It's possible that multiple decodebins start
1753      * pushing data into the selectors before we have a chance to collect all
1754      * streams and connect the sinks, resulting in not-linked errors. After we
1755      * configured the sinks we will unblock them all. */
1756     gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
1757   }
1758
1759   /* get sinkpad for the new stream */
1760   if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
1761     GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
1762         GST_DEBUG_PAD_NAME (sinkpad));
1763
1764     /* store the selector for the pad */
1765     g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
1766
1767     /* store the pad in the array */
1768     GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
1769     g_ptr_array_add (select->channels, sinkpad);
1770
1771     res = gst_pad_link (pad, sinkpad);
1772     if (GST_PAD_LINK_FAILED (res))
1773       goto link_failed;
1774
1775     /* store selector pad so we can release it */
1776     g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
1777
1778     changed = TRUE;
1779   }
1780   GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
1781       GST_DEBUG_PAD_NAME (pad), select->selector);
1782   GST_SOURCE_GROUP_UNLOCK (group);
1783
1784   if (changed) {
1785     int signal;
1786     switch (select->type) {
1787       case GST_PLAY_SINK_TYPE_VIDEO:
1788       case GST_PLAY_SINK_TYPE_VIDEO_RAW:
1789         signal = SIGNAL_VIDEO_CHANGED;
1790         break;
1791       case GST_PLAY_SINK_TYPE_AUDIO:
1792       case GST_PLAY_SINK_TYPE_AUDIO_RAW:
1793         signal = SIGNAL_AUDIO_CHANGED;
1794         break;
1795       case GST_PLAY_SINK_TYPE_TEXT:
1796         signal = SIGNAL_TEXT_CHANGED;
1797         break;
1798       default:
1799         signal = -1;
1800     }
1801
1802     if (signal >= 0)
1803       g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
1804   }
1805
1806 done:
1807   gst_caps_unref (caps);
1808   return;
1809
1810   /* ERRORS */
1811 unknown_type:
1812   {
1813     GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
1814         name, GST_DEBUG_PAD_NAME (pad));
1815     goto done;
1816   }
1817 no_selector:
1818   {
1819     GST_SOURCE_GROUP_UNLOCK (group);
1820
1821     gst_element_post_message (GST_ELEMENT_CAST (playbin),
1822         gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
1823             "input-selector"));
1824     GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
1825         (_("Missing element '%s' - check your GStreamer installation."),
1826             "input-selector"), (NULL));
1827     goto done;
1828   }
1829 link_failed:
1830   {
1831     GST_ERROR_OBJECT (playbin,
1832         "failed to link pad %s:%s to selector, reason %d",
1833         GST_DEBUG_PAD_NAME (pad), res);
1834     GST_SOURCE_GROUP_UNLOCK (group);
1835     goto done;
1836   }
1837 }
1838
1839 /* called when a pad is removed from the uridecodebin. We unlink the pad from
1840  * the selector. This will make the selector select a new pad. */
1841 static void
1842 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
1843 {
1844   GstPlayBin *playbin;
1845   GstPad *peer;
1846   GstElement *selector;
1847   GstSourceSelect *select;
1848
1849   playbin = group->playbin;
1850
1851   GST_DEBUG_OBJECT (playbin,
1852       "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
1853
1854   GST_SOURCE_GROUP_LOCK (group);
1855   /* get the selector sinkpad */
1856   if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
1857     goto not_linked;
1858
1859   if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
1860     /* remove the pad from the array */
1861     g_ptr_array_remove (select->channels, peer);
1862     GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
1863   }
1864
1865   /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
1866   gst_pad_unlink (pad, peer);
1867
1868   /* get selector, this can be NULL when the element is removing the pads
1869    * because it's being disposed. */
1870   selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
1871   if (!selector) {
1872     gst_object_unref (peer);
1873     goto no_selector;
1874   }
1875
1876   /* release the pad to the selector, this will make the selector choose a new
1877    * pad. */
1878   gst_element_release_request_pad (selector, peer);
1879   gst_object_unref (peer);
1880
1881   gst_object_unref (selector);
1882   GST_SOURCE_GROUP_UNLOCK (group);
1883
1884   return;
1885
1886   /* ERRORS */
1887 not_linked:
1888   {
1889     GST_DEBUG_OBJECT (playbin, "pad not linked");
1890     GST_SOURCE_GROUP_UNLOCK (group);
1891     return;
1892   }
1893 no_selector:
1894   {
1895     GST_DEBUG_OBJECT (playbin, "selector not found");
1896     GST_SOURCE_GROUP_UNLOCK (group);
1897     return;
1898   }
1899 }
1900
1901 /* we get called when all pads are available and we must connect the sinks to
1902  * them.
1903  * The main purpose of the code is to see if we have video/audio and subtitles
1904  * and pick the right pipelines to display them.
1905  *
1906  * The selectors installed on the group tell us about the presence of
1907  * audio/video and subtitle streams. This allows us to see if we need
1908  * visualisation, video or/and audio.
1909  */
1910 static void
1911 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
1912 {
1913   GstPlayBin *playbin;
1914   GstPadLinkReturn res;
1915   gint i;
1916   gboolean configure;
1917
1918   playbin = group->playbin;
1919
1920   GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
1921
1922   GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
1923
1924   GST_SOURCE_GROUP_LOCK (group);
1925   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
1926     GstSourceSelect *select = &group->selector[i];
1927
1928     /* check if the specific media type was detected and thus has a selector
1929      * created for it. If there is the media type, get a sinkpad from the sink
1930      * and link it. We only do this if we have not yet requested the sinkpad
1931      * before. */
1932     if (select->selector && select->sinkpad == NULL) {
1933       GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
1934       select->sinkpad =
1935           gst_play_sink_request_pad (playbin->playsink, select->type);
1936       res = gst_pad_link (select->srcpad, select->sinkpad);
1937       GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d", select->media,
1938           res);
1939       if (res != GST_PAD_LINK_OK) {
1940         GST_ELEMENT_ERROR (playbin, CORE, PAD,
1941             ("Internal playbin error."),
1942             ("Failed to link selector to sink. Error %d", res));
1943       }
1944     }
1945   }
1946   GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
1947       group->pending - 1);
1948
1949   if (group->pending > 0)
1950     group->pending--;
1951
1952   if (group->pending == 0) {
1953     /* we are the last group to complete, we will configure the output and then
1954      * signal the other waiters. */
1955     GST_LOG_OBJECT (playbin, "last group complete");
1956     configure = TRUE;
1957   } else {
1958     GST_LOG_OBJECT (playbin, "have more pending groups");
1959     configure = FALSE;
1960     /* check if there are more decodebins to wait for */
1961     while (group->pending) {
1962       GST_DEBUG_OBJECT (playbin, "%d pending in group %p, waiting",
1963           group->pending, group);
1964       /* FIXME, unlock when shutting down */
1965       GST_SOURCE_GROUP_WAIT (group);
1966     }
1967   }
1968   GST_SOURCE_GROUP_UNLOCK (group);
1969
1970   if (configure) {
1971     GST_LOG_OBJECT (playbin, "reconfigure sink");
1972     /* we configure the modes if we were the last decodebin to complete. */
1973     gst_play_sink_reconfigure (playbin->playsink);
1974
1975     /* signal the other decodebins that they can continue now. */
1976     GST_SOURCE_GROUP_LOCK (group);
1977     /* unblock all selectors */
1978     for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
1979       GstSourceSelect *select = &group->selector[i];
1980
1981       if (select->selector) {
1982         GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
1983             select->srcpad);
1984         gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
1985             NULL);
1986       }
1987     }
1988     GST_DEBUG_OBJECT (playbin, "signal other decodebins");
1989     GST_SOURCE_GROUP_BROADCAST (group);
1990     GST_SOURCE_GROUP_UNLOCK (group);
1991   }
1992
1993   GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
1994
1995   return;
1996
1997 shutdown:
1998   {
1999     GST_DEBUG ("ignoring, we are shutting down");
2000     /* Request a flushing pad from playsink that we then link to the selector.
2001      * Then we unblock the selectors so that they stop with a WRONG_STATE
2002      * instead of a NOT_LINKED error.
2003      */
2004     GST_SOURCE_GROUP_LOCK (group);
2005     for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2006       GstSourceSelect *select = &group->selector[i];
2007
2008       if (select->selector && select->sinkpad == NULL) {
2009         GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2010         select->sinkpad =
2011             gst_play_sink_request_pad (playbin->playsink,
2012             GST_PLAY_SINK_TYPE_FLUSHING);
2013         res = gst_pad_link (select->srcpad, select->sinkpad);
2014         GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2015       }
2016       if (select->srcpad) {
2017         GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2018             select->srcpad);
2019         gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2020             NULL);
2021       }
2022     }
2023     GST_SOURCE_GROUP_UNLOCK (group);
2024     return;
2025   }
2026 }
2027
2028 static void
2029 drained_cb (GstElement * decodebin, GstSourceGroup * group)
2030 {
2031   GstPlayBin *playbin;
2032
2033   playbin = group->playbin;
2034
2035   GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
2036
2037   /* mark us as sending out the about-to-finish signal. When the app sets a URI
2038    * when this signal is emitted, we're marking it as next-uri */
2039   playbin->about_to_finish = TRUE;
2040
2041   /* after this call, we should have a next group to activate or we EOS */
2042   g_signal_emit (G_OBJECT (playbin),
2043       gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
2044
2045   playbin->about_to_finish = FALSE;
2046
2047   /* now activate the next group. If the app did not set a next-uri, this will
2048    * fail and we can do EOS */
2049   setup_next_source (playbin);
2050 }
2051
2052 /* Called when we must provide a list of factories to plug to @pad with @caps.
2053  * We first check if we have a sink that can handle the format and if we do, we
2054  * return NULL, to expose the pad. If we have no sink (or the sink does not
2055  * work), we return the list of elements that can connect. */
2056 static GValueArray *
2057 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
2058     GstCaps * caps, GstSourceGroup * group)
2059 {
2060   GstPlayBin *playbin;
2061   GValueArray *result;
2062
2063   playbin = group->playbin;
2064
2065   GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
2066       group, GST_DEBUG_PAD_NAME (pad), caps);
2067
2068   /* filter out the elements based on the caps. */
2069   result = gst_factory_list_filter (playbin->elements, caps);
2070
2071   GST_DEBUG_OBJECT (playbin, "found factories %p", result);
2072   gst_factory_list_debug (result);
2073
2074   return result;
2075 }
2076
2077 /* We are asked to select an element. See if the next element to check
2078  * is a sink. If this is the case, we see if the sink works by setting it to
2079  * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
2080  * expose the raw pad so that we can setup the mixers. */
2081 static GstAutoplugSelectResult
2082 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
2083     GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
2084 {
2085   GstPlayBin *playbin;
2086   GstElement *element;
2087   const gchar *klass;
2088
2089   playbin = group->playbin;
2090
2091   GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
2092       group, GST_DEBUG_PAD_NAME (pad), caps);
2093
2094   GST_DEBUG_OBJECT (playbin, "checking factory %s",
2095       GST_PLUGIN_FEATURE_NAME (factory));
2096
2097   /* if it's not a sink, we just make decodebin try it */
2098   if (!gst_factory_list_is_type (factory, GST_FACTORY_LIST_SINK))
2099     return GST_AUTOPLUG_SELECT_TRY;
2100
2101   /* it's a sink, see if an instance of it actually works */
2102   GST_DEBUG_OBJECT (playbin, "we found a sink");
2103
2104   klass = gst_element_factory_get_klass (factory);
2105
2106   /* if we are asked to do visualisations and it's an audio sink, skip the
2107    * element. We can only do visualisations with raw sinks */
2108   if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
2109     if (strstr (klass, "Audio")) {
2110       GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
2111       return GST_AUTOPLUG_SELECT_SKIP;
2112     }
2113   }
2114
2115   if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
2116     GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
2117         gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
2118     return GST_AUTOPLUG_SELECT_SKIP;
2119   }
2120
2121   /* ... activate it ... We do this before adding it to the bin so that we
2122    * don't accidentally make it post error messages that will stop
2123    * everything. */
2124   if ((gst_element_set_state (element,
2125               GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
2126     GST_WARNING_OBJECT (playbin, "Couldn't set %s to READY",
2127         GST_ELEMENT_NAME (element));
2128     gst_object_unref (element);
2129     return GST_AUTOPLUG_SELECT_SKIP;
2130   }
2131
2132   /* get klass to figure out if it's audio or video */
2133   if (strstr (klass, "Audio")) {
2134     GST_DEBUG_OBJECT (playbin, "configure audio sink");
2135     gst_play_sink_set_audio_sink (playbin->playsink, element);
2136     g_object_notify (G_OBJECT (playbin), "audio-sink");
2137   } else if (strstr (klass, "Video")) {
2138     GST_DEBUG_OBJECT (playbin, "configure video sink");
2139     gst_play_sink_set_video_sink (playbin->playsink, element);
2140     g_object_notify (G_OBJECT (playbin), "video-sink");
2141   } else {
2142     GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
2143   }
2144
2145   /* tell decodebin to expose the pad because we are going to use this
2146    * sink */
2147   GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
2148
2149   return GST_AUTOPLUG_SELECT_EXPOSE;
2150 }
2151
2152 static void
2153 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
2154     GstSourceGroup * group)
2155 {
2156   GstPlayBin *playbin;
2157   GstElement *source;
2158
2159   playbin = group->playbin;
2160
2161   GST_OBJECT_LOCK (playbin);
2162   g_object_get (group->uridecodebin, "source", &source, NULL);
2163   if (playbin->source)
2164     gst_object_unref (playbin->source);
2165   playbin->source = source;
2166   GST_OBJECT_UNLOCK (playbin);
2167
2168   g_object_notify (G_OBJECT (playbin), "source");
2169 }
2170
2171 /* must be called with the group lock */
2172 static gboolean
2173 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
2174     gboolean locked)
2175 {
2176   GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
2177
2178   if (group->uridecodebin)
2179     gst_element_set_locked_state (group->uridecodebin, locked);
2180   if (group->suburidecodebin)
2181     gst_element_set_locked_state (group->suburidecodebin, locked);
2182
2183   return TRUE;
2184 }
2185
2186 #define REMOVE_SIGNAL(obj,id)            \
2187 if (id) {                                \
2188   g_signal_handler_disconnect (obj, id); \
2189   id = 0;                                \
2190 }
2191
2192 /* must be called with PLAY_BIN_LOCK */
2193 static gboolean
2194 activate_group (GstPlayBin * playbin, GstSourceGroup * group)
2195 {
2196   GstElement *uridecodebin;
2197   GstElement *suburidecodebin = NULL;
2198
2199   g_return_val_if_fail (group->valid, FALSE);
2200   g_return_val_if_fail (!group->active, FALSE);
2201
2202   GST_SOURCE_GROUP_LOCK (group);
2203   if (group->uridecodebin) {
2204     GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
2205     REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
2206     REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
2207     REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
2208     REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
2209     REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
2210     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
2211     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
2212     gst_element_set_state (group->uridecodebin, GST_STATE_NULL);
2213     uridecodebin = group->uridecodebin;
2214   } else {
2215     GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
2216     uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
2217     if (!uridecodebin)
2218       goto no_decodebin;
2219     gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
2220     group->uridecodebin = uridecodebin;
2221   }
2222
2223   /* configure connection speed */
2224   g_object_set (uridecodebin, "connection-speed", playbin->connection_speed,
2225       NULL);
2226   /* configure subtitle encoding */
2227   g_object_set (uridecodebin, "subtitle-encoding", playbin->encoding, NULL);
2228   /* configure uri */
2229   g_object_set (uridecodebin, "uri", group->uri, NULL);
2230   g_object_set (uridecodebin, "buffer-duration", playbin->buffer_duration,
2231       NULL);
2232   g_object_set (uridecodebin, "buffer-size", playbin->buffer_size, NULL);
2233
2234   /* connect pads and other things */
2235   group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
2236       G_CALLBACK (pad_added_cb), group);
2237   group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
2238       G_CALLBACK (pad_removed_cb), group);
2239   group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
2240       G_CALLBACK (no_more_pads_cb), group);
2241   group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
2242       G_CALLBACK (notify_source_cb), group);
2243   /* we have 1 pending no-more-pads */
2244   group->pending = 1;
2245
2246   /* is called when the uridecodebin is out of data and we can switch to the
2247    * next uri */
2248   group->drained_id =
2249       g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
2250       group);
2251
2252   /* will be called when a new media type is found. We return a list of decoders
2253    * including sinks for decodebin to try */
2254   group->autoplug_factories_id =
2255       g_signal_connect (uridecodebin, "autoplug-factories",
2256       G_CALLBACK (autoplug_factories_cb), group);
2257   group->autoplug_select_id = g_signal_connect (uridecodebin, "autoplug-select",
2258       G_CALLBACK (autoplug_select_cb), group);
2259
2260   if (group->suburi) {
2261     /* subtitles */
2262     if (group->suburidecodebin) {
2263       GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
2264       REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2265       REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2266       REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2267       gst_element_set_state (group->suburidecodebin, GST_STATE_NULL);
2268       suburidecodebin = group->suburidecodebin;
2269     } else {
2270       GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
2271       suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
2272       if (!suburidecodebin)
2273         goto no_decodebin;
2274
2275       gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
2276       group->suburidecodebin = suburidecodebin;
2277     }
2278
2279     /* configure connection speed */
2280     g_object_set (suburidecodebin, "connection-speed",
2281         playbin->connection_speed, NULL);
2282     /* configure subtitle encoding */
2283     g_object_set (suburidecodebin, "subtitle-encoding", playbin->encoding,
2284         NULL);
2285     /* configure uri */
2286     g_object_set (suburidecodebin, "uri", group->suburi, NULL);
2287
2288     /* connect pads and other things */
2289     group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
2290         G_CALLBACK (pad_added_cb), group);
2291     group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
2292         "pad-removed", G_CALLBACK (pad_removed_cb), group);
2293     group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
2294         "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
2295
2296     /* we have 2 pending no-more-pads */
2297     group->pending = 2;
2298   }
2299
2300   /* release the group lock before setting the state of the decodebins, they
2301    * might fire signals in this thread that we need to handle with the
2302    * group_lock taken. */
2303   GST_SOURCE_GROUP_UNLOCK (group);
2304
2305   if (suburidecodebin) {
2306     if (gst_element_set_state (suburidecodebin,
2307             GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE)
2308       goto suburidecodebin_failure;
2309   }
2310   if (gst_element_set_state (uridecodebin,
2311           GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE)
2312     goto uridecodebin_failure;
2313
2314   GST_SOURCE_GROUP_LOCK (group);
2315   /* alow state changes of the playbin2 affect the group elements now */
2316   group_set_locked_state_unlocked (playbin, group, FALSE);
2317   group->active = TRUE;
2318   GST_SOURCE_GROUP_UNLOCK (group);
2319
2320   return TRUE;
2321
2322   /* ERRORS */
2323 no_decodebin:
2324   {
2325     GST_SOURCE_GROUP_UNLOCK (group);
2326     return FALSE;
2327   }
2328 suburidecodebin_failure:
2329   {
2330     GST_DEBUG_OBJECT (playbin, "failed state change of subtitle uridecodebin");
2331     return FALSE;
2332   }
2333 uridecodebin_failure:
2334   {
2335     GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
2336     return FALSE;
2337   }
2338 }
2339
2340 /* unlink a group of uridecodebins from the sink.
2341  * must be called with PLAY_BIN_LOCK */
2342 static gboolean
2343 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
2344 {
2345   gint i;
2346
2347   g_return_val_if_fail (group->valid, FALSE);
2348   g_return_val_if_fail (group->active, FALSE);
2349
2350   GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
2351
2352   GST_SOURCE_GROUP_LOCK (group);
2353   group->active = FALSE;
2354   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2355     GstSourceSelect *select = &group->selector[i];
2356
2357     if (!select->selector)
2358       continue;
2359
2360     GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media);
2361
2362     if (select->sinkpad) {
2363       GST_LOG_OBJECT (playbin, "unlinking from sink");
2364       gst_pad_unlink (select->srcpad, select->sinkpad);
2365
2366       /* release back */
2367       GST_LOG_OBJECT (playbin, "release sink pad");
2368       gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
2369       select->sinkpad = NULL;
2370     }
2371
2372     gst_object_unref (select->srcpad);
2373     select->srcpad = NULL;
2374
2375     gst_element_set_state (select->selector, GST_STATE_NULL);
2376     gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
2377     select->selector = NULL;
2378   }
2379   /* we still have the decodebins added to the playbin2 but we can't remove them
2380    * yet or change their state because this function might be called from the
2381    * streaming threads, instead block the state so that state changes on the
2382    * playbin2 don't affect us anymore */
2383   group_set_locked_state_unlocked (playbin, group, TRUE);
2384   GST_SOURCE_GROUP_UNLOCK (group);
2385
2386   return TRUE;
2387 }
2388
2389 /* setup the next group to play, this assumes the next_group is valid and
2390  * configured. It swaps out the current_group and activates the valid 
2391  * next_group. */
2392 static gboolean
2393 setup_next_source (GstPlayBin * playbin)
2394 {
2395   GstSourceGroup *new_group, *old_group;
2396
2397   GST_DEBUG_OBJECT (playbin, "setup sources");
2398
2399   /* see if there is a next group */
2400   GST_PLAY_BIN_LOCK (playbin);
2401   new_group = playbin->next_group;
2402   if (!new_group || !new_group->valid)
2403     goto no_next_group;
2404
2405   /* first unlink the current source, if any */
2406   old_group = playbin->curr_group;
2407   if (old_group && old_group->valid) {
2408     /* unlink our pads with the sink */
2409     deactivate_group (playbin, old_group);
2410     old_group->valid = FALSE;
2411   }
2412
2413   /* activate the new group */
2414   if (!activate_group (playbin, new_group))
2415     goto activate_failed;
2416
2417   /* swap old and new */
2418   playbin->curr_group = new_group;
2419   playbin->next_group = old_group;
2420   GST_PLAY_BIN_UNLOCK (playbin);
2421
2422   return TRUE;
2423
2424   /* ERRORS */
2425 no_next_group:
2426   {
2427     GST_DEBUG_OBJECT (playbin, "no next group");
2428     GST_PLAY_BIN_UNLOCK (playbin);
2429     return FALSE;
2430   }
2431 activate_failed:
2432   {
2433     GST_DEBUG_OBJECT (playbin, "activate failed");
2434     GST_PLAY_BIN_UNLOCK (playbin);
2435     return FALSE;
2436   }
2437 }
2438
2439 /* The group that is currently playing is copied again to the
2440  * next_group so that it will start playing the next time.
2441  */
2442 static gboolean
2443 save_current_group (GstPlayBin * playbin)
2444 {
2445   GstSourceGroup *curr_group;
2446
2447   GST_DEBUG_OBJECT (playbin, "save current group");
2448
2449   /* see if there is a current group */
2450   GST_PLAY_BIN_LOCK (playbin);
2451   curr_group = playbin->curr_group;
2452   if (curr_group && curr_group->valid) {
2453     /* unlink our pads with the sink */
2454     deactivate_group (playbin, curr_group);
2455   }
2456   /* swap old and new */
2457   playbin->curr_group = playbin->next_group;
2458   playbin->next_group = curr_group;
2459   GST_PLAY_BIN_UNLOCK (playbin);
2460
2461   return TRUE;
2462 }
2463
2464 /* clear the locked state from all groups. This function is called before a
2465  * state change to NULL is performed on them. */
2466 static gboolean
2467 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
2468 {
2469   GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
2470       locked);
2471
2472   GST_PLAY_BIN_LOCK (playbin);
2473   GST_SOURCE_GROUP_LOCK (playbin->curr_group);
2474   group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
2475   GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
2476   GST_SOURCE_GROUP_LOCK (playbin->next_group);
2477   group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
2478   GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
2479   GST_PLAY_BIN_UNLOCK (playbin);
2480
2481   return TRUE;
2482 }
2483
2484 static GstStateChangeReturn
2485 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
2486 {
2487   GstStateChangeReturn ret;
2488   GstPlayBin *playbin;
2489
2490   playbin = GST_PLAY_BIN (element);
2491
2492   switch (transition) {
2493     case GST_STATE_CHANGE_READY_TO_PAUSED:
2494       GST_LOG_OBJECT (playbin, "clearing shutdown flag");
2495       g_atomic_int_set (&playbin->shutdown, 0);
2496       if (!setup_next_source (playbin))
2497         goto source_failed;
2498       break;
2499     case GST_STATE_CHANGE_PAUSED_TO_READY:
2500       /* FIXME unlock our waiting groups */
2501       GST_LOG_OBJECT (playbin, "setting shutdown flag");
2502       g_atomic_int_set (&playbin->shutdown, 1);
2503       /* wait for all callbacks to end by taking the lock.
2504        * No dynamic (critical) new callbacks will
2505        * be able to happen as we set the shutdown flag. */
2506       GST_PLAY_BIN_DYN_LOCK (playbin);
2507       GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
2508       GST_PLAY_BIN_DYN_UNLOCK (playbin);
2509       break;
2510     case GST_STATE_CHANGE_READY_TO_NULL:
2511       /* unlock so that all groups go to NULL */
2512       groups_set_locked_state (playbin, FALSE);
2513       break;
2514     default:
2515       break;
2516   }
2517
2518   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2519   if (ret == GST_STATE_CHANGE_FAILURE)
2520     return ret;
2521
2522   switch (transition) {
2523     case GST_STATE_CHANGE_READY_TO_PAUSED:
2524       break;
2525     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2526       /* FIXME Release audio device when we implement that */
2527       break;
2528     case GST_STATE_CHANGE_PAUSED_TO_READY:
2529       save_current_group (playbin);
2530       break;
2531     case GST_STATE_CHANGE_READY_TO_NULL:
2532       /* make sure the groups don't perform a state change anymore until we
2533        * enable them again */
2534       groups_set_locked_state (playbin, TRUE);
2535       break;
2536     default:
2537       break;
2538   }
2539
2540   return ret;
2541
2542   /* ERRORS */
2543 source_failed:
2544   {
2545     return GST_STATE_CHANGE_FAILURE;
2546   }
2547 }
2548
2549 gboolean
2550 gst_play_bin2_plugin_init (GstPlugin * plugin)
2551 {
2552   GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
2553
2554   return gst_element_register (plugin, "playbin2", GST_RANK_NONE,
2555       GST_TYPE_PLAY_BIN);
2556 }