2 * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
3 * Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * SECTION:element-playbin
24 * Playbin provides a stand-alone everything-in-one abstraction for an
25 * audio and/or video player.
27 * Playbin can handle both audio and video files and features
30 * automatic file type recognition and based on that automatic
31 * selection and usage of the right audio/video/subtitle demuxers/decoders
34 * visualisations for audio files
37 * subtitle support for video files. Subtitles can be store in external
41 * stream selection between different video/audio/subtitles streams
44 * meta info (tag) extraction
47 * easy access to the last video sample
50 * buffering when playing streams over a network
53 * volume control with mute option
58 * <title>Usage</title>
60 * A playbin element can be created just like any other element using
61 * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin:uri
62 * property. This must be an absolute URI, relative file paths are not allowed.
63 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
65 * Playbin is a #GstPipeline. It will notify the application of everything
66 * that's happening (errors, end of stream, tags found, state changes, etc.)
67 * by posting messages on its #GstBus. The application needs to watch the
70 * Playback can be initiated by setting the element to PLAYING state using
71 * gst_element_set_state(). Note that the state change will take place in
72 * the background in a separate thread, when the function returns playback
73 * is probably not happening yet and any errors might not have occured yet.
74 * Applications using playbin should ideally be written to deal with things
75 * completely asynchroneous.
77 * When playback has finished (an EOS message has been received on the bus)
78 * or an error has occured (an ERROR message has been received on the bus) or
79 * the user wants to play a different track, playbin should be set back to
80 * READY or NULL state, then the #GstPlayBin:uri property should be set to the
81 * new location and then playbin be set to PLAYING state again.
83 * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
84 * on the playbin element. Again, the seek will not be executed
85 * instantaneously, but will be done in a background thread. When the seek
86 * call returns the seek will most likely still be in process. An application
87 * may wait for the seek to finish (or fail) using gst_element_get_state() with
88 * -1 as the timeout, but this will block the user interface and is not
91 * Applications may query the current position and duration of the stream
92 * via gst_element_query_position() and gst_element_query_duration() and
93 * setting the format passed to GST_FORMAT_TIME. If the query was successful,
94 * the duration or position will have been returned in units of nanoseconds.
98 * <title>Advanced Usage: specifying the audio and video sink</title>
100 * By default, if no audio sink or video sink has been specified via the
101 * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property, playbin will use the autoaudiosink
102 * and autovideosink elements to find the first-best available output method.
103 * This should work in most cases, but is not always desirable. Often either
104 * the user or application might want to specify more explicitly what to use
105 * for audio and video output.
107 * If the application wants more control over how audio or video should be
108 * output, it may create the audio/video sink elements itself (for example
109 * using gst_element_factory_make()) and provide them to playbin using the
110 * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property.
112 * GNOME-based applications, for example, will usually want to create
113 * gconfaudiosink and gconfvideosink elements and make playbin use those,
114 * so that output happens to whatever the user has configured in the GNOME
115 * Multimedia System Selector configuration dialog.
117 * The sink elements do not necessarily need to be ready-made sinks. It is
118 * possible to create container elements that look like a sink to playbin,
119 * but in reality contain a number of custom elements linked together. This
120 * can be achieved by creating a #GstBin and putting elements in there and
121 * linking them, and then creating a sink #GstGhostPad for the bin and pointing
122 * it to the sink pad of the first element within the bin. This can be used
123 * for a number of purposes, for example to force output to a particular
124 * format or to modify or observe the data before it is output.
126 * It is also possible to 'suppress' audio and/or video output by using
127 * 'fakesink' elements (or capture it from there using the fakesink element's
128 * "handoff" signal, which, nota bene, is fired from the streaming thread!).
132 * <title>Retrieving Tags and Other Meta Data</title>
134 * Most of the common meta data (artist, title, etc.) can be retrieved by
135 * watching for TAG messages on the pipeline's bus (see above).
137 * Other more specific meta information like width/height/framerate of video
138 * streams or samplerate/number of channels of audio streams can be obtained
139 * from the negotiated caps on the sink pads of the sinks.
143 * <title>Buffering</title>
144 * Playbin handles buffering automatically for the most part, but applications
145 * need to handle parts of the buffering process as well. Whenever playbin is
146 * buffering, it will post BUFFERING messages on the bus with a percentage
147 * value that shows the progress of the buffering process. Applications need
148 * to set playbin to PLAYING or PAUSED state in response to these messages.
149 * They may also want to convey the buffering progress to the user in some
150 * way. Here is how to extract the percentage information from the message
151 * (requires GStreamer >= 0.10.11):
153 * switch (GST_MESSAGE_TYPE (msg)) {
154 * case GST_MESSAGE_BUFFERING: {
156 * gst_message_parse_buffering (msg, &percent);
157 * g_print ("Buffering (%%u percent done)", percent);
163 * Note that applications should keep/set the pipeline in the PAUSED state when
164 * a BUFFERING message is received with a buffer percent value < 100 and set
165 * the pipeline back to PLAYING state when a BUFFERING message with a value
166 * of 100 percent is received (if PLAYING is the desired state, that is).
169 * <title>Embedding the video window in your application</title>
170 * By default, playbin (or rather the video sinks used) will create their own
171 * window. Applications will usually want to force output to a window of their
172 * own, however. This can be done using the #GstXOverlay interface, which most
173 * video sinks implement. See the documentation there for more details.
176 * <title>Specifying which CD/DVD device to use</title>
177 * The device to use for CDs/DVDs needs to be set on the source element
178 * playbin creates before it is opened. The only way to do this at the moment
179 * is to connect to playbin's "notify::source" signal, which will be emitted
180 * by playbin when it has created the source element for a particular URI.
181 * In the signal callback you can check if the source element has a "device"
182 * property and set it appropriately. In future ways might be added to specify
183 * the device as part of the URI, but at the time of writing this is not
187 * <title>Handling redirects</title>
189 * Some elements may post 'redirect' messages on the bus to tell the
190 * application to open another location. These are element messages containing
191 * a structure named 'redirect' along with a 'new-location' field of string
192 * type. The new location may be a relative or an absolute URI. Examples
193 * for such redirects can be found in many quicktime movie trailers.
197 * <title>Examples</title>
199 * gst-launch -v playbin uri=file:///path/to/somefile.avi
200 * ]| This will play back the given AVI video file, given that the video and
201 * audio decoders required to decode the content are installed. Since no
202 * special audio sink or video sink is supplied (not possible via gst-launch),
203 * playbin will try to find a suitable audio and video sink automatically
204 * using the autoaudiosink and autovideosink elements.
206 * gst-launch -v playbin uri=cdda://4
207 * ]| This will play back track 4 on an audio CD in your disc drive (assuming
208 * the drive is detected automatically by the plugin).
210 * gst-launch -v playbin uri=dvd://1
211 * ]| This will play back title 1 of a DVD in your disc drive (assuming
212 * the drive is detected automatically by the plugin).
220 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
221 * with newer GLib versions (>= 2.31.0) */
222 #define GLIB_DISABLE_DEPRECATION_WARNINGS
227 #include <gst/gst-i18n-plugin.h>
228 #include <gst/pbutils/pbutils.h>
229 #include <gst/audio/streamvolume.h>
231 #include "gstplay-enum.h"
232 #include "gstplay-marshal.h"
233 #include "gstplayback.h"
234 #include "gstplaysink.h"
235 #include "gstsubtitleoverlay.h"
237 #include "gst/glib-compat-private.h"
239 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
240 #define GST_CAT_DEFAULT gst_play_bin_debug
242 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type())
243 #define GST_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
244 #define GST_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
245 #define GST_IS_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
246 #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
248 #define VOLUME_MAX_DOUBLE 10.0
250 typedef struct _GstPlayBin GstPlayBin;
251 typedef struct _GstPlayBinClass GstPlayBinClass;
252 typedef struct _GstSourceGroup GstSourceGroup;
253 typedef struct _GstSourceSelect GstSourceSelect;
255 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
257 /* has the info for a selector and provides the link to the sink */
258 struct _GstSourceSelect
260 const gchar *media_list[8]; /* the media types for the selector */
261 SourceSelectGetMediaCapsFunc get_media_caps; /* more complex caps for the selector */
262 GstPlaySinkType type; /* the sink pad type of the selector */
264 GstElement *selector; /* the selector */
266 GstPad *srcpad; /* the source pad of the selector */
267 GstPad *sinkpad; /* the sinkpad of the sink when the selector
270 GstEvent *sinkpad_delayed_event;
271 gulong sinkpad_data_probe;
275 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
276 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
277 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
281 PLAYBIN_STREAM_AUDIO = 0,
282 PLAYBIN_STREAM_VIDEO,
287 /* a structure to hold the objects for decoding a uri and the subtitle uri
289 struct _GstSourceGroup
295 gboolean valid; /* the group has valid info to start playback */
296 gboolean active; /* the group is active */
301 GValueArray *streaminfo;
304 GPtrArray *video_channels; /* links to selector pads */
305 GPtrArray *audio_channels; /* links to selector pads */
306 GPtrArray *text_channels; /* links to selector pads */
308 GstElement *audio_sink; /* autoplugged audio and video sinks */
309 GstElement *video_sink;
311 /* uridecodebins for uri and subtitle uri */
312 GstElement *uridecodebin;
313 GstElement *suburidecodebin;
315 gboolean sub_pending;
318 gulong pad_removed_id;
319 gulong no_more_pads_id;
320 gulong notify_source_id;
322 gulong autoplug_factories_id;
323 gulong autoplug_select_id;
324 gulong autoplug_continue_id;
326 gulong sub_pad_added_id;
327 gulong sub_pad_removed_id;
328 gulong sub_no_more_pads_id;
329 gulong sub_autoplug_continue_id;
333 GMutex *stream_changed_pending_lock;
334 GList *stream_changed_pending;
336 /* selectors for different streams */
337 GstSourceSelect selector[PLAYBIN_STREAM_LAST];
340 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
341 #define GST_PLAY_BIN_LOCK(bin) (g_static_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
342 #define GST_PLAY_BIN_UNLOCK(bin) (g_static_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
344 /* lock to protect dynamic callbacks, like no-more-pads */
345 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->dyn_lock)
346 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->dyn_lock)
348 /* lock for shutdown */
349 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
351 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
353 GST_PLAY_BIN_DYN_LOCK (bin); \
354 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
355 GST_PLAY_BIN_DYN_UNLOCK (bin); \
360 /* unlock for shutdown */
361 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
362 GST_PLAY_BIN_DYN_UNLOCK (bin); \
367 * playbin element structure
373 GStaticRecMutex lock; /* to protect group switching */
375 /* the groups, we use a double buffer to switch between current and next */
376 GstSourceGroup groups[2]; /* array with group info */
377 GstSourceGroup *curr_group; /* pointer to the currently playing group */
378 GstSourceGroup *next_group; /* pointer to the next group */
381 guint64 connection_speed; /* connection speed in bits/sec (0 = unknown) */
382 gint current_video; /* the currently selected stream */
383 gint current_audio; /* the currently selected stream */
384 gint current_text; /* the currently selected stream */
386 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
387 guint buffer_size; /* When buffering, the max buffer size (bytes) */
390 GstPlaySink *playsink;
392 /* the last activated source */
395 /* lock protecting dynamic adding/removing */
397 /* if we are shutting down or not */
400 GMutex *elements_lock;
401 guint32 elements_cookie;
402 GList *elements; /* factories we can use for selecting elements */
404 gboolean have_selector; /* set to FALSE when we fail to create an
405 * input-selector, so that we only post a
408 GstElement *audio_sink; /* configured audio sink, or NULL */
409 GstElement *video_sink; /* configured video sink, or NULL */
410 GstElement *text_sink; /* configured text sink, or NULL */
417 } duration[5]; /* cached durations */
419 guint64 ring_buffer_max_size; /* 0 means disabled */
422 struct _GstPlayBinClass
424 GstPipelineClass parent_class;
426 /* notify app that the current uri finished decoding and it is possible to
427 * queue a new one for gapless playback */
428 void (*about_to_finish) (GstPlayBin * playbin);
430 /* notify app that number of audio/video/text streams changed */
431 void (*video_changed) (GstPlayBin * playbin);
432 void (*audio_changed) (GstPlayBin * playbin);
433 void (*text_changed) (GstPlayBin * playbin);
435 /* notify app that the tags of audio/video/text streams changed */
436 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
437 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
438 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
440 /* get audio/video/text tags for a stream */
441 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
442 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
443 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
445 /* get the last video sample and convert it to the given caps */
446 GstSample *(*convert_sample) (GstPlayBin * playbin, GstCaps * caps);
448 /* get audio/video/text pad for a stream */
449 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
450 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
451 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
455 #define DEFAULT_URI NULL
456 #define DEFAULT_SUBURI NULL
457 #define DEFAULT_SOURCE NULL
458 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
459 GST_PLAY_FLAG_SOFT_VOLUME
460 #define DEFAULT_N_VIDEO 0
461 #define DEFAULT_CURRENT_VIDEO -1
462 #define DEFAULT_N_AUDIO 0
463 #define DEFAULT_CURRENT_AUDIO -1
464 #define DEFAULT_N_TEXT 0
465 #define DEFAULT_CURRENT_TEXT -1
466 #define DEFAULT_SUBTITLE_ENCODING NULL
467 #define DEFAULT_AUDIO_SINK NULL
468 #define DEFAULT_VIDEO_SINK NULL
469 #define DEFAULT_VIS_PLUGIN NULL
470 #define DEFAULT_TEXT_SINK NULL
471 #define DEFAULT_VOLUME 1.0
472 #define DEFAULT_MUTE FALSE
473 #define DEFAULT_FRAME NULL
474 #define DEFAULT_FONT_DESC NULL
475 #define DEFAULT_CONNECTION_SPEED 0
476 #define DEFAULT_BUFFER_DURATION -1
477 #define DEFAULT_BUFFER_SIZE -1
478 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
493 PROP_SUBTITLE_ENCODING,
502 PROP_CONNECTION_SPEED,
504 PROP_BUFFER_DURATION,
506 PROP_RING_BUFFER_MAX_SIZE,
513 SIGNAL_ABOUT_TO_FINISH,
514 SIGNAL_CONVERT_SAMPLE,
515 SIGNAL_VIDEO_CHANGED,
516 SIGNAL_AUDIO_CHANGED,
518 SIGNAL_VIDEO_TAGS_CHANGED,
519 SIGNAL_AUDIO_TAGS_CHANGED,
520 SIGNAL_TEXT_TAGS_CHANGED,
521 SIGNAL_GET_VIDEO_TAGS,
522 SIGNAL_GET_AUDIO_TAGS,
523 SIGNAL_GET_TEXT_TAGS,
524 SIGNAL_GET_VIDEO_PAD,
525 SIGNAL_GET_AUDIO_PAD,
531 static void gst_play_bin_class_init (GstPlayBinClass * klass);
532 static void gst_play_bin_init (GstPlayBin * playbin);
533 static void gst_play_bin_finalize (GObject * object);
535 static void gst_play_bin_set_property (GObject * object, guint prop_id,
536 const GValue * value, GParamSpec * spec);
537 static void gst_play_bin_get_property (GObject * object, guint prop_id,
538 GValue * value, GParamSpec * spec);
540 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
541 GstStateChange transition);
543 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
544 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
546 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
548 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
550 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
553 static GstSample *gst_play_bin_convert_sample (GstPlayBin * playbin,
556 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
557 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
558 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
560 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
562 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
563 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
564 GstSourceGroup * group);
566 static void gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
567 GstElement * suburidecodebin, gboolean block);
568 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
571 static GstElementClass *parent_class;
573 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
575 #define REMOVE_SIGNAL(obj,id) \
577 g_signal_handler_disconnect (obj, id); \
582 gst_play_bin_get_type (void)
584 static GType gst_play_bin_type = 0;
586 if (!gst_play_bin_type) {
587 static const GTypeInfo gst_play_bin_info = {
588 sizeof (GstPlayBinClass),
591 (GClassInitFunc) gst_play_bin_class_init,
596 (GInstanceInitFunc) gst_play_bin_init,
599 static const GInterfaceInfo svol_info = {
603 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
604 "GstPlayBin", &gst_play_bin_info, 0);
606 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
610 return gst_play_bin_type;
614 gst_play_bin_class_init (GstPlayBinClass * klass)
616 GObjectClass *gobject_klass;
617 GstElementClass *gstelement_klass;
618 GstBinClass *gstbin_klass;
620 gobject_klass = (GObjectClass *) klass;
621 gstelement_klass = (GstElementClass *) klass;
622 gstbin_klass = (GstBinClass *) klass;
624 parent_class = g_type_class_peek_parent (klass);
626 gobject_klass->set_property = gst_play_bin_set_property;
627 gobject_klass->get_property = gst_play_bin_get_property;
629 gobject_klass->finalize = gst_play_bin_finalize;
634 * Set the next URI that playbin will play. This property can be set from the
635 * about-to-finish signal to queue the next media file.
637 g_object_class_install_property (gobject_klass, PROP_URI,
638 g_param_spec_string ("uri", "URI", "URI of the media to play",
639 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
644 * Set the next subtitle URI that playbin will play. This property can be
645 * set from the about-to-finish signal to queue the next subtitle media file.
647 g_object_class_install_property (gobject_klass, PROP_SUBURI,
648 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
649 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
651 g_object_class_install_property (gobject_klass, PROP_SOURCE,
652 g_param_spec_object ("source", "Source", "Source element",
653 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
658 * Control the behaviour of playbin.
660 g_object_class_install_property (gobject_klass, PROP_FLAGS,
661 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
662 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
663 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
668 * Get the total number of available video streams.
670 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
671 g_param_spec_int ("n-video", "Number Video",
672 "Total number of video streams", 0, G_MAXINT, 0,
673 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
675 * GstPlayBin:current-video
677 * Get or set the currently playing video stream. By default the first video
678 * stream with data is played.
680 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
681 g_param_spec_int ("current-video", "Current Video",
682 "Currently playing video stream (-1 = auto)",
683 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
687 * Get the total number of available audio streams.
689 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
690 g_param_spec_int ("n-audio", "Number Audio",
691 "Total number of audio streams", 0, G_MAXINT, 0,
692 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
694 * GstPlayBin:current-audio
696 * Get or set the currently playing audio stream. By default the first audio
697 * stream with data is played.
699 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
700 g_param_spec_int ("current-audio", "Current audio",
701 "Currently playing audio stream (-1 = auto)",
702 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
706 * Get the total number of available subtitle streams.
708 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
709 g_param_spec_int ("n-text", "Number Text",
710 "Total number of text streams", 0, G_MAXINT, 0,
711 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
713 * GstPlayBin:current-text:
715 * Get or set the currently playing subtitle stream. By default the first
716 * subtitle stream with data is played.
718 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
719 g_param_spec_int ("current-text", "Current Text",
720 "Currently playing text stream (-1 = auto)",
721 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
723 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
724 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
725 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
726 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
727 "be checked for an encoding to use. If that is not set either, "
728 "ISO-8859-15 will be assumed.", NULL,
729 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
731 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
732 g_param_spec_object ("video-sink", "Video Sink",
733 "the video output element to use (NULL = default sink)",
734 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
735 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
736 g_param_spec_object ("audio-sink", "Audio Sink",
737 "the audio output element to use (NULL = default sink)",
738 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
739 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
740 g_param_spec_object ("vis-plugin", "Vis plugin",
741 "the visualization element to use (NULL = default)",
742 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
743 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
744 g_param_spec_object ("text-sink", "Text plugin",
745 "the text output element to use (NULL = default textoverlay)",
746 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
751 * Get or set the current audio stream volume. 1.0 means 100%,
752 * 0.0 means mute. This uses a linear volume scale.
755 g_object_class_install_property (gobject_klass, PROP_VOLUME,
756 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
757 0.0, VOLUME_MAX_DOUBLE, 1.0,
758 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
759 g_object_class_install_property (gobject_klass, PROP_MUTE,
760 g_param_spec_boolean ("mute", "Mute",
761 "Mute the audio channel without changing the volume", FALSE,
762 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
766 * @playbin: a #GstPlayBin
768 * Get the currently rendered or prerolled sample in the video sink.
769 * The #GstCaps in the sample will describe the format of the buffer.
771 g_object_class_install_property (gobject_klass, PROP_SAMPLE,
772 g_param_spec_boxed ("sample", "Sample",
773 "The last sample (NULL = no video available)",
774 GST_TYPE_SAMPLE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
776 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
777 g_param_spec_string ("subtitle-font-desc",
778 "Subtitle font description",
779 "Pango font description of font "
780 "to be used for subtitle rendering", NULL,
781 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
783 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
784 g_param_spec_uint64 ("connection-speed", "Connection Speed",
785 "Network connection speed in kbps (0 = unknown)",
786 0, G_MAXUINT64 / 1000, DEFAULT_CONNECTION_SPEED,
787 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
789 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
790 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
791 "Buffer size when buffering network streams",
792 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
793 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
794 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
795 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
796 "Buffer duration when buffering network streams",
797 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
798 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
800 * GstPlayBin:av-offset:
802 * Control the synchronisation offset between the audio and video streams.
803 * Positive values make the audio ahead of the video and negative values make
804 * the audio go behind the video.
808 g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
809 g_param_spec_int64 ("av-offset", "AV Offset",
810 "The synchronisation offset between audio and video in nanoseconds",
811 G_MININT64, G_MAXINT64, 0,
812 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
815 * GstQueue2:ring-buffer-max-size
817 * The maximum size of the ring buffer in bytes. If set to 0, the ring
818 * buffer is disabled. Default 0.
822 g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
823 g_param_spec_uint64 ("ring-buffer-max-size",
824 "Max. ring buffer size (bytes)",
825 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
826 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
827 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
830 * GstPlayBin::about-to-finish
831 * @playbin: a #GstPlayBin
833 * This signal is emitted when the current uri is about to finish. You can
834 * set the uri and suburi to make sure that playback continues.
836 * This signal is emitted from the context of a GStreamer streaming thread.
838 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
839 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
841 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
842 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
845 * GstPlayBin::video-changed
846 * @playbin: a #GstPlayBin
848 * This signal is emitted whenever the number or order of the video
849 * streams has changed. The application will most likely want to select
850 * a new video stream.
852 * This signal is usually emitted from the context of a GStreamer streaming
853 * thread. You can use gst_message_new_application() and
854 * gst_element_post_message() to notify your application's main thread.
856 /* FIXME 0.11: turn video-changed signal into message? */
857 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
858 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
860 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
861 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
863 * GstPlayBin::audio-changed
864 * @playbin: a #GstPlayBin
866 * This signal is emitted whenever the number or order of the audio
867 * streams has changed. The application will most likely want to select
868 * a new audio stream.
870 * This signal may be emitted from the context of a GStreamer streaming thread.
871 * You can use gst_message_new_application() and gst_element_post_message()
872 * to notify your application's main thread.
874 /* FIXME 0.11: turn audio-changed signal into message? */
875 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
876 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
878 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
879 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
881 * GstPlayBin::text-changed
882 * @playbin: a #GstPlayBin
884 * This signal is emitted whenever the number or order of the text
885 * streams has changed. The application will most likely want to select
888 * This signal may be emitted from the context of a GStreamer streaming thread.
889 * You can use gst_message_new_application() and gst_element_post_message()
890 * to notify your application's main thread.
892 /* FIXME 0.11: turn text-changed signal into message? */
893 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
894 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
896 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
897 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
900 * GstPlayBin::video-tags-changed
901 * @playbin: a #GstPlayBin
902 * @stream: stream index with changed tags
904 * This signal is emitted whenever the tags of a video stream have changed.
905 * The application will most likely want to get the new tags.
907 * This signal may be emitted from the context of a GStreamer streaming thread.
908 * You can use gst_message_new_application() and gst_element_post_message()
909 * to notify your application's main thread.
913 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
914 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
916 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
917 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
920 * GstPlayBin::audio-tags-changed
921 * @playbin: a #GstPlayBin
922 * @stream: stream index with changed tags
924 * This signal is emitted whenever the tags of an audio stream have changed.
925 * The application will most likely want to get the new tags.
927 * This signal may be emitted from the context of a GStreamer streaming thread.
928 * You can use gst_message_new_application() and gst_element_post_message()
929 * to notify your application's main thread.
933 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
934 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
936 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
937 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
940 * GstPlayBin::text-tags-changed
941 * @playbin: a #GstPlayBin
942 * @stream: stream index with changed tags
944 * This signal is emitted whenever the tags of a text stream have changed.
945 * The application will most likely want to get the new tags.
947 * This signal may be emitted from the context of a GStreamer streaming thread.
948 * You can use gst_message_new_application() and gst_element_post_message()
949 * to notify your application's main thread.
953 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
954 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
956 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
957 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
960 * GstPlayBin::source-setup:
961 * @playbin: a #GstPlayBin
962 * @source: source element
964 * This signal is emitted after the source element has been created, so
965 * it can be configured by setting additional properties (e.g. set a
966 * proxy server for an http source, or set the device and read speed for
967 * an audio cd source). This is functionally equivalent to connecting to
968 * the notify::source signal, but more convenient.
970 * This signal is usually emitted from the context of a GStreamer streaming
975 gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
976 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
977 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
978 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
981 * GstPlayBin::get-video-tags
982 * @playbin: a #GstPlayBin
983 * @stream: a video stream number
985 * Action signal to retrieve the tags of a specific video stream number.
986 * This information can be used to select a stream.
988 * Returns: a GstTagList with tags or NULL when the stream number does not
991 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
992 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
993 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
994 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
995 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
997 * GstPlayBin::get-audio-tags
998 * @playbin: a #GstPlayBin
999 * @stream: an audio stream number
1001 * Action signal to retrieve the tags of a specific audio stream number.
1002 * This information can be used to select a stream.
1004 * Returns: a GstTagList with tags or NULL when the stream number does not
1007 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
1008 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
1009 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1010 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
1011 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1013 * GstPlayBin::get-text-tags
1014 * @playbin: a #GstPlayBin
1015 * @stream: a text stream number
1017 * Action signal to retrieve the tags of a specific text stream number.
1018 * This information can be used to select a stream.
1020 * Returns: a GstTagList with tags or NULL when the stream number does not
1023 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
1024 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
1025 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1026 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
1027 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1029 * GstPlayBin::convert-sample
1030 * @playbin: a #GstPlayBin
1031 * @caps: the target format of the frame
1033 * Action signal to retrieve the currently playing video frame in the format
1034 * specified by @caps.
1035 * If @caps is %NULL, no conversion will be performed and this function is
1036 * equivalent to the #GstPlayBin::frame property.
1038 * Returns: a #GstBuffer of the current video frame converted to #caps.
1039 * The caps on the buffer will describe the final layout of the buffer data.
1040 * %NULL is returned when no current buffer can be retrieved or when the
1041 * conversion failed.
1043 gst_play_bin_signals[SIGNAL_CONVERT_SAMPLE] =
1044 g_signal_new ("convert-sample", G_TYPE_FROM_CLASS (klass),
1045 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1046 G_STRUCT_OFFSET (GstPlayBinClass, convert_sample), NULL, NULL,
1047 gst_play_marshal_SAMPLE__BOXED, GST_TYPE_SAMPLE, 1, GST_TYPE_CAPS);
1050 * GstPlayBin::get-video-pad
1051 * @playbin: a #GstPlayBin
1052 * @stream: a video stream number
1054 * Action signal to retrieve the stream-selector sinkpad for a specific
1056 * This pad can be used for notifications of caps changes, stream-specific
1059 * Returns: a #GstPad, or NULL when the stream number does not exist.
1061 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1062 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1063 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1064 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1065 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1067 * GstPlayBin::get-audio-pad
1068 * @playbin: a #GstPlayBin
1069 * @stream: an audio stream number
1071 * Action signal to retrieve the stream-selector sinkpad for a specific
1073 * This pad can be used for notifications of caps changes, stream-specific
1076 * Returns: a #GstPad, or NULL when the stream number does not exist.
1078 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1079 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1080 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1081 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1082 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1084 * GstPlayBin::get-text-pad
1085 * @playbin: a #GstPlayBin
1086 * @stream: a text stream number
1088 * Action signal to retrieve the stream-selector sinkpad for a specific
1090 * This pad can be used for notifications of caps changes, stream-specific
1093 * Returns: a #GstPad, or NULL when the stream number does not exist.
1095 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1096 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1097 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1098 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1099 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1101 klass->get_video_tags = gst_play_bin_get_video_tags;
1102 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1103 klass->get_text_tags = gst_play_bin_get_text_tags;
1105 klass->convert_sample = gst_play_bin_convert_sample;
1107 klass->get_video_pad = gst_play_bin_get_video_pad;
1108 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1109 klass->get_text_pad = gst_play_bin_get_text_pad;
1111 gst_element_class_set_details_simple (gstelement_klass,
1112 "Player Bin 2", "Generic/Bin/Player",
1113 "Autoplug and play media from an uri",
1114 "Wim Taymans <wim.taymans@gmail.com>");
1116 gstelement_klass->change_state =
1117 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1118 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1120 gstbin_klass->handle_message =
1121 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1125 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1129 /* store the array for the different channels */
1130 group->video_channels = g_ptr_array_new ();
1131 group->audio_channels = g_ptr_array_new ();
1132 group->text_channels = g_ptr_array_new ();
1133 group->lock = g_mutex_new ();
1134 /* init selectors. The selector is found by finding the first prefix that
1135 * matches the media. */
1136 group->playbin = playbin;
1137 /* If you add any items to these lists, check that media_list[] is defined
1138 * above to be large enough to hold MAX(items)+1, so as to accommodate a
1139 * NULL terminator (set when the memory is zeroed on allocation) */
1140 group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
1141 group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
1142 group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
1143 group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
1144 group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
1145 group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
1146 group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
1147 group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
1148 group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
1149 group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
1150 group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
1151 group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
1152 group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
1153 group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
1154 gst_subtitle_overlay_create_factory_caps;
1155 group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
1156 group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
1158 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1159 GstSourceSelect *select = &group->selector[n];
1160 select->sinkpad_delayed_event = NULL;
1161 select->sinkpad_data_probe = 0;
1166 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1170 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1171 GstSourceSelect *select = &group->selector[n];
1172 if (select->sinkpad && select->sinkpad_data_probe)
1173 gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
1174 if (select->sinkpad_delayed_event)
1175 gst_event_unref (select->sinkpad_delayed_event);
1178 g_free (group->uri);
1179 g_free (group->suburi);
1180 g_ptr_array_free (group->video_channels, TRUE);
1181 g_ptr_array_free (group->audio_channels, TRUE);
1182 g_ptr_array_free (group->text_channels, TRUE);
1184 g_mutex_free (group->lock);
1185 if (group->audio_sink) {
1186 if (group->audio_sink != playbin->audio_sink)
1187 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1188 gst_object_unref (group->audio_sink);
1190 group->audio_sink = NULL;
1191 if (group->video_sink) {
1192 if (group->video_sink != playbin->video_sink)
1193 gst_element_set_state (group->video_sink, GST_STATE_NULL);
1194 gst_object_unref (group->video_sink);
1196 group->video_sink = NULL;
1198 g_list_free (group->stream_changed_pending);
1199 group->stream_changed_pending = NULL;
1201 if (group->stream_changed_pending_lock)
1202 g_mutex_free (group->stream_changed_pending_lock);
1203 group->stream_changed_pending_lock = NULL;
1207 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1209 g_object_notify (G_OBJECT (playbin), "volume");
1213 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1215 g_object_notify (G_OBJECT (playbin), "mute");
1218 /* Must be called with elements lock! */
1220 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1224 if (!playbin->elements ||
1225 playbin->elements_cookie !=
1226 gst_default_registry_get_feature_list_cookie ()) {
1227 if (playbin->elements)
1228 gst_plugin_feature_list_free (playbin->elements);
1230 gst_element_factory_list_get_elements
1231 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1233 gst_element_factory_list_get_elements
1234 (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1235 playbin->elements = g_list_concat (res, tmp);
1237 g_list_sort (playbin->elements, gst_plugin_feature_rank_compare_func);
1238 playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1243 gst_play_bin_init (GstPlayBin * playbin)
1245 g_static_rec_mutex_init (&playbin->lock);
1246 playbin->dyn_lock = g_mutex_new ();
1248 /* assume we can create a selector */
1249 playbin->have_selector = TRUE;
1252 playbin->curr_group = &playbin->groups[0];
1253 playbin->next_group = &playbin->groups[1];
1254 init_group (playbin, &playbin->groups[0]);
1255 init_group (playbin, &playbin->groups[1]);
1257 /* first filter out the interesting element factories */
1258 playbin->elements_lock = g_mutex_new ();
1261 playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1262 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1263 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1264 /* Connect to notify::volume and notify::mute signals for proxying */
1265 g_signal_connect (playbin->playsink, "notify::volume",
1266 G_CALLBACK (notify_volume_cb), playbin);
1267 g_signal_connect (playbin->playsink, "notify::mute",
1268 G_CALLBACK (notify_mute_cb), playbin);
1270 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1271 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1272 playbin->current_text = DEFAULT_CURRENT_TEXT;
1274 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1275 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1276 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1280 gst_play_bin_finalize (GObject * object)
1282 GstPlayBin *playbin;
1284 playbin = GST_PLAY_BIN (object);
1286 free_group (playbin, &playbin->groups[0]);
1287 free_group (playbin, &playbin->groups[1]);
1289 if (playbin->source)
1290 gst_object_unref (playbin->source);
1291 if (playbin->video_sink) {
1292 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1293 gst_object_unref (playbin->video_sink);
1295 if (playbin->audio_sink) {
1296 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1297 gst_object_unref (playbin->audio_sink);
1299 if (playbin->text_sink) {
1300 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1301 gst_object_unref (playbin->text_sink);
1304 if (playbin->elements)
1305 gst_plugin_feature_list_free (playbin->elements);
1307 g_static_rec_mutex_free (&playbin->lock);
1308 g_mutex_free (playbin->dyn_lock);
1309 g_mutex_free (playbin->elements_lock);
1311 G_OBJECT_CLASS (parent_class)->finalize (object);
1315 gst_playbin_uri_is_valid (GstPlayBin * playbin, const gchar * uri)
1319 GST_LOG_OBJECT (playbin, "checking uri '%s'", uri);
1321 /* this just checks the protocol */
1322 if (!gst_uri_is_valid (uri))
1325 for (c = uri; *c != '\0'; ++c) {
1326 if (!g_ascii_isprint (*c))
1336 GST_WARNING_OBJECT (playbin, "uri '%s' not valid, character #%u",
1337 uri, (guint) ((guintptr) c - (guintptr) uri));
1343 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1345 GstSourceGroup *group;
1348 g_warning ("cannot set NULL uri");
1352 if (!gst_playbin_uri_is_valid (playbin, uri)) {
1353 if (g_str_has_prefix (uri, "file:")) {
1354 GST_WARNING_OBJECT (playbin, "not entirely correct file URI '%s' - make "
1355 "sure to escape spaces and non-ASCII characters properly and specify "
1356 "an absolute path. Use gst_filename_to_uri() to convert filenames "
1359 /* GST_ERROR_OBJECT (playbin, "malformed URI '%s'", uri); */
1363 GST_PLAY_BIN_LOCK (playbin);
1364 group = playbin->next_group;
1366 GST_SOURCE_GROUP_LOCK (group);
1367 /* store the uri in the next group we will play */
1368 g_free (group->uri);
1369 group->uri = g_strdup (uri);
1370 group->valid = TRUE;
1371 GST_SOURCE_GROUP_UNLOCK (group);
1373 GST_DEBUG ("set new uri to %s", uri);
1374 GST_PLAY_BIN_UNLOCK (playbin);
1378 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1380 GstSourceGroup *group;
1382 GST_PLAY_BIN_LOCK (playbin);
1383 group = playbin->next_group;
1385 GST_SOURCE_GROUP_LOCK (group);
1386 g_free (group->suburi);
1387 group->suburi = g_strdup (suburi);
1388 GST_SOURCE_GROUP_UNLOCK (group);
1390 GST_DEBUG ("setting new .sub uri to %s", suburi);
1392 GST_PLAY_BIN_UNLOCK (playbin);
1396 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1398 gst_play_sink_set_flags (playbin->playsink, flags);
1399 gst_play_sink_reconfigure (playbin->playsink);
1403 gst_play_bin_get_flags (GstPlayBin * playbin)
1407 flags = gst_play_sink_get_flags (playbin->playsink);
1412 /* get the currently playing group or if nothing is playing, the next
1413 * group. Must be called with the PLAY_BIN_LOCK. */
1414 static GstSourceGroup *
1415 get_group (GstPlayBin * playbin)
1417 GstSourceGroup *result;
1419 if (!(result = playbin->curr_group))
1420 result = playbin->next_group;
1426 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1428 GstPad *sinkpad = NULL;
1429 GstSourceGroup *group;
1431 GST_PLAY_BIN_LOCK (playbin);
1432 group = get_group (playbin);
1433 if (stream < group->video_channels->len) {
1434 sinkpad = g_ptr_array_index (group->video_channels, stream);
1435 gst_object_ref (sinkpad);
1437 GST_PLAY_BIN_UNLOCK (playbin);
1443 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1445 GstPad *sinkpad = NULL;
1446 GstSourceGroup *group;
1448 GST_PLAY_BIN_LOCK (playbin);
1449 group = get_group (playbin);
1450 if (stream < group->audio_channels->len) {
1451 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1452 gst_object_ref (sinkpad);
1454 GST_PLAY_BIN_UNLOCK (playbin);
1460 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1462 GstPad *sinkpad = NULL;
1463 GstSourceGroup *group;
1465 GST_PLAY_BIN_LOCK (playbin);
1466 group = get_group (playbin);
1467 if (stream < group->text_channels->len) {
1468 sinkpad = g_ptr_array_index (group->text_channels, stream);
1469 gst_object_ref (sinkpad);
1471 GST_PLAY_BIN_UNLOCK (playbin);
1478 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1483 if (!channels || stream >= channels->len)
1486 sinkpad = g_ptr_array_index (channels, stream);
1487 g_object_get (sinkpad, "tags", &result, NULL);
1493 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1496 GstSourceGroup *group;
1498 GST_PLAY_BIN_LOCK (playbin);
1499 group = get_group (playbin);
1500 result = get_tags (playbin, group->video_channels, stream);
1501 GST_PLAY_BIN_UNLOCK (playbin);
1507 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1510 GstSourceGroup *group;
1512 GST_PLAY_BIN_LOCK (playbin);
1513 group = get_group (playbin);
1514 result = get_tags (playbin, group->audio_channels, stream);
1515 GST_PLAY_BIN_UNLOCK (playbin);
1521 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1524 GstSourceGroup *group;
1526 GST_PLAY_BIN_LOCK (playbin);
1527 group = get_group (playbin);
1528 result = get_tags (playbin, group->text_channels, stream);
1529 GST_PLAY_BIN_UNLOCK (playbin);
1535 gst_play_bin_convert_sample (GstPlayBin * playbin, GstCaps * caps)
1537 return gst_play_sink_convert_sample (playbin->playsink, caps);
1540 /* Returns current stream number, or -1 if none has been selected yet */
1542 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1544 /* Internal API cleanup would make this easier... */
1546 GstPad *pad, *current;
1547 GstObject *selector = NULL;
1550 for (i = 0; i < channels->len; i++) {
1551 pad = g_ptr_array_index (channels, i);
1552 if ((selector = gst_pad_get_parent (pad))) {
1553 g_object_get (selector, "active-pad", ¤t, NULL);
1554 gst_object_unref (selector);
1556 if (pad == current) {
1557 gst_object_unref (current);
1563 gst_object_unref (current);
1571 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1573 GstSourceGroup *group;
1574 GPtrArray *channels;
1577 GST_PLAY_BIN_LOCK (playbin);
1579 GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1580 playbin->current_video, stream);
1582 group = get_group (playbin);
1583 if (!(channels = group->video_channels))
1586 if (stream == -1 || channels->len <= stream) {
1589 /* take channel from selected stream */
1590 sinkpad = g_ptr_array_index (channels, stream);
1594 gst_object_ref (sinkpad);
1595 GST_PLAY_BIN_UNLOCK (playbin);
1598 GstObject *selector;
1600 if ((selector = gst_pad_get_parent (sinkpad))) {
1601 /* activate the selected pad */
1602 g_object_set (selector, "active-pad", sinkpad, NULL);
1603 gst_object_unref (selector);
1605 gst_object_unref (sinkpad);
1611 GST_PLAY_BIN_UNLOCK (playbin);
1612 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1618 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1620 GstSourceGroup *group;
1621 GPtrArray *channels;
1624 GST_PLAY_BIN_LOCK (playbin);
1626 GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1627 playbin->current_audio, stream);
1629 group = get_group (playbin);
1630 if (!(channels = group->audio_channels))
1633 if (stream == -1 || channels->len <= stream) {
1636 /* take channel from selected stream */
1637 sinkpad = g_ptr_array_index (channels, stream);
1641 gst_object_ref (sinkpad);
1642 GST_PLAY_BIN_UNLOCK (playbin);
1645 GstObject *selector;
1647 if ((selector = gst_pad_get_parent (sinkpad))) {
1648 /* activate the selected pad */
1649 g_object_set (selector, "active-pad", sinkpad, NULL);
1650 gst_object_unref (selector);
1652 gst_object_unref (sinkpad);
1658 GST_PLAY_BIN_UNLOCK (playbin);
1659 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1665 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1667 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1669 GValue item = { 0, };
1671 if (it && gst_iterator_next (it, &item) == GST_ITERATOR_OK
1672 && ((sinkpad = g_value_get_object (&item)) != NULL)) {
1676 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1677 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1678 if (!gst_pad_send_event (sinkpad, event)) {
1680 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1681 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1682 if (!gst_pad_send_event (sinkpad, event))
1683 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1686 g_value_unset (&item);
1690 gst_iterator_free (it);
1694 gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
1695 GstElement * suburidecodebin, gboolean block)
1697 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1698 gboolean done = FALSE;
1699 GValue item = { 0, };
1701 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1708 switch (gst_iterator_next (it, &item)) {
1709 case GST_ITERATOR_OK:
1710 sinkpad = g_value_get_object (&item);
1713 gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1715 } else if (group->block_id) {
1716 gst_pad_remove_probe (sinkpad, group->block_id);
1717 group->block_id = 0;
1719 g_value_reset (&item);
1721 case GST_ITERATOR_DONE:
1724 case GST_ITERATOR_RESYNC:
1725 gst_iterator_resync (it);
1727 case GST_ITERATOR_ERROR:
1732 g_value_unset (&item);
1733 gst_iterator_free (it);
1737 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1739 GstSourceGroup *group;
1740 GPtrArray *channels;
1743 GST_PLAY_BIN_LOCK (playbin);
1745 GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1746 playbin->current_text, stream);
1748 group = get_group (playbin);
1749 if (!(channels = group->text_channels))
1752 if (stream == -1 || channels->len <= stream) {
1755 /* take channel from selected stream */
1756 sinkpad = g_ptr_array_index (channels, stream);
1760 gst_object_ref (sinkpad);
1761 GST_PLAY_BIN_UNLOCK (playbin);
1764 GstObject *selector;
1766 if ((selector = gst_pad_get_parent (sinkpad))) {
1767 GstPad *old_sinkpad;
1769 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1771 if (old_sinkpad != sinkpad) {
1772 gboolean need_unblock, need_block, need_seek;
1773 GstPad *src, *peer = NULL, *oldpeer = NULL;
1774 GstElement *parent_element = NULL, *old_parent_element = NULL;
1776 /* Now check if we need to seek the suburidecodebin to the beginning
1777 * or if we need to block all suburidecodebin sinkpads or if we need
1778 * to unblock all suburidecodebin sinkpads
1781 peer = gst_pad_get_peer (sinkpad);
1783 oldpeer = gst_pad_get_peer (old_sinkpad);
1786 parent_element = gst_pad_get_parent_element (peer);
1788 old_parent_element = gst_pad_get_parent_element (oldpeer);
1790 need_block = (old_parent_element == group->suburidecodebin
1791 && parent_element != old_parent_element);
1792 need_unblock = (parent_element == group->suburidecodebin
1793 && parent_element != old_parent_element);
1794 need_seek = (parent_element == group->suburidecodebin);
1797 gst_object_unref (peer);
1799 gst_object_unref (oldpeer);
1801 gst_object_unref (parent_element);
1802 if (old_parent_element)
1803 gst_object_unref (old_parent_element);
1805 /* Block all suburidecodebin sinkpads */
1807 gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1810 /* activate the selected pad */
1811 g_object_set (selector, "active-pad", sinkpad, NULL);
1813 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1814 peer = gst_pad_get_peer (src);
1818 /* Flush the subtitle renderer to remove any
1819 * currently displayed subtitles. This event will
1820 * never travel outside subtitleoverlay!
1822 s = gst_structure_new_empty ("subtitleoverlay-flush-subtitle");
1823 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1824 gst_pad_send_event (peer, event);
1825 gst_object_unref (peer);
1827 gst_object_unref (src);
1829 /* Unblock pads if necessary */
1831 gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1834 /* seek to the beginning */
1836 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1838 gst_object_unref (selector);
1841 gst_object_unref (old_sinkpad);
1843 gst_object_unref (sinkpad);
1849 GST_PLAY_BIN_UNLOCK (playbin);
1855 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1856 const gchar * dbg, GstElement * sink)
1858 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1860 GST_PLAY_BIN_LOCK (playbin);
1861 if (*elem != sink) {
1866 gst_object_ref_sink (sink);
1870 gst_object_unref (old);
1872 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1873 GST_PLAY_BIN_UNLOCK (playbin);
1877 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1881 GST_PLAY_BIN_LOCK (playbin);
1883 /* set subtitles on all current and next decodebins. */
1884 if ((elem = playbin->groups[0].uridecodebin))
1885 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1886 if ((elem = playbin->groups[0].suburidecodebin))
1887 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1888 if ((elem = playbin->groups[1].uridecodebin))
1889 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1890 if ((elem = playbin->groups[1].suburidecodebin))
1891 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1893 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1894 GST_PLAY_BIN_UNLOCK (playbin);
1898 gst_play_bin_set_property (GObject * object, guint prop_id,
1899 const GValue * value, GParamSpec * pspec)
1901 GstPlayBin *playbin = GST_PLAY_BIN (object);
1905 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1908 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1911 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1913 case PROP_CURRENT_VIDEO:
1914 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1916 case PROP_CURRENT_AUDIO:
1917 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1919 case PROP_CURRENT_TEXT:
1920 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1922 case PROP_SUBTITLE_ENCODING:
1923 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1925 case PROP_VIDEO_SINK:
1926 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1927 g_value_get_object (value));
1929 case PROP_AUDIO_SINK:
1930 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1931 g_value_get_object (value));
1933 case PROP_VIS_PLUGIN:
1934 gst_play_sink_set_vis_plugin (playbin->playsink,
1935 g_value_get_object (value));
1937 case PROP_TEXT_SINK:
1938 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1939 g_value_get_object (value));
1942 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1945 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1947 case PROP_FONT_DESC:
1948 gst_play_sink_set_font_desc (playbin->playsink,
1949 g_value_get_string (value));
1951 case PROP_CONNECTION_SPEED:
1952 GST_PLAY_BIN_LOCK (playbin);
1953 playbin->connection_speed = g_value_get_uint64 (value) * 1000;
1954 GST_PLAY_BIN_UNLOCK (playbin);
1956 case PROP_BUFFER_SIZE:
1957 playbin->buffer_size = g_value_get_int (value);
1959 case PROP_BUFFER_DURATION:
1960 playbin->buffer_duration = g_value_get_int64 (value);
1962 case PROP_AV_OFFSET:
1963 gst_play_sink_set_av_offset (playbin->playsink,
1964 g_value_get_int64 (value));
1966 case PROP_RING_BUFFER_MAX_SIZE:
1967 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
1970 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1976 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1977 const gchar * dbg, GstPlaySinkType type)
1979 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
1981 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1982 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1983 dbg, sink, dbg, *elem);
1986 GST_PLAY_BIN_LOCK (playbin);
1988 gst_object_ref (sink);
1989 GST_PLAY_BIN_UNLOCK (playbin);
1996 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1999 GstPlayBin *playbin = GST_PLAY_BIN (object);
2004 GstSourceGroup *group;
2006 GST_PLAY_BIN_LOCK (playbin);
2007 group = get_group (playbin);
2008 g_value_set_string (value, group->uri);
2009 GST_PLAY_BIN_UNLOCK (playbin);
2014 GstSourceGroup *group;
2016 GST_PLAY_BIN_LOCK (playbin);
2017 group = get_group (playbin);
2018 g_value_set_string (value, group->suburi);
2019 GST_PLAY_BIN_UNLOCK (playbin);
2024 GST_OBJECT_LOCK (playbin);
2025 g_value_set_object (value, playbin->source);
2026 GST_OBJECT_UNLOCK (playbin);
2030 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
2034 GstSourceGroup *group;
2037 GST_PLAY_BIN_LOCK (playbin);
2038 group = get_group (playbin);
2039 n_video = (group->video_channels ? group->video_channels->len : 0);
2040 g_value_set_int (value, n_video);
2041 GST_PLAY_BIN_UNLOCK (playbin);
2044 case PROP_CURRENT_VIDEO:
2045 GST_PLAY_BIN_LOCK (playbin);
2046 g_value_set_int (value, playbin->current_video);
2047 GST_PLAY_BIN_UNLOCK (playbin);
2051 GstSourceGroup *group;
2054 GST_PLAY_BIN_LOCK (playbin);
2055 group = get_group (playbin);
2056 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
2057 g_value_set_int (value, n_audio);
2058 GST_PLAY_BIN_UNLOCK (playbin);
2061 case PROP_CURRENT_AUDIO:
2062 GST_PLAY_BIN_LOCK (playbin);
2063 g_value_set_int (value, playbin->current_audio);
2064 GST_PLAY_BIN_UNLOCK (playbin);
2068 GstSourceGroup *group;
2071 GST_PLAY_BIN_LOCK (playbin);
2072 group = get_group (playbin);
2073 n_text = (group->text_channels ? group->text_channels->len : 0);
2074 g_value_set_int (value, n_text);
2075 GST_PLAY_BIN_UNLOCK (playbin);
2078 case PROP_CURRENT_TEXT:
2079 GST_PLAY_BIN_LOCK (playbin);
2080 g_value_set_int (value, playbin->current_text);
2081 GST_PLAY_BIN_UNLOCK (playbin);
2083 case PROP_SUBTITLE_ENCODING:
2084 GST_PLAY_BIN_LOCK (playbin);
2085 g_value_take_string (value,
2086 gst_play_sink_get_subtitle_encoding (playbin->playsink));
2087 GST_PLAY_BIN_UNLOCK (playbin);
2089 case PROP_VIDEO_SINK:
2090 g_value_take_object (value,
2091 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2092 "video", GST_PLAY_SINK_TYPE_VIDEO));
2094 case PROP_AUDIO_SINK:
2095 g_value_take_object (value,
2096 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2097 "audio", GST_PLAY_SINK_TYPE_AUDIO));
2099 case PROP_VIS_PLUGIN:
2100 g_value_take_object (value,
2101 gst_play_sink_get_vis_plugin (playbin->playsink));
2103 case PROP_TEXT_SINK:
2104 g_value_take_object (value,
2105 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2106 "text", GST_PLAY_SINK_TYPE_TEXT));
2109 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2112 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2115 gst_value_take_sample (value,
2116 gst_play_sink_get_last_sample (playbin->playsink));
2118 case PROP_FONT_DESC:
2119 g_value_take_string (value,
2120 gst_play_sink_get_font_desc (playbin->playsink));
2122 case PROP_CONNECTION_SPEED:
2123 GST_PLAY_BIN_LOCK (playbin);
2124 g_value_set_uint64 (value, playbin->connection_speed / 1000);
2125 GST_PLAY_BIN_UNLOCK (playbin);
2127 case PROP_BUFFER_SIZE:
2128 GST_OBJECT_LOCK (playbin);
2129 g_value_set_int (value, playbin->buffer_size);
2130 GST_OBJECT_UNLOCK (playbin);
2132 case PROP_BUFFER_DURATION:
2133 GST_OBJECT_LOCK (playbin);
2134 g_value_set_int64 (value, playbin->buffer_duration);
2135 GST_OBJECT_UNLOCK (playbin);
2137 case PROP_AV_OFFSET:
2138 g_value_set_int64 (value,
2139 gst_play_sink_get_av_offset (playbin->playsink));
2141 case PROP_RING_BUFFER_MAX_SIZE:
2142 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2145 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2151 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2152 gboolean valid, GstQuery * query)
2158 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2159 gst_query_parse_duration (query, &fmt, &duration);
2161 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2162 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2163 playbin->duration[i].valid = valid;
2164 playbin->duration[i].format = fmt;
2165 playbin->duration[i].duration = valid ? duration : -1;
2172 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2174 const GstFormat formats[] =
2175 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2180 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2181 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2182 query = gst_query_new_duration (formats[i]);
2184 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2186 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2187 gst_query_unref (query);
2192 gst_play_bin_query (GstElement * element, GstQuery * query)
2194 GstPlayBin *playbin = GST_PLAY_BIN (element);
2197 /* During a group switch we shouldn't allow duration queries
2198 * because it's not clear if the old or new group's duration
2199 * is returned and if the sinks are already playing new data
2200 * or old data. See bug #585969
2202 * While we're at it, also don't do any other queries during
2203 * a group switch or any other event that causes topology changes
2204 * by taking the playbin lock in any case.
2206 GST_PLAY_BIN_LOCK (playbin);
2208 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2209 GstSourceGroup *group = playbin->curr_group;
2212 GST_SOURCE_GROUP_LOCK (group);
2213 if (group->stream_changed_pending_lock) {
2214 g_mutex_lock (group->stream_changed_pending_lock);
2215 pending = group->pending || group->stream_changed_pending;
2216 g_mutex_unlock (group->stream_changed_pending_lock);
2218 pending = group->pending;
2225 gst_query_parse_duration (query, &fmt, NULL);
2226 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2227 if (fmt == playbin->duration[i].format) {
2228 ret = playbin->duration[i].valid;
2229 gst_query_set_duration (query, fmt,
2230 (ret ? playbin->duration[i].duration : -1));
2234 /* if nothing cached yet, we might as well request duration,
2235 * such as during initial startup */
2237 GST_DEBUG_OBJECT (playbin,
2238 "Taking cached duration because of pending group switch: %d", ret);
2239 GST_SOURCE_GROUP_UNLOCK (group);
2240 GST_PLAY_BIN_UNLOCK (playbin);
2244 GST_SOURCE_GROUP_UNLOCK (group);
2247 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2249 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2250 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2251 GST_PLAY_BIN_UNLOCK (playbin);
2256 /* mime types we are not handling on purpose right now, don't post a
2257 * missing-plugin message for these */
2258 static const gchar *blacklisted_mimes[] = {
2263 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2265 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2266 GstSourceGroup *group;
2268 if (gst_is_missing_plugin_message (msg)) {
2272 detail = gst_missing_plugin_message_get_installer_detail (msg);
2273 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2274 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2275 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2276 gst_message_unref (msg);
2282 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2283 const GstStructure *s = gst_message_get_structure (msg);
2285 /* Drop all stream-changed messages except the last one */
2286 if (strcmp ("playbin-stream-changed", gst_structure_get_name (s)) == 0) {
2287 guint32 seqnum = gst_message_get_seqnum (msg);
2290 group = playbin->curr_group;
2291 g_mutex_lock (group->stream_changed_pending_lock);
2292 for (l = group->stream_changed_pending; l;) {
2293 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2295 if (l_seqnum == seqnum) {
2298 group->stream_changed_pending =
2299 g_list_delete_link (group->stream_changed_pending, l_prev);
2300 if (group->stream_changed_pending) {
2301 gst_message_unref (msg);
2309 g_mutex_unlock (group->stream_changed_pending_lock);
2311 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2312 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2313 GstObject *src = GST_OBJECT_CAST (msg->src);
2315 /* Ignore async state changes from the uridecodebin children,
2316 * see bug #602000. */
2317 group = playbin->curr_group;
2318 if (src && (group = playbin->curr_group) &&
2319 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2320 || (group->suburidecodebin
2321 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2322 GST_DEBUG_OBJECT (playbin,
2323 "Ignoring async state change of uridecodebin: %s",
2324 GST_OBJECT_NAME (src));
2325 gst_message_unref (msg);
2328 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2329 /* If we get an error of the subtitle uridecodebin transform
2330 * them into warnings and disable the subtitles */
2331 group = playbin->curr_group;
2332 if (group && group->suburidecodebin) {
2333 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2334 (group->suburidecodebin)))) {
2336 gchar *debug = NULL;
2337 GstMessage *new_msg;
2339 gboolean done = FALSE;
2340 GValue item = { 0, };
2342 gst_message_parse_error (msg, &err, &debug);
2343 new_msg = gst_message_new_warning (msg->src, err, debug);
2345 gst_message_unref (msg);
2350 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2351 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2352 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2353 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2355 it = gst_element_iterate_src_pads (group->suburidecodebin);
2356 while (it && !done) {
2358 GstIteratorResult res;
2360 res = gst_iterator_next (it, &item);
2363 case GST_ITERATOR_DONE:
2366 case GST_ITERATOR_OK:
2367 p = g_value_get_object (&item);
2368 pad_removed_cb (NULL, p, group);
2369 g_value_reset (&item);
2372 case GST_ITERATOR_RESYNC:
2373 gst_iterator_resync (it);
2375 case GST_ITERATOR_ERROR:
2380 g_value_unset (&item);
2382 gst_iterator_free (it);
2384 gst_object_ref (group->suburidecodebin);
2385 gst_bin_remove (bin, group->suburidecodebin);
2386 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2388 if (group->sub_pending) {
2389 group->sub_pending = FALSE;
2390 no_more_pads_cb (NULL, group);
2397 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2401 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2402 GstPlayBin * playbin)
2404 const gchar *property;
2405 GstSourceGroup *group;
2406 GstSourceSelect *select = NULL;
2409 GST_PLAY_BIN_LOCK (playbin);
2410 group = get_group (playbin);
2412 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2413 if (selector == G_OBJECT (group->selector[i].selector)) {
2414 select = &group->selector[i];
2418 /* We got a pad-change after our group got switched out; no need to notify */
2420 GST_PLAY_BIN_UNLOCK (playbin);
2424 switch (select->type) {
2425 case GST_PLAY_SINK_TYPE_VIDEO:
2426 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2427 property = "current-video";
2428 playbin->current_video = get_current_stream_number (playbin,
2429 group->video_channels);
2431 case GST_PLAY_SINK_TYPE_AUDIO:
2432 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2433 property = "current-audio";
2434 playbin->current_audio = get_current_stream_number (playbin,
2435 group->audio_channels);
2437 case GST_PLAY_SINK_TYPE_TEXT:
2438 property = "current-text";
2439 playbin->current_text = get_current_stream_number (playbin,
2440 group->text_channels);
2445 GST_PLAY_BIN_UNLOCK (playbin);
2448 g_object_notify (G_OBJECT (playbin), property);
2451 /* this callback sends a delayed event once the pad becomes unblocked */
2452 static GstPadProbeReturn
2453 stream_changed_data_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
2455 GstMiniObject *object = GST_PAD_PROBE_INFO_DATA (info);
2456 GstSourceSelect *select = (GstSourceSelect *) data;
2459 /* we need do this just once, so cleanup first */
2460 gst_pad_remove_probe (pad, select->sinkpad_data_probe);
2461 select->sinkpad_data_probe = 0;
2462 e = select->sinkpad_delayed_event;
2463 select->sinkpad_delayed_event = NULL;
2465 /* really, this should not happen */
2467 GST_WARNING ("Data probed called, but no delayed event");
2468 return GST_PAD_PROBE_OK;
2471 if (GST_IS_EVENT (object)
2472 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_SEGMENT) {
2473 /* push the event first, then send the delayed one */
2474 gst_event_ref (GST_EVENT_CAST (object));
2475 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2476 gst_pad_send_event (pad, e);
2477 return GST_PAD_PROBE_DROP;
2479 /* send delayed event, then allow the caller to go on */
2480 gst_pad_send_event (pad, e);
2481 return GST_PAD_PROBE_OK;
2485 /* helper function to lookup stuff in lists */
2487 array_has_value (const gchar * values[], const gchar * value, gboolean exact)
2491 for (i = 0; values[i]; i++) {
2492 if (exact && !strcmp (value, values[i]))
2494 if (!exact && g_str_has_prefix (value, values[i]))
2502 GstPlayBin *playbin;
2504 GstPlaySinkType type;
2508 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2510 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2513 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2514 " with stream id %d and type %d have changed",
2515 object, ntdata->stream_id, ntdata->type);
2517 switch (ntdata->type) {
2518 case GST_PLAY_SINK_TYPE_VIDEO:
2519 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2520 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2522 case GST_PLAY_SINK_TYPE_AUDIO:
2523 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2524 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2526 case GST_PLAY_SINK_TYPE_TEXT:
2527 signal = SIGNAL_TEXT_TAGS_CHANGED;
2535 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2539 /* this function is called when a new pad is added to decodebin. We check the
2540 * type of the pad and add it to the selector element of the group.
2543 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2545 GstPlayBin *playbin;
2547 const GstStructure *s;
2550 GstPadLinkReturn res;
2551 GstSourceSelect *select = NULL;
2553 gboolean changed = FALSE;
2555 playbin = group->playbin;
2557 caps = gst_pad_query_caps (pad, NULL);
2558 s = gst_caps_get_structure (caps, 0);
2559 name = gst_structure_get_name (s);
2561 GST_DEBUG_OBJECT (playbin,
2562 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2563 GST_DEBUG_PAD_NAME (pad), caps, group);
2565 /* major type of the pad, this determines the selector to use,
2566 try exact match first so we don't prematurely match video/
2567 for video/x-dvd-subpicture */
2568 for (pass = 0; !select && pass < 2; pass++) {
2569 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2570 if (array_has_value (group->selector[i].media_list, name, pass == 0)) {
2571 select = &group->selector[i];
2573 } else if (group->selector[i].get_media_caps) {
2574 GstCaps *media_caps = group->selector[i].get_media_caps ();
2576 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2577 select = &group->selector[i];
2578 gst_caps_unref (media_caps);
2581 gst_caps_unref (media_caps);
2585 /* no selector found for the media type, don't bother linking it to a
2586 * selector. This will leave the pad unlinked and thus ignored. */
2590 GST_SOURCE_GROUP_LOCK (group);
2591 if (select->selector == NULL && playbin->have_selector) {
2592 /* no selector, create one */
2593 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2594 select->selector = gst_element_factory_make ("input-selector", NULL);
2595 if (select->selector == NULL) {
2596 /* post the missing selector message only once */
2597 playbin->have_selector = FALSE;
2598 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2599 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2601 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2602 (_("Missing element '%s' - check your GStreamer installation."),
2603 "input-selector"), (NULL));
2605 g_object_set (select->selector, "sync-streams", TRUE, NULL);
2607 g_signal_connect (select->selector, "notify::active-pad",
2608 G_CALLBACK (selector_active_pad_changed), playbin);
2610 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2611 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2612 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2616 if (select->srcpad == NULL) {
2617 if (select->selector) {
2618 /* save source pad of the selector */
2619 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2621 /* no selector, use the pad as the source pad then */
2622 select->srcpad = gst_object_ref (pad);
2625 /* block the selector srcpad. It's possible that multiple decodebins start
2626 * pushing data into the selectors before we have a chance to collect all
2627 * streams and connect the sinks, resulting in not-linked errors. After we
2628 * configured the sinks we will unblock them all. */
2629 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2631 gst_pad_add_probe (select->srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2635 /* get sinkpad for the new stream */
2636 if (select->selector) {
2637 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink_%u"))) {
2638 gulong notify_tags_handler = 0;
2639 NotifyTagsData *ntdata;
2641 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2642 GST_DEBUG_PAD_NAME (sinkpad));
2644 /* store the selector for the pad */
2645 g_object_set_data (G_OBJECT (sinkpad), "playbin.select", select);
2647 /* connect to the notify::tags signal for our
2648 * own *-tags-changed signals
2650 ntdata = g_new0 (NotifyTagsData, 1);
2651 ntdata->playbin = playbin;
2652 ntdata->stream_id = select->channels->len;
2653 ntdata->type = select->type;
2655 notify_tags_handler =
2656 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2657 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2659 g_object_set_data (G_OBJECT (sinkpad), "playbin.notify_tags_handler",
2660 (gpointer) (guintptr) notify_tags_handler);
2662 /* store the pad in the array */
2663 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2664 g_ptr_array_add (select->channels, sinkpad);
2666 res = gst_pad_link (pad, sinkpad);
2667 if (GST_PAD_LINK_FAILED (res))
2670 /* store selector pad so we can release it */
2671 g_object_set_data (G_OBJECT (pad), "playbin.sinkpad", sinkpad);
2674 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2675 GST_DEBUG_PAD_NAME (pad), select->selector);
2678 /* no selector, don't configure anything, we'll link the new pad directly to
2683 GST_SOURCE_GROUP_UNLOCK (group);
2687 gboolean always_ok = (decodebin == group->suburidecodebin);
2689 switch (select->type) {
2690 case GST_PLAY_SINK_TYPE_VIDEO:
2691 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2692 /* we want to return NOT_LINKED for unselected pads but only for pads
2693 * from the normal uridecodebin. This makes sure that subtitle streams
2694 * are not raced past audio/video from decodebin's multiqueue.
2695 * For pads from suburidecodebin OK should always be returned, otherwise
2696 * it will most likely stop. */
2697 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2698 signal = SIGNAL_VIDEO_CHANGED;
2700 case GST_PLAY_SINK_TYPE_AUDIO:
2701 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2702 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2703 signal = SIGNAL_AUDIO_CHANGED;
2705 case GST_PLAY_SINK_TYPE_TEXT:
2706 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2707 signal = SIGNAL_TEXT_CHANGED;
2714 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2718 gst_caps_unref (caps);
2724 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2725 name, GST_DEBUG_PAD_NAME (pad));
2730 GST_ERROR_OBJECT (playbin,
2731 "failed to link pad %s:%s to selector, reason %d",
2732 GST_DEBUG_PAD_NAME (pad), res);
2733 GST_SOURCE_GROUP_UNLOCK (group);
2738 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2739 * the selector. This will make the selector select a new pad. */
2741 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2743 GstPlayBin *playbin;
2745 GstElement *selector;
2746 GstSourceSelect *select;
2748 playbin = group->playbin;
2750 GST_DEBUG_OBJECT (playbin,
2751 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2753 GST_SOURCE_GROUP_LOCK (group);
2754 /* get the selector sinkpad */
2755 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin.sinkpad")))
2758 if ((select = g_object_get_data (G_OBJECT (peer), "playbin.select"))) {
2759 gulong notify_tags_handler;
2761 notify_tags_handler =
2762 (guintptr) g_object_get_data (G_OBJECT (peer),
2763 "playbin.notify_tags_handler");
2764 if (notify_tags_handler != 0)
2765 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2766 g_object_set_data (G_OBJECT (peer), "playbin.notify_tags_handler", NULL);
2768 /* remove the pad from the array */
2769 g_ptr_array_remove (select->channels, peer);
2770 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2773 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2774 gst_pad_unlink (pad, peer);
2776 /* get selector, this can be NULL when the element is removing the pads
2777 * because it's being disposed. */
2778 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2780 gst_object_unref (peer);
2784 /* release the pad to the selector, this will make the selector choose a new
2786 gst_element_release_request_pad (selector, peer);
2787 gst_object_unref (peer);
2789 gst_object_unref (selector);
2790 GST_SOURCE_GROUP_UNLOCK (group);
2797 GST_DEBUG_OBJECT (playbin, "pad not linked");
2798 GST_SOURCE_GROUP_UNLOCK (group);
2803 GST_DEBUG_OBJECT (playbin, "selector not found");
2804 GST_SOURCE_GROUP_UNLOCK (group);
2809 /* we get called when all pads are available and we must connect the sinks to
2811 * The main purpose of the code is to see if we have video/audio and subtitles
2812 * and pick the right pipelines to display them.
2814 * The selectors installed on the group tell us about the presence of
2815 * audio/video and subtitle streams. This allows us to see if we need
2816 * visualisation, video or/and audio.
2819 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2821 GstPlayBin *playbin;
2822 GstPadLinkReturn res;
2826 playbin = group->playbin;
2828 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2830 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2832 GST_SOURCE_GROUP_LOCK (group);
2833 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2834 GstSourceSelect *select = &group->selector[i];
2836 /* check if the specific media type was detected and thus has a selector
2837 * created for it. If there is the media type, get a sinkpad from the sink
2838 * and link it. We only do this if we have not yet requested the sinkpad
2840 if (select->srcpad && select->sinkpad == NULL) {
2841 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2843 gst_play_sink_request_pad (playbin->playsink, select->type);
2845 res = gst_pad_link (select->srcpad, select->sinkpad);
2846 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2847 select->media_list[0], res);
2848 if (res != GST_PAD_LINK_OK) {
2849 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2850 ("Internal playbin error."),
2851 ("Failed to link selector to sink. Error %d", res));
2855 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2856 group->pending - 1);
2858 if (group->pending > 0)
2861 if (group->suburidecodebin == decodebin)
2862 group->sub_pending = FALSE;
2864 if (group->pending == 0) {
2865 /* we are the last group to complete, we will configure the output and then
2866 * signal the other waiters. */
2867 GST_LOG_OBJECT (playbin, "last group complete");
2870 GST_LOG_OBJECT (playbin, "have more pending groups");
2873 GST_SOURCE_GROUP_UNLOCK (group);
2876 /* if we have custom sinks, configure them now */
2877 GST_SOURCE_GROUP_LOCK (group);
2879 if (group->audio_sink) {
2880 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2882 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2886 if (group->video_sink) {
2887 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2889 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2893 if (playbin->text_sink) {
2894 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
2895 playbin->text_sink);
2896 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2897 playbin->text_sink);
2900 GST_SOURCE_GROUP_UNLOCK (group);
2902 /* signal the other decodebins that they can continue now. */
2903 GST_SOURCE_GROUP_LOCK (group);
2904 /* unblock all selectors */
2905 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2906 GstSourceSelect *select = &group->selector[i];
2908 /* All streamsynchronizer streams should see stream-changed message,
2909 * to arrange for blocking unblocking. */
2910 if (select->sinkpad) {
2916 s = gst_structure_new ("playbin-stream-changed", "uri", G_TYPE_STRING,
2919 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2920 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2921 seqnum = gst_message_get_seqnum (msg);
2922 event = gst_event_new_sink_message (msg);
2923 g_mutex_lock (group->stream_changed_pending_lock);
2924 group->stream_changed_pending =
2925 g_list_prepend (group->stream_changed_pending,
2926 GUINT_TO_POINTER (seqnum));
2928 /* remove any data probe we might have, and replace */
2929 if (select->sinkpad_delayed_event)
2930 gst_event_unref (select->sinkpad_delayed_event);
2931 select->sinkpad_delayed_event = event;
2932 if (select->sinkpad_data_probe)
2933 gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
2935 /* we go to the trouble of setting a probe on the pad to send
2936 the playbin-stream-changed event as sending it here might
2937 find that the pad is blocked, so we'd block here, and the
2938 pad might not be linked yet. Additionally, sending it here
2939 apparently would be on the wrong thread */
2940 select->sinkpad_data_probe =
2941 gst_pad_add_probe (select->sinkpad,
2942 GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
2943 stream_changed_data_probe, (gpointer) select, NULL);
2945 g_mutex_unlock (group->stream_changed_pending_lock);
2946 gst_message_unref (msg);
2949 if (select->srcpad) {
2950 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2952 if (select->block_id) {
2953 gst_pad_remove_probe (select->srcpad, select->block_id);
2954 select->block_id = 0;
2958 GST_SOURCE_GROUP_UNLOCK (group);
2961 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2967 GST_DEBUG ("ignoring, we are shutting down");
2968 /* Request a flushing pad from playsink that we then link to the selector.
2969 * Then we unblock the selectors so that they stop with a WRONG_STATE
2970 * instead of a NOT_LINKED error.
2972 GST_SOURCE_GROUP_LOCK (group);
2973 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2974 GstSourceSelect *select = &group->selector[i];
2976 if (select->srcpad) {
2977 if (select->sinkpad == NULL) {
2978 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2980 gst_play_sink_request_pad (playbin->playsink,
2981 GST_PLAY_SINK_TYPE_FLUSHING);
2982 res = gst_pad_link (select->srcpad, select->sinkpad);
2983 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2985 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2987 if (select->block_id) {
2988 gst_pad_remove_probe (select->srcpad, select->block_id);
2989 select->block_id = 0;
2993 GST_SOURCE_GROUP_UNLOCK (group);
2999 drained_cb (GstElement * decodebin, GstSourceGroup * group)
3001 GstPlayBin *playbin;
3003 playbin = group->playbin;
3005 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
3007 /* after this call, we should have a next group to activate or we EOS */
3008 g_signal_emit (G_OBJECT (playbin),
3009 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
3011 /* now activate the next group. If the app did not set a uri, this will
3012 * fail and we can do EOS */
3013 setup_next_source (playbin, GST_STATE_PAUSED);
3016 /* Like gst_element_factory_can_sink_any_caps() but doesn't
3017 * allow ANY caps on the sinkpad template */
3019 _factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps)
3021 const GList *templs;
3023 templs = gst_element_factory_get_static_pad_templates (factory);
3026 GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
3028 if (templ->direction == GST_PAD_SINK) {
3029 GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
3031 if (!gst_caps_is_any (templcaps)
3032 && gst_caps_can_intersect (templcaps, caps)) {
3033 gst_caps_unref (templcaps);
3036 gst_caps_unref (templcaps);
3038 templs = g_list_next (templs);
3044 /* Called when we must provide a list of factories to plug to @pad with @caps.
3045 * We first check if we have a sink that can handle the format and if we do, we
3046 * return NULL, to expose the pad. If we have no sink (or the sink does not
3047 * work), we return the list of elements that can connect. */
3048 static GValueArray *
3049 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
3050 GstCaps * caps, GstSourceGroup * group)
3052 GstPlayBin *playbin;
3053 GList *mylist, *tmp;
3054 GValueArray *result;
3056 playbin = group->playbin;
3058 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
3059 group, GST_DEBUG_PAD_NAME (pad), caps);
3061 /* filter out the elements based on the caps. */
3062 g_mutex_lock (playbin->elements_lock);
3063 gst_play_bin_update_elements_list (playbin);
3065 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
3067 g_mutex_unlock (playbin->elements_lock);
3069 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
3070 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
3072 /* 2 additional elements for the already set audio/video sinks */
3073 result = g_value_array_new (g_list_length (mylist) + 2);
3075 /* Check if we already have an audio/video sink and if this is the case
3076 * put it as the first element of the array */
3077 if (group->audio_sink) {
3078 GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
3080 if (factory && _factory_can_sink_caps (factory, caps)) {
3081 GValue val = { 0, };
3083 g_value_init (&val, G_TYPE_OBJECT);
3084 g_value_set_object (&val, factory);
3085 result = g_value_array_append (result, &val);
3086 g_value_unset (&val);
3090 if (group->video_sink) {
3091 GstElementFactory *factory = gst_element_get_factory (group->video_sink);
3093 if (factory && _factory_can_sink_caps (factory, caps)) {
3094 GValue val = { 0, };
3096 g_value_init (&val, G_TYPE_OBJECT);
3097 g_value_set_object (&val, factory);
3098 result = g_value_array_append (result, &val);
3099 g_value_unset (&val);
3103 for (tmp = mylist; tmp; tmp = tmp->next) {
3104 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
3105 GValue val = { 0, };
3107 if (group->audio_sink && gst_element_factory_list_is_type (factory,
3108 GST_ELEMENT_FACTORY_TYPE_SINK |
3109 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
3112 if (group->video_sink && gst_element_factory_list_is_type (factory,
3113 GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
3114 | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
3118 g_value_init (&val, G_TYPE_OBJECT);
3119 g_value_set_object (&val, factory);
3120 g_value_array_append (result, &val);
3121 g_value_unset (&val);
3123 gst_plugin_feature_list_free (mylist);
3128 /* autoplug-continue decides, if a pad has raw caps that can be exposed
3129 * directly or if further decoding is necessary. We use this to expose
3130 * supported subtitles directly */
3132 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
3133 * explicitly the caps it supports and if it claims to support ANY
3134 * caps it really should support everything */
3136 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
3137 GstSourceGroup * group)
3139 gboolean ret = TRUE;
3141 GstPad *sinkpad = NULL;
3143 GST_PLAY_BIN_LOCK (group->playbin);
3144 GST_SOURCE_GROUP_LOCK (group);
3146 if ((sink = group->playbin->text_sink))
3147 sinkpad = gst_element_get_static_pad (sink, "sink");
3151 /* Ignore errors here, if a custom sink fails to go
3152 * to READY things are wrong and will error out later
3154 if (GST_STATE (sink) < GST_STATE_READY)
3155 gst_element_set_state (sink, GST_STATE_READY);
3157 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3158 if (!gst_caps_is_any (sinkcaps))
3159 ret = !gst_pad_query_accept_caps (sinkpad, caps);
3160 gst_caps_unref (sinkcaps);
3161 gst_object_unref (sinkpad);
3163 GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3164 ret = !gst_caps_is_subset (caps, subcaps);
3165 gst_caps_unref (subcaps);
3167 /* If autoplugging can stop don't do additional checks */
3171 /* If this is from the subtitle uridecodebin we don't need to
3172 * check the audio and video sink */
3173 if (group->suburidecodebin
3174 && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3175 GST_OBJECT_CAST (group->suburidecodebin)))
3178 if ((sink = group->audio_sink)) {
3179 sinkpad = gst_element_get_static_pad (sink, "sink");
3183 /* Ignore errors here, if a custom sink fails to go
3184 * to READY things are wrong and will error out later
3186 if (GST_STATE (sink) < GST_STATE_READY)
3187 gst_element_set_state (sink, GST_STATE_READY);
3189 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3190 if (!gst_caps_is_any (sinkcaps))
3191 ret = !gst_pad_query_accept_caps (sinkpad, caps);
3192 gst_caps_unref (sinkcaps);
3193 gst_object_unref (sinkpad);
3199 if ((sink = group->video_sink)) {
3200 sinkpad = gst_element_get_static_pad (sink, "sink");
3204 /* Ignore errors here, if a custom sink fails to go
3205 * to READY things are wrong and will error out later
3207 if (GST_STATE (sink) < GST_STATE_READY)
3208 gst_element_set_state (sink, GST_STATE_READY);
3210 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3211 if (!gst_caps_is_any (sinkcaps))
3212 ret = !gst_pad_query_accept_caps (sinkpad, caps);
3213 gst_caps_unref (sinkcaps);
3214 gst_object_unref (sinkpad);
3219 GST_SOURCE_GROUP_UNLOCK (group);
3220 GST_PLAY_BIN_UNLOCK (group->playbin);
3222 GST_DEBUG_OBJECT (group->playbin,
3223 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3224 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3230 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3234 /* ... activate it ... We do this before adding it to the bin so that we
3235 * don't accidentally make it post error messages that will stop
3237 if (GST_STATE (sink) < GST_STATE_READY &&
3238 gst_element_set_state (sink,
3239 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3243 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3244 /* Got the sink pad, now let's see if the element actually does accept the
3245 * caps that we have */
3246 if (!gst_pad_query_accept_caps (sinkpad, caps)) {
3247 gst_object_unref (sinkpad);
3250 gst_object_unref (sinkpad);
3256 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw-int; "
3257 "audio/x-raw-float");
3258 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw-rgb; "
3259 "video/x-raw-yuv; " "video/x-raw-gray");
3261 /* We are asked to select an element. See if the next element to check
3262 * is a sink. If this is the case, we see if the sink works by setting it to
3263 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3264 * expose the raw pad so that we can setup the mixers. */
3265 static GstAutoplugSelectResult
3266 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3267 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3269 GstPlayBin *playbin;
3270 GstElement *element;
3272 GstPlaySinkType type;
3275 playbin = group->playbin;
3277 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3278 group, GST_DEBUG_PAD_NAME (pad), caps);
3280 GST_DEBUG_OBJECT (playbin, "checking factory %s", GST_OBJECT_NAME (factory));
3282 /* if it's not a sink, we make sure the element is compatible with
3284 if (!gst_element_factory_list_is_type (factory,
3285 GST_ELEMENT_FACTORY_TYPE_SINK)) {
3286 gboolean isvideodec = gst_element_factory_list_is_type (factory,
3287 GST_ELEMENT_FACTORY_TYPE_DECODER |
3288 GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
3289 GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
3290 gboolean isaudiodec = gst_element_factory_list_is_type (factory,
3291 GST_ELEMENT_FACTORY_TYPE_DECODER |
3292 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
3294 /* If it is a decoder and we have a fixed sink for the media
3295 * type it outputs, check that the decoder is compatible with this sink */
3296 if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) {
3297 gboolean compatible = TRUE;
3303 sink = group->audio_sink;
3305 sink = group->video_sink;
3307 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3308 GstPlayFlags flags = gst_play_bin_get_flags (playbin);
3310 (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) :
3311 gst_static_caps_get (&raw_video_caps);
3313 caps = gst_pad_query_caps (sinkpad, NULL);
3315 /* If the sink supports raw audio/video, we first check
3316 * if the decoder could output any raw audio/video format
3317 * and assume it is compatible with the sink then. We don't
3318 * do a complete compatibility check here if converters
3319 * are plugged between the decoder and the sink because
3320 * the converters will convert between raw formats and
3321 * even if the decoder format is not supported by the decoder
3322 * a converter will convert it.
3324 * We assume here that the converters can convert between
3327 if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO)
3328 && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec
3329 && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO)
3330 && gst_caps_can_intersect (caps, raw_caps))) {
3331 compatible = gst_element_factory_can_src_any_caps (factory, raw_caps)
3332 || gst_element_factory_can_src_any_caps (factory, caps);
3334 compatible = gst_element_factory_can_src_any_caps (factory, caps);
3337 gst_object_unref (sinkpad);
3338 gst_caps_unref (caps);
3342 return GST_AUTOPLUG_SELECT_TRY;
3344 GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink",
3345 GST_OBJECT_NAME (factory));
3347 return GST_AUTOPLUG_SELECT_SKIP;
3349 return GST_AUTOPLUG_SELECT_TRY;
3352 /* it's a sink, see if an instance of it actually works */
3353 GST_DEBUG_OBJECT (playbin, "we found a sink");
3355 klass = gst_element_factory_get_klass (factory);
3357 /* figure out the klass */
3358 if (strstr (klass, "Audio")) {
3359 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3360 type = GST_PLAY_SINK_TYPE_AUDIO;
3361 sinkp = &group->audio_sink;
3362 } else if (strstr (klass, "Video")) {
3363 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3364 type = GST_PLAY_SINK_TYPE_VIDEO;
3365 sinkp = &group->video_sink;
3367 /* unknown klass, skip this element */
3368 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3369 return GST_AUTOPLUG_SELECT_SKIP;
3372 /* if we are asked to do visualisations and it's an audio sink, skip the
3373 * element. We can only do visualisations with raw sinks */
3374 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3375 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3376 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3377 return GST_AUTOPLUG_SELECT_SKIP;
3381 /* now see if we already have a sink element */
3382 GST_SOURCE_GROUP_LOCK (group);
3384 GstElement *sink = gst_object_ref (*sinkp);
3386 if (sink_accepts_caps (sink, caps)) {
3387 GST_DEBUG_OBJECT (playbin,
3388 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3389 GST_ELEMENT_NAME (sink), caps);
3390 gst_object_unref (sink);
3391 GST_SOURCE_GROUP_UNLOCK (group);
3392 return GST_AUTOPLUG_SELECT_EXPOSE;
3394 GST_DEBUG_OBJECT (playbin,
3395 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3396 GST_ELEMENT_NAME (sink), caps);
3397 gst_object_unref (sink);
3398 GST_SOURCE_GROUP_UNLOCK (group);
3399 return GST_AUTOPLUG_SELECT_SKIP;
3402 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3404 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3405 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3406 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3407 GST_SOURCE_GROUP_UNLOCK (group);
3408 return GST_AUTOPLUG_SELECT_SKIP;
3411 /* Check if the selected sink actually supports the
3412 * caps and can be set to READY*/
3413 if (!sink_accepts_caps (element, caps)) {
3414 gst_element_set_state (element, GST_STATE_NULL);
3415 gst_object_unref (element);
3416 GST_SOURCE_GROUP_UNLOCK (group);
3417 return GST_AUTOPLUG_SELECT_SKIP;
3420 /* remember the sink in the group now, the element is floating, we take
3423 * store the sink in the group, we will configure it later when we
3424 * reconfigure the sink */
3425 GST_DEBUG_OBJECT (playbin, "remember sink");
3426 gst_object_ref_sink (element);
3428 GST_SOURCE_GROUP_UNLOCK (group);
3430 /* tell decodebin to expose the pad because we are going to use this
3432 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3434 return GST_AUTOPLUG_SELECT_EXPOSE;
3438 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3439 GstSourceGroup * group)
3441 GstPlayBin *playbin;
3444 playbin = group->playbin;
3446 g_object_get (group->uridecodebin, "source", &source, NULL);
3448 GST_OBJECT_LOCK (playbin);
3449 if (playbin->source)
3450 gst_object_unref (playbin->source);
3451 playbin->source = source;
3452 GST_OBJECT_UNLOCK (playbin);
3454 g_object_notify (G_OBJECT (playbin), "source");
3456 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3457 0, playbin->source);
3460 /* must be called with the group lock */
3462 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3465 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3467 if (group->uridecodebin)
3468 gst_element_set_locked_state (group->uridecodebin, locked);
3469 if (group->suburidecodebin)
3470 gst_element_set_locked_state (group->suburidecodebin, locked);
3475 /* must be called with PLAY_BIN_LOCK */
3477 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3479 GstElement *uridecodebin;
3480 GstElement *suburidecodebin = NULL;
3483 g_return_val_if_fail (group->valid, FALSE);
3484 g_return_val_if_fail (!group->active, FALSE);
3486 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3488 GST_SOURCE_GROUP_LOCK (group);
3490 /* First set up the custom sources */
3491 if (playbin->audio_sink)
3492 group->audio_sink = gst_object_ref (playbin->audio_sink);
3493 if (playbin->video_sink)
3494 group->video_sink = gst_object_ref (playbin->video_sink);
3496 g_list_free (group->stream_changed_pending);
3497 group->stream_changed_pending = NULL;
3498 if (!group->stream_changed_pending_lock)
3499 group->stream_changed_pending_lock = g_mutex_new ();
3501 if (group->uridecodebin) {
3502 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3503 uridecodebin = group->uridecodebin;
3504 gst_element_set_state (uridecodebin, GST_STATE_READY);
3505 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3507 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3508 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3511 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3512 group->uridecodebin = gst_object_ref (uridecodebin);
3515 flags = gst_play_sink_get_flags (playbin->playsink);
3517 g_object_set (uridecodebin,
3518 /* configure connection speed */
3519 "connection-speed", playbin->connection_speed / 1000,
3522 /* configure download buffering */
3523 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3524 /* configure buffering of demuxed/parsed data */
3525 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3526 /* configure buffering parameters */
3527 "buffer-duration", playbin->buffer_duration,
3528 "buffer-size", playbin->buffer_size,
3529 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3531 /* connect pads and other things */
3532 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3533 G_CALLBACK (pad_added_cb), group);
3534 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3535 G_CALLBACK (pad_removed_cb), group);
3536 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3537 G_CALLBACK (no_more_pads_cb), group);
3538 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3539 G_CALLBACK (notify_source_cb), group);
3541 /* we have 1 pending no-more-pads */
3544 /* is called when the uridecodebin is out of data and we can switch to the
3547 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3550 /* will be called when a new media type is found. We return a list of decoders
3551 * including sinks for decodebin to try */
3552 group->autoplug_factories_id =
3553 g_signal_connect (uridecodebin, "autoplug-factories",
3554 G_CALLBACK (autoplug_factories_cb), group);
3555 group->autoplug_select_id =
3556 g_signal_connect (uridecodebin, "autoplug-select",
3557 G_CALLBACK (autoplug_select_cb), group);
3558 group->autoplug_continue_id =
3559 g_signal_connect (uridecodebin, "autoplug-continue",
3560 G_CALLBACK (autoplug_continue_cb), group);
3562 if (group->suburi) {
3564 if (group->suburidecodebin) {
3565 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3566 suburidecodebin = group->suburidecodebin;
3567 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3568 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3570 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3571 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3572 if (!suburidecodebin)
3575 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3576 group->suburidecodebin = gst_object_ref (suburidecodebin);
3579 g_object_set (suburidecodebin,
3580 /* configure connection speed */
3581 "connection-speed", playbin->connection_speed,
3583 "uri", group->suburi, NULL);
3585 /* connect pads and other things */
3586 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3587 G_CALLBACK (pad_added_cb), group);
3588 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3589 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3590 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3591 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3593 group->sub_autoplug_continue_id =
3594 g_signal_connect (suburidecodebin, "autoplug-continue",
3595 G_CALLBACK (autoplug_continue_cb), group);
3597 /* we have 2 pending no-more-pads */
3599 group->sub_pending = TRUE;
3601 group->sub_pending = FALSE;
3604 /* release the group lock before setting the state of the decodebins, they
3605 * might fire signals in this thread that we need to handle with the
3606 * group_lock taken. */
3607 GST_SOURCE_GROUP_UNLOCK (group);
3609 if (suburidecodebin) {
3610 if (gst_element_set_state (suburidecodebin,
3611 target) == GST_STATE_CHANGE_FAILURE) {
3612 GST_DEBUG_OBJECT (playbin,
3613 "failed state change of subtitle uridecodebin");
3614 GST_SOURCE_GROUP_LOCK (group);
3616 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3617 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3618 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3619 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3620 /* Might already be removed because of an error message */
3621 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3622 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3623 if (group->sub_pending) {
3625 group->sub_pending = FALSE;
3627 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3628 GST_SOURCE_GROUP_UNLOCK (group);
3631 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3632 goto uridecodebin_failure;
3634 GST_SOURCE_GROUP_LOCK (group);
3635 /* alow state changes of the playbin affect the group elements now */
3636 group_set_locked_state_unlocked (playbin, group, FALSE);
3637 group->active = TRUE;
3638 GST_SOURCE_GROUP_UNLOCK (group);
3647 /* delete any custom sinks we might have */
3648 if (group->audio_sink) {
3649 /* If this is a automatically created sink set it to NULL */
3650 if (group->audio_sink != playbin->audio_sink)
3651 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3652 gst_object_unref (group->audio_sink);
3654 group->audio_sink = NULL;
3655 if (group->video_sink) {
3656 /* If this is a automatically created sink set it to NULL */
3657 if (group->video_sink != playbin->video_sink)
3658 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3659 gst_object_unref (group->video_sink);
3661 group->video_sink = NULL;
3663 GST_SOURCE_GROUP_UNLOCK (group);
3665 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3667 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3669 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3670 (_("Could not create \"uridecodebin\" element.")), (NULL));
3673 uridecodebin_failure:
3675 /* delete any custom sinks we might have */
3676 if (group->audio_sink) {
3677 /* If this is a automatically created sink set it to NULL */
3678 if (group->audio_sink != playbin->audio_sink)
3679 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3680 gst_object_unref (group->audio_sink);
3682 group->audio_sink = NULL;
3683 if (group->video_sink) {
3684 /* If this is a automatically created sink set it to NULL */
3685 if (group->video_sink != playbin->video_sink)
3686 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3687 gst_object_unref (group->video_sink);
3689 group->video_sink = NULL;
3691 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3696 /* unlink a group of uridecodebins from the sink.
3697 * must be called with PLAY_BIN_LOCK */
3699 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3703 g_return_val_if_fail (group->valid, FALSE);
3704 g_return_val_if_fail (group->active, FALSE);
3706 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3708 GST_SOURCE_GROUP_LOCK (group);
3709 group->active = FALSE;
3710 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3711 GstSourceSelect *select = &group->selector[i];
3713 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3715 if (select->srcpad) {
3716 if (select->sinkpad) {
3717 GST_LOG_OBJECT (playbin, "unlinking from sink");
3718 gst_pad_unlink (select->srcpad, select->sinkpad);
3721 GST_LOG_OBJECT (playbin, "release sink pad");
3722 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3723 select->sinkpad = NULL;
3726 gst_object_unref (select->srcpad);
3727 select->srcpad = NULL;
3730 if (select->selector) {
3733 /* release and unref requests pad from the selector */
3734 for (n = 0; n < select->channels->len; n++) {
3735 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3737 gst_element_release_request_pad (select->selector, sinkpad);
3738 gst_object_unref (sinkpad);
3740 g_ptr_array_set_size (select->channels, 0);
3742 gst_element_set_state (select->selector, GST_STATE_NULL);
3743 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3744 select->selector = NULL;
3747 /* delete any custom sinks we might have */
3748 if (group->audio_sink) {
3749 /* If this is a automatically created sink set it to NULL */
3750 if (group->audio_sink != playbin->audio_sink)
3751 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3752 gst_object_unref (group->audio_sink);
3754 group->audio_sink = NULL;
3755 if (group->video_sink) {
3756 /* If this is a automatically created sink set it to NULL */
3757 if (group->video_sink != playbin->video_sink)
3758 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3759 gst_object_unref (group->video_sink);
3761 group->video_sink = NULL;
3763 if (group->uridecodebin) {
3764 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3765 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3766 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3767 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3768 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3769 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3770 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3771 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3772 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3775 if (group->suburidecodebin) {
3776 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3777 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3778 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3779 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3781 /* Might already be removed because of errors */
3782 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3783 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3786 GST_SOURCE_GROUP_UNLOCK (group);
3791 /* setup the next group to play, this assumes the next_group is valid and
3792 * configured. It swaps out the current_group and activates the valid
3795 setup_next_source (GstPlayBin * playbin, GstState target)
3797 GstSourceGroup *new_group, *old_group;
3799 GST_DEBUG_OBJECT (playbin, "setup sources");
3801 /* see if there is a next group */
3802 GST_PLAY_BIN_LOCK (playbin);
3803 new_group = playbin->next_group;
3804 if (!new_group || !new_group->valid)
3807 /* first unlink the current source, if any */
3808 old_group = playbin->curr_group;
3809 if (old_group && old_group->valid && old_group->active) {
3810 gst_play_bin_update_cached_duration (playbin);
3811 /* unlink our pads with the sink */
3812 deactivate_group (playbin, old_group);
3813 old_group->valid = FALSE;
3816 /* swap old and new */
3817 playbin->curr_group = new_group;
3818 playbin->next_group = old_group;
3820 /* activate the new group */
3821 if (!activate_group (playbin, new_group, target))
3822 goto activate_failed;
3824 GST_PLAY_BIN_UNLOCK (playbin);
3831 GST_DEBUG_OBJECT (playbin, "no next group");
3832 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3833 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3834 GST_PLAY_BIN_UNLOCK (playbin);
3839 GST_DEBUG_OBJECT (playbin, "activate failed");
3840 GST_PLAY_BIN_UNLOCK (playbin);
3845 /* The group that is currently playing is copied again to the
3846 * next_group so that it will start playing the next time.
3849 save_current_group (GstPlayBin * playbin)
3851 GstSourceGroup *curr_group;
3853 GST_DEBUG_OBJECT (playbin, "save current group");
3855 /* see if there is a current group */
3856 GST_PLAY_BIN_LOCK (playbin);
3857 curr_group = playbin->curr_group;
3858 if (curr_group && curr_group->valid) {
3859 /* unlink our pads with the sink */
3860 deactivate_group (playbin, curr_group);
3862 /* swap old and new */
3863 playbin->curr_group = playbin->next_group;
3864 playbin->next_group = curr_group;
3865 GST_PLAY_BIN_UNLOCK (playbin);
3870 /* clear the locked state from all groups. This function is called before a
3871 * state change to NULL is performed on them. */
3873 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3875 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3878 GST_PLAY_BIN_LOCK (playbin);
3879 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3880 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3881 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3882 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3883 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3884 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3885 GST_PLAY_BIN_UNLOCK (playbin);
3890 static GstStateChangeReturn
3891 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3893 GstStateChangeReturn ret;
3894 GstPlayBin *playbin;
3895 gboolean do_save = FALSE;
3897 playbin = GST_PLAY_BIN (element);
3899 switch (transition) {
3900 case GST_STATE_CHANGE_NULL_TO_READY:
3901 memset (&playbin->duration, 0, sizeof (playbin->duration));
3903 case GST_STATE_CHANGE_READY_TO_PAUSED:
3904 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3905 memset (&playbin->duration, 0, sizeof (playbin->duration));
3906 g_atomic_int_set (&playbin->shutdown, 0);
3908 if (!setup_next_source (playbin, GST_STATE_READY)) {
3909 ret = GST_STATE_CHANGE_FAILURE;
3913 case GST_STATE_CHANGE_PAUSED_TO_READY:
3915 /* FIXME unlock our waiting groups */
3916 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3917 g_atomic_int_set (&playbin->shutdown, 1);
3918 memset (&playbin->duration, 0, sizeof (playbin->duration));
3920 /* wait for all callbacks to end by taking the lock.
3921 * No dynamic (critical) new callbacks will
3922 * be able to happen as we set the shutdown flag. */
3923 GST_PLAY_BIN_DYN_LOCK (playbin);
3924 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3925 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3928 case GST_STATE_CHANGE_READY_TO_NULL:
3929 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3930 * an no state change PAUSED to READY passes here,
3931 * though it is a nice-to-have ... */
3932 if (!g_atomic_int_get (&playbin->shutdown)) {
3936 memset (&playbin->duration, 0, sizeof (playbin->duration));
3938 /* unlock so that all groups go to NULL */
3939 groups_set_locked_state (playbin, FALSE);
3945 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3946 if (ret == GST_STATE_CHANGE_FAILURE)
3949 switch (transition) {
3950 case GST_STATE_CHANGE_READY_TO_PAUSED:
3952 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3953 /* FIXME Release audio device when we implement that */
3955 case GST_STATE_CHANGE_PAUSED_TO_READY:
3956 save_current_group (playbin);
3958 case GST_STATE_CHANGE_READY_TO_NULL:
3962 /* also do missed state change down to READY */
3964 save_current_group (playbin);
3965 /* Deactive the groups, set the uridecodebins to NULL
3968 for (i = 0; i < 2; i++) {
3969 if (playbin->groups[i].active && playbin->groups[i].valid) {
3970 deactivate_group (playbin, &playbin->groups[i]);
3971 playbin->groups[i].valid = FALSE;
3974 if (playbin->groups[i].uridecodebin) {
3975 gst_element_set_state (playbin->groups[i].uridecodebin,
3977 gst_object_unref (playbin->groups[i].uridecodebin);
3978 playbin->groups[i].uridecodebin = NULL;
3981 if (playbin->groups[i].suburidecodebin) {
3982 gst_element_set_state (playbin->groups[i].suburidecodebin,
3984 gst_object_unref (playbin->groups[i].suburidecodebin);
3985 playbin->groups[i].suburidecodebin = NULL;
3989 /* Set our sinks back to NULL, they might not be child of playbin */
3990 if (playbin->audio_sink)
3991 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
3992 if (playbin->video_sink)
3993 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
3994 if (playbin->text_sink)
3995 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
3997 /* make sure the groups don't perform a state change anymore until we
3998 * enable them again */
3999 groups_set_locked_state (playbin, TRUE);
4011 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
4012 GstSourceGroup *curr_group;
4014 curr_group = playbin->curr_group;
4015 if (curr_group && curr_group->active && curr_group->valid) {
4016 /* unlink our pads with the sink */
4017 deactivate_group (playbin, curr_group);
4018 curr_group->valid = FALSE;
4021 /* Swap current and next group back */
4022 playbin->curr_group = playbin->next_group;
4023 playbin->next_group = curr_group;
4030 gst_play_bin2_plugin_init (GstPlugin * plugin)
4032 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin", 0, "play bin");
4034 return gst_element_register (plugin, "playbin", GST_RANK_NONE,