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