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