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