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-playbin2
24 * Playbin2 provides a stand-alone everything-in-one abstraction for an
25 * audio and/or video player.
27 * playbin2 is considered stable now. It is the prefered playback API now,
28 * and replaces the old #playbin element, which is no longer supported.
30 * It can handle both audio and video files and features
33 * automatic file type recognition and based on that automatic
34 * selection and usage of the right audio/video/subtitle demuxers/decoders
37 * visualisations for audio files
40 * subtitle support for video files. Subtitles can be store in external
44 * stream selection between different video/audio/subtitles streams
47 * meta info (tag) extraction
50 * easy access to the last video frame
53 * buffering when playing streams over a network
56 * volume control with mute option
61 * <title>Usage</title>
63 * A playbin2 element can be created just like any other element using
64 * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin2:uri
65 * property. This must be an absolute URI, relative file paths are not allowed.
66 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
68 * Playbin is a #GstPipeline. It will notify the application of everything
69 * that's happening (errors, end of stream, tags found, state changes, etc.)
70 * by posting messages on its #GstBus. The application needs to watch the
73 * Playback can be initiated by setting the element to PLAYING state using
74 * gst_element_set_state(). Note that the state change will take place in
75 * the background in a separate thread, when the function returns playback
76 * is probably not happening yet and any errors might not have occured yet.
77 * Applications using playbin should ideally be written to deal with things
78 * completely asynchroneous.
80 * When playback has finished (an EOS message has been received on the bus)
81 * or an error has occured (an ERROR message has been received on the bus) or
82 * the user wants to play a different track, playbin should be set back to
83 * READY or NULL state, then the #GstPlayBin2:uri property should be set to the
84 * new location and then playbin be set to PLAYING state again.
86 * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
87 * on the playbin element. Again, the seek will not be executed
88 * instantaneously, but will be done in a background thread. When the seek
89 * call returns the seek will most likely still be in process. An application
90 * may wait for the seek to finish (or fail) using gst_element_get_state() with
91 * -1 as the timeout, but this will block the user interface and is not
94 * Applications may query the current position and duration of the stream
95 * via gst_element_query_position() and gst_element_query_duration() and
96 * setting the format passed to GST_FORMAT_TIME. If the query was successful,
97 * the duration or position will have been returned in units of nanoseconds.
101 * <title>Advanced Usage: specifying the audio and video sink</title>
103 * By default, if no audio sink or video sink has been specified via the
104 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property, playbin will use the autoaudiosink
105 * and autovideosink elements to find the first-best available output method.
106 * This should work in most cases, but is not always desirable. Often either
107 * the user or application might want to specify more explicitly what to use
108 * for audio and video output.
110 * If the application wants more control over how audio or video should be
111 * output, it may create the audio/video sink elements itself (for example
112 * using gst_element_factory_make()) and provide them to playbin using the
113 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property.
115 * GNOME-based applications, for example, will usually want to create
116 * gconfaudiosink and gconfvideosink elements and make playbin use those,
117 * so that output happens to whatever the user has configured in the GNOME
118 * Multimedia System Selector configuration dialog.
120 * The sink elements do not necessarily need to be ready-made sinks. It is
121 * possible to create container elements that look like a sink to playbin,
122 * but in reality contain a number of custom elements linked together. This
123 * can be achieved by creating a #GstBin and putting elements in there and
124 * linking them, and then creating a sink #GstGhostPad for the bin and pointing
125 * it to the sink pad of the first element within the bin. This can be used
126 * for a number of purposes, for example to force output to a particular
127 * format or to modify or observe the data before it is output.
129 * It is also possible to 'suppress' audio and/or video output by using
130 * 'fakesink' elements (or capture it from there using the fakesink element's
131 * "handoff" signal, which, nota bene, is fired from the streaming thread!).
135 * <title>Retrieving Tags and Other Meta Data</title>
137 * Most of the common meta data (artist, title, etc.) can be retrieved by
138 * watching for TAG messages on the pipeline's bus (see above).
140 * Other more specific meta information like width/height/framerate of video
141 * streams or samplerate/number of channels of audio streams can be obtained
142 * from the negotiated caps on the sink pads of the sinks.
146 * <title>Buffering</title>
147 * Playbin handles buffering automatically for the most part, but applications
148 * need to handle parts of the buffering process as well. Whenever playbin is
149 * buffering, it will post BUFFERING messages on the bus with a percentage
150 * value that shows the progress of the buffering process. Applications need
151 * to set playbin to PLAYING or PAUSED state in response to these messages.
152 * They may also want to convey the buffering progress to the user in some
153 * way. Here is how to extract the percentage information from the message
154 * (requires GStreamer >= 0.10.11):
156 * switch (GST_MESSAGE_TYPE (msg)) {
157 * case GST_MESSAGE_BUFFERING: {
159 * gst_message_parse_buffering (msg, &percent);
160 * g_print ("Buffering (%%u percent done)", percent);
166 * Note that applications should keep/set the pipeline in the PAUSED state when
167 * a BUFFERING message is received with a buffer percent value < 100 and set
168 * the pipeline back to PLAYING state when a BUFFERING message with a value
169 * of 100 percent is received (if PLAYING is the desired state, that is).
172 * <title>Embedding the video window in your application</title>
173 * By default, playbin (or rather the video sinks used) will create their own
174 * window. Applications will usually want to force output to a window of their
175 * own, however. This can be done using the #GstXOverlay interface, which most
176 * video sinks implement. See the documentation there for more details.
179 * <title>Specifying which CD/DVD device to use</title>
180 * The device to use for CDs/DVDs needs to be set on the source element
181 * playbin creates before it is opened. The only way to do this at the moment
182 * is to connect to playbin's "notify::source" signal, which will be emitted
183 * by playbin when it has created the source element for a particular URI.
184 * In the signal callback you can check if the source element has a "device"
185 * property and set it appropriately. In future ways might be added to specify
186 * the device as part of the URI, but at the time of writing this is not
190 * <title>Handling redirects</title>
192 * Some elements may post 'redirect' messages on the bus to tell the
193 * application to open another location. These are element messages containing
194 * a structure named 'redirect' along with a 'new-location' field of string
195 * type. The new location may be a relative or an absolute URI. Examples
196 * for such redirects can be found in many quicktime movie trailers.
200 * <title>Examples</title>
202 * gst-launch -v playbin uri=file:///path/to/somefile.avi
203 * ]| This will play back the given AVI video file, given that the video and
204 * audio decoders required to decode the content are installed. Since no
205 * special audio sink or video sink is supplied (not possible via gst-launch),
206 * playbin will try to find a suitable audio and video sink automatically
207 * using the autoaudiosink and autovideosink elements.
209 * gst-launch -v playbin uri=cdda://4
210 * ]| This will play back track 4 on an audio CD in your disc drive (assuming
211 * the drive is detected automatically by the plugin).
213 * gst-launch -v playbin uri=dvd://1
214 * ]| This will play back title 1 of a DVD in your disc drive (assuming
215 * the drive is detected automatically by the plugin).
226 #include <gst/gst-i18n-plugin.h>
227 #include <gst/pbutils/pbutils.h>
228 #include <gst/interfaces/streamvolume.h>
230 #include "gstplay-enum.h"
231 #include "gstplay-marshal.h"
232 #include "gstplayback.h"
233 #include "gstplaysink.h"
234 #include "gstsubtitleoverlay.h"
236 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
237 #define GST_CAT_DEFAULT gst_play_bin_debug
239 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type())
240 #define GST_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
241 #define GST_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
242 #define GST_IS_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
243 #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
245 #define VOLUME_MAX_DOUBLE 10.0
247 typedef struct _GstPlayBin GstPlayBin;
248 typedef struct _GstPlayBinClass GstPlayBinClass;
249 typedef struct _GstSourceGroup GstSourceGroup;
250 typedef struct _GstSourceSelect GstSourceSelect;
252 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
254 /* has the info for a selector and provides the link to the sink */
255 struct _GstSourceSelect
257 const gchar *media_list[8]; /* the media types for the selector */
258 SourceSelectGetMediaCapsFunc get_media_caps; /* more complex caps for the selector */
259 GstPlaySinkType type; /* the sink pad type of the selector */
261 GstElement *selector; /* the selector */
263 GstPad *srcpad; /* the source pad of the selector */
264 GstPad *sinkpad; /* the sinkpad of the sink when the selector
267 GstEvent *sinkpad_delayed_event;
268 gulong sinkpad_data_probe;
271 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
272 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
273 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
277 PLAYBIN_STREAM_AUDIO = 0,
278 PLAYBIN_STREAM_VIDEO,
283 /* a structure to hold the objects for decoding a uri and the subtitle uri
285 struct _GstSourceGroup
291 gboolean valid; /* the group has valid info to start playback */
292 gboolean active; /* the group is active */
297 GValueArray *streaminfo;
300 GPtrArray *video_channels; /* links to selector pads */
301 GPtrArray *audio_channels; /* links to selector pads */
302 GPtrArray *text_channels; /* links to selector pads */
304 GstElement *audio_sink; /* autoplugged audio and video sinks */
305 GstElement *video_sink;
307 /* uridecodebins for uri and subtitle uri */
308 GstElement *uridecodebin;
309 GstElement *suburidecodebin;
311 gboolean sub_pending;
314 gulong pad_removed_id;
315 gulong no_more_pads_id;
316 gulong notify_source_id;
318 gulong autoplug_factories_id;
319 gulong autoplug_select_id;
320 gulong autoplug_continue_id;
322 gulong sub_pad_added_id;
323 gulong sub_pad_removed_id;
324 gulong sub_no_more_pads_id;
325 gulong sub_autoplug_continue_id;
327 GMutex *stream_changed_pending_lock;
328 GList *stream_changed_pending;
330 /* selectors for different streams */
331 GstSourceSelect selector[PLAYBIN_STREAM_LAST];
334 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
335 #define GST_PLAY_BIN_LOCK(bin) (g_static_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
336 #define GST_PLAY_BIN_UNLOCK(bin) (g_static_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
338 /* lock to protect dynamic callbacks, like no-more-pads */
339 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->dyn_lock)
340 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->dyn_lock)
342 /* lock for shutdown */
343 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
345 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
347 GST_PLAY_BIN_DYN_LOCK (bin); \
348 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
349 GST_PLAY_BIN_DYN_UNLOCK (bin); \
354 /* unlock for shutdown */
355 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
356 GST_PLAY_BIN_DYN_UNLOCK (bin); \
361 * playbin element structure
367 GStaticRecMutex lock; /* to protect group switching */
369 /* the groups, we use a double buffer to switch between current and next */
370 GstSourceGroup groups[2]; /* array with group info */
371 GstSourceGroup *curr_group; /* pointer to the currently playing group */
372 GstSourceGroup *next_group; /* pointer to the next group */
375 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
376 gint current_video; /* the currently selected stream */
377 gint current_audio; /* the currently selected stream */
378 gint current_text; /* the currently selected stream */
380 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
381 guint buffer_size; /* When buffering, the max buffer size (bytes) */
384 GstPlaySink *playsink;
386 /* the last activated source */
389 /* lock protecting dynamic adding/removing */
391 /* if we are shutting down or not */
394 GMutex *elements_lock;
395 guint32 elements_cookie;
396 GList *elements; /* factories we can use for selecting elements */
398 gboolean have_selector; /* set to FALSE when we fail to create an
399 * input-selector, so that we only post a
402 GstElement *audio_sink; /* configured audio sink, or NULL */
403 GstElement *video_sink; /* configured video sink, or NULL */
404 GstElement *text_sink; /* configured text sink, or NULL */
411 } duration[5]; /* cached durations */
413 guint64 ring_buffer_max_size; /* 0 means disabled */
416 struct _GstPlayBinClass
418 GstPipelineClass parent_class;
420 /* notify app that the current uri finished decoding and it is possible to
421 * queue a new one for gapless playback */
422 void (*about_to_finish) (GstPlayBin * playbin);
424 /* notify app that number of audio/video/text streams changed */
425 void (*video_changed) (GstPlayBin * playbin);
426 void (*audio_changed) (GstPlayBin * playbin);
427 void (*text_changed) (GstPlayBin * playbin);
429 /* notify app that the tags of audio/video/text streams changed */
430 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
431 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
432 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
434 /* get audio/video/text tags for a stream */
435 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
436 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
437 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
439 /* get the last video frame and convert it to the given caps */
440 GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
442 /* get audio/video/text pad for a stream */
443 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
444 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
445 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
449 #define DEFAULT_URI NULL
450 #define DEFAULT_SUBURI NULL
451 #define DEFAULT_SOURCE NULL
452 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
453 GST_PLAY_FLAG_SOFT_VOLUME
454 #define DEFAULT_N_VIDEO 0
455 #define DEFAULT_CURRENT_VIDEO -1
456 #define DEFAULT_N_AUDIO 0
457 #define DEFAULT_CURRENT_AUDIO -1
458 #define DEFAULT_N_TEXT 0
459 #define DEFAULT_CURRENT_TEXT -1
460 #define DEFAULT_SUBTITLE_ENCODING NULL
461 #define DEFAULT_AUDIO_SINK NULL
462 #define DEFAULT_VIDEO_SINK NULL
463 #define DEFAULT_VIS_PLUGIN NULL
464 #define DEFAULT_TEXT_SINK NULL
465 #define DEFAULT_VOLUME 1.0
466 #define DEFAULT_MUTE FALSE
467 #define DEFAULT_FRAME NULL
468 #define DEFAULT_FONT_DESC NULL
469 #define DEFAULT_CONNECTION_SPEED 0
470 #define DEFAULT_BUFFER_DURATION -1
471 #define DEFAULT_BUFFER_SIZE -1
472 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
487 PROP_SUBTITLE_ENCODING,
496 PROP_CONNECTION_SPEED,
498 PROP_BUFFER_DURATION,
500 PROP_RING_BUFFER_MAX_SIZE,
507 SIGNAL_ABOUT_TO_FINISH,
508 SIGNAL_CONVERT_FRAME,
509 SIGNAL_VIDEO_CHANGED,
510 SIGNAL_AUDIO_CHANGED,
512 SIGNAL_VIDEO_TAGS_CHANGED,
513 SIGNAL_AUDIO_TAGS_CHANGED,
514 SIGNAL_TEXT_TAGS_CHANGED,
515 SIGNAL_GET_VIDEO_TAGS,
516 SIGNAL_GET_AUDIO_TAGS,
517 SIGNAL_GET_TEXT_TAGS,
518 SIGNAL_GET_VIDEO_PAD,
519 SIGNAL_GET_AUDIO_PAD,
525 static void gst_play_bin_class_init (GstPlayBinClass * klass);
526 static void gst_play_bin_init (GstPlayBin * playbin);
527 static void gst_play_bin_finalize (GObject * object);
529 static void gst_play_bin_set_property (GObject * object, guint prop_id,
530 const GValue * value, GParamSpec * spec);
531 static void gst_play_bin_get_property (GObject * object, guint prop_id,
532 GValue * value, GParamSpec * spec);
534 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
535 GstStateChange transition);
537 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
538 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
540 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
542 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
544 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
547 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
550 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
551 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
552 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
554 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
556 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
557 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
558 GstSourceGroup * group);
560 static void gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
562 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
565 static GstElementClass *parent_class;
567 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
569 #define REMOVE_SIGNAL(obj,id) \
571 g_signal_handler_disconnect (obj, id); \
576 gst_play_bin_get_type (void)
578 static GType gst_play_bin_type = 0;
580 if (!gst_play_bin_type) {
581 static const GTypeInfo gst_play_bin_info = {
582 sizeof (GstPlayBinClass),
585 (GClassInitFunc) gst_play_bin_class_init,
590 (GInstanceInitFunc) gst_play_bin_init,
593 static const GInterfaceInfo svol_info = {
597 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
598 "GstPlayBin2", &gst_play_bin_info, 0);
600 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
604 return gst_play_bin_type;
608 gst_play_bin_class_init (GstPlayBinClass * klass)
610 GObjectClass *gobject_klass;
611 GstElementClass *gstelement_klass;
612 GstBinClass *gstbin_klass;
614 gobject_klass = (GObjectClass *) klass;
615 gstelement_klass = (GstElementClass *) klass;
616 gstbin_klass = (GstBinClass *) klass;
618 parent_class = g_type_class_peek_parent (klass);
620 gobject_klass->set_property = gst_play_bin_set_property;
621 gobject_klass->get_property = gst_play_bin_get_property;
623 gobject_klass->finalize = gst_play_bin_finalize;
628 * Set the next URI that playbin will play. This property can be set from the
629 * about-to-finish signal to queue the next media file.
631 g_object_class_install_property (gobject_klass, PROP_URI,
632 g_param_spec_string ("uri", "URI", "URI of the media to play",
633 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
638 * Set the next subtitle URI that playbin will play. This property can be
639 * set from the about-to-finish signal to queue the next subtitle media file.
641 g_object_class_install_property (gobject_klass, PROP_SUBURI,
642 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
643 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
645 g_object_class_install_property (gobject_klass, PROP_SOURCE,
646 g_param_spec_object ("source", "Source", "Source element",
647 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
652 * Control the behaviour of playbin.
654 g_object_class_install_property (gobject_klass, PROP_FLAGS,
655 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
656 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
657 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
660 * GstPlayBin2:n-video
662 * Get the total number of available video streams.
664 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
665 g_param_spec_int ("n-video", "Number Video",
666 "Total number of video streams", 0, G_MAXINT, 0,
667 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
669 * GstPlayBin2:current-video
671 * Get or set the currently playing video stream. By default the first video
672 * stream with data is played.
674 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
675 g_param_spec_int ("current-video", "Current Video",
676 "Currently playing video stream (-1 = auto)",
677 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
679 * GstPlayBin2:n-audio
681 * Get the total number of available audio streams.
683 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
684 g_param_spec_int ("n-audio", "Number Audio",
685 "Total number of audio streams", 0, G_MAXINT, 0,
686 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
688 * GstPlayBin2:current-audio
690 * Get or set the currently playing audio stream. By default the first audio
691 * stream with data is played.
693 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
694 g_param_spec_int ("current-audio", "Current audio",
695 "Currently playing audio stream (-1 = auto)",
696 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
700 * Get the total number of available subtitle streams.
702 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
703 g_param_spec_int ("n-text", "Number Text",
704 "Total number of text streams", 0, G_MAXINT, 0,
705 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
707 * GstPlayBin2:current-text:
709 * Get or set the currently playing subtitle stream. By default the first
710 * subtitle stream with data is played.
712 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
713 g_param_spec_int ("current-text", "Current Text",
714 "Currently playing text stream (-1 = auto)",
715 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
717 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
718 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
719 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
720 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
721 "be checked for an encoding to use. If that is not set either, "
722 "ISO-8859-15 will be assumed.", NULL,
723 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
725 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
726 g_param_spec_object ("video-sink", "Video Sink",
727 "the video output element to use (NULL = default sink)",
728 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
729 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
730 g_param_spec_object ("audio-sink", "Audio Sink",
731 "the audio output element to use (NULL = default sink)",
732 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
733 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
734 g_param_spec_object ("vis-plugin", "Vis plugin",
735 "the visualization element to use (NULL = default)",
736 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
737 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
738 g_param_spec_object ("text-sink", "Text plugin",
739 "the text output element to use (NULL = default textoverlay)",
740 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
743 * GstPlayBin2:volume:
745 * Get or set the current audio stream volume. 1.0 means 100%,
746 * 0.0 means mute. This uses a linear volume scale.
749 g_object_class_install_property (gobject_klass, PROP_VOLUME,
750 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
751 0.0, VOLUME_MAX_DOUBLE, 1.0,
752 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
753 g_object_class_install_property (gobject_klass, PROP_MUTE,
754 g_param_spec_boolean ("mute", "Mute",
755 "Mute the audio channel without changing the volume", FALSE,
756 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
760 * @playbin: a #GstPlayBin2
762 * Get the currently rendered or prerolled frame in the video sink.
763 * The #GstCaps on the buffer will describe the format of the buffer.
765 g_object_class_install_property (gobject_klass, PROP_FRAME,
766 g_param_spec_boxed ("frame", "Frame",
767 "The last frame (NULL = no video available)",
768 GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
769 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
770 g_param_spec_string ("subtitle-font-desc",
771 "Subtitle font description",
772 "Pango font description of font "
773 "to be used for subtitle rendering", NULL,
774 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
776 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
777 g_param_spec_uint ("connection-speed", "Connection Speed",
778 "Network connection speed in kbps (0 = unknown)",
779 0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
780 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
782 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
783 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
784 "Buffer size when buffering network streams",
785 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
786 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
787 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
788 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
789 "Buffer duration when buffering network streams",
790 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
791 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
793 * GstPlayBin2:av-offset:
795 * Control the synchronisation offset between the audio and video streams.
796 * Positive values make the audio ahead of the video and negative values make
797 * the audio go behind the video.
801 g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
802 g_param_spec_int64 ("av-offset", "AV Offset",
803 "The synchronisation offset between audio and video in nanoseconds",
804 G_MININT64, G_MAXINT64, 0,
805 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
808 * GstQueue2:ring-buffer-max-size
810 * The maximum size of the ring buffer in bytes. If set to 0, the ring
811 * buffer is disabled. Default 0.
815 g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
816 g_param_spec_uint64 ("ring-buffer-max-size",
817 "Max. ring buffer size (bytes)",
818 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
819 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
820 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
823 * GstPlayBin2::about-to-finish
824 * @playbin: a #GstPlayBin2
826 * This signal is emitted when the current uri is about to finish. You can
827 * set the uri and suburi to make sure that playback continues.
829 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
830 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
832 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
833 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
836 * GstPlayBin2::video-changed
837 * @playbin: a #GstPlayBin2
839 * This signal is emitted whenever the number or order of the video
840 * streams has changed. The application will most likely want to select
841 * a new video stream.
843 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
844 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
846 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
847 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
849 * GstPlayBin2::audio-changed
850 * @playbin: a #GstPlayBin2
852 * This signal is emitted whenever the number or order of the audio
853 * streams has changed. The application will most likely want to select
854 * a new audio stream.
856 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
857 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
859 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
860 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
862 * GstPlayBin2::text-changed
863 * @playbin: a #GstPlayBin2
865 * This signal is emitted whenever the number or order of the text
866 * streams has changed. The application will most likely want to select
869 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
870 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
872 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
873 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
876 * GstPlayBin2::video-tags-changed
877 * @playbin: a #GstPlayBin2
878 * @stream: stream index with changed tags
880 * This signal is emitted whenever the tags of a video stream have changed.
881 * The application will most likely want to get the new tags.
885 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
886 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
888 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
889 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
892 * GstPlayBin2::audio-tags-changed
893 * @playbin: a #GstPlayBin2
894 * @stream: stream index with changed tags
896 * This signal is emitted whenever the tags of an audio stream have changed.
897 * The application will most likely want to get the new tags.
901 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
902 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
904 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
905 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
908 * GstPlayBin2::text-tags-changed
909 * @playbin: a #GstPlayBin2
910 * @stream: stream index with changed tags
912 * This signal is emitted whenever the tags of a text stream have changed.
913 * The application will most likely want to get the new tags.
917 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
918 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
920 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
921 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
924 * GstPlayBin2::source-setup:
925 * @playbin: a #GstPlayBin2
926 * @source: source element
928 * This signal is emitted after the source element has been created, so
929 * it can be configured by setting additional properties (e.g. set a
930 * proxy server for an http source, or set the device and read speed for
931 * an audio cd source). This is functionally equivalent to connecting to
932 * the notify::source signal, but more convenient.
936 gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
937 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
938 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
939 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
942 * GstPlayBin2::get-video-tags
943 * @playbin: a #GstPlayBin2
944 * @stream: a video stream number
946 * Action signal to retrieve the tags of a specific video stream number.
947 * This information can be used to select a stream.
949 * Returns: a GstTagList with tags or NULL when the stream number does not
952 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
953 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
954 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
955 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
956 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
958 * GstPlayBin2::get-audio-tags
959 * @playbin: a #GstPlayBin2
960 * @stream: an audio stream number
962 * Action signal to retrieve the tags of a specific audio stream number.
963 * This information can be used to select a stream.
965 * Returns: a GstTagList with tags or NULL when the stream number does not
968 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
969 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
970 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
971 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
972 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
974 * GstPlayBin2::get-text-tags
975 * @playbin: a #GstPlayBin2
976 * @stream: a text stream number
978 * Action signal to retrieve the tags of a specific text stream number.
979 * This information can be used to select a stream.
981 * Returns: a GstTagList with tags or NULL when the stream number does not
984 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
985 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
986 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
987 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
988 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
990 * GstPlayBin2::convert-frame
991 * @playbin: a #GstPlayBin2
992 * @caps: the target format of the frame
994 * Action signal to retrieve the currently playing video frame in the format
995 * specified by @caps.
996 * If @caps is %NULL, no conversion will be performed and this function is
997 * equivalent to the #GstPlayBin::frame property.
999 * Returns: a #GstBuffer of the current video frame converted to #caps.
1000 * The caps on the buffer will describe the final layout of the buffer data.
1001 * %NULL is returned when no current buffer can be retrieved or when the
1002 * conversion failed.
1004 gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
1005 g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
1006 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1007 G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
1008 gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
1011 * GstPlayBin2::get-video-pad
1012 * @playbin: a #GstPlayBin2
1013 * @stream: a video stream number
1015 * Action signal to retrieve the stream-selector sinkpad for a specific
1017 * This pad can be used for notifications of caps changes, stream-specific
1020 * Returns: a #GstPad, or NULL when the stream number does not exist.
1022 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1023 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1024 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1025 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1026 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1028 * GstPlayBin2::get-audio-pad
1029 * @playbin: a #GstPlayBin2
1030 * @stream: an audio stream number
1032 * Action signal to retrieve the stream-selector sinkpad for a specific
1034 * This pad can be used for notifications of caps changes, stream-specific
1037 * Returns: a #GstPad, or NULL when the stream number does not exist.
1039 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1040 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1041 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1042 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1043 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1045 * GstPlayBin2::get-text-pad
1046 * @playbin: a #GstPlayBin2
1047 * @stream: a text stream number
1049 * Action signal to retrieve the stream-selector sinkpad for a specific
1051 * This pad can be used for notifications of caps changes, stream-specific
1054 * Returns: a #GstPad, or NULL when the stream number does not exist.
1056 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1057 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1058 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1059 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1060 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1062 klass->get_video_tags = gst_play_bin_get_video_tags;
1063 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1064 klass->get_text_tags = gst_play_bin_get_text_tags;
1066 klass->convert_frame = gst_play_bin_convert_frame;
1068 klass->get_video_pad = gst_play_bin_get_video_pad;
1069 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1070 klass->get_text_pad = gst_play_bin_get_text_pad;
1072 gst_element_class_set_details_simple (gstelement_klass,
1073 "Player Bin 2", "Generic/Bin/Player",
1074 "Autoplug and play media from an uri",
1075 "Wim Taymans <wim.taymans@gmail.com>");
1077 gstelement_klass->change_state =
1078 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1079 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1081 gstbin_klass->handle_message =
1082 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1086 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1090 /* store the array for the different channels */
1091 group->video_channels = g_ptr_array_new ();
1092 group->audio_channels = g_ptr_array_new ();
1093 group->text_channels = g_ptr_array_new ();
1094 group->lock = g_mutex_new ();
1095 /* init selectors. The selector is found by finding the first prefix that
1096 * matches the media. */
1097 group->playbin = playbin;
1098 /* If you add any items to these lists, check that media_list[] is defined
1099 * above to be large enough to hold MAX(items)+1, so as to accomodate a
1100 * NULL terminator (set when the memory is zeroed on allocation) */
1101 group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
1102 group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
1103 group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
1104 group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
1105 group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
1106 group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
1107 group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
1108 group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
1109 group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
1110 group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
1111 group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
1112 group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
1113 group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
1114 group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
1115 gst_subtitle_overlay_create_factory_caps;
1116 group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
1117 group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
1119 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1120 GstSourceSelect *select = &group->selector[n];
1121 select->sinkpad_delayed_event = NULL;
1122 select->sinkpad_data_probe = 0;
1127 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1131 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1132 GstSourceSelect *select = &group->selector[n];
1133 if (select->sinkpad && select->sinkpad_data_probe)
1134 gst_pad_remove_data_probe (select->sinkpad, select->sinkpad_data_probe);
1135 if (select->sinkpad_delayed_event)
1136 gst_event_unref (select->sinkpad_delayed_event);
1139 g_free (group->uri);
1140 g_free (group->suburi);
1141 g_ptr_array_free (group->video_channels, TRUE);
1142 g_ptr_array_free (group->audio_channels, TRUE);
1143 g_ptr_array_free (group->text_channels, TRUE);
1145 g_mutex_free (group->lock);
1146 if (group->audio_sink) {
1147 if (group->audio_sink != playbin->audio_sink)
1148 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1149 gst_object_unref (group->audio_sink);
1151 group->audio_sink = NULL;
1152 if (group->video_sink) {
1153 if (group->video_sink != playbin->video_sink)
1154 gst_element_set_state (group->video_sink, GST_STATE_NULL);
1155 gst_object_unref (group->video_sink);
1157 group->video_sink = NULL;
1159 g_list_free (group->stream_changed_pending);
1160 group->stream_changed_pending = NULL;
1162 if (group->stream_changed_pending_lock)
1163 g_mutex_free (group->stream_changed_pending_lock);
1164 group->stream_changed_pending_lock = NULL;
1168 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1170 g_object_notify (G_OBJECT (playbin), "volume");
1174 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1176 g_object_notify (G_OBJECT (playbin), "mute");
1179 /* Must be called with elements lock! */
1181 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1185 if (!playbin->elements ||
1186 playbin->elements_cookie !=
1187 gst_default_registry_get_feature_list_cookie ()) {
1188 if (playbin->elements)
1189 gst_plugin_feature_list_free (playbin->elements);
1191 gst_element_factory_list_get_elements
1192 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1194 gst_element_factory_list_get_elements
1195 (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1196 playbin->elements = g_list_concat (res, tmp);
1198 g_list_sort (playbin->elements, gst_plugin_feature_rank_compare_func);
1199 playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1204 gst_play_bin_init (GstPlayBin * playbin)
1206 g_static_rec_mutex_init (&playbin->lock);
1207 playbin->dyn_lock = g_mutex_new ();
1209 /* assume we can create a selector */
1210 playbin->have_selector = TRUE;
1213 playbin->curr_group = &playbin->groups[0];
1214 playbin->next_group = &playbin->groups[1];
1215 init_group (playbin, &playbin->groups[0]);
1216 init_group (playbin, &playbin->groups[1]);
1218 /* first filter out the interesting element factories */
1219 playbin->elements_lock = g_mutex_new ();
1222 playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1223 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1224 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1225 /* Connect to notify::volume and notify::mute signals for proxying */
1226 g_signal_connect (playbin->playsink, "notify::volume",
1227 G_CALLBACK (notify_volume_cb), playbin);
1228 g_signal_connect (playbin->playsink, "notify::mute",
1229 G_CALLBACK (notify_mute_cb), playbin);
1231 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1232 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1233 playbin->current_text = DEFAULT_CURRENT_TEXT;
1235 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1236 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1237 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1241 gst_play_bin_finalize (GObject * object)
1243 GstPlayBin *playbin;
1245 playbin = GST_PLAY_BIN (object);
1247 free_group (playbin, &playbin->groups[0]);
1248 free_group (playbin, &playbin->groups[1]);
1250 if (playbin->source)
1251 gst_object_unref (playbin->source);
1252 if (playbin->video_sink) {
1253 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1254 gst_object_unref (playbin->video_sink);
1256 if (playbin->audio_sink) {
1257 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1258 gst_object_unref (playbin->audio_sink);
1260 if (playbin->text_sink) {
1261 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1262 gst_object_unref (playbin->text_sink);
1265 if (playbin->elements)
1266 gst_plugin_feature_list_free (playbin->elements);
1268 g_static_rec_mutex_free (&playbin->lock);
1269 g_mutex_free (playbin->dyn_lock);
1270 g_mutex_free (playbin->elements_lock);
1272 G_OBJECT_CLASS (parent_class)->finalize (object);
1276 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1278 GstSourceGroup *group;
1281 g_warning ("cannot set NULL uri");
1285 GST_PLAY_BIN_LOCK (playbin);
1286 group = playbin->next_group;
1288 GST_SOURCE_GROUP_LOCK (group);
1289 /* store the uri in the next group we will play */
1290 g_free (group->uri);
1291 group->uri = g_strdup (uri);
1292 group->valid = TRUE;
1293 GST_SOURCE_GROUP_UNLOCK (group);
1295 GST_DEBUG ("set new uri to %s", uri);
1296 GST_PLAY_BIN_UNLOCK (playbin);
1300 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1302 GstSourceGroup *group;
1304 GST_PLAY_BIN_LOCK (playbin);
1305 group = playbin->next_group;
1307 GST_SOURCE_GROUP_LOCK (group);
1308 g_free (group->suburi);
1309 group->suburi = g_strdup (suburi);
1310 GST_SOURCE_GROUP_UNLOCK (group);
1312 GST_DEBUG ("setting new .sub uri to %s", suburi);
1314 GST_PLAY_BIN_UNLOCK (playbin);
1318 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1320 gst_play_sink_set_flags (playbin->playsink, flags);
1321 gst_play_sink_reconfigure (playbin->playsink);
1325 gst_play_bin_get_flags (GstPlayBin * playbin)
1329 flags = gst_play_sink_get_flags (playbin->playsink);
1334 /* get the currently playing group or if nothing is playing, the next
1335 * group. Must be called with the PLAY_BIN_LOCK. */
1336 static GstSourceGroup *
1337 get_group (GstPlayBin * playbin)
1339 GstSourceGroup *result;
1341 if (!(result = playbin->curr_group))
1342 result = playbin->next_group;
1348 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1350 GstPad *sinkpad = NULL;
1351 GstSourceGroup *group;
1353 GST_PLAY_BIN_LOCK (playbin);
1354 group = get_group (playbin);
1355 if (stream < group->video_channels->len) {
1356 sinkpad = g_ptr_array_index (group->video_channels, stream);
1357 gst_object_ref (sinkpad);
1359 GST_PLAY_BIN_UNLOCK (playbin);
1365 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1367 GstPad *sinkpad = NULL;
1368 GstSourceGroup *group;
1370 GST_PLAY_BIN_LOCK (playbin);
1371 group = get_group (playbin);
1372 if (stream < group->audio_channels->len) {
1373 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1374 gst_object_ref (sinkpad);
1376 GST_PLAY_BIN_UNLOCK (playbin);
1382 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1384 GstPad *sinkpad = NULL;
1385 GstSourceGroup *group;
1387 GST_PLAY_BIN_LOCK (playbin);
1388 group = get_group (playbin);
1389 if (stream < group->text_channels->len) {
1390 sinkpad = g_ptr_array_index (group->text_channels, stream);
1391 gst_object_ref (sinkpad);
1393 GST_PLAY_BIN_UNLOCK (playbin);
1400 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1405 if (!channels || stream >= channels->len)
1408 sinkpad = g_ptr_array_index (channels, stream);
1409 g_object_get (sinkpad, "tags", &result, NULL);
1415 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1418 GstSourceGroup *group;
1420 GST_PLAY_BIN_LOCK (playbin);
1421 group = get_group (playbin);
1422 result = get_tags (playbin, group->video_channels, stream);
1423 GST_PLAY_BIN_UNLOCK (playbin);
1429 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1432 GstSourceGroup *group;
1434 GST_PLAY_BIN_LOCK (playbin);
1435 group = get_group (playbin);
1436 result = get_tags (playbin, group->audio_channels, stream);
1437 GST_PLAY_BIN_UNLOCK (playbin);
1443 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1446 GstSourceGroup *group;
1448 GST_PLAY_BIN_LOCK (playbin);
1449 group = get_group (playbin);
1450 result = get_tags (playbin, group->text_channels, stream);
1451 GST_PLAY_BIN_UNLOCK (playbin);
1457 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1459 return gst_play_sink_convert_frame (playbin->playsink, caps);
1462 /* Returns current stream number, or -1 if none has been selected yet */
1464 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1466 /* Internal API cleanup would make this easier... */
1468 GstPad *pad, *current;
1469 GstObject *selector = NULL;
1472 for (i = 0; i < channels->len; i++) {
1473 pad = g_ptr_array_index (channels, i);
1474 if ((selector = gst_pad_get_parent (pad))) {
1475 g_object_get (selector, "active-pad", ¤t, NULL);
1476 gst_object_unref (selector);
1478 if (pad == current) {
1479 gst_object_unref (current);
1485 gst_object_unref (current);
1493 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1495 GstSourceGroup *group;
1496 GPtrArray *channels;
1499 GST_PLAY_BIN_LOCK (playbin);
1501 GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1502 playbin->current_video, stream);
1504 group = get_group (playbin);
1505 if (!(channels = group->video_channels))
1508 if (stream == -1 || channels->len <= stream) {
1511 /* take channel from selected stream */
1512 sinkpad = g_ptr_array_index (channels, stream);
1516 gst_object_ref (sinkpad);
1517 GST_PLAY_BIN_UNLOCK (playbin);
1520 GstObject *selector;
1522 if ((selector = gst_pad_get_parent (sinkpad))) {
1523 /* activate the selected pad */
1524 g_object_set (selector, "active-pad", sinkpad, NULL);
1525 gst_object_unref (selector);
1527 gst_object_unref (sinkpad);
1533 GST_PLAY_BIN_UNLOCK (playbin);
1534 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1540 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1542 GstSourceGroup *group;
1543 GPtrArray *channels;
1546 GST_PLAY_BIN_LOCK (playbin);
1548 GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1549 playbin->current_audio, stream);
1551 group = get_group (playbin);
1552 if (!(channels = group->audio_channels))
1555 if (stream == -1 || channels->len <= stream) {
1558 /* take channel from selected stream */
1559 sinkpad = g_ptr_array_index (channels, stream);
1563 gst_object_ref (sinkpad);
1564 GST_PLAY_BIN_UNLOCK (playbin);
1567 GstObject *selector;
1569 if ((selector = gst_pad_get_parent (sinkpad))) {
1570 /* activate the selected pad */
1571 g_object_set (selector, "active-pad", sinkpad, NULL);
1572 gst_object_unref (selector);
1574 gst_object_unref (sinkpad);
1580 GST_PLAY_BIN_UNLOCK (playbin);
1581 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1587 _suburidecodebin_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
1589 GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
1593 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1595 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1597 GValue item = { 0, };
1599 if (it && gst_iterator_next (it, &item) == GST_ITERATOR_OK
1600 && ((sinkpad = g_value_get_object (&item)) != NULL)) {
1604 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1605 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1606 if (!gst_pad_send_event (sinkpad, event)) {
1608 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1609 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1610 if (!gst_pad_send_event (sinkpad, event))
1611 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1614 g_value_unset (&item);
1618 gst_iterator_free (it);
1622 gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
1625 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1626 gboolean done = FALSE;
1627 GValue item = { 0, };
1629 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1636 switch (gst_iterator_next (it, &item)) {
1637 case GST_ITERATOR_OK:
1638 sinkpad = g_value_get_object (&item);
1639 gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
1641 g_value_reset (&item);
1643 case GST_ITERATOR_DONE:
1646 case GST_ITERATOR_RESYNC:
1647 gst_iterator_resync (it);
1649 case GST_ITERATOR_ERROR:
1654 g_value_unset (&item);
1655 gst_iterator_free (it);
1659 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1661 GstSourceGroup *group;
1662 GPtrArray *channels;
1665 GST_PLAY_BIN_LOCK (playbin);
1667 GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1668 playbin->current_text, stream);
1670 group = get_group (playbin);
1671 if (!(channels = group->text_channels))
1674 if (stream == -1 || channels->len <= stream) {
1677 /* take channel from selected stream */
1678 sinkpad = g_ptr_array_index (channels, stream);
1682 gst_object_ref (sinkpad);
1683 GST_PLAY_BIN_UNLOCK (playbin);
1686 GstObject *selector;
1688 if ((selector = gst_pad_get_parent (sinkpad))) {
1689 GstPad *old_sinkpad;
1691 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1693 if (old_sinkpad != sinkpad) {
1694 gboolean need_unblock, need_block, need_seek;
1695 GstPad *src, *peer = NULL, *oldpeer = NULL;
1696 GstElement *parent_element = NULL, *old_parent_element = NULL;
1698 /* Now check if we need to seek the suburidecodebin to the beginning
1699 * or if we need to block all suburidecodebin sinkpads or if we need
1700 * to unblock all suburidecodebin sinkpads
1703 peer = gst_pad_get_peer (sinkpad);
1705 oldpeer = gst_pad_get_peer (old_sinkpad);
1708 parent_element = gst_pad_get_parent_element (peer);
1710 old_parent_element = gst_pad_get_parent_element (oldpeer);
1712 need_block = (old_parent_element == group->suburidecodebin
1713 && parent_element != old_parent_element);
1714 need_unblock = (parent_element == group->suburidecodebin
1715 && parent_element != old_parent_element);
1716 need_seek = (parent_element == group->suburidecodebin);
1719 gst_object_unref (peer);
1721 gst_object_unref (oldpeer);
1723 gst_object_unref (parent_element);
1724 if (old_parent_element)
1725 gst_object_unref (old_parent_element);
1727 /* Block all suburidecodebin sinkpads */
1729 gst_play_bin_suburidecodebin_block (group->suburidecodebin, TRUE);
1731 /* activate the selected pad */
1732 g_object_set (selector, "active-pad", sinkpad, NULL);
1734 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1735 peer = gst_pad_get_peer (src);
1739 /* Flush the subtitle renderer to remove any
1740 * currently displayed subtitles. This event will
1741 * never travel outside subtitleoverlay!
1743 s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1744 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1745 gst_pad_send_event (peer, event);
1746 gst_object_unref (peer);
1748 gst_object_unref (src);
1750 /* Unblock pads if necessary */
1752 gst_play_bin_suburidecodebin_block (group->suburidecodebin, FALSE);
1754 /* seek to the beginning */
1756 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1758 gst_object_unref (selector);
1761 gst_object_unref (old_sinkpad);
1763 gst_object_unref (sinkpad);
1769 GST_PLAY_BIN_UNLOCK (playbin);
1775 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1776 const gchar * dbg, GstElement * sink)
1778 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1780 GST_PLAY_BIN_LOCK (playbin);
1781 if (*elem != sink) {
1786 gst_object_ref_sink (sink);
1790 gst_object_unref (old);
1792 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1793 GST_PLAY_BIN_UNLOCK (playbin);
1797 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1801 GST_PLAY_BIN_LOCK (playbin);
1803 /* set subtitles on all current and next decodebins. */
1804 if ((elem = playbin->groups[0].uridecodebin))
1805 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1806 if ((elem = playbin->groups[0].suburidecodebin))
1807 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1808 if ((elem = playbin->groups[1].uridecodebin))
1809 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1810 if ((elem = playbin->groups[1].suburidecodebin))
1811 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1813 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1814 GST_PLAY_BIN_UNLOCK (playbin);
1818 gst_play_bin_set_property (GObject * object, guint prop_id,
1819 const GValue * value, GParamSpec * pspec)
1821 GstPlayBin *playbin = GST_PLAY_BIN (object);
1825 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1828 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1831 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1833 case PROP_CURRENT_VIDEO:
1834 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1836 case PROP_CURRENT_AUDIO:
1837 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1839 case PROP_CURRENT_TEXT:
1840 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1842 case PROP_SUBTITLE_ENCODING:
1843 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1845 case PROP_VIDEO_SINK:
1846 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1847 g_value_get_object (value));
1849 case PROP_AUDIO_SINK:
1850 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1851 g_value_get_object (value));
1853 case PROP_VIS_PLUGIN:
1854 gst_play_sink_set_vis_plugin (playbin->playsink,
1855 g_value_get_object (value));
1857 case PROP_TEXT_SINK:
1858 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1859 g_value_get_object (value));
1862 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1865 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1867 case PROP_FONT_DESC:
1868 gst_play_sink_set_font_desc (playbin->playsink,
1869 g_value_get_string (value));
1871 case PROP_CONNECTION_SPEED:
1872 GST_PLAY_BIN_LOCK (playbin);
1873 playbin->connection_speed = g_value_get_uint (value) * 1000;
1874 GST_PLAY_BIN_UNLOCK (playbin);
1876 case PROP_BUFFER_SIZE:
1877 playbin->buffer_size = g_value_get_int (value);
1879 case PROP_BUFFER_DURATION:
1880 playbin->buffer_duration = g_value_get_int64 (value);
1882 case PROP_AV_OFFSET:
1883 gst_play_sink_set_av_offset (playbin->playsink,
1884 g_value_get_int64 (value));
1886 case PROP_RING_BUFFER_MAX_SIZE:
1887 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
1890 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1896 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1897 const gchar * dbg, GstPlaySinkType type)
1899 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
1901 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1902 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1903 dbg, sink, dbg, *elem);
1906 GST_PLAY_BIN_LOCK (playbin);
1908 gst_object_ref (sink);
1909 GST_PLAY_BIN_UNLOCK (playbin);
1916 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1919 GstPlayBin *playbin = GST_PLAY_BIN (object);
1924 GstSourceGroup *group;
1926 GST_PLAY_BIN_LOCK (playbin);
1927 group = get_group (playbin);
1928 g_value_set_string (value, group->uri);
1929 GST_PLAY_BIN_UNLOCK (playbin);
1934 GstSourceGroup *group;
1936 GST_PLAY_BIN_LOCK (playbin);
1937 group = get_group (playbin);
1938 g_value_set_string (value, group->suburi);
1939 GST_PLAY_BIN_UNLOCK (playbin);
1944 GST_OBJECT_LOCK (playbin);
1945 g_value_set_object (value, playbin->source);
1946 GST_OBJECT_UNLOCK (playbin);
1950 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
1954 GstSourceGroup *group;
1957 GST_PLAY_BIN_LOCK (playbin);
1958 group = get_group (playbin);
1959 n_video = (group->video_channels ? group->video_channels->len : 0);
1960 g_value_set_int (value, n_video);
1961 GST_PLAY_BIN_UNLOCK (playbin);
1964 case PROP_CURRENT_VIDEO:
1965 GST_PLAY_BIN_LOCK (playbin);
1966 g_value_set_int (value, playbin->current_video);
1967 GST_PLAY_BIN_UNLOCK (playbin);
1971 GstSourceGroup *group;
1974 GST_PLAY_BIN_LOCK (playbin);
1975 group = get_group (playbin);
1976 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
1977 g_value_set_int (value, n_audio);
1978 GST_PLAY_BIN_UNLOCK (playbin);
1981 case PROP_CURRENT_AUDIO:
1982 GST_PLAY_BIN_LOCK (playbin);
1983 g_value_set_int (value, playbin->current_audio);
1984 GST_PLAY_BIN_UNLOCK (playbin);
1988 GstSourceGroup *group;
1991 GST_PLAY_BIN_LOCK (playbin);
1992 group = get_group (playbin);
1993 n_text = (group->text_channels ? group->text_channels->len : 0);
1994 g_value_set_int (value, n_text);
1995 GST_PLAY_BIN_UNLOCK (playbin);
1998 case PROP_CURRENT_TEXT:
1999 GST_PLAY_BIN_LOCK (playbin);
2000 g_value_set_int (value, playbin->current_text);
2001 GST_PLAY_BIN_UNLOCK (playbin);
2003 case PROP_SUBTITLE_ENCODING:
2004 GST_PLAY_BIN_LOCK (playbin);
2005 g_value_take_string (value,
2006 gst_play_sink_get_subtitle_encoding (playbin->playsink));
2007 GST_PLAY_BIN_UNLOCK (playbin);
2009 case PROP_VIDEO_SINK:
2010 g_value_take_object (value,
2011 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2012 "video", GST_PLAY_SINK_TYPE_VIDEO));
2014 case PROP_AUDIO_SINK:
2015 g_value_take_object (value,
2016 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2017 "audio", GST_PLAY_SINK_TYPE_AUDIO));
2019 case PROP_VIS_PLUGIN:
2020 g_value_take_object (value,
2021 gst_play_sink_get_vis_plugin (playbin->playsink));
2023 case PROP_TEXT_SINK:
2024 g_value_take_object (value,
2025 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2026 "text", GST_PLAY_SINK_TYPE_TEXT));
2029 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2032 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2035 gst_value_take_buffer (value,
2036 gst_play_sink_get_last_frame (playbin->playsink));
2038 case PROP_FONT_DESC:
2039 g_value_take_string (value,
2040 gst_play_sink_get_font_desc (playbin->playsink));
2042 case PROP_CONNECTION_SPEED:
2043 GST_PLAY_BIN_LOCK (playbin);
2044 g_value_set_uint (value, playbin->connection_speed / 1000);
2045 GST_PLAY_BIN_UNLOCK (playbin);
2047 case PROP_BUFFER_SIZE:
2048 GST_OBJECT_LOCK (playbin);
2049 g_value_set_int (value, playbin->buffer_size);
2050 GST_OBJECT_UNLOCK (playbin);
2052 case PROP_BUFFER_DURATION:
2053 GST_OBJECT_LOCK (playbin);
2054 g_value_set_int64 (value, playbin->buffer_duration);
2055 GST_OBJECT_UNLOCK (playbin);
2057 case PROP_AV_OFFSET:
2058 g_value_set_int64 (value,
2059 gst_play_sink_get_av_offset (playbin->playsink));
2061 case PROP_RING_BUFFER_MAX_SIZE:
2062 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2065 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2071 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2072 gboolean valid, GstQuery * query)
2078 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2079 gst_query_parse_duration (query, &fmt, &duration);
2081 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2082 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2083 playbin->duration[i].valid = valid;
2084 playbin->duration[i].format = fmt;
2085 playbin->duration[i].duration = valid ? duration : -1;
2092 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2094 const GstFormat formats[] =
2095 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2100 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2101 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2102 query = gst_query_new_duration (formats[i]);
2104 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2106 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2107 gst_query_unref (query);
2112 gst_play_bin_query (GstElement * element, GstQuery * query)
2114 GstPlayBin *playbin = GST_PLAY_BIN (element);
2117 /* During a group switch we shouldn't allow duration queries
2118 * because it's not clear if the old or new group's duration
2119 * is returned and if the sinks are already playing new data
2120 * or old data. See bug #585969
2122 * While we're at it, also don't do any other queries during
2123 * a group switch or any other event that causes topology changes
2124 * by taking the playbin lock in any case.
2126 GST_PLAY_BIN_LOCK (playbin);
2128 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2129 GstSourceGroup *group = playbin->curr_group;
2132 GST_SOURCE_GROUP_LOCK (group);
2133 if (group->stream_changed_pending_lock) {
2134 g_mutex_lock (group->stream_changed_pending_lock);
2135 pending = group->pending || group->stream_changed_pending;
2136 g_mutex_unlock (group->stream_changed_pending_lock);
2138 pending = group->pending;
2145 gst_query_parse_duration (query, &fmt, NULL);
2146 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2147 if (fmt == playbin->duration[i].format) {
2148 ret = playbin->duration[i].valid;
2149 gst_query_set_duration (query, fmt,
2150 (ret ? playbin->duration[i].duration : -1));
2154 /* if nothing cached yet, we might as well request duration,
2155 * such as during initial startup */
2157 GST_DEBUG_OBJECT (playbin,
2158 "Taking cached duration because of pending group switch: %d", ret);
2159 GST_SOURCE_GROUP_UNLOCK (group);
2160 GST_PLAY_BIN_UNLOCK (playbin);
2164 GST_SOURCE_GROUP_UNLOCK (group);
2167 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2169 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2170 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2171 GST_PLAY_BIN_UNLOCK (playbin);
2176 /* mime types we are not handling on purpose right now, don't post a
2177 * missing-plugin message for these */
2178 static const gchar *blacklisted_mimes[] = {
2183 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2185 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2186 GstSourceGroup *group;
2188 if (gst_is_missing_plugin_message (msg)) {
2192 detail = gst_missing_plugin_message_get_installer_detail (msg);
2193 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2194 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2195 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2196 gst_message_unref (msg);
2202 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2203 const GstStructure *s = gst_message_get_structure (msg);
2205 /* Drop all stream-changed messages except the last one */
2206 if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2207 guint32 seqnum = gst_message_get_seqnum (msg);
2210 group = playbin->curr_group;
2211 g_mutex_lock (group->stream_changed_pending_lock);
2212 for (l = group->stream_changed_pending; l;) {
2213 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2215 if (l_seqnum == seqnum) {
2218 group->stream_changed_pending =
2219 g_list_delete_link (group->stream_changed_pending, l_prev);
2220 if (group->stream_changed_pending) {
2221 gst_message_unref (msg);
2229 g_mutex_unlock (group->stream_changed_pending_lock);
2231 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2232 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2233 GstObject *src = GST_OBJECT_CAST (msg->src);
2235 /* Ignore async state changes from the uridecodebin children,
2236 * see bug #602000. */
2237 group = playbin->curr_group;
2238 if (src && (group = playbin->curr_group) &&
2239 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2240 || (group->suburidecodebin
2241 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2242 GST_DEBUG_OBJECT (playbin,
2243 "Ignoring async state change of uridecodebin: %s",
2244 GST_OBJECT_NAME (src));
2245 gst_message_unref (msg);
2248 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2249 /* If we get an error of the subtitle uridecodebin transform
2250 * them into warnings and disable the subtitles */
2251 group = playbin->curr_group;
2252 if (group && group->suburidecodebin) {
2253 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2254 (group->suburidecodebin)))) {
2256 gchar *debug = NULL;
2257 GstMessage *new_msg;
2259 gboolean done = FALSE;
2260 GValue item = { 0, };
2262 gst_message_parse_error (msg, &err, &debug);
2263 new_msg = gst_message_new_warning (msg->src, err, debug);
2265 gst_message_unref (msg);
2270 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2271 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2272 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2273 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2275 it = gst_element_iterate_src_pads (group->suburidecodebin);
2276 while (it && !done) {
2278 GstIteratorResult res;
2280 res = gst_iterator_next (it, &item);
2283 case GST_ITERATOR_DONE:
2286 case GST_ITERATOR_OK:
2287 p = g_value_get_object (&item);
2288 pad_removed_cb (NULL, p, group);
2289 g_value_reset (&item);
2292 case GST_ITERATOR_RESYNC:
2293 gst_iterator_resync (it);
2295 case GST_ITERATOR_ERROR:
2300 g_value_unset (&item);
2302 gst_iterator_free (it);
2304 gst_object_ref (group->suburidecodebin);
2305 gst_bin_remove (bin, group->suburidecodebin);
2306 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2308 if (group->sub_pending) {
2309 group->sub_pending = FALSE;
2310 no_more_pads_cb (NULL, group);
2317 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2321 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2322 GstPlayBin * playbin)
2324 const gchar *property;
2325 GstSourceGroup *group;
2326 GstSourceSelect *select = NULL;
2329 GST_PLAY_BIN_LOCK (playbin);
2330 group = get_group (playbin);
2332 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2333 if (selector == G_OBJECT (group->selector[i].selector)) {
2334 select = &group->selector[i];
2338 /* We got a pad-change after our group got switched out; no need to notify */
2340 GST_PLAY_BIN_UNLOCK (playbin);
2344 switch (select->type) {
2345 case GST_PLAY_SINK_TYPE_VIDEO:
2346 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2347 property = "current-video";
2348 playbin->current_video = get_current_stream_number (playbin,
2349 group->video_channels);
2351 case GST_PLAY_SINK_TYPE_AUDIO:
2352 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2353 property = "current-audio";
2354 playbin->current_audio = get_current_stream_number (playbin,
2355 group->audio_channels);
2357 case GST_PLAY_SINK_TYPE_TEXT:
2358 property = "current-text";
2359 playbin->current_text = get_current_stream_number (playbin,
2360 group->text_channels);
2365 GST_PLAY_BIN_UNLOCK (playbin);
2368 g_object_notify (G_OBJECT (playbin), property);
2372 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
2375 GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
2378 /* this callback sends a delayed event once the pad becomes unblocked */
2380 stream_changed_data_probe (GstPad * pad, GstMiniObject * object, gpointer data)
2382 GstSourceSelect *select = (GstSourceSelect *) data;
2385 /* we need do this just once, so cleanup first */
2386 gst_pad_remove_data_probe (pad, select->sinkpad_data_probe);
2387 select->sinkpad_data_probe = 0;
2388 e = select->sinkpad_delayed_event;
2389 select->sinkpad_delayed_event = NULL;
2391 /* really, this should not happen */
2393 GST_WARNING ("Data probed called, but no delayed event");
2397 if (GST_IS_EVENT (object)
2398 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_SEGMENT) {
2399 /* push the event first, then send the delayed one */
2400 gst_event_ref (GST_EVENT_CAST (object));
2401 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2402 gst_pad_send_event (pad, e);
2405 /* send delayed event, then allow the caller to go on */
2406 gst_pad_send_event (pad, e);
2411 /* helper function to lookup stuff in lists */
2413 array_has_value (const gchar * values[], const gchar * value)
2417 for (i = 0; values[i]; i++) {
2418 if (values[i] && g_str_has_prefix (value, values[i]))
2426 GstPlayBin *playbin;
2428 GstPlaySinkType type;
2432 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2434 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2437 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2438 " with stream id %d and type %d have changed",
2439 object, ntdata->stream_id, ntdata->type);
2441 switch (ntdata->type) {
2442 case GST_PLAY_SINK_TYPE_VIDEO:
2443 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2444 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2446 case GST_PLAY_SINK_TYPE_AUDIO:
2447 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2448 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2450 case GST_PLAY_SINK_TYPE_TEXT:
2451 signal = SIGNAL_TEXT_TAGS_CHANGED;
2459 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2463 /* this function is called when a new pad is added to decodebin. We check the
2464 * type of the pad and add it to the selector element of the group.
2467 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2469 GstPlayBin *playbin;
2471 const GstStructure *s;
2474 GstPadLinkReturn res;
2475 GstSourceSelect *select = NULL;
2477 gboolean changed = FALSE;
2479 playbin = group->playbin;
2481 caps = gst_pad_get_caps (pad, NULL);
2482 s = gst_caps_get_structure (caps, 0);
2483 name = gst_structure_get_name (s);
2485 GST_DEBUG_OBJECT (playbin,
2486 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2487 GST_DEBUG_PAD_NAME (pad), caps, group);
2489 /* major type of the pad, this determines the selector to use */
2490 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2491 if (array_has_value (group->selector[i].media_list, name)) {
2492 select = &group->selector[i];
2494 } else if (group->selector[i].get_media_caps) {
2495 GstCaps *media_caps = group->selector[i].get_media_caps ();
2497 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2498 select = &group->selector[i];
2499 gst_caps_unref (media_caps);
2502 gst_caps_unref (media_caps);
2505 /* no selector found for the media type, don't bother linking it to a
2506 * selector. This will leave the pad unlinked and thus ignored. */
2510 GST_SOURCE_GROUP_LOCK (group);
2511 if (select->selector == NULL && playbin->have_selector) {
2512 /* no selector, create one */
2513 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2514 select->selector = gst_element_factory_make ("input-selector", NULL);
2515 if (select->selector == NULL) {
2516 /* post the missing selector message only once */
2517 playbin->have_selector = FALSE;
2518 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2519 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2521 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2522 (_("Missing element '%s' - check your GStreamer installation."),
2523 "input-selector"), (NULL));
2525 g_object_set (select->selector, "sync-streams", TRUE, NULL);
2527 g_signal_connect (select->selector, "notify::active-pad",
2528 G_CALLBACK (selector_active_pad_changed), playbin);
2530 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2531 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2532 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2536 if (select->srcpad == NULL) {
2537 if (select->selector) {
2538 /* save source pad of the selector */
2539 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2541 /* no selector, use the pad as the source pad then */
2542 select->srcpad = gst_object_ref (pad);
2545 /* block the selector srcpad. It's possible that multiple decodebins start
2546 * pushing data into the selectors before we have a chance to collect all
2547 * streams and connect the sinks, resulting in not-linked errors. After we
2548 * configured the sinks we will unblock them all. */
2549 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2550 gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
2553 /* get sinkpad for the new stream */
2554 if (select->selector) {
2555 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2556 gulong notify_tags_handler = 0;
2557 NotifyTagsData *ntdata;
2559 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2560 GST_DEBUG_PAD_NAME (sinkpad));
2562 /* store the selector for the pad */
2563 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2565 /* connect to the notify::tags signal for our
2566 * own *-tags-changed signals
2568 ntdata = g_new0 (NotifyTagsData, 1);
2569 ntdata->playbin = playbin;
2570 ntdata->stream_id = select->channels->len;
2571 ntdata->type = select->type;
2573 notify_tags_handler =
2574 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2575 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2577 g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2578 (gpointer) notify_tags_handler);
2580 /* store the pad in the array */
2581 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2582 g_ptr_array_add (select->channels, sinkpad);
2584 res = gst_pad_link (pad, sinkpad);
2585 if (GST_PAD_LINK_FAILED (res))
2588 /* store selector pad so we can release it */
2589 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2592 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2593 GST_DEBUG_PAD_NAME (pad), select->selector);
2596 /* no selector, don't configure anything, we'll link the new pad directly to
2601 GST_SOURCE_GROUP_UNLOCK (group);
2605 gboolean always_ok = (decodebin == group->suburidecodebin);
2607 switch (select->type) {
2608 case GST_PLAY_SINK_TYPE_VIDEO:
2609 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2610 /* we want to return NOT_LINKED for unselected pads but only for pads
2611 * from the normal uridecodebin. This makes sure that subtitle streams
2612 * are not raced past audio/video from decodebin2's multiqueue.
2613 * For pads from suburidecodebin OK should always be returned, otherwise
2614 * it will most likely stop. */
2615 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2616 signal = SIGNAL_VIDEO_CHANGED;
2618 case GST_PLAY_SINK_TYPE_AUDIO:
2619 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2620 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2621 signal = SIGNAL_AUDIO_CHANGED;
2623 case GST_PLAY_SINK_TYPE_TEXT:
2624 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2625 signal = SIGNAL_TEXT_CHANGED;
2632 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2636 gst_caps_unref (caps);
2642 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2643 name, GST_DEBUG_PAD_NAME (pad));
2648 GST_ERROR_OBJECT (playbin,
2649 "failed to link pad %s:%s to selector, reason %d",
2650 GST_DEBUG_PAD_NAME (pad), res);
2651 GST_SOURCE_GROUP_UNLOCK (group);
2656 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2657 * the selector. This will make the selector select a new pad. */
2659 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2661 GstPlayBin *playbin;
2663 GstElement *selector;
2664 GstSourceSelect *select;
2666 playbin = group->playbin;
2668 GST_DEBUG_OBJECT (playbin,
2669 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2671 GST_SOURCE_GROUP_LOCK (group);
2672 /* get the selector sinkpad */
2673 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2676 if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2677 gulong notify_tags_handler;
2679 notify_tags_handler =
2680 (gulong) g_object_get_data (G_OBJECT (peer),
2681 "playbin2.notify_tags_handler");
2682 if (notify_tags_handler != 0)
2683 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2684 g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2686 /* remove the pad from the array */
2687 g_ptr_array_remove (select->channels, peer);
2688 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2691 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2692 gst_pad_unlink (pad, peer);
2694 /* get selector, this can be NULL when the element is removing the pads
2695 * because it's being disposed. */
2696 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2698 gst_object_unref (peer);
2702 /* release the pad to the selector, this will make the selector choose a new
2704 gst_element_release_request_pad (selector, peer);
2705 gst_object_unref (peer);
2707 gst_object_unref (selector);
2708 GST_SOURCE_GROUP_UNLOCK (group);
2715 GST_DEBUG_OBJECT (playbin, "pad not linked");
2716 GST_SOURCE_GROUP_UNLOCK (group);
2721 GST_DEBUG_OBJECT (playbin, "selector not found");
2722 GST_SOURCE_GROUP_UNLOCK (group);
2727 /* we get called when all pads are available and we must connect the sinks to
2729 * The main purpose of the code is to see if we have video/audio and subtitles
2730 * and pick the right pipelines to display them.
2732 * The selectors installed on the group tell us about the presence of
2733 * audio/video and subtitle streams. This allows us to see if we need
2734 * visualisation, video or/and audio.
2737 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2739 GstPlayBin *playbin;
2740 GstPadLinkReturn res;
2744 playbin = group->playbin;
2746 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2748 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2750 GST_SOURCE_GROUP_LOCK (group);
2751 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2752 GstSourceSelect *select = &group->selector[i];
2754 /* check if the specific media type was detected and thus has a selector
2755 * created for it. If there is the media type, get a sinkpad from the sink
2756 * and link it. We only do this if we have not yet requested the sinkpad
2758 if (select->srcpad && select->sinkpad == NULL) {
2759 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2761 gst_play_sink_request_pad (playbin->playsink, select->type);
2763 res = gst_pad_link (select->srcpad, select->sinkpad);
2764 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2765 select->media_list[0], res);
2766 if (res != GST_PAD_LINK_OK) {
2767 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2768 ("Internal playbin error."),
2769 ("Failed to link selector to sink. Error %d", res));
2773 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2774 group->pending - 1);
2776 if (group->pending > 0)
2779 if (group->suburidecodebin == decodebin)
2780 group->sub_pending = FALSE;
2782 if (group->pending == 0) {
2783 /* we are the last group to complete, we will configure the output and then
2784 * signal the other waiters. */
2785 GST_LOG_OBJECT (playbin, "last group complete");
2788 GST_LOG_OBJECT (playbin, "have more pending groups");
2791 GST_SOURCE_GROUP_UNLOCK (group);
2794 /* if we have custom sinks, configure them now */
2795 GST_SOURCE_GROUP_LOCK (group);
2797 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2799 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2802 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2804 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2807 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
2808 playbin->text_sink);
2809 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2810 playbin->text_sink);
2812 GST_SOURCE_GROUP_UNLOCK (group);
2814 /* signal the other decodebins that they can continue now. */
2815 GST_SOURCE_GROUP_LOCK (group);
2816 /* unblock all selectors */
2817 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2818 GstSourceSelect *select = &group->selector[i];
2820 /* All streamsynchronizer streams should see stream-changed message,
2821 * to arrange for blocking unblocking. */
2822 if (select->sinkpad) {
2828 s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2831 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2832 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2833 seqnum = gst_message_get_seqnum (msg);
2834 event = gst_event_new_sink_message (msg);
2835 g_mutex_lock (group->stream_changed_pending_lock);
2836 group->stream_changed_pending =
2837 g_list_prepend (group->stream_changed_pending,
2838 GUINT_TO_POINTER (seqnum));
2840 /* remove any data probe we might have, and replace */
2841 if (select->sinkpad_delayed_event)
2842 gst_event_unref (select->sinkpad_delayed_event);
2843 select->sinkpad_delayed_event = event;
2844 if (select->sinkpad_data_probe)
2845 gst_pad_remove_data_probe (select->sinkpad,
2846 select->sinkpad_data_probe);
2848 /* we go to the trouble of setting a probe on the pad to send
2849 the playbin2-stream-changed event as sending it here might
2850 find that the pad is blocked, so we'd block here, and the
2851 pad might not be linked yet. Additionally, sending it here
2852 apparently would be on the wrong thread */
2853 select->sinkpad_data_probe =
2854 gst_pad_add_data_probe (select->sinkpad,
2855 (GCallback) stream_changed_data_probe, (gpointer) select);
2857 g_mutex_unlock (group->stream_changed_pending_lock);
2858 gst_message_unref (msg);
2861 if (select->srcpad) {
2862 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2864 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2868 GST_SOURCE_GROUP_UNLOCK (group);
2871 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2877 GST_DEBUG ("ignoring, we are shutting down");
2878 /* Request a flushing pad from playsink that we then link to the selector.
2879 * Then we unblock the selectors so that they stop with a WRONG_STATE
2880 * instead of a NOT_LINKED error.
2882 GST_SOURCE_GROUP_LOCK (group);
2883 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2884 GstSourceSelect *select = &group->selector[i];
2886 if (select->srcpad) {
2887 if (select->sinkpad == NULL) {
2888 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2890 gst_play_sink_request_pad (playbin->playsink,
2891 GST_PLAY_SINK_TYPE_FLUSHING);
2892 res = gst_pad_link (select->srcpad, select->sinkpad);
2893 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2895 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2897 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2901 GST_SOURCE_GROUP_UNLOCK (group);
2907 drained_cb (GstElement * decodebin, GstSourceGroup * group)
2909 GstPlayBin *playbin;
2911 playbin = group->playbin;
2913 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
2915 /* after this call, we should have a next group to activate or we EOS */
2916 g_signal_emit (G_OBJECT (playbin),
2917 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
2919 /* now activate the next group. If the app did not set a uri, this will
2920 * fail and we can do EOS */
2921 setup_next_source (playbin, GST_STATE_PAUSED);
2924 /* Called when we must provide a list of factories to plug to @pad with @caps.
2925 * We first check if we have a sink that can handle the format and if we do, we
2926 * return NULL, to expose the pad. If we have no sink (or the sink does not
2927 * work), we return the list of elements that can connect. */
2928 static GValueArray *
2929 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
2930 GstCaps * caps, GstSourceGroup * group)
2932 GstPlayBin *playbin;
2933 GList *mylist, *tmp;
2934 GValueArray *result;
2936 playbin = group->playbin;
2938 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
2939 group, GST_DEBUG_PAD_NAME (pad), caps);
2941 /* filter out the elements based on the caps. */
2942 g_mutex_lock (playbin->elements_lock);
2943 gst_play_bin_update_elements_list (playbin);
2945 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
2947 g_mutex_unlock (playbin->elements_lock);
2949 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
2950 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
2952 result = g_value_array_new (g_list_length (mylist));
2954 for (tmp = mylist; tmp; tmp = tmp->next) {
2955 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
2956 GValue val = { 0, };
2958 g_value_init (&val, G_TYPE_OBJECT);
2959 g_value_set_object (&val, factory);
2960 g_value_array_append (result, &val);
2961 g_value_unset (&val);
2963 gst_plugin_feature_list_free (mylist);
2968 /* autoplug-continue decides, if a pad has raw caps that can be exposed
2969 * directly or if further decoding is necessary. We use this to expose
2970 * supported subtitles directly */
2972 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
2973 * explicitely the caps it supports and if it claims to support ANY
2974 * caps it really should support everything */
2976 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
2977 GstSourceGroup * group)
2979 gboolean ret = TRUE;
2981 GstPad *sinkpad = NULL;
2983 GST_PLAY_BIN_LOCK (group->playbin);
2984 GST_SOURCE_GROUP_LOCK (group);
2986 if ((sink = group->playbin->text_sink))
2987 sinkpad = gst_element_get_static_pad (sink, "sink");
2991 /* Ignore errors here, if a custom sink fails to go
2992 * to READY things are wrong and will error out later
2994 if (GST_STATE (sink) < GST_STATE_READY)
2995 gst_element_set_state (sink, GST_STATE_READY);
2997 sinkcaps = gst_pad_get_caps (sinkpad, NULL);
2998 if (!gst_caps_is_any (sinkcaps))
2999 ret = !gst_pad_accept_caps (sinkpad, caps);
3000 gst_caps_unref (sinkcaps);
3001 gst_object_unref (sinkpad);
3003 GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3004 ret = !gst_caps_can_intersect (caps, subcaps);
3005 gst_caps_unref (subcaps);
3007 /* If autoplugging can stop don't do additional checks */
3011 /* If this is from the subtitle uridecodebin we don't need to
3012 * check the audio and video sink */
3013 if (group->suburidecodebin
3014 && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3015 GST_OBJECT_CAST (group->suburidecodebin)))
3018 if ((sink = group->audio_sink)) {
3019 sinkpad = gst_element_get_static_pad (sink, "sink");
3023 /* Ignore errors here, if a custom sink fails to go
3024 * to READY things are wrong and will error out later
3026 if (GST_STATE (sink) < GST_STATE_READY)
3027 gst_element_set_state (sink, GST_STATE_READY);
3029 sinkcaps = gst_pad_get_caps (sinkpad, NULL);
3030 if (!gst_caps_is_any (sinkcaps))
3031 ret = !gst_pad_accept_caps (sinkpad, caps);
3032 gst_caps_unref (sinkcaps);
3033 gst_object_unref (sinkpad);
3039 if ((sink = group->video_sink)) {
3040 sinkpad = gst_element_get_static_pad (sink, "sink");
3044 /* Ignore errors here, if a custom sink fails to go
3045 * to READY things are wrong and will error out later
3047 if (GST_STATE (sink) < GST_STATE_READY)
3048 gst_element_set_state (sink, GST_STATE_READY);
3050 sinkcaps = gst_pad_get_caps (sinkpad, NULL);
3051 if (!gst_caps_is_any (sinkcaps))
3052 ret = !gst_pad_accept_caps (sinkpad, caps);
3053 gst_caps_unref (sinkcaps);
3054 gst_object_unref (sinkpad);
3059 GST_SOURCE_GROUP_UNLOCK (group);
3060 GST_PLAY_BIN_UNLOCK (group->playbin);
3062 GST_DEBUG_OBJECT (group->playbin,
3063 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3064 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3070 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3074 /* ... activate it ... We do this before adding it to the bin so that we
3075 * don't accidentally make it post error messages that will stop
3077 if (GST_STATE (sink) < GST_STATE_READY &&
3078 gst_element_set_state (sink,
3079 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3083 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3084 /* Got the sink pad, now let's see if the element actually does accept the
3085 * caps that we have */
3086 if (!gst_pad_accept_caps (sinkpad, caps)) {
3087 gst_object_unref (sinkpad);
3090 gst_object_unref (sinkpad);
3096 /* We are asked to select an element. See if the next element to check
3097 * is a sink. If this is the case, we see if the sink works by setting it to
3098 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3099 * expose the raw pad so that we can setup the mixers. */
3100 static GstAutoplugSelectResult
3101 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3102 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3104 GstPlayBin *playbin;
3105 GstElement *element;
3107 GstPlaySinkType type;
3110 playbin = group->playbin;
3112 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3113 group, GST_DEBUG_PAD_NAME (pad), caps);
3115 GST_DEBUG_OBJECT (playbin, "checking factory %s", GST_OBJECT_NAME (factory));
3117 /* if it's not a sink, we just make decodebin try it */
3118 if (!gst_element_factory_list_is_type (factory,
3119 GST_ELEMENT_FACTORY_TYPE_SINK))
3120 return GST_AUTOPLUG_SELECT_TRY;
3122 /* it's a sink, see if an instance of it actually works */
3123 GST_DEBUG_OBJECT (playbin, "we found a sink");
3125 klass = gst_element_factory_get_klass (factory);
3127 /* figure out the klass */
3128 if (strstr (klass, "Audio")) {
3129 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3130 type = GST_PLAY_SINK_TYPE_AUDIO;
3131 sinkp = &group->audio_sink;
3132 } else if (strstr (klass, "Video")) {
3133 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3134 type = GST_PLAY_SINK_TYPE_VIDEO;
3135 sinkp = &group->video_sink;
3137 /* unknown klass, skip this element */
3138 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3139 return GST_AUTOPLUG_SELECT_SKIP;
3142 /* if we are asked to do visualisations and it's an audio sink, skip the
3143 * element. We can only do visualisations with raw sinks */
3144 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3145 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3146 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3147 return GST_AUTOPLUG_SELECT_SKIP;
3151 /* now see if we already have a sink element */
3152 GST_SOURCE_GROUP_LOCK (group);
3154 GstElement *sink = gst_object_ref (*sinkp);
3156 if (sink_accepts_caps (sink, caps)) {
3157 GST_DEBUG_OBJECT (playbin,
3158 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3159 GST_ELEMENT_NAME (sink), caps);
3160 gst_object_unref (sink);
3161 GST_SOURCE_GROUP_UNLOCK (group);
3162 return GST_AUTOPLUG_SELECT_EXPOSE;
3164 GST_DEBUG_OBJECT (playbin,
3165 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3166 GST_ELEMENT_NAME (sink), caps);
3167 gst_object_unref (sink);
3168 GST_SOURCE_GROUP_UNLOCK (group);
3169 return GST_AUTOPLUG_SELECT_SKIP;
3172 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3174 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3175 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3176 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3177 GST_SOURCE_GROUP_UNLOCK (group);
3178 return GST_AUTOPLUG_SELECT_SKIP;
3181 /* Check if the selected sink actually supports the
3182 * caps and can be set to READY*/
3183 if (!sink_accepts_caps (element, caps)) {
3184 gst_element_set_state (element, GST_STATE_NULL);
3185 gst_object_unref (element);
3186 GST_SOURCE_GROUP_UNLOCK (group);
3187 return GST_AUTOPLUG_SELECT_SKIP;
3190 /* remember the sink in the group now, the element is floating, we take
3193 * store the sink in the group, we will configure it later when we
3194 * reconfigure the sink */
3195 GST_DEBUG_OBJECT (playbin, "remember sink");
3196 gst_object_ref_sink (element);
3198 GST_SOURCE_GROUP_UNLOCK (group);
3200 /* tell decodebin to expose the pad because we are going to use this
3202 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3204 return GST_AUTOPLUG_SELECT_EXPOSE;
3208 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3209 GstSourceGroup * group)
3211 GstPlayBin *playbin;
3214 playbin = group->playbin;
3216 g_object_get (group->uridecodebin, "source", &source, NULL);
3218 GST_OBJECT_LOCK (playbin);
3219 if (playbin->source)
3220 gst_object_unref (playbin->source);
3221 playbin->source = source;
3222 GST_OBJECT_UNLOCK (playbin);
3224 g_object_notify (G_OBJECT (playbin), "source");
3226 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3227 0, playbin->source);
3230 /* must be called with the group lock */
3232 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3235 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3237 if (group->uridecodebin)
3238 gst_element_set_locked_state (group->uridecodebin, locked);
3239 if (group->suburidecodebin)
3240 gst_element_set_locked_state (group->suburidecodebin, locked);
3245 /* must be called with PLAY_BIN_LOCK */
3247 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3249 GstElement *uridecodebin;
3250 GstElement *suburidecodebin = NULL;
3253 g_return_val_if_fail (group->valid, FALSE);
3254 g_return_val_if_fail (!group->active, FALSE);
3256 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3258 GST_SOURCE_GROUP_LOCK (group);
3260 /* First set up the custom sources */
3261 if (playbin->audio_sink)
3262 group->audio_sink = gst_object_ref (playbin->audio_sink);
3263 if (playbin->video_sink)
3264 group->video_sink = gst_object_ref (playbin->video_sink);
3266 g_list_free (group->stream_changed_pending);
3267 group->stream_changed_pending = NULL;
3268 if (!group->stream_changed_pending_lock)
3269 group->stream_changed_pending_lock = g_mutex_new ();
3271 if (group->uridecodebin) {
3272 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3273 uridecodebin = group->uridecodebin;
3274 gst_element_set_state (uridecodebin, GST_STATE_READY);
3275 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3277 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3278 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3281 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3282 group->uridecodebin = gst_object_ref (uridecodebin);
3285 flags = gst_play_sink_get_flags (playbin->playsink);
3287 g_object_set (uridecodebin,
3288 /* configure connection speed */
3289 "connection-speed", playbin->connection_speed / 1000,
3292 /* configure download buffering */
3293 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3294 /* configure buffering of demuxed/parsed data */
3295 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3296 /* configure buffering parameters */
3297 "buffer-duration", playbin->buffer_duration,
3298 "buffer-size", playbin->buffer_size,
3299 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3301 /* connect pads and other things */
3302 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3303 G_CALLBACK (pad_added_cb), group);
3304 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3305 G_CALLBACK (pad_removed_cb), group);
3306 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3307 G_CALLBACK (no_more_pads_cb), group);
3308 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3309 G_CALLBACK (notify_source_cb), group);
3311 /* we have 1 pending no-more-pads */
3314 /* is called when the uridecodebin is out of data and we can switch to the
3317 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3320 /* will be called when a new media type is found. We return a list of decoders
3321 * including sinks for decodebin to try */
3322 group->autoplug_factories_id =
3323 g_signal_connect (uridecodebin, "autoplug-factories",
3324 G_CALLBACK (autoplug_factories_cb), group);
3325 group->autoplug_select_id =
3326 g_signal_connect (uridecodebin, "autoplug-select",
3327 G_CALLBACK (autoplug_select_cb), group);
3328 group->autoplug_continue_id =
3329 g_signal_connect (uridecodebin, "autoplug-continue",
3330 G_CALLBACK (autoplug_continue_cb), group);
3332 if (group->suburi) {
3334 if (group->suburidecodebin) {
3335 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3336 suburidecodebin = group->suburidecodebin;
3337 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3338 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3340 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3341 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3342 if (!suburidecodebin)
3345 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3346 group->suburidecodebin = gst_object_ref (suburidecodebin);
3349 g_object_set (suburidecodebin,
3350 /* configure connection speed */
3351 "connection-speed", playbin->connection_speed,
3353 "uri", group->suburi, NULL);
3355 /* connect pads and other things */
3356 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3357 G_CALLBACK (pad_added_cb), group);
3358 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3359 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3360 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3361 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3363 group->sub_autoplug_continue_id =
3364 g_signal_connect (suburidecodebin, "autoplug-continue",
3365 G_CALLBACK (autoplug_continue_cb), group);
3367 /* we have 2 pending no-more-pads */
3369 group->sub_pending = TRUE;
3371 group->sub_pending = FALSE;
3374 /* release the group lock before setting the state of the decodebins, they
3375 * might fire signals in this thread that we need to handle with the
3376 * group_lock taken. */
3377 GST_SOURCE_GROUP_UNLOCK (group);
3379 if (suburidecodebin) {
3380 if (gst_element_set_state (suburidecodebin,
3381 target) == GST_STATE_CHANGE_FAILURE) {
3382 GST_DEBUG_OBJECT (playbin,
3383 "failed state change of subtitle uridecodebin");
3384 GST_SOURCE_GROUP_LOCK (group);
3386 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3387 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3388 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3389 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3390 /* Might already be removed because of an error message */
3391 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3392 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3393 if (group->sub_pending) {
3395 group->sub_pending = FALSE;
3397 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3398 GST_SOURCE_GROUP_UNLOCK (group);
3401 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3402 goto uridecodebin_failure;
3404 GST_SOURCE_GROUP_LOCK (group);
3405 /* alow state changes of the playbin2 affect the group elements now */
3406 group_set_locked_state_unlocked (playbin, group, FALSE);
3407 group->active = TRUE;
3408 GST_SOURCE_GROUP_UNLOCK (group);
3417 /* delete any custom sinks we might have */
3418 if (group->audio_sink) {
3419 /* If this is a automatically created sink set it to NULL */
3420 if (group->audio_sink != playbin->audio_sink)
3421 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3422 gst_object_unref (group->audio_sink);
3424 group->audio_sink = NULL;
3425 if (group->video_sink) {
3426 /* If this is a automatically created sink set it to NULL */
3427 if (group->video_sink != playbin->video_sink)
3428 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3429 gst_object_unref (group->video_sink);
3431 group->video_sink = NULL;
3433 GST_SOURCE_GROUP_UNLOCK (group);
3435 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3437 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3439 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3440 (_("Could not create \"uridecodebin\" element.")), (NULL));
3443 uridecodebin_failure:
3445 /* delete any custom sinks we might have */
3446 if (group->audio_sink) {
3447 /* If this is a automatically created sink set it to NULL */
3448 if (group->audio_sink != playbin->audio_sink)
3449 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3450 gst_object_unref (group->audio_sink);
3452 group->audio_sink = NULL;
3453 if (group->video_sink) {
3454 /* If this is a automatically created sink set it to NULL */
3455 if (group->video_sink != playbin->video_sink)
3456 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3457 gst_object_unref (group->video_sink);
3459 group->video_sink = NULL;
3461 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3466 /* unlink a group of uridecodebins from the sink.
3467 * must be called with PLAY_BIN_LOCK */
3469 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3473 g_return_val_if_fail (group->valid, FALSE);
3474 g_return_val_if_fail (group->active, FALSE);
3476 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3478 GST_SOURCE_GROUP_LOCK (group);
3479 group->active = FALSE;
3480 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3481 GstSourceSelect *select = &group->selector[i];
3483 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3485 if (select->srcpad) {
3486 if (select->sinkpad) {
3487 GST_LOG_OBJECT (playbin, "unlinking from sink");
3488 gst_pad_unlink (select->srcpad, select->sinkpad);
3491 GST_LOG_OBJECT (playbin, "release sink pad");
3492 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3493 select->sinkpad = NULL;
3496 gst_object_unref (select->srcpad);
3497 select->srcpad = NULL;
3500 if (select->selector) {
3503 /* release and unref requests pad from the selector */
3504 for (n = 0; n < select->channels->len; n++) {
3505 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3507 gst_element_release_request_pad (select->selector, sinkpad);
3508 gst_object_unref (sinkpad);
3510 g_ptr_array_set_size (select->channels, 0);
3512 gst_element_set_state (select->selector, GST_STATE_NULL);
3513 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3514 select->selector = NULL;
3517 /* delete any custom sinks we might have */
3518 if (group->audio_sink) {
3519 /* If this is a automatically created sink set it to NULL */
3520 if (group->audio_sink != playbin->audio_sink)
3521 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3522 gst_object_unref (group->audio_sink);
3524 group->audio_sink = NULL;
3525 if (group->video_sink) {
3526 /* If this is a automatically created sink set it to NULL */
3527 if (group->video_sink != playbin->video_sink)
3528 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3529 gst_object_unref (group->video_sink);
3531 group->video_sink = NULL;
3533 if (group->uridecodebin) {
3534 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3535 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3536 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3537 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3538 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3539 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3540 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3541 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3542 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3545 if (group->suburidecodebin) {
3546 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3547 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3548 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3549 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3551 /* Might already be removed because of errors */
3552 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3553 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3556 GST_SOURCE_GROUP_UNLOCK (group);
3561 /* setup the next group to play, this assumes the next_group is valid and
3562 * configured. It swaps out the current_group and activates the valid
3565 setup_next_source (GstPlayBin * playbin, GstState target)
3567 GstSourceGroup *new_group, *old_group;
3569 GST_DEBUG_OBJECT (playbin, "setup sources");
3571 /* see if there is a next group */
3572 GST_PLAY_BIN_LOCK (playbin);
3573 new_group = playbin->next_group;
3574 if (!new_group || !new_group->valid)
3577 /* first unlink the current source, if any */
3578 old_group = playbin->curr_group;
3579 if (old_group && old_group->valid && old_group->active) {
3580 gst_play_bin_update_cached_duration (playbin);
3581 /* unlink our pads with the sink */
3582 deactivate_group (playbin, old_group);
3583 old_group->valid = FALSE;
3586 /* swap old and new */
3587 playbin->curr_group = new_group;
3588 playbin->next_group = old_group;
3590 /* activate the new group */
3591 if (!activate_group (playbin, new_group, target))
3592 goto activate_failed;
3594 GST_PLAY_BIN_UNLOCK (playbin);
3601 GST_DEBUG_OBJECT (playbin, "no next group");
3602 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3603 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3604 GST_PLAY_BIN_UNLOCK (playbin);
3609 GST_DEBUG_OBJECT (playbin, "activate failed");
3610 GST_PLAY_BIN_UNLOCK (playbin);
3615 /* The group that is currently playing is copied again to the
3616 * next_group so that it will start playing the next time.
3619 save_current_group (GstPlayBin * playbin)
3621 GstSourceGroup *curr_group;
3623 GST_DEBUG_OBJECT (playbin, "save current group");
3625 /* see if there is a current group */
3626 GST_PLAY_BIN_LOCK (playbin);
3627 curr_group = playbin->curr_group;
3628 if (curr_group && curr_group->valid) {
3629 /* unlink our pads with the sink */
3630 deactivate_group (playbin, curr_group);
3632 /* swap old and new */
3633 playbin->curr_group = playbin->next_group;
3634 playbin->next_group = curr_group;
3635 GST_PLAY_BIN_UNLOCK (playbin);
3640 /* clear the locked state from all groups. This function is called before a
3641 * state change to NULL is performed on them. */
3643 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3645 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3648 GST_PLAY_BIN_LOCK (playbin);
3649 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3650 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3651 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3652 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3653 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3654 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3655 GST_PLAY_BIN_UNLOCK (playbin);
3660 static GstStateChangeReturn
3661 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3663 GstStateChangeReturn ret;
3664 GstPlayBin *playbin;
3665 gboolean do_save = FALSE;
3667 playbin = GST_PLAY_BIN (element);
3669 switch (transition) {
3670 case GST_STATE_CHANGE_NULL_TO_READY:
3671 memset (&playbin->duration, 0, sizeof (playbin->duration));
3673 case GST_STATE_CHANGE_READY_TO_PAUSED:
3674 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3675 memset (&playbin->duration, 0, sizeof (playbin->duration));
3676 g_atomic_int_set (&playbin->shutdown, 0);
3678 if (!setup_next_source (playbin, GST_STATE_READY)) {
3679 ret = GST_STATE_CHANGE_FAILURE;
3683 case GST_STATE_CHANGE_PAUSED_TO_READY:
3685 /* FIXME unlock our waiting groups */
3686 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3687 g_atomic_int_set (&playbin->shutdown, 1);
3688 memset (&playbin->duration, 0, sizeof (playbin->duration));
3690 /* wait for all callbacks to end by taking the lock.
3691 * No dynamic (critical) new callbacks will
3692 * be able to happen as we set the shutdown flag. */
3693 GST_PLAY_BIN_DYN_LOCK (playbin);
3694 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3695 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3698 case GST_STATE_CHANGE_READY_TO_NULL:
3699 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3700 * an no state change PAUSED to READY passes here,
3701 * though it is a nice-to-have ... */
3702 if (!g_atomic_int_get (&playbin->shutdown)) {
3706 memset (&playbin->duration, 0, sizeof (playbin->duration));
3708 /* unlock so that all groups go to NULL */
3709 groups_set_locked_state (playbin, FALSE);
3715 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3716 if (ret == GST_STATE_CHANGE_FAILURE)
3719 switch (transition) {
3720 case GST_STATE_CHANGE_READY_TO_PAUSED:
3722 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3723 /* FIXME Release audio device when we implement that */
3725 case GST_STATE_CHANGE_PAUSED_TO_READY:
3726 save_current_group (playbin);
3728 case GST_STATE_CHANGE_READY_TO_NULL:
3732 /* also do missed state change down to READY */
3734 save_current_group (playbin);
3735 /* Deactive the groups, set the uridecodebins to NULL
3738 for (i = 0; i < 2; i++) {
3739 if (playbin->groups[i].active && playbin->groups[i].valid) {
3740 deactivate_group (playbin, &playbin->groups[i]);
3741 playbin->groups[i].valid = FALSE;
3744 if (playbin->groups[i].uridecodebin) {
3745 gst_element_set_state (playbin->groups[i].uridecodebin,
3747 gst_object_unref (playbin->groups[i].uridecodebin);
3748 playbin->groups[i].uridecodebin = NULL;
3751 if (playbin->groups[i].suburidecodebin) {
3752 gst_element_set_state (playbin->groups[i].suburidecodebin,
3754 gst_object_unref (playbin->groups[i].suburidecodebin);
3755 playbin->groups[i].suburidecodebin = NULL;
3759 /* Set our sinks back to NULL, they might not be child of playbin */
3760 if (playbin->audio_sink)
3761 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
3762 if (playbin->video_sink)
3763 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
3764 if (playbin->text_sink)
3765 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
3767 /* make sure the groups don't perform a state change anymore until we
3768 * enable them again */
3769 groups_set_locked_state (playbin, TRUE);
3781 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
3782 GstSourceGroup *curr_group;
3784 curr_group = playbin->curr_group;
3785 if (curr_group && curr_group->active && curr_group->valid) {
3786 /* unlink our pads with the sink */
3787 deactivate_group (playbin, curr_group);
3788 curr_group->valid = FALSE;
3791 /* Swap current and next group back */
3792 playbin->curr_group = playbin->next_group;
3793 playbin->next_group = curr_group;
3800 gst_play_bin2_plugin_init (GstPlugin * plugin)
3802 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
3804 return gst_element_register (plugin, "playbin2", GST_RANK_NONE,