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