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;
272 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
273 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
274 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
278 PLAYBIN_STREAM_AUDIO = 0,
279 PLAYBIN_STREAM_VIDEO,
284 /* a structure to hold the objects for decoding a uri and the subtitle uri
286 struct _GstSourceGroup
292 gboolean valid; /* the group has valid info to start playback */
293 gboolean active; /* the group is active */
298 GValueArray *streaminfo;
301 GPtrArray *video_channels; /* links to selector pads */
302 GPtrArray *audio_channels; /* links to selector pads */
303 GPtrArray *text_channels; /* links to selector pads */
305 GstElement *audio_sink; /* autoplugged audio and video sinks */
306 GstElement *video_sink;
308 /* uridecodebins for uri and subtitle uri */
309 GstElement *uridecodebin;
310 GstElement *suburidecodebin;
312 gboolean sub_pending;
315 gulong pad_removed_id;
316 gulong no_more_pads_id;
317 gulong notify_source_id;
319 gulong autoplug_factories_id;
320 gulong autoplug_select_id;
321 gulong autoplug_continue_id;
323 gulong sub_pad_added_id;
324 gulong sub_pad_removed_id;
325 gulong sub_no_more_pads_id;
326 gulong sub_autoplug_continue_id;
330 GMutex *stream_changed_pending_lock;
331 GList *stream_changed_pending;
333 /* selectors for different streams */
334 GstSourceSelect selector[PLAYBIN_STREAM_LAST];
337 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
338 #define GST_PLAY_BIN_LOCK(bin) (g_static_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
339 #define GST_PLAY_BIN_UNLOCK(bin) (g_static_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
341 /* lock to protect dynamic callbacks, like no-more-pads */
342 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->dyn_lock)
343 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->dyn_lock)
345 /* lock for shutdown */
346 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
348 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
350 GST_PLAY_BIN_DYN_LOCK (bin); \
351 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
352 GST_PLAY_BIN_DYN_UNLOCK (bin); \
357 /* unlock for shutdown */
358 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
359 GST_PLAY_BIN_DYN_UNLOCK (bin); \
364 * playbin element structure
370 GStaticRecMutex lock; /* to protect group switching */
372 /* the groups, we use a double buffer to switch between current and next */
373 GstSourceGroup groups[2]; /* array with group info */
374 GstSourceGroup *curr_group; /* pointer to the currently playing group */
375 GstSourceGroup *next_group; /* pointer to the next group */
378 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
379 gint current_video; /* the currently selected stream */
380 gint current_audio; /* the currently selected stream */
381 gint current_text; /* the currently selected stream */
383 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
384 guint buffer_size; /* When buffering, the max buffer size (bytes) */
387 GstPlaySink *playsink;
389 /* the last activated source */
392 /* lock protecting dynamic adding/removing */
394 /* if we are shutting down or not */
397 GMutex *elements_lock;
398 guint32 elements_cookie;
399 GList *elements; /* factories we can use for selecting elements */
401 gboolean have_selector; /* set to FALSE when we fail to create an
402 * input-selector, so that we only post a
405 GstElement *audio_sink; /* configured audio sink, or NULL */
406 GstElement *video_sink; /* configured video sink, or NULL */
407 GstElement *text_sink; /* configured text sink, or NULL */
414 } duration[5]; /* cached durations */
416 guint64 ring_buffer_max_size; /* 0 means disabled */
419 struct _GstPlayBinClass
421 GstPipelineClass parent_class;
423 /* notify app that the current uri finished decoding and it is possible to
424 * queue a new one for gapless playback */
425 void (*about_to_finish) (GstPlayBin * playbin);
427 /* notify app that number of audio/video/text streams changed */
428 void (*video_changed) (GstPlayBin * playbin);
429 void (*audio_changed) (GstPlayBin * playbin);
430 void (*text_changed) (GstPlayBin * playbin);
432 /* notify app that the tags of audio/video/text streams changed */
433 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
434 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
435 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
437 /* get audio/video/text tags for a stream */
438 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
439 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
440 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
442 /* get the last video frame and convert it to the given caps */
443 GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
445 /* get audio/video/text pad for a stream */
446 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
447 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
448 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
452 #define DEFAULT_URI NULL
453 #define DEFAULT_SUBURI NULL
454 #define DEFAULT_SOURCE NULL
455 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
456 GST_PLAY_FLAG_SOFT_VOLUME
457 #define DEFAULT_N_VIDEO 0
458 #define DEFAULT_CURRENT_VIDEO -1
459 #define DEFAULT_N_AUDIO 0
460 #define DEFAULT_CURRENT_AUDIO -1
461 #define DEFAULT_N_TEXT 0
462 #define DEFAULT_CURRENT_TEXT -1
463 #define DEFAULT_SUBTITLE_ENCODING NULL
464 #define DEFAULT_AUDIO_SINK NULL
465 #define DEFAULT_VIDEO_SINK NULL
466 #define DEFAULT_VIS_PLUGIN NULL
467 #define DEFAULT_TEXT_SINK NULL
468 #define DEFAULT_VOLUME 1.0
469 #define DEFAULT_MUTE FALSE
470 #define DEFAULT_FRAME NULL
471 #define DEFAULT_FONT_DESC NULL
472 #define DEFAULT_CONNECTION_SPEED 0
473 #define DEFAULT_BUFFER_DURATION -1
474 #define DEFAULT_BUFFER_SIZE -1
475 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
490 PROP_SUBTITLE_ENCODING,
499 PROP_CONNECTION_SPEED,
501 PROP_BUFFER_DURATION,
503 PROP_RING_BUFFER_MAX_SIZE,
510 SIGNAL_ABOUT_TO_FINISH,
511 SIGNAL_CONVERT_FRAME,
512 SIGNAL_VIDEO_CHANGED,
513 SIGNAL_AUDIO_CHANGED,
515 SIGNAL_VIDEO_TAGS_CHANGED,
516 SIGNAL_AUDIO_TAGS_CHANGED,
517 SIGNAL_TEXT_TAGS_CHANGED,
518 SIGNAL_GET_VIDEO_TAGS,
519 SIGNAL_GET_AUDIO_TAGS,
520 SIGNAL_GET_TEXT_TAGS,
521 SIGNAL_GET_VIDEO_PAD,
522 SIGNAL_GET_AUDIO_PAD,
528 static void gst_play_bin_class_init (GstPlayBinClass * klass);
529 static void gst_play_bin_init (GstPlayBin * playbin);
530 static void gst_play_bin_finalize (GObject * object);
532 static void gst_play_bin_set_property (GObject * object, guint prop_id,
533 const GValue * value, GParamSpec * spec);
534 static void gst_play_bin_get_property (GObject * object, guint prop_id,
535 GValue * value, GParamSpec * spec);
537 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
538 GstStateChange transition);
540 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
541 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
543 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
545 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
547 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
550 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
553 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
554 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
555 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
557 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
559 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
560 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
561 GstSourceGroup * group);
563 static void gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
564 GstElement * suburidecodebin, gboolean block);
565 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
568 static GstElementClass *parent_class;
570 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
572 #define REMOVE_SIGNAL(obj,id) \
574 g_signal_handler_disconnect (obj, id); \
579 gst_play_bin_get_type (void)
581 static GType gst_play_bin_type = 0;
583 if (!gst_play_bin_type) {
584 static const GTypeInfo gst_play_bin_info = {
585 sizeof (GstPlayBinClass),
588 (GClassInitFunc) gst_play_bin_class_init,
593 (GInstanceInitFunc) gst_play_bin_init,
596 static const GInterfaceInfo svol_info = {
600 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
601 "GstPlayBin2", &gst_play_bin_info, 0);
603 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
607 return gst_play_bin_type;
611 gst_play_bin_class_init (GstPlayBinClass * klass)
613 GObjectClass *gobject_klass;
614 GstElementClass *gstelement_klass;
615 GstBinClass *gstbin_klass;
617 gobject_klass = (GObjectClass *) klass;
618 gstelement_klass = (GstElementClass *) klass;
619 gstbin_klass = (GstBinClass *) klass;
621 parent_class = g_type_class_peek_parent (klass);
623 gobject_klass->set_property = gst_play_bin_set_property;
624 gobject_klass->get_property = gst_play_bin_get_property;
626 gobject_klass->finalize = gst_play_bin_finalize;
631 * Set the next URI that playbin will play. This property can be set from the
632 * about-to-finish signal to queue the next media file.
634 g_object_class_install_property (gobject_klass, PROP_URI,
635 g_param_spec_string ("uri", "URI", "URI of the media to play",
636 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
641 * Set the next subtitle URI that playbin will play. This property can be
642 * set from the about-to-finish signal to queue the next subtitle media file.
644 g_object_class_install_property (gobject_klass, PROP_SUBURI,
645 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
646 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
648 g_object_class_install_property (gobject_klass, PROP_SOURCE,
649 g_param_spec_object ("source", "Source", "Source element",
650 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
655 * Control the behaviour of playbin.
657 g_object_class_install_property (gobject_klass, PROP_FLAGS,
658 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
659 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
660 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
663 * GstPlayBin2:n-video
665 * Get the total number of available video streams.
667 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
668 g_param_spec_int ("n-video", "Number Video",
669 "Total number of video streams", 0, G_MAXINT, 0,
670 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
672 * GstPlayBin2:current-video
674 * Get or set the currently playing video stream. By default the first video
675 * stream with data is played.
677 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
678 g_param_spec_int ("current-video", "Current Video",
679 "Currently playing video stream (-1 = auto)",
680 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
682 * GstPlayBin2:n-audio
684 * Get the total number of available audio streams.
686 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
687 g_param_spec_int ("n-audio", "Number Audio",
688 "Total number of audio streams", 0, G_MAXINT, 0,
689 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
691 * GstPlayBin2:current-audio
693 * Get or set the currently playing audio stream. By default the first audio
694 * stream with data is played.
696 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
697 g_param_spec_int ("current-audio", "Current audio",
698 "Currently playing audio stream (-1 = auto)",
699 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
703 * Get the total number of available subtitle streams.
705 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
706 g_param_spec_int ("n-text", "Number Text",
707 "Total number of text streams", 0, G_MAXINT, 0,
708 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
710 * GstPlayBin2:current-text:
712 * Get or set the currently playing subtitle stream. By default the first
713 * subtitle stream with data is played.
715 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
716 g_param_spec_int ("current-text", "Current Text",
717 "Currently playing text stream (-1 = auto)",
718 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
720 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
721 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
722 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
723 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
724 "be checked for an encoding to use. If that is not set either, "
725 "ISO-8859-15 will be assumed.", NULL,
726 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
728 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
729 g_param_spec_object ("video-sink", "Video Sink",
730 "the video output element to use (NULL = default sink)",
731 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
732 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
733 g_param_spec_object ("audio-sink", "Audio Sink",
734 "the audio output element to use (NULL = default sink)",
735 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
736 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
737 g_param_spec_object ("vis-plugin", "Vis plugin",
738 "the visualization element to use (NULL = default)",
739 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
740 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
741 g_param_spec_object ("text-sink", "Text plugin",
742 "the text output element to use (NULL = default textoverlay)",
743 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
746 * GstPlayBin2:volume:
748 * Get or set the current audio stream volume. 1.0 means 100%,
749 * 0.0 means mute. This uses a linear volume scale.
752 g_object_class_install_property (gobject_klass, PROP_VOLUME,
753 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
754 0.0, VOLUME_MAX_DOUBLE, 1.0,
755 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
756 g_object_class_install_property (gobject_klass, PROP_MUTE,
757 g_param_spec_boolean ("mute", "Mute",
758 "Mute the audio channel without changing the volume", FALSE,
759 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
763 * @playbin: a #GstPlayBin2
765 * Get the currently rendered or prerolled frame in the video sink.
766 * The #GstCaps on the buffer will describe the format of the buffer.
768 g_object_class_install_property (gobject_klass, PROP_FRAME,
769 g_param_spec_boxed ("frame", "Frame",
770 "The last frame (NULL = no video available)",
771 GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
772 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
773 g_param_spec_string ("subtitle-font-desc",
774 "Subtitle font description",
775 "Pango font description of font "
776 "to be used for subtitle rendering", NULL,
777 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
779 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
780 g_param_spec_uint ("connection-speed", "Connection Speed",
781 "Network connection speed in kbps (0 = unknown)",
782 0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
783 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
785 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
786 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
787 "Buffer size when buffering network streams",
788 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
789 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
790 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
791 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
792 "Buffer duration when buffering network streams",
793 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
794 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
796 * GstPlayBin2:av-offset:
798 * Control the synchronisation offset between the audio and video streams.
799 * Positive values make the audio ahead of the video and negative values make
800 * the audio go behind the video.
804 g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
805 g_param_spec_int64 ("av-offset", "AV Offset",
806 "The synchronisation offset between audio and video in nanoseconds",
807 G_MININT64, G_MAXINT64, 0,
808 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
811 * GstQueue2:ring-buffer-max-size
813 * The maximum size of the ring buffer in bytes. If set to 0, the ring
814 * buffer is disabled. Default 0.
818 g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
819 g_param_spec_uint64 ("ring-buffer-max-size",
820 "Max. ring buffer size (bytes)",
821 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
822 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
823 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
826 * GstPlayBin2::about-to-finish
827 * @playbin: a #GstPlayBin2
829 * This signal is emitted when the current uri is about to finish. You can
830 * set the uri and suburi to make sure that playback continues.
832 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
833 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
835 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
836 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
839 * GstPlayBin2::video-changed
840 * @playbin: a #GstPlayBin2
842 * This signal is emitted whenever the number or order of the video
843 * streams has changed. The application will most likely want to select
844 * a new video stream.
846 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
847 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
849 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
850 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
852 * GstPlayBin2::audio-changed
853 * @playbin: a #GstPlayBin2
855 * This signal is emitted whenever the number or order of the audio
856 * streams has changed. The application will most likely want to select
857 * a new audio stream.
859 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
860 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
862 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
863 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
865 * GstPlayBin2::text-changed
866 * @playbin: a #GstPlayBin2
868 * This signal is emitted whenever the number or order of the text
869 * streams has changed. The application will most likely want to select
872 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
873 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
875 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
876 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
879 * GstPlayBin2::video-tags-changed
880 * @playbin: a #GstPlayBin2
881 * @stream: stream index with changed tags
883 * This signal is emitted whenever the tags of a video stream have changed.
884 * The application will most likely want to get the new tags.
888 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
889 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
891 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
892 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
895 * GstPlayBin2::audio-tags-changed
896 * @playbin: a #GstPlayBin2
897 * @stream: stream index with changed tags
899 * This signal is emitted whenever the tags of an audio stream have changed.
900 * The application will most likely want to get the new tags.
904 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
905 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
907 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
908 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
911 * GstPlayBin2::text-tags-changed
912 * @playbin: a #GstPlayBin2
913 * @stream: stream index with changed tags
915 * This signal is emitted whenever the tags of a text stream have changed.
916 * The application will most likely want to get the new tags.
920 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
921 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
923 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
924 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
927 * GstPlayBin2::source-setup:
928 * @playbin: a #GstPlayBin2
929 * @source: source element
931 * This signal is emitted after the source element has been created, so
932 * it can be configured by setting additional properties (e.g. set a
933 * proxy server for an http source, or set the device and read speed for
934 * an audio cd source). This is functionally equivalent to connecting to
935 * the notify::source signal, but more convenient.
939 gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
940 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
941 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
942 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
945 * GstPlayBin2::get-video-tags
946 * @playbin: a #GstPlayBin2
947 * @stream: a video stream number
949 * Action signal to retrieve the tags of a specific video stream number.
950 * This information can be used to select a stream.
952 * Returns: a GstTagList with tags or NULL when the stream number does not
955 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
956 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
957 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
958 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
959 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
961 * GstPlayBin2::get-audio-tags
962 * @playbin: a #GstPlayBin2
963 * @stream: an audio stream number
965 * Action signal to retrieve the tags of a specific audio stream number.
966 * This information can be used to select a stream.
968 * Returns: a GstTagList with tags or NULL when the stream number does not
971 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
972 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
973 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
974 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
975 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
977 * GstPlayBin2::get-text-tags
978 * @playbin: a #GstPlayBin2
979 * @stream: a text stream number
981 * Action signal to retrieve the tags of a specific text stream number.
982 * This information can be used to select a stream.
984 * Returns: a GstTagList with tags or NULL when the stream number does not
987 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
988 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
989 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
990 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
991 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
993 * GstPlayBin2::convert-frame
994 * @playbin: a #GstPlayBin2
995 * @caps: the target format of the frame
997 * Action signal to retrieve the currently playing video frame in the format
998 * specified by @caps.
999 * If @caps is %NULL, no conversion will be performed and this function is
1000 * equivalent to the #GstPlayBin::frame property.
1002 * Returns: a #GstBuffer of the current video frame converted to #caps.
1003 * The caps on the buffer will describe the final layout of the buffer data.
1004 * %NULL is returned when no current buffer can be retrieved or when the
1005 * conversion failed.
1007 gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
1008 g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
1009 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1010 G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
1011 gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
1014 * GstPlayBin2::get-video-pad
1015 * @playbin: a #GstPlayBin2
1016 * @stream: a video stream number
1018 * Action signal to retrieve the stream-selector sinkpad for a specific
1020 * This pad can be used for notifications of caps changes, stream-specific
1023 * Returns: a #GstPad, or NULL when the stream number does not exist.
1025 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1026 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1027 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1028 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1029 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1031 * GstPlayBin2::get-audio-pad
1032 * @playbin: a #GstPlayBin2
1033 * @stream: an audio stream number
1035 * Action signal to retrieve the stream-selector sinkpad for a specific
1037 * This pad can be used for notifications of caps changes, stream-specific
1040 * Returns: a #GstPad, or NULL when the stream number does not exist.
1042 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1043 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1044 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1045 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1046 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1048 * GstPlayBin2::get-text-pad
1049 * @playbin: a #GstPlayBin2
1050 * @stream: a text stream number
1052 * Action signal to retrieve the stream-selector sinkpad for a specific
1054 * This pad can be used for notifications of caps changes, stream-specific
1057 * Returns: a #GstPad, or NULL when the stream number does not exist.
1059 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1060 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1061 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1062 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1063 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1065 klass->get_video_tags = gst_play_bin_get_video_tags;
1066 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1067 klass->get_text_tags = gst_play_bin_get_text_tags;
1069 klass->convert_frame = gst_play_bin_convert_frame;
1071 klass->get_video_pad = gst_play_bin_get_video_pad;
1072 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1073 klass->get_text_pad = gst_play_bin_get_text_pad;
1075 gst_element_class_set_details_simple (gstelement_klass,
1076 "Player Bin 2", "Generic/Bin/Player",
1077 "Autoplug and play media from an uri",
1078 "Wim Taymans <wim.taymans@gmail.com>");
1080 gstelement_klass->change_state =
1081 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1082 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1084 gstbin_klass->handle_message =
1085 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1089 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1093 /* store the array for the different channels */
1094 group->video_channels = g_ptr_array_new ();
1095 group->audio_channels = g_ptr_array_new ();
1096 group->text_channels = g_ptr_array_new ();
1097 group->lock = g_mutex_new ();
1098 /* init selectors. The selector is found by finding the first prefix that
1099 * matches the media. */
1100 group->playbin = playbin;
1101 /* If you add any items to these lists, check that media_list[] is defined
1102 * above to be large enough to hold MAX(items)+1, so as to accomodate a
1103 * NULL terminator (set when the memory is zeroed on allocation) */
1104 group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
1105 group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
1106 group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
1107 group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
1108 group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
1109 group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
1110 group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
1111 group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
1112 group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
1113 group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
1114 group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
1115 group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
1116 group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
1117 group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
1118 gst_subtitle_overlay_create_factory_caps;
1119 group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
1120 group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
1122 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1123 GstSourceSelect *select = &group->selector[n];
1124 select->sinkpad_delayed_event = NULL;
1125 select->sinkpad_data_probe = 0;
1130 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1134 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1135 GstSourceSelect *select = &group->selector[n];
1136 if (select->sinkpad && select->sinkpad_data_probe)
1137 gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
1138 if (select->sinkpad_delayed_event)
1139 gst_event_unref (select->sinkpad_delayed_event);
1142 g_free (group->uri);
1143 g_free (group->suburi);
1144 g_ptr_array_free (group->video_channels, TRUE);
1145 g_ptr_array_free (group->audio_channels, TRUE);
1146 g_ptr_array_free (group->text_channels, TRUE);
1148 g_mutex_free (group->lock);
1149 if (group->audio_sink) {
1150 if (group->audio_sink != playbin->audio_sink)
1151 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1152 gst_object_unref (group->audio_sink);
1154 group->audio_sink = NULL;
1155 if (group->video_sink) {
1156 if (group->video_sink != playbin->video_sink)
1157 gst_element_set_state (group->video_sink, GST_STATE_NULL);
1158 gst_object_unref (group->video_sink);
1160 group->video_sink = NULL;
1162 g_list_free (group->stream_changed_pending);
1163 group->stream_changed_pending = NULL;
1165 if (group->stream_changed_pending_lock)
1166 g_mutex_free (group->stream_changed_pending_lock);
1167 group->stream_changed_pending_lock = NULL;
1171 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1173 g_object_notify (G_OBJECT (playbin), "volume");
1177 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1179 g_object_notify (G_OBJECT (playbin), "mute");
1182 /* Must be called with elements lock! */
1184 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1188 if (!playbin->elements ||
1189 playbin->elements_cookie !=
1190 gst_default_registry_get_feature_list_cookie ()) {
1191 if (playbin->elements)
1192 gst_plugin_feature_list_free (playbin->elements);
1194 gst_element_factory_list_get_elements
1195 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1197 gst_element_factory_list_get_elements
1198 (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1199 playbin->elements = g_list_concat (res, tmp);
1201 g_list_sort (playbin->elements, gst_plugin_feature_rank_compare_func);
1202 playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1207 gst_play_bin_init (GstPlayBin * playbin)
1209 g_static_rec_mutex_init (&playbin->lock);
1210 playbin->dyn_lock = g_mutex_new ();
1212 /* assume we can create a selector */
1213 playbin->have_selector = TRUE;
1216 playbin->curr_group = &playbin->groups[0];
1217 playbin->next_group = &playbin->groups[1];
1218 init_group (playbin, &playbin->groups[0]);
1219 init_group (playbin, &playbin->groups[1]);
1221 /* first filter out the interesting element factories */
1222 playbin->elements_lock = g_mutex_new ();
1225 playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1226 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1227 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1228 /* Connect to notify::volume and notify::mute signals for proxying */
1229 g_signal_connect (playbin->playsink, "notify::volume",
1230 G_CALLBACK (notify_volume_cb), playbin);
1231 g_signal_connect (playbin->playsink, "notify::mute",
1232 G_CALLBACK (notify_mute_cb), playbin);
1234 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1235 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1236 playbin->current_text = DEFAULT_CURRENT_TEXT;
1238 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1239 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1240 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1244 gst_play_bin_finalize (GObject * object)
1246 GstPlayBin *playbin;
1248 playbin = GST_PLAY_BIN (object);
1250 free_group (playbin, &playbin->groups[0]);
1251 free_group (playbin, &playbin->groups[1]);
1253 if (playbin->source)
1254 gst_object_unref (playbin->source);
1255 if (playbin->video_sink) {
1256 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1257 gst_object_unref (playbin->video_sink);
1259 if (playbin->audio_sink) {
1260 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1261 gst_object_unref (playbin->audio_sink);
1263 if (playbin->text_sink) {
1264 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1265 gst_object_unref (playbin->text_sink);
1268 if (playbin->elements)
1269 gst_plugin_feature_list_free (playbin->elements);
1271 g_static_rec_mutex_free (&playbin->lock);
1272 g_mutex_free (playbin->dyn_lock);
1273 g_mutex_free (playbin->elements_lock);
1275 G_OBJECT_CLASS (parent_class)->finalize (object);
1279 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1281 GstSourceGroup *group;
1284 g_warning ("cannot set NULL uri");
1288 GST_PLAY_BIN_LOCK (playbin);
1289 group = playbin->next_group;
1291 GST_SOURCE_GROUP_LOCK (group);
1292 /* store the uri in the next group we will play */
1293 g_free (group->uri);
1294 group->uri = g_strdup (uri);
1295 group->valid = TRUE;
1296 GST_SOURCE_GROUP_UNLOCK (group);
1298 GST_DEBUG ("set new uri to %s", uri);
1299 GST_PLAY_BIN_UNLOCK (playbin);
1303 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1305 GstSourceGroup *group;
1307 GST_PLAY_BIN_LOCK (playbin);
1308 group = playbin->next_group;
1310 GST_SOURCE_GROUP_LOCK (group);
1311 g_free (group->suburi);
1312 group->suburi = g_strdup (suburi);
1313 GST_SOURCE_GROUP_UNLOCK (group);
1315 GST_DEBUG ("setting new .sub uri to %s", suburi);
1317 GST_PLAY_BIN_UNLOCK (playbin);
1321 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1323 gst_play_sink_set_flags (playbin->playsink, flags);
1324 gst_play_sink_reconfigure (playbin->playsink);
1328 gst_play_bin_get_flags (GstPlayBin * playbin)
1332 flags = gst_play_sink_get_flags (playbin->playsink);
1337 /* get the currently playing group or if nothing is playing, the next
1338 * group. Must be called with the PLAY_BIN_LOCK. */
1339 static GstSourceGroup *
1340 get_group (GstPlayBin * playbin)
1342 GstSourceGroup *result;
1344 if (!(result = playbin->curr_group))
1345 result = playbin->next_group;
1351 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1353 GstPad *sinkpad = NULL;
1354 GstSourceGroup *group;
1356 GST_PLAY_BIN_LOCK (playbin);
1357 group = get_group (playbin);
1358 if (stream < group->video_channels->len) {
1359 sinkpad = g_ptr_array_index (group->video_channels, stream);
1360 gst_object_ref (sinkpad);
1362 GST_PLAY_BIN_UNLOCK (playbin);
1368 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1370 GstPad *sinkpad = NULL;
1371 GstSourceGroup *group;
1373 GST_PLAY_BIN_LOCK (playbin);
1374 group = get_group (playbin);
1375 if (stream < group->audio_channels->len) {
1376 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1377 gst_object_ref (sinkpad);
1379 GST_PLAY_BIN_UNLOCK (playbin);
1385 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1387 GstPad *sinkpad = NULL;
1388 GstSourceGroup *group;
1390 GST_PLAY_BIN_LOCK (playbin);
1391 group = get_group (playbin);
1392 if (stream < group->text_channels->len) {
1393 sinkpad = g_ptr_array_index (group->text_channels, stream);
1394 gst_object_ref (sinkpad);
1396 GST_PLAY_BIN_UNLOCK (playbin);
1403 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1408 if (!channels || stream >= channels->len)
1411 sinkpad = g_ptr_array_index (channels, stream);
1412 g_object_get (sinkpad, "tags", &result, NULL);
1418 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1421 GstSourceGroup *group;
1423 GST_PLAY_BIN_LOCK (playbin);
1424 group = get_group (playbin);
1425 result = get_tags (playbin, group->video_channels, stream);
1426 GST_PLAY_BIN_UNLOCK (playbin);
1432 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1435 GstSourceGroup *group;
1437 GST_PLAY_BIN_LOCK (playbin);
1438 group = get_group (playbin);
1439 result = get_tags (playbin, group->audio_channels, stream);
1440 GST_PLAY_BIN_UNLOCK (playbin);
1446 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1449 GstSourceGroup *group;
1451 GST_PLAY_BIN_LOCK (playbin);
1452 group = get_group (playbin);
1453 result = get_tags (playbin, group->text_channels, stream);
1454 GST_PLAY_BIN_UNLOCK (playbin);
1460 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1462 return gst_play_sink_convert_frame (playbin->playsink, caps);
1465 /* Returns current stream number, or -1 if none has been selected yet */
1467 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1469 /* Internal API cleanup would make this easier... */
1471 GstPad *pad, *current;
1472 GstObject *selector = NULL;
1475 for (i = 0; i < channels->len; i++) {
1476 pad = g_ptr_array_index (channels, i);
1477 if ((selector = gst_pad_get_parent (pad))) {
1478 g_object_get (selector, "active-pad", ¤t, NULL);
1479 gst_object_unref (selector);
1481 if (pad == current) {
1482 gst_object_unref (current);
1488 gst_object_unref (current);
1496 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1498 GstSourceGroup *group;
1499 GPtrArray *channels;
1502 GST_PLAY_BIN_LOCK (playbin);
1504 GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1505 playbin->current_video, stream);
1507 group = get_group (playbin);
1508 if (!(channels = group->video_channels))
1511 if (stream == -1 || channels->len <= stream) {
1514 /* take channel from selected stream */
1515 sinkpad = g_ptr_array_index (channels, stream);
1519 gst_object_ref (sinkpad);
1520 GST_PLAY_BIN_UNLOCK (playbin);
1523 GstObject *selector;
1525 if ((selector = gst_pad_get_parent (sinkpad))) {
1526 /* activate the selected pad */
1527 g_object_set (selector, "active-pad", sinkpad, NULL);
1528 gst_object_unref (selector);
1530 gst_object_unref (sinkpad);
1536 GST_PLAY_BIN_UNLOCK (playbin);
1537 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1543 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1545 GstSourceGroup *group;
1546 GPtrArray *channels;
1549 GST_PLAY_BIN_LOCK (playbin);
1551 GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1552 playbin->current_audio, stream);
1554 group = get_group (playbin);
1555 if (!(channels = group->audio_channels))
1558 if (stream == -1 || channels->len <= stream) {
1561 /* take channel from selected stream */
1562 sinkpad = g_ptr_array_index (channels, stream);
1566 gst_object_ref (sinkpad);
1567 GST_PLAY_BIN_UNLOCK (playbin);
1570 GstObject *selector;
1572 if ((selector = gst_pad_get_parent (sinkpad))) {
1573 /* activate the selected pad */
1574 g_object_set (selector, "active-pad", sinkpad, NULL);
1575 gst_object_unref (selector);
1577 gst_object_unref (sinkpad);
1583 GST_PLAY_BIN_UNLOCK (playbin);
1584 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1590 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1592 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1594 GValue item = { 0, };
1596 if (it && gst_iterator_next (it, &item) == GST_ITERATOR_OK
1597 && ((sinkpad = g_value_get_object (&item)) != NULL)) {
1601 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1602 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1603 if (!gst_pad_send_event (sinkpad, event)) {
1605 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1606 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1607 if (!gst_pad_send_event (sinkpad, event))
1608 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1611 g_value_unset (&item);
1615 gst_iterator_free (it);
1619 gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
1620 GstElement * suburidecodebin, gboolean block)
1622 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1623 gboolean done = FALSE;
1624 GValue item = { 0, };
1626 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1633 switch (gst_iterator_next (it, &item)) {
1634 case GST_ITERATOR_OK:
1635 sinkpad = g_value_get_object (&item);
1638 gst_pad_add_probe (sinkpad, GST_PROBE_TYPE_BLOCK, NULL, NULL,
1640 } else if (group->block_id) {
1641 gst_pad_remove_probe (sinkpad, group->block_id);
1642 group->block_id = 0;
1644 g_value_reset (&item);
1646 case GST_ITERATOR_DONE:
1649 case GST_ITERATOR_RESYNC:
1650 gst_iterator_resync (it);
1652 case GST_ITERATOR_ERROR:
1657 g_value_unset (&item);
1658 gst_iterator_free (it);
1662 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1664 GstSourceGroup *group;
1665 GPtrArray *channels;
1668 GST_PLAY_BIN_LOCK (playbin);
1670 GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1671 playbin->current_text, stream);
1673 group = get_group (playbin);
1674 if (!(channels = group->text_channels))
1677 if (stream == -1 || channels->len <= stream) {
1680 /* take channel from selected stream */
1681 sinkpad = g_ptr_array_index (channels, stream);
1685 gst_object_ref (sinkpad);
1686 GST_PLAY_BIN_UNLOCK (playbin);
1689 GstObject *selector;
1691 if ((selector = gst_pad_get_parent (sinkpad))) {
1692 GstPad *old_sinkpad;
1694 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1696 if (old_sinkpad != sinkpad) {
1697 gboolean need_unblock, need_block, need_seek;
1698 GstPad *src, *peer = NULL, *oldpeer = NULL;
1699 GstElement *parent_element = NULL, *old_parent_element = NULL;
1701 /* Now check if we need to seek the suburidecodebin to the beginning
1702 * or if we need to block all suburidecodebin sinkpads or if we need
1703 * to unblock all suburidecodebin sinkpads
1706 peer = gst_pad_get_peer (sinkpad);
1708 oldpeer = gst_pad_get_peer (old_sinkpad);
1711 parent_element = gst_pad_get_parent_element (peer);
1713 old_parent_element = gst_pad_get_parent_element (oldpeer);
1715 need_block = (old_parent_element == group->suburidecodebin
1716 && parent_element != old_parent_element);
1717 need_unblock = (parent_element == group->suburidecodebin
1718 && parent_element != old_parent_element);
1719 need_seek = (parent_element == group->suburidecodebin);
1722 gst_object_unref (peer);
1724 gst_object_unref (oldpeer);
1726 gst_object_unref (parent_element);
1727 if (old_parent_element)
1728 gst_object_unref (old_parent_element);
1730 /* Block all suburidecodebin sinkpads */
1732 gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1735 /* activate the selected pad */
1736 g_object_set (selector, "active-pad", sinkpad, NULL);
1738 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1739 peer = gst_pad_get_peer (src);
1743 /* Flush the subtitle renderer to remove any
1744 * currently displayed subtitles. This event will
1745 * never travel outside subtitleoverlay!
1747 s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1748 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1749 gst_pad_send_event (peer, event);
1750 gst_object_unref (peer);
1752 gst_object_unref (src);
1754 /* Unblock pads if necessary */
1756 gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1759 /* seek to the beginning */
1761 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1763 gst_object_unref (selector);
1766 gst_object_unref (old_sinkpad);
1768 gst_object_unref (sinkpad);
1774 GST_PLAY_BIN_UNLOCK (playbin);
1780 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1781 const gchar * dbg, GstElement * sink)
1783 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1785 GST_PLAY_BIN_LOCK (playbin);
1786 if (*elem != sink) {
1791 gst_object_ref_sink (sink);
1795 gst_object_unref (old);
1797 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1798 GST_PLAY_BIN_UNLOCK (playbin);
1802 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1806 GST_PLAY_BIN_LOCK (playbin);
1808 /* set subtitles on all current and next decodebins. */
1809 if ((elem = playbin->groups[0].uridecodebin))
1810 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1811 if ((elem = playbin->groups[0].suburidecodebin))
1812 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1813 if ((elem = playbin->groups[1].uridecodebin))
1814 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1815 if ((elem = playbin->groups[1].suburidecodebin))
1816 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1818 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1819 GST_PLAY_BIN_UNLOCK (playbin);
1823 gst_play_bin_set_property (GObject * object, guint prop_id,
1824 const GValue * value, GParamSpec * pspec)
1826 GstPlayBin *playbin = GST_PLAY_BIN (object);
1830 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1833 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1836 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1838 case PROP_CURRENT_VIDEO:
1839 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1841 case PROP_CURRENT_AUDIO:
1842 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1844 case PROP_CURRENT_TEXT:
1845 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1847 case PROP_SUBTITLE_ENCODING:
1848 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1850 case PROP_VIDEO_SINK:
1851 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1852 g_value_get_object (value));
1854 case PROP_AUDIO_SINK:
1855 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1856 g_value_get_object (value));
1858 case PROP_VIS_PLUGIN:
1859 gst_play_sink_set_vis_plugin (playbin->playsink,
1860 g_value_get_object (value));
1862 case PROP_TEXT_SINK:
1863 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1864 g_value_get_object (value));
1867 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1870 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1872 case PROP_FONT_DESC:
1873 gst_play_sink_set_font_desc (playbin->playsink,
1874 g_value_get_string (value));
1876 case PROP_CONNECTION_SPEED:
1877 GST_PLAY_BIN_LOCK (playbin);
1878 playbin->connection_speed = g_value_get_uint (value) * 1000;
1879 GST_PLAY_BIN_UNLOCK (playbin);
1881 case PROP_BUFFER_SIZE:
1882 playbin->buffer_size = g_value_get_int (value);
1884 case PROP_BUFFER_DURATION:
1885 playbin->buffer_duration = g_value_get_int64 (value);
1887 case PROP_AV_OFFSET:
1888 gst_play_sink_set_av_offset (playbin->playsink,
1889 g_value_get_int64 (value));
1891 case PROP_RING_BUFFER_MAX_SIZE:
1892 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
1895 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1901 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1902 const gchar * dbg, GstPlaySinkType type)
1904 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
1906 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1907 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1908 dbg, sink, dbg, *elem);
1911 GST_PLAY_BIN_LOCK (playbin);
1913 gst_object_ref (sink);
1914 GST_PLAY_BIN_UNLOCK (playbin);
1921 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1924 GstPlayBin *playbin = GST_PLAY_BIN (object);
1929 GstSourceGroup *group;
1931 GST_PLAY_BIN_LOCK (playbin);
1932 group = get_group (playbin);
1933 g_value_set_string (value, group->uri);
1934 GST_PLAY_BIN_UNLOCK (playbin);
1939 GstSourceGroup *group;
1941 GST_PLAY_BIN_LOCK (playbin);
1942 group = get_group (playbin);
1943 g_value_set_string (value, group->suburi);
1944 GST_PLAY_BIN_UNLOCK (playbin);
1949 GST_OBJECT_LOCK (playbin);
1950 g_value_set_object (value, playbin->source);
1951 GST_OBJECT_UNLOCK (playbin);
1955 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
1959 GstSourceGroup *group;
1962 GST_PLAY_BIN_LOCK (playbin);
1963 group = get_group (playbin);
1964 n_video = (group->video_channels ? group->video_channels->len : 0);
1965 g_value_set_int (value, n_video);
1966 GST_PLAY_BIN_UNLOCK (playbin);
1969 case PROP_CURRENT_VIDEO:
1970 GST_PLAY_BIN_LOCK (playbin);
1971 g_value_set_int (value, playbin->current_video);
1972 GST_PLAY_BIN_UNLOCK (playbin);
1976 GstSourceGroup *group;
1979 GST_PLAY_BIN_LOCK (playbin);
1980 group = get_group (playbin);
1981 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
1982 g_value_set_int (value, n_audio);
1983 GST_PLAY_BIN_UNLOCK (playbin);
1986 case PROP_CURRENT_AUDIO:
1987 GST_PLAY_BIN_LOCK (playbin);
1988 g_value_set_int (value, playbin->current_audio);
1989 GST_PLAY_BIN_UNLOCK (playbin);
1993 GstSourceGroup *group;
1996 GST_PLAY_BIN_LOCK (playbin);
1997 group = get_group (playbin);
1998 n_text = (group->text_channels ? group->text_channels->len : 0);
1999 g_value_set_int (value, n_text);
2000 GST_PLAY_BIN_UNLOCK (playbin);
2003 case PROP_CURRENT_TEXT:
2004 GST_PLAY_BIN_LOCK (playbin);
2005 g_value_set_int (value, playbin->current_text);
2006 GST_PLAY_BIN_UNLOCK (playbin);
2008 case PROP_SUBTITLE_ENCODING:
2009 GST_PLAY_BIN_LOCK (playbin);
2010 g_value_take_string (value,
2011 gst_play_sink_get_subtitle_encoding (playbin->playsink));
2012 GST_PLAY_BIN_UNLOCK (playbin);
2014 case PROP_VIDEO_SINK:
2015 g_value_take_object (value,
2016 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2017 "video", GST_PLAY_SINK_TYPE_VIDEO));
2019 case PROP_AUDIO_SINK:
2020 g_value_take_object (value,
2021 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2022 "audio", GST_PLAY_SINK_TYPE_AUDIO));
2024 case PROP_VIS_PLUGIN:
2025 g_value_take_object (value,
2026 gst_play_sink_get_vis_plugin (playbin->playsink));
2028 case PROP_TEXT_SINK:
2029 g_value_take_object (value,
2030 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2031 "text", GST_PLAY_SINK_TYPE_TEXT));
2034 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2037 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2040 gst_value_take_buffer (value,
2041 gst_play_sink_get_last_frame (playbin->playsink));
2043 case PROP_FONT_DESC:
2044 g_value_take_string (value,
2045 gst_play_sink_get_font_desc (playbin->playsink));
2047 case PROP_CONNECTION_SPEED:
2048 GST_PLAY_BIN_LOCK (playbin);
2049 g_value_set_uint (value, playbin->connection_speed / 1000);
2050 GST_PLAY_BIN_UNLOCK (playbin);
2052 case PROP_BUFFER_SIZE:
2053 GST_OBJECT_LOCK (playbin);
2054 g_value_set_int (value, playbin->buffer_size);
2055 GST_OBJECT_UNLOCK (playbin);
2057 case PROP_BUFFER_DURATION:
2058 GST_OBJECT_LOCK (playbin);
2059 g_value_set_int64 (value, playbin->buffer_duration);
2060 GST_OBJECT_UNLOCK (playbin);
2062 case PROP_AV_OFFSET:
2063 g_value_set_int64 (value,
2064 gst_play_sink_get_av_offset (playbin->playsink));
2066 case PROP_RING_BUFFER_MAX_SIZE:
2067 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2070 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2076 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2077 gboolean valid, GstQuery * query)
2083 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2084 gst_query_parse_duration (query, &fmt, &duration);
2086 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2087 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2088 playbin->duration[i].valid = valid;
2089 playbin->duration[i].format = fmt;
2090 playbin->duration[i].duration = valid ? duration : -1;
2097 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2099 const GstFormat formats[] =
2100 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2105 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2106 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2107 query = gst_query_new_duration (formats[i]);
2109 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2111 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2112 gst_query_unref (query);
2117 gst_play_bin_query (GstElement * element, GstQuery * query)
2119 GstPlayBin *playbin = GST_PLAY_BIN (element);
2122 /* During a group switch we shouldn't allow duration queries
2123 * because it's not clear if the old or new group's duration
2124 * is returned and if the sinks are already playing new data
2125 * or old data. See bug #585969
2127 * While we're at it, also don't do any other queries during
2128 * a group switch or any other event that causes topology changes
2129 * by taking the playbin lock in any case.
2131 GST_PLAY_BIN_LOCK (playbin);
2133 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2134 GstSourceGroup *group = playbin->curr_group;
2137 GST_SOURCE_GROUP_LOCK (group);
2138 if (group->stream_changed_pending_lock) {
2139 g_mutex_lock (group->stream_changed_pending_lock);
2140 pending = group->pending || group->stream_changed_pending;
2141 g_mutex_unlock (group->stream_changed_pending_lock);
2143 pending = group->pending;
2150 gst_query_parse_duration (query, &fmt, NULL);
2151 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2152 if (fmt == playbin->duration[i].format) {
2153 ret = playbin->duration[i].valid;
2154 gst_query_set_duration (query, fmt,
2155 (ret ? playbin->duration[i].duration : -1));
2159 /* if nothing cached yet, we might as well request duration,
2160 * such as during initial startup */
2162 GST_DEBUG_OBJECT (playbin,
2163 "Taking cached duration because of pending group switch: %d", ret);
2164 GST_SOURCE_GROUP_UNLOCK (group);
2165 GST_PLAY_BIN_UNLOCK (playbin);
2169 GST_SOURCE_GROUP_UNLOCK (group);
2172 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2174 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2175 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2176 GST_PLAY_BIN_UNLOCK (playbin);
2181 /* mime types we are not handling on purpose right now, don't post a
2182 * missing-plugin message for these */
2183 static const gchar *blacklisted_mimes[] = {
2188 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2190 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2191 GstSourceGroup *group;
2193 if (gst_is_missing_plugin_message (msg)) {
2197 detail = gst_missing_plugin_message_get_installer_detail (msg);
2198 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2199 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2200 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2201 gst_message_unref (msg);
2207 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2208 const GstStructure *s = gst_message_get_structure (msg);
2210 /* Drop all stream-changed messages except the last one */
2211 if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2212 guint32 seqnum = gst_message_get_seqnum (msg);
2215 group = playbin->curr_group;
2216 g_mutex_lock (group->stream_changed_pending_lock);
2217 for (l = group->stream_changed_pending; l;) {
2218 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2220 if (l_seqnum == seqnum) {
2223 group->stream_changed_pending =
2224 g_list_delete_link (group->stream_changed_pending, l_prev);
2225 if (group->stream_changed_pending) {
2226 gst_message_unref (msg);
2234 g_mutex_unlock (group->stream_changed_pending_lock);
2236 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2237 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2238 GstObject *src = GST_OBJECT_CAST (msg->src);
2240 /* Ignore async state changes from the uridecodebin children,
2241 * see bug #602000. */
2242 group = playbin->curr_group;
2243 if (src && (group = playbin->curr_group) &&
2244 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2245 || (group->suburidecodebin
2246 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2247 GST_DEBUG_OBJECT (playbin,
2248 "Ignoring async state change of uridecodebin: %s",
2249 GST_OBJECT_NAME (src));
2250 gst_message_unref (msg);
2253 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2254 /* If we get an error of the subtitle uridecodebin transform
2255 * them into warnings and disable the subtitles */
2256 group = playbin->curr_group;
2257 if (group && group->suburidecodebin) {
2258 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2259 (group->suburidecodebin)))) {
2261 gchar *debug = NULL;
2262 GstMessage *new_msg;
2264 gboolean done = FALSE;
2265 GValue item = { 0, };
2267 gst_message_parse_error (msg, &err, &debug);
2268 new_msg = gst_message_new_warning (msg->src, err, debug);
2270 gst_message_unref (msg);
2275 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2276 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2277 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2278 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2280 it = gst_element_iterate_src_pads (group->suburidecodebin);
2281 while (it && !done) {
2283 GstIteratorResult res;
2285 res = gst_iterator_next (it, &item);
2288 case GST_ITERATOR_DONE:
2291 case GST_ITERATOR_OK:
2292 p = g_value_get_object (&item);
2293 pad_removed_cb (NULL, p, group);
2294 g_value_reset (&item);
2297 case GST_ITERATOR_RESYNC:
2298 gst_iterator_resync (it);
2300 case GST_ITERATOR_ERROR:
2305 g_value_unset (&item);
2307 gst_iterator_free (it);
2309 gst_object_ref (group->suburidecodebin);
2310 gst_bin_remove (bin, group->suburidecodebin);
2311 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2313 if (group->sub_pending) {
2314 group->sub_pending = FALSE;
2315 no_more_pads_cb (NULL, group);
2322 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2326 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2327 GstPlayBin * playbin)
2329 const gchar *property;
2330 GstSourceGroup *group;
2331 GstSourceSelect *select = NULL;
2334 GST_PLAY_BIN_LOCK (playbin);
2335 group = get_group (playbin);
2337 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2338 if (selector == G_OBJECT (group->selector[i].selector)) {
2339 select = &group->selector[i];
2343 /* We got a pad-change after our group got switched out; no need to notify */
2345 GST_PLAY_BIN_UNLOCK (playbin);
2349 switch (select->type) {
2350 case GST_PLAY_SINK_TYPE_VIDEO:
2351 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2352 property = "current-video";
2353 playbin->current_video = get_current_stream_number (playbin,
2354 group->video_channels);
2356 case GST_PLAY_SINK_TYPE_AUDIO:
2357 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2358 property = "current-audio";
2359 playbin->current_audio = get_current_stream_number (playbin,
2360 group->audio_channels);
2362 case GST_PLAY_SINK_TYPE_TEXT:
2363 property = "current-text";
2364 playbin->current_text = get_current_stream_number (playbin,
2365 group->text_channels);
2370 GST_PLAY_BIN_UNLOCK (playbin);
2373 g_object_notify (G_OBJECT (playbin), property);
2376 /* this callback sends a delayed event once the pad becomes unblocked */
2377 static GstProbeReturn
2378 stream_changed_data_probe (GstPad * pad, GstProbeType type,
2379 GstMiniObject * object, gpointer data)
2381 GstSourceSelect *select = (GstSourceSelect *) data;
2384 /* we need do this just once, so cleanup first */
2385 gst_pad_remove_probe (pad, select->sinkpad_data_probe);
2386 select->sinkpad_data_probe = 0;
2387 e = select->sinkpad_delayed_event;
2388 select->sinkpad_delayed_event = NULL;
2390 /* really, this should not happen */
2392 GST_WARNING ("Data probed called, but no delayed event");
2393 return GST_PROBE_OK;
2396 if (GST_IS_EVENT (object)
2397 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_SEGMENT) {
2398 /* push the event first, then send the delayed one */
2399 gst_event_ref (GST_EVENT_CAST (object));
2400 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2401 gst_pad_send_event (pad, e);
2402 return GST_PROBE_DROP;
2404 /* send delayed event, then allow the caller to go on */
2405 gst_pad_send_event (pad, e);
2406 return GST_PROBE_OK;
2410 /* helper function to lookup stuff in lists */
2412 array_has_value (const gchar * values[], const gchar * value)
2416 for (i = 0; values[i]; i++) {
2417 if (values[i] && g_str_has_prefix (value, values[i]))
2425 GstPlayBin *playbin;
2427 GstPlaySinkType type;
2431 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2433 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2436 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2437 " with stream id %d and type %d have changed",
2438 object, ntdata->stream_id, ntdata->type);
2440 switch (ntdata->type) {
2441 case GST_PLAY_SINK_TYPE_VIDEO:
2442 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2443 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2445 case GST_PLAY_SINK_TYPE_AUDIO:
2446 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2447 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2449 case GST_PLAY_SINK_TYPE_TEXT:
2450 signal = SIGNAL_TEXT_TAGS_CHANGED;
2458 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2462 /* this function is called when a new pad is added to decodebin. We check the
2463 * type of the pad and add it to the selector element of the group.
2466 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2468 GstPlayBin *playbin;
2470 const GstStructure *s;
2473 GstPadLinkReturn res;
2474 GstSourceSelect *select = NULL;
2476 gboolean changed = FALSE;
2478 playbin = group->playbin;
2480 caps = gst_pad_get_caps (pad, NULL);
2481 s = gst_caps_get_structure (caps, 0);
2482 name = gst_structure_get_name (s);
2484 GST_DEBUG_OBJECT (playbin,
2485 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2486 GST_DEBUG_PAD_NAME (pad), caps, group);
2488 /* major type of the pad, this determines the selector to use */
2489 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2490 if (array_has_value (group->selector[i].media_list, name)) {
2491 select = &group->selector[i];
2493 } else if (group->selector[i].get_media_caps) {
2494 GstCaps *media_caps = group->selector[i].get_media_caps ();
2496 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2497 select = &group->selector[i];
2498 gst_caps_unref (media_caps);
2501 gst_caps_unref (media_caps);
2504 /* no selector found for the media type, don't bother linking it to a
2505 * selector. This will leave the pad unlinked and thus ignored. */
2509 GST_SOURCE_GROUP_LOCK (group);
2510 if (select->selector == NULL && playbin->have_selector) {
2511 /* no selector, create one */
2512 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2513 select->selector = gst_element_factory_make ("input-selector", NULL);
2514 if (select->selector == NULL) {
2515 /* post the missing selector message only once */
2516 playbin->have_selector = FALSE;
2517 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2518 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2520 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2521 (_("Missing element '%s' - check your GStreamer installation."),
2522 "input-selector"), (NULL));
2524 g_object_set (select->selector, "sync-streams", TRUE, NULL);
2526 g_signal_connect (select->selector, "notify::active-pad",
2527 G_CALLBACK (selector_active_pad_changed), playbin);
2529 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2530 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2531 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2535 if (select->srcpad == NULL) {
2536 if (select->selector) {
2537 /* save source pad of the selector */
2538 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2540 /* no selector, use the pad as the source pad then */
2541 select->srcpad = gst_object_ref (pad);
2544 /* block the selector srcpad. It's possible that multiple decodebins start
2545 * pushing data into the selectors before we have a chance to collect all
2546 * streams and connect the sinks, resulting in not-linked errors. After we
2547 * configured the sinks we will unblock them all. */
2548 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2550 gst_pad_add_probe (select->srcpad, GST_PROBE_TYPE_BLOCK, NULL, NULL,
2554 /* get sinkpad for the new stream */
2555 if (select->selector) {
2556 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2557 gulong notify_tags_handler = 0;
2558 NotifyTagsData *ntdata;
2560 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2561 GST_DEBUG_PAD_NAME (sinkpad));
2563 /* store the selector for the pad */
2564 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2566 /* connect to the notify::tags signal for our
2567 * own *-tags-changed signals
2569 ntdata = g_new0 (NotifyTagsData, 1);
2570 ntdata->playbin = playbin;
2571 ntdata->stream_id = select->channels->len;
2572 ntdata->type = select->type;
2574 notify_tags_handler =
2575 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2576 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2578 g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2579 (gpointer) notify_tags_handler);
2581 /* store the pad in the array */
2582 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2583 g_ptr_array_add (select->channels, sinkpad);
2585 res = gst_pad_link (pad, sinkpad);
2586 if (GST_PAD_LINK_FAILED (res))
2589 /* store selector pad so we can release it */
2590 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2593 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2594 GST_DEBUG_PAD_NAME (pad), select->selector);
2597 /* no selector, don't configure anything, we'll link the new pad directly to
2602 GST_SOURCE_GROUP_UNLOCK (group);
2606 gboolean always_ok = (decodebin == group->suburidecodebin);
2608 switch (select->type) {
2609 case GST_PLAY_SINK_TYPE_VIDEO:
2610 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2611 /* we want to return NOT_LINKED for unselected pads but only for pads
2612 * from the normal uridecodebin. This makes sure that subtitle streams
2613 * are not raced past audio/video from decodebin's multiqueue.
2614 * For pads from suburidecodebin OK should always be returned, otherwise
2615 * it will most likely stop. */
2616 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2617 signal = SIGNAL_VIDEO_CHANGED;
2619 case GST_PLAY_SINK_TYPE_AUDIO:
2620 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2621 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2622 signal = SIGNAL_AUDIO_CHANGED;
2624 case GST_PLAY_SINK_TYPE_TEXT:
2625 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2626 signal = SIGNAL_TEXT_CHANGED;
2633 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2637 gst_caps_unref (caps);
2643 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2644 name, GST_DEBUG_PAD_NAME (pad));
2649 GST_ERROR_OBJECT (playbin,
2650 "failed to link pad %s:%s to selector, reason %d",
2651 GST_DEBUG_PAD_NAME (pad), res);
2652 GST_SOURCE_GROUP_UNLOCK (group);
2657 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2658 * the selector. This will make the selector select a new pad. */
2660 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2662 GstPlayBin *playbin;
2664 GstElement *selector;
2665 GstSourceSelect *select;
2667 playbin = group->playbin;
2669 GST_DEBUG_OBJECT (playbin,
2670 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2672 GST_SOURCE_GROUP_LOCK (group);
2673 /* get the selector sinkpad */
2674 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2677 if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2678 gulong notify_tags_handler;
2680 notify_tags_handler =
2681 (gulong) g_object_get_data (G_OBJECT (peer),
2682 "playbin2.notify_tags_handler");
2683 if (notify_tags_handler != 0)
2684 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2685 g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2687 /* remove the pad from the array */
2688 g_ptr_array_remove (select->channels, peer);
2689 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2692 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2693 gst_pad_unlink (pad, peer);
2695 /* get selector, this can be NULL when the element is removing the pads
2696 * because it's being disposed. */
2697 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2699 gst_object_unref (peer);
2703 /* release the pad to the selector, this will make the selector choose a new
2705 gst_element_release_request_pad (selector, peer);
2706 gst_object_unref (peer);
2708 gst_object_unref (selector);
2709 GST_SOURCE_GROUP_UNLOCK (group);
2716 GST_DEBUG_OBJECT (playbin, "pad not linked");
2717 GST_SOURCE_GROUP_UNLOCK (group);
2722 GST_DEBUG_OBJECT (playbin, "selector not found");
2723 GST_SOURCE_GROUP_UNLOCK (group);
2728 /* we get called when all pads are available and we must connect the sinks to
2730 * The main purpose of the code is to see if we have video/audio and subtitles
2731 * and pick the right pipelines to display them.
2733 * The selectors installed on the group tell us about the presence of
2734 * audio/video and subtitle streams. This allows us to see if we need
2735 * visualisation, video or/and audio.
2738 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2740 GstPlayBin *playbin;
2741 GstPadLinkReturn res;
2745 playbin = group->playbin;
2747 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2749 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2751 GST_SOURCE_GROUP_LOCK (group);
2752 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2753 GstSourceSelect *select = &group->selector[i];
2755 /* check if the specific media type was detected and thus has a selector
2756 * created for it. If there is the media type, get a sinkpad from the sink
2757 * and link it. We only do this if we have not yet requested the sinkpad
2759 if (select->srcpad && select->sinkpad == NULL) {
2760 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2762 gst_play_sink_request_pad (playbin->playsink, select->type);
2764 res = gst_pad_link (select->srcpad, select->sinkpad);
2765 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2766 select->media_list[0], res);
2767 if (res != GST_PAD_LINK_OK) {
2768 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2769 ("Internal playbin error."),
2770 ("Failed to link selector to sink. Error %d", res));
2774 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2775 group->pending - 1);
2777 if (group->pending > 0)
2780 if (group->suburidecodebin == decodebin)
2781 group->sub_pending = FALSE;
2783 if (group->pending == 0) {
2784 /* we are the last group to complete, we will configure the output and then
2785 * signal the other waiters. */
2786 GST_LOG_OBJECT (playbin, "last group complete");
2789 GST_LOG_OBJECT (playbin, "have more pending groups");
2792 GST_SOURCE_GROUP_UNLOCK (group);
2795 /* if we have custom sinks, configure them now */
2796 GST_SOURCE_GROUP_LOCK (group);
2798 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2800 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2803 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2805 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2808 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
2809 playbin->text_sink);
2810 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2811 playbin->text_sink);
2813 GST_SOURCE_GROUP_UNLOCK (group);
2815 /* signal the other decodebins that they can continue now. */
2816 GST_SOURCE_GROUP_LOCK (group);
2817 /* unblock all selectors */
2818 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2819 GstSourceSelect *select = &group->selector[i];
2821 /* All streamsynchronizer streams should see stream-changed message,
2822 * to arrange for blocking unblocking. */
2823 if (select->sinkpad) {
2829 s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2832 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2833 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2834 seqnum = gst_message_get_seqnum (msg);
2835 event = gst_event_new_sink_message (msg);
2836 g_mutex_lock (group->stream_changed_pending_lock);
2837 group->stream_changed_pending =
2838 g_list_prepend (group->stream_changed_pending,
2839 GUINT_TO_POINTER (seqnum));
2841 /* remove any data probe we might have, and replace */
2842 if (select->sinkpad_delayed_event)
2843 gst_event_unref (select->sinkpad_delayed_event);
2844 select->sinkpad_delayed_event = event;
2845 if (select->sinkpad_data_probe)
2846 gst_pad_remove_probe (select->sinkpad, 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_probe (select->sinkpad, GST_PROBE_TYPE_DATA,
2855 (GstPadProbeCallback) stream_changed_data_probe, (gpointer) select,
2858 g_mutex_unlock (group->stream_changed_pending_lock);
2859 gst_message_unref (msg);
2862 if (select->srcpad) {
2863 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2865 if (select->block_id) {
2866 gst_pad_remove_probe (select->srcpad, select->block_id);
2867 select->block_id = 0;
2871 GST_SOURCE_GROUP_UNLOCK (group);
2874 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2880 GST_DEBUG ("ignoring, we are shutting down");
2881 /* Request a flushing pad from playsink that we then link to the selector.
2882 * Then we unblock the selectors so that they stop with a WRONG_STATE
2883 * instead of a NOT_LINKED error.
2885 GST_SOURCE_GROUP_LOCK (group);
2886 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2887 GstSourceSelect *select = &group->selector[i];
2889 if (select->srcpad) {
2890 if (select->sinkpad == NULL) {
2891 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2893 gst_play_sink_request_pad (playbin->playsink,
2894 GST_PLAY_SINK_TYPE_FLUSHING);
2895 res = gst_pad_link (select->srcpad, select->sinkpad);
2896 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2898 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2900 if (select->block_id) {
2901 gst_pad_remove_probe (select->srcpad, select->block_id);
2902 select->block_id = 0;
2906 GST_SOURCE_GROUP_UNLOCK (group);
2912 drained_cb (GstElement * decodebin, GstSourceGroup * group)
2914 GstPlayBin *playbin;
2916 playbin = group->playbin;
2918 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
2920 /* after this call, we should have a next group to activate or we EOS */
2921 g_signal_emit (G_OBJECT (playbin),
2922 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
2924 /* now activate the next group. If the app did not set a uri, this will
2925 * fail and we can do EOS */
2926 setup_next_source (playbin, GST_STATE_PAUSED);
2929 /* Called when we must provide a list of factories to plug to @pad with @caps.
2930 * We first check if we have a sink that can handle the format and if we do, we
2931 * return NULL, to expose the pad. If we have no sink (or the sink does not
2932 * work), we return the list of elements that can connect. */
2933 static GValueArray *
2934 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
2935 GstCaps * caps, GstSourceGroup * group)
2937 GstPlayBin *playbin;
2938 GList *mylist, *tmp;
2939 GValueArray *result;
2941 playbin = group->playbin;
2943 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
2944 group, GST_DEBUG_PAD_NAME (pad), caps);
2946 /* filter out the elements based on the caps. */
2947 g_mutex_lock (playbin->elements_lock);
2948 gst_play_bin_update_elements_list (playbin);
2950 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
2952 g_mutex_unlock (playbin->elements_lock);
2954 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
2955 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
2957 result = g_value_array_new (g_list_length (mylist));
2959 for (tmp = mylist; tmp; tmp = tmp->next) {
2960 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
2961 GValue val = { 0, };
2963 g_value_init (&val, G_TYPE_OBJECT);
2964 g_value_set_object (&val, factory);
2965 g_value_array_append (result, &val);
2966 g_value_unset (&val);
2968 gst_plugin_feature_list_free (mylist);
2973 /* autoplug-continue decides, if a pad has raw caps that can be exposed
2974 * directly or if further decoding is necessary. We use this to expose
2975 * supported subtitles directly */
2977 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
2978 * explicitely the caps it supports and if it claims to support ANY
2979 * caps it really should support everything */
2981 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
2982 GstSourceGroup * group)
2984 gboolean ret = TRUE;
2986 GstPad *sinkpad = NULL;
2988 GST_PLAY_BIN_LOCK (group->playbin);
2989 GST_SOURCE_GROUP_LOCK (group);
2991 if ((sink = group->playbin->text_sink))
2992 sinkpad = gst_element_get_static_pad (sink, "sink");
2996 /* Ignore errors here, if a custom sink fails to go
2997 * to READY things are wrong and will error out later
2999 if (GST_STATE (sink) < GST_STATE_READY)
3000 gst_element_set_state (sink, GST_STATE_READY);
3002 sinkcaps = gst_pad_get_caps (sinkpad, NULL);
3003 if (!gst_caps_is_any (sinkcaps))
3004 ret = !gst_pad_accept_caps (sinkpad, caps);
3005 gst_caps_unref (sinkcaps);
3006 gst_object_unref (sinkpad);
3008 GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3009 ret = !gst_caps_can_intersect (caps, subcaps);
3010 gst_caps_unref (subcaps);
3012 /* If autoplugging can stop don't do additional checks */
3016 /* If this is from the subtitle uridecodebin we don't need to
3017 * check the audio and video sink */
3018 if (group->suburidecodebin
3019 && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3020 GST_OBJECT_CAST (group->suburidecodebin)))
3023 if ((sink = group->audio_sink)) {
3024 sinkpad = gst_element_get_static_pad (sink, "sink");
3028 /* Ignore errors here, if a custom sink fails to go
3029 * to READY things are wrong and will error out later
3031 if (GST_STATE (sink) < GST_STATE_READY)
3032 gst_element_set_state (sink, GST_STATE_READY);
3034 sinkcaps = gst_pad_get_caps (sinkpad, NULL);
3035 if (!gst_caps_is_any (sinkcaps))
3036 ret = !gst_pad_accept_caps (sinkpad, caps);
3037 gst_caps_unref (sinkcaps);
3038 gst_object_unref (sinkpad);
3044 if ((sink = group->video_sink)) {
3045 sinkpad = gst_element_get_static_pad (sink, "sink");
3049 /* Ignore errors here, if a custom sink fails to go
3050 * to READY things are wrong and will error out later
3052 if (GST_STATE (sink) < GST_STATE_READY)
3053 gst_element_set_state (sink, GST_STATE_READY);
3055 sinkcaps = gst_pad_get_caps (sinkpad, NULL);
3056 if (!gst_caps_is_any (sinkcaps))
3057 ret = !gst_pad_accept_caps (sinkpad, caps);
3058 gst_caps_unref (sinkcaps);
3059 gst_object_unref (sinkpad);
3064 GST_SOURCE_GROUP_UNLOCK (group);
3065 GST_PLAY_BIN_UNLOCK (group->playbin);
3067 GST_DEBUG_OBJECT (group->playbin,
3068 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3069 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3075 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3079 /* ... activate it ... We do this before adding it to the bin so that we
3080 * don't accidentally make it post error messages that will stop
3082 if (GST_STATE (sink) < GST_STATE_READY &&
3083 gst_element_set_state (sink,
3084 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3088 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3089 /* Got the sink pad, now let's see if the element actually does accept the
3090 * caps that we have */
3091 if (!gst_pad_accept_caps (sinkpad, caps)) {
3092 gst_object_unref (sinkpad);
3095 gst_object_unref (sinkpad);
3101 /* We are asked to select an element. See if the next element to check
3102 * is a sink. If this is the case, we see if the sink works by setting it to
3103 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3104 * expose the raw pad so that we can setup the mixers. */
3105 static GstAutoplugSelectResult
3106 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3107 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3109 GstPlayBin *playbin;
3110 GstElement *element;
3112 GstPlaySinkType type;
3115 playbin = group->playbin;
3117 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3118 group, GST_DEBUG_PAD_NAME (pad), caps);
3120 GST_DEBUG_OBJECT (playbin, "checking factory %s", GST_OBJECT_NAME (factory));
3122 /* if it's not a sink, we just make decodebin try it */
3123 if (!gst_element_factory_list_is_type (factory,
3124 GST_ELEMENT_FACTORY_TYPE_SINK))
3125 return GST_AUTOPLUG_SELECT_TRY;
3127 /* it's a sink, see if an instance of it actually works */
3128 GST_DEBUG_OBJECT (playbin, "we found a sink");
3130 klass = gst_element_factory_get_klass (factory);
3132 /* figure out the klass */
3133 if (strstr (klass, "Audio")) {
3134 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3135 type = GST_PLAY_SINK_TYPE_AUDIO;
3136 sinkp = &group->audio_sink;
3137 } else if (strstr (klass, "Video")) {
3138 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3139 type = GST_PLAY_SINK_TYPE_VIDEO;
3140 sinkp = &group->video_sink;
3142 /* unknown klass, skip this element */
3143 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3144 return GST_AUTOPLUG_SELECT_SKIP;
3147 /* if we are asked to do visualisations and it's an audio sink, skip the
3148 * element. We can only do visualisations with raw sinks */
3149 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3150 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3151 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3152 return GST_AUTOPLUG_SELECT_SKIP;
3156 /* now see if we already have a sink element */
3157 GST_SOURCE_GROUP_LOCK (group);
3159 GstElement *sink = gst_object_ref (*sinkp);
3161 if (sink_accepts_caps (sink, caps)) {
3162 GST_DEBUG_OBJECT (playbin,
3163 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3164 GST_ELEMENT_NAME (sink), caps);
3165 gst_object_unref (sink);
3166 GST_SOURCE_GROUP_UNLOCK (group);
3167 return GST_AUTOPLUG_SELECT_EXPOSE;
3169 GST_DEBUG_OBJECT (playbin,
3170 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3171 GST_ELEMENT_NAME (sink), caps);
3172 gst_object_unref (sink);
3173 GST_SOURCE_GROUP_UNLOCK (group);
3174 return GST_AUTOPLUG_SELECT_SKIP;
3177 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3179 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3180 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3181 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3182 GST_SOURCE_GROUP_UNLOCK (group);
3183 return GST_AUTOPLUG_SELECT_SKIP;
3186 /* Check if the selected sink actually supports the
3187 * caps and can be set to READY*/
3188 if (!sink_accepts_caps (element, caps)) {
3189 gst_element_set_state (element, GST_STATE_NULL);
3190 gst_object_unref (element);
3191 GST_SOURCE_GROUP_UNLOCK (group);
3192 return GST_AUTOPLUG_SELECT_SKIP;
3195 /* remember the sink in the group now, the element is floating, we take
3198 * store the sink in the group, we will configure it later when we
3199 * reconfigure the sink */
3200 GST_DEBUG_OBJECT (playbin, "remember sink");
3201 gst_object_ref_sink (element);
3203 GST_SOURCE_GROUP_UNLOCK (group);
3205 /* tell decodebin to expose the pad because we are going to use this
3207 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3209 return GST_AUTOPLUG_SELECT_EXPOSE;
3213 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3214 GstSourceGroup * group)
3216 GstPlayBin *playbin;
3219 playbin = group->playbin;
3221 g_object_get (group->uridecodebin, "source", &source, NULL);
3223 GST_OBJECT_LOCK (playbin);
3224 if (playbin->source)
3225 gst_object_unref (playbin->source);
3226 playbin->source = source;
3227 GST_OBJECT_UNLOCK (playbin);
3229 g_object_notify (G_OBJECT (playbin), "source");
3231 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3232 0, playbin->source);
3235 /* must be called with the group lock */
3237 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3240 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3242 if (group->uridecodebin)
3243 gst_element_set_locked_state (group->uridecodebin, locked);
3244 if (group->suburidecodebin)
3245 gst_element_set_locked_state (group->suburidecodebin, locked);
3250 /* must be called with PLAY_BIN_LOCK */
3252 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3254 GstElement *uridecodebin;
3255 GstElement *suburidecodebin = NULL;
3258 g_return_val_if_fail (group->valid, FALSE);
3259 g_return_val_if_fail (!group->active, FALSE);
3261 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3263 GST_SOURCE_GROUP_LOCK (group);
3265 /* First set up the custom sources */
3266 if (playbin->audio_sink)
3267 group->audio_sink = gst_object_ref (playbin->audio_sink);
3268 if (playbin->video_sink)
3269 group->video_sink = gst_object_ref (playbin->video_sink);
3271 g_list_free (group->stream_changed_pending);
3272 group->stream_changed_pending = NULL;
3273 if (!group->stream_changed_pending_lock)
3274 group->stream_changed_pending_lock = g_mutex_new ();
3276 if (group->uridecodebin) {
3277 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3278 uridecodebin = group->uridecodebin;
3279 gst_element_set_state (uridecodebin, GST_STATE_READY);
3280 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3282 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3283 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3286 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3287 group->uridecodebin = gst_object_ref (uridecodebin);
3290 flags = gst_play_sink_get_flags (playbin->playsink);
3292 g_object_set (uridecodebin,
3293 /* configure connection speed */
3294 "connection-speed", playbin->connection_speed / 1000,
3297 /* configure download buffering */
3298 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3299 /* configure buffering of demuxed/parsed data */
3300 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3301 /* configure buffering parameters */
3302 "buffer-duration", playbin->buffer_duration,
3303 "buffer-size", playbin->buffer_size,
3304 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3306 /* connect pads and other things */
3307 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3308 G_CALLBACK (pad_added_cb), group);
3309 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3310 G_CALLBACK (pad_removed_cb), group);
3311 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3312 G_CALLBACK (no_more_pads_cb), group);
3313 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3314 G_CALLBACK (notify_source_cb), group);
3316 /* we have 1 pending no-more-pads */
3319 /* is called when the uridecodebin is out of data and we can switch to the
3322 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3325 /* will be called when a new media type is found. We return a list of decoders
3326 * including sinks for decodebin to try */
3327 group->autoplug_factories_id =
3328 g_signal_connect (uridecodebin, "autoplug-factories",
3329 G_CALLBACK (autoplug_factories_cb), group);
3330 group->autoplug_select_id =
3331 g_signal_connect (uridecodebin, "autoplug-select",
3332 G_CALLBACK (autoplug_select_cb), group);
3333 group->autoplug_continue_id =
3334 g_signal_connect (uridecodebin, "autoplug-continue",
3335 G_CALLBACK (autoplug_continue_cb), group);
3337 if (group->suburi) {
3339 if (group->suburidecodebin) {
3340 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3341 suburidecodebin = group->suburidecodebin;
3342 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3343 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3345 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3346 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3347 if (!suburidecodebin)
3350 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3351 group->suburidecodebin = gst_object_ref (suburidecodebin);
3354 g_object_set (suburidecodebin,
3355 /* configure connection speed */
3356 "connection-speed", playbin->connection_speed,
3358 "uri", group->suburi, NULL);
3360 /* connect pads and other things */
3361 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3362 G_CALLBACK (pad_added_cb), group);
3363 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3364 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3365 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3366 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3368 group->sub_autoplug_continue_id =
3369 g_signal_connect (suburidecodebin, "autoplug-continue",
3370 G_CALLBACK (autoplug_continue_cb), group);
3372 /* we have 2 pending no-more-pads */
3374 group->sub_pending = TRUE;
3376 group->sub_pending = FALSE;
3379 /* release the group lock before setting the state of the decodebins, they
3380 * might fire signals in this thread that we need to handle with the
3381 * group_lock taken. */
3382 GST_SOURCE_GROUP_UNLOCK (group);
3384 if (suburidecodebin) {
3385 if (gst_element_set_state (suburidecodebin,
3386 target) == GST_STATE_CHANGE_FAILURE) {
3387 GST_DEBUG_OBJECT (playbin,
3388 "failed state change of subtitle uridecodebin");
3389 GST_SOURCE_GROUP_LOCK (group);
3391 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3392 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3393 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3394 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3395 /* Might already be removed because of an error message */
3396 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3397 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3398 if (group->sub_pending) {
3400 group->sub_pending = FALSE;
3402 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3403 GST_SOURCE_GROUP_UNLOCK (group);
3406 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3407 goto uridecodebin_failure;
3409 GST_SOURCE_GROUP_LOCK (group);
3410 /* alow state changes of the playbin2 affect the group elements now */
3411 group_set_locked_state_unlocked (playbin, group, FALSE);
3412 group->active = TRUE;
3413 GST_SOURCE_GROUP_UNLOCK (group);
3422 /* delete any custom sinks we might have */
3423 if (group->audio_sink) {
3424 /* If this is a automatically created sink set it to NULL */
3425 if (group->audio_sink != playbin->audio_sink)
3426 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3427 gst_object_unref (group->audio_sink);
3429 group->audio_sink = NULL;
3430 if (group->video_sink) {
3431 /* If this is a automatically created sink set it to NULL */
3432 if (group->video_sink != playbin->video_sink)
3433 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3434 gst_object_unref (group->video_sink);
3436 group->video_sink = NULL;
3438 GST_SOURCE_GROUP_UNLOCK (group);
3440 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3442 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3444 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3445 (_("Could not create \"uridecodebin\" element.")), (NULL));
3448 uridecodebin_failure:
3450 /* delete any custom sinks we might have */
3451 if (group->audio_sink) {
3452 /* If this is a automatically created sink set it to NULL */
3453 if (group->audio_sink != playbin->audio_sink)
3454 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3455 gst_object_unref (group->audio_sink);
3457 group->audio_sink = NULL;
3458 if (group->video_sink) {
3459 /* If this is a automatically created sink set it to NULL */
3460 if (group->video_sink != playbin->video_sink)
3461 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3462 gst_object_unref (group->video_sink);
3464 group->video_sink = NULL;
3466 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3471 /* unlink a group of uridecodebins from the sink.
3472 * must be called with PLAY_BIN_LOCK */
3474 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3478 g_return_val_if_fail (group->valid, FALSE);
3479 g_return_val_if_fail (group->active, FALSE);
3481 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3483 GST_SOURCE_GROUP_LOCK (group);
3484 group->active = FALSE;
3485 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3486 GstSourceSelect *select = &group->selector[i];
3488 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3490 if (select->srcpad) {
3491 if (select->sinkpad) {
3492 GST_LOG_OBJECT (playbin, "unlinking from sink");
3493 gst_pad_unlink (select->srcpad, select->sinkpad);
3496 GST_LOG_OBJECT (playbin, "release sink pad");
3497 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3498 select->sinkpad = NULL;
3501 gst_object_unref (select->srcpad);
3502 select->srcpad = NULL;
3505 if (select->selector) {
3508 /* release and unref requests pad from the selector */
3509 for (n = 0; n < select->channels->len; n++) {
3510 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3512 gst_element_release_request_pad (select->selector, sinkpad);
3513 gst_object_unref (sinkpad);
3515 g_ptr_array_set_size (select->channels, 0);
3517 gst_element_set_state (select->selector, GST_STATE_NULL);
3518 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3519 select->selector = NULL;
3522 /* delete any custom sinks we might have */
3523 if (group->audio_sink) {
3524 /* If this is a automatically created sink set it to NULL */
3525 if (group->audio_sink != playbin->audio_sink)
3526 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3527 gst_object_unref (group->audio_sink);
3529 group->audio_sink = NULL;
3530 if (group->video_sink) {
3531 /* If this is a automatically created sink set it to NULL */
3532 if (group->video_sink != playbin->video_sink)
3533 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3534 gst_object_unref (group->video_sink);
3536 group->video_sink = NULL;
3538 if (group->uridecodebin) {
3539 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3540 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3541 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3542 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3543 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3544 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3545 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3546 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3547 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3550 if (group->suburidecodebin) {
3551 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3552 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3553 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3554 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3556 /* Might already be removed because of errors */
3557 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3558 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3561 GST_SOURCE_GROUP_UNLOCK (group);
3566 /* setup the next group to play, this assumes the next_group is valid and
3567 * configured. It swaps out the current_group and activates the valid
3570 setup_next_source (GstPlayBin * playbin, GstState target)
3572 GstSourceGroup *new_group, *old_group;
3574 GST_DEBUG_OBJECT (playbin, "setup sources");
3576 /* see if there is a next group */
3577 GST_PLAY_BIN_LOCK (playbin);
3578 new_group = playbin->next_group;
3579 if (!new_group || !new_group->valid)
3582 /* first unlink the current source, if any */
3583 old_group = playbin->curr_group;
3584 if (old_group && old_group->valid && old_group->active) {
3585 gst_play_bin_update_cached_duration (playbin);
3586 /* unlink our pads with the sink */
3587 deactivate_group (playbin, old_group);
3588 old_group->valid = FALSE;
3591 /* swap old and new */
3592 playbin->curr_group = new_group;
3593 playbin->next_group = old_group;
3595 /* activate the new group */
3596 if (!activate_group (playbin, new_group, target))
3597 goto activate_failed;
3599 GST_PLAY_BIN_UNLOCK (playbin);
3606 GST_DEBUG_OBJECT (playbin, "no next group");
3607 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3608 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3609 GST_PLAY_BIN_UNLOCK (playbin);
3614 GST_DEBUG_OBJECT (playbin, "activate failed");
3615 GST_PLAY_BIN_UNLOCK (playbin);
3620 /* The group that is currently playing is copied again to the
3621 * next_group so that it will start playing the next time.
3624 save_current_group (GstPlayBin * playbin)
3626 GstSourceGroup *curr_group;
3628 GST_DEBUG_OBJECT (playbin, "save current group");
3630 /* see if there is a current group */
3631 GST_PLAY_BIN_LOCK (playbin);
3632 curr_group = playbin->curr_group;
3633 if (curr_group && curr_group->valid) {
3634 /* unlink our pads with the sink */
3635 deactivate_group (playbin, curr_group);
3637 /* swap old and new */
3638 playbin->curr_group = playbin->next_group;
3639 playbin->next_group = curr_group;
3640 GST_PLAY_BIN_UNLOCK (playbin);
3645 /* clear the locked state from all groups. This function is called before a
3646 * state change to NULL is performed on them. */
3648 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3650 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3653 GST_PLAY_BIN_LOCK (playbin);
3654 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3655 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3656 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3657 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3658 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3659 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3660 GST_PLAY_BIN_UNLOCK (playbin);
3665 static GstStateChangeReturn
3666 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3668 GstStateChangeReturn ret;
3669 GstPlayBin *playbin;
3670 gboolean do_save = FALSE;
3672 playbin = GST_PLAY_BIN (element);
3674 switch (transition) {
3675 case GST_STATE_CHANGE_NULL_TO_READY:
3676 memset (&playbin->duration, 0, sizeof (playbin->duration));
3678 case GST_STATE_CHANGE_READY_TO_PAUSED:
3679 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3680 memset (&playbin->duration, 0, sizeof (playbin->duration));
3681 g_atomic_int_set (&playbin->shutdown, 0);
3683 if (!setup_next_source (playbin, GST_STATE_READY)) {
3684 ret = GST_STATE_CHANGE_FAILURE;
3688 case GST_STATE_CHANGE_PAUSED_TO_READY:
3690 /* FIXME unlock our waiting groups */
3691 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3692 g_atomic_int_set (&playbin->shutdown, 1);
3693 memset (&playbin->duration, 0, sizeof (playbin->duration));
3695 /* wait for all callbacks to end by taking the lock.
3696 * No dynamic (critical) new callbacks will
3697 * be able to happen as we set the shutdown flag. */
3698 GST_PLAY_BIN_DYN_LOCK (playbin);
3699 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3700 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3703 case GST_STATE_CHANGE_READY_TO_NULL:
3704 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3705 * an no state change PAUSED to READY passes here,
3706 * though it is a nice-to-have ... */
3707 if (!g_atomic_int_get (&playbin->shutdown)) {
3711 memset (&playbin->duration, 0, sizeof (playbin->duration));
3713 /* unlock so that all groups go to NULL */
3714 groups_set_locked_state (playbin, FALSE);
3720 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3721 if (ret == GST_STATE_CHANGE_FAILURE)
3724 switch (transition) {
3725 case GST_STATE_CHANGE_READY_TO_PAUSED:
3727 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3728 /* FIXME Release audio device when we implement that */
3730 case GST_STATE_CHANGE_PAUSED_TO_READY:
3731 save_current_group (playbin);
3733 case GST_STATE_CHANGE_READY_TO_NULL:
3737 /* also do missed state change down to READY */
3739 save_current_group (playbin);
3740 /* Deactive the groups, set the uridecodebins to NULL
3743 for (i = 0; i < 2; i++) {
3744 if (playbin->groups[i].active && playbin->groups[i].valid) {
3745 deactivate_group (playbin, &playbin->groups[i]);
3746 playbin->groups[i].valid = FALSE;
3749 if (playbin->groups[i].uridecodebin) {
3750 gst_element_set_state (playbin->groups[i].uridecodebin,
3752 gst_object_unref (playbin->groups[i].uridecodebin);
3753 playbin->groups[i].uridecodebin = NULL;
3756 if (playbin->groups[i].suburidecodebin) {
3757 gst_element_set_state (playbin->groups[i].suburidecodebin,
3759 gst_object_unref (playbin->groups[i].suburidecodebin);
3760 playbin->groups[i].suburidecodebin = NULL;
3764 /* Set our sinks back to NULL, they might not be child of playbin */
3765 if (playbin->audio_sink)
3766 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
3767 if (playbin->video_sink)
3768 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
3769 if (playbin->text_sink)
3770 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
3772 /* make sure the groups don't perform a state change anymore until we
3773 * enable them again */
3774 groups_set_locked_state (playbin, TRUE);
3786 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
3787 GstSourceGroup *curr_group;
3789 curr_group = playbin->curr_group;
3790 if (curr_group && curr_group->active && curr_group->valid) {
3791 /* unlink our pads with the sink */
3792 deactivate_group (playbin, curr_group);
3793 curr_group->valid = FALSE;
3796 /* Swap current and next group back */
3797 playbin->curr_group = playbin->next_group;
3798 playbin->next_group = curr_group;
3805 gst_play_bin2_plugin_init (GstPlugin * plugin)
3807 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
3809 return gst_element_register (plugin, "playbin2", GST_RANK_NONE,