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).
223 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
224 * with newer GLib versions (>= 2.31.0) */
225 #define GLIB_DISABLE_DEPRECATION_WARNINGS
230 #include <gst/gst-i18n-plugin.h>
231 #include <gst/pbutils/pbutils.h>
232 #include <gst/interfaces/streamvolume.h>
234 #include "gstplay-enum.h"
235 #include "gstplay-marshal.h"
236 #include "gstplayback.h"
237 #include "gstplaysink.h"
238 #include "gstsubtitleoverlay.h"
240 #include "gst/glib-compat-private.h"
242 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
243 #define GST_CAT_DEFAULT gst_play_bin_debug
245 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type())
246 #define GST_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
247 #define GST_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
248 #define GST_IS_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
249 #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
251 #define VOLUME_MAX_DOUBLE 10.0
253 typedef struct _GstPlayBin GstPlayBin;
254 typedef struct _GstPlayBinClass GstPlayBinClass;
255 typedef struct _GstSourceGroup GstSourceGroup;
256 typedef struct _GstSourceSelect GstSourceSelect;
258 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
260 /* has the info for a selector and provides the link to the sink */
261 struct _GstSourceSelect
263 const gchar *media_list[8]; /* the media types for the selector */
264 SourceSelectGetMediaCapsFunc get_media_caps; /* more complex caps for the selector */
265 GstPlaySinkType type; /* the sink pad type of the selector */
267 GstElement *selector; /* the selector */
269 GstPad *srcpad; /* the source pad of the selector */
270 GstPad *sinkpad; /* the sinkpad of the sink when the selector
273 GstEvent *sinkpad_delayed_event;
274 gulong sinkpad_data_probe;
277 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
278 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
279 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
283 PLAYBIN_STREAM_AUDIO = 0,
284 PLAYBIN_STREAM_VIDEO,
289 /* a structure to hold the objects for decoding a uri and the subtitle uri
291 struct _GstSourceGroup
297 gboolean valid; /* the group has valid info to start playback */
298 gboolean active; /* the group is active */
303 GValueArray *streaminfo;
306 GPtrArray *video_channels; /* links to selector pads */
307 GPtrArray *audio_channels; /* links to selector pads */
308 GPtrArray *text_channels; /* links to selector pads */
310 GstElement *audio_sink; /* autoplugged audio and video sinks */
311 GstElement *video_sink;
313 /* uridecodebins for uri and subtitle uri */
314 GstElement *uridecodebin;
315 GstElement *suburidecodebin;
317 gboolean sub_pending;
320 gulong pad_removed_id;
321 gulong no_more_pads_id;
322 gulong notify_source_id;
324 gulong autoplug_factories_id;
325 gulong autoplug_select_id;
326 gulong autoplug_continue_id;
328 gulong sub_pad_added_id;
329 gulong sub_pad_removed_id;
330 gulong sub_no_more_pads_id;
331 gulong sub_autoplug_continue_id;
333 GMutex *stream_changed_pending_lock;
334 GList *stream_changed_pending;
336 /* selectors for different streams */
337 GstSourceSelect selector[PLAYBIN_STREAM_LAST];
340 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
341 #define GST_PLAY_BIN_LOCK(bin) (g_static_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
342 #define GST_PLAY_BIN_UNLOCK(bin) (g_static_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
344 /* lock to protect dynamic callbacks, like no-more-pads */
345 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->dyn_lock)
346 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->dyn_lock)
348 /* lock for shutdown */
349 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
351 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
353 GST_PLAY_BIN_DYN_LOCK (bin); \
354 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
355 GST_PLAY_BIN_DYN_UNLOCK (bin); \
360 /* unlock for shutdown */
361 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
362 GST_PLAY_BIN_DYN_UNLOCK (bin); \
367 * playbin element structure
373 GStaticRecMutex lock; /* to protect group switching */
375 /* the groups, we use a double buffer to switch between current and next */
376 GstSourceGroup groups[2]; /* array with group info */
377 GstSourceGroup *curr_group; /* pointer to the currently playing group */
378 GstSourceGroup *next_group; /* pointer to the next group */
381 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
382 gint current_video; /* the currently selected stream */
383 gint current_audio; /* the currently selected stream */
384 gint current_text; /* the currently selected stream */
386 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
387 guint buffer_size; /* When buffering, the max buffer size (bytes) */
390 GstPlaySink *playsink;
392 /* the last activated source */
395 /* lock protecting dynamic adding/removing */
397 /* if we are shutting down or not */
400 GMutex *elements_lock;
401 guint32 elements_cookie;
402 GList *elements; /* factories we can use for selecting elements */
404 gboolean have_selector; /* set to FALSE when we fail to create an
405 * input-selector, so that we only post a
408 GstElement *audio_sink; /* configured audio sink, or NULL */
409 GstElement *video_sink; /* configured video sink, or NULL */
410 GstElement *text_sink; /* configured text sink, or NULL */
417 } duration[5]; /* cached durations */
419 guint64 ring_buffer_max_size; /* 0 means disabled */
422 struct _GstPlayBinClass
424 GstPipelineClass parent_class;
426 /* notify app that the current uri finished decoding and it is possible to
427 * queue a new one for gapless playback */
428 void (*about_to_finish) (GstPlayBin * playbin);
430 /* notify app that number of audio/video/text streams changed */
431 void (*video_changed) (GstPlayBin * playbin);
432 void (*audio_changed) (GstPlayBin * playbin);
433 void (*text_changed) (GstPlayBin * playbin);
435 /* notify app that the tags of audio/video/text streams changed */
436 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
437 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
438 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
440 /* get audio/video/text tags for a stream */
441 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
442 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
443 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
445 /* get the last video frame and convert it to the given caps */
446 GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
448 /* get audio/video/text pad for a stream */
449 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
450 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
451 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
455 #define DEFAULT_URI NULL
456 #define DEFAULT_SUBURI NULL
457 #define DEFAULT_SOURCE NULL
458 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
459 GST_PLAY_FLAG_SOFT_VOLUME
460 #define DEFAULT_N_VIDEO 0
461 #define DEFAULT_CURRENT_VIDEO -1
462 #define DEFAULT_N_AUDIO 0
463 #define DEFAULT_CURRENT_AUDIO -1
464 #define DEFAULT_N_TEXT 0
465 #define DEFAULT_CURRENT_TEXT -1
466 #define DEFAULT_SUBTITLE_ENCODING NULL
467 #define DEFAULT_AUDIO_SINK NULL
468 #define DEFAULT_VIDEO_SINK NULL
469 #define DEFAULT_VIS_PLUGIN NULL
470 #define DEFAULT_TEXT_SINK NULL
471 #define DEFAULT_VOLUME 1.0
472 #define DEFAULT_MUTE FALSE
473 #define DEFAULT_FRAME NULL
474 #define DEFAULT_FONT_DESC NULL
475 #define DEFAULT_CONNECTION_SPEED 0
476 #define DEFAULT_BUFFER_DURATION -1
477 #define DEFAULT_BUFFER_SIZE -1
478 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
493 PROP_SUBTITLE_ENCODING,
502 PROP_CONNECTION_SPEED,
504 PROP_BUFFER_DURATION,
506 PROP_RING_BUFFER_MAX_SIZE,
514 SIGNAL_ABOUT_TO_FINISH,
515 SIGNAL_CONVERT_FRAME,
516 SIGNAL_VIDEO_CHANGED,
517 SIGNAL_AUDIO_CHANGED,
519 SIGNAL_VIDEO_TAGS_CHANGED,
520 SIGNAL_AUDIO_TAGS_CHANGED,
521 SIGNAL_TEXT_TAGS_CHANGED,
522 SIGNAL_GET_VIDEO_TAGS,
523 SIGNAL_GET_AUDIO_TAGS,
524 SIGNAL_GET_TEXT_TAGS,
525 SIGNAL_GET_VIDEO_PAD,
526 SIGNAL_GET_AUDIO_PAD,
532 static void gst_play_bin_class_init (GstPlayBinClass * klass);
533 static void gst_play_bin_init (GstPlayBin * playbin);
534 static void gst_play_bin_finalize (GObject * object);
536 static void gst_play_bin_set_property (GObject * object, guint prop_id,
537 const GValue * value, GParamSpec * spec);
538 static void gst_play_bin_get_property (GObject * object, guint prop_id,
539 GValue * value, GParamSpec * spec);
541 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
542 GstStateChange transition);
544 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
545 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
547 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
549 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
551 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
554 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
557 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
558 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
559 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
561 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
563 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
564 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
565 GstSourceGroup * group);
567 static void gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
569 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
572 static GstElementClass *parent_class;
574 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
576 #define REMOVE_SIGNAL(obj,id) \
578 g_signal_handler_disconnect (obj, id); \
583 gst_play_bin_get_type (void)
585 static GType gst_play_bin_type = 0;
587 if (!gst_play_bin_type) {
588 static const GTypeInfo gst_play_bin_info = {
589 sizeof (GstPlayBinClass),
592 (GClassInitFunc) gst_play_bin_class_init,
597 (GInstanceInitFunc) gst_play_bin_init,
600 static const GInterfaceInfo svol_info = {
604 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
605 "GstPlayBin2", &gst_play_bin_info, 0);
607 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
611 return gst_play_bin_type;
615 gst_play_bin_class_init (GstPlayBinClass * klass)
617 GObjectClass *gobject_klass;
618 GstElementClass *gstelement_klass;
619 GstBinClass *gstbin_klass;
621 gobject_klass = (GObjectClass *) klass;
622 gstelement_klass = (GstElementClass *) klass;
623 gstbin_klass = (GstBinClass *) klass;
625 parent_class = g_type_class_peek_parent (klass);
627 gobject_klass->set_property = gst_play_bin_set_property;
628 gobject_klass->get_property = gst_play_bin_get_property;
630 gobject_klass->finalize = gst_play_bin_finalize;
635 * Set the next URI that playbin will play. This property can be set from the
636 * about-to-finish signal to queue the next media file.
638 g_object_class_install_property (gobject_klass, PROP_URI,
639 g_param_spec_string ("uri", "URI", "URI of the media to play",
640 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
645 * Set the next subtitle URI that playbin will play. This property can be
646 * set from the about-to-finish signal to queue the next subtitle media file.
648 g_object_class_install_property (gobject_klass, PROP_SUBURI,
649 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
650 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
652 g_object_class_install_property (gobject_klass, PROP_SOURCE,
653 g_param_spec_object ("source", "Source", "Source element",
654 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
659 * Control the behaviour of playbin.
661 g_object_class_install_property (gobject_klass, PROP_FLAGS,
662 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
663 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
664 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
667 * GstPlayBin2:n-video
669 * Get the total number of available video streams.
671 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
672 g_param_spec_int ("n-video", "Number Video",
673 "Total number of video streams", 0, G_MAXINT, 0,
674 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
676 * GstPlayBin2:current-video
678 * Get or set the currently playing video stream. By default the first video
679 * stream with data is played.
681 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
682 g_param_spec_int ("current-video", "Current Video",
683 "Currently playing video stream (-1 = auto)",
684 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
686 * GstPlayBin2:n-audio
688 * Get the total number of available audio streams.
690 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
691 g_param_spec_int ("n-audio", "Number Audio",
692 "Total number of audio streams", 0, G_MAXINT, 0,
693 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
695 * GstPlayBin2:current-audio
697 * Get or set the currently playing audio stream. By default the first audio
698 * stream with data is played.
700 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
701 g_param_spec_int ("current-audio", "Current audio",
702 "Currently playing audio stream (-1 = auto)",
703 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
707 * Get the total number of available subtitle streams.
709 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
710 g_param_spec_int ("n-text", "Number Text",
711 "Total number of text streams", 0, G_MAXINT, 0,
712 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
714 * GstPlayBin2:current-text:
716 * Get or set the currently playing subtitle stream. By default the first
717 * subtitle stream with data is played.
719 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
720 g_param_spec_int ("current-text", "Current Text",
721 "Currently playing text stream (-1 = auto)",
722 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
724 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
725 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
726 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
727 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
728 "be checked for an encoding to use. If that is not set either, "
729 "ISO-8859-15 will be assumed.", NULL,
730 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
732 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
733 g_param_spec_object ("video-sink", "Video Sink",
734 "the video 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_AUDIO_SINK,
737 g_param_spec_object ("audio-sink", "Audio Sink",
738 "the audio output element to use (NULL = default sink)",
739 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
740 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
741 g_param_spec_object ("vis-plugin", "Vis plugin",
742 "the visualization element to use (NULL = default)",
743 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
744 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
745 g_param_spec_object ("text-sink", "Text plugin",
746 "the text output element to use (NULL = default textoverlay)",
747 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
750 * GstPlayBin2:volume:
752 * Get or set the current audio stream volume. 1.0 means 100%,
753 * 0.0 means mute. This uses a linear volume scale.
756 g_object_class_install_property (gobject_klass, PROP_VOLUME,
757 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
758 0.0, VOLUME_MAX_DOUBLE, 1.0,
759 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
760 g_object_class_install_property (gobject_klass, PROP_MUTE,
761 g_param_spec_boolean ("mute", "Mute",
762 "Mute the audio channel without changing the volume", FALSE,
763 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
767 * @playbin: a #GstPlayBin2
769 * Get the currently rendered or prerolled frame in the video sink.
770 * The #GstCaps on the buffer will describe the format of the buffer.
772 g_object_class_install_property (gobject_klass, PROP_FRAME,
773 gst_param_spec_mini_object ("frame", "Frame",
774 "The last frame (NULL = no video available)",
775 GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
776 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
777 g_param_spec_string ("subtitle-font-desc",
778 "Subtitle font description",
779 "Pango font description of font "
780 "to be used for subtitle rendering", NULL,
781 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
783 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
784 g_param_spec_uint ("connection-speed", "Connection Speed",
785 "Network connection speed in kbps (0 = unknown)",
786 0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
787 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
789 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
790 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
791 "Buffer size when buffering network streams",
792 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
793 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
794 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
795 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
796 "Buffer duration when buffering network streams",
797 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
798 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
800 * GstPlayBin2:av-offset:
802 * Control the synchronisation offset between the audio and video streams.
803 * Positive values make the audio ahead of the video and negative values make
804 * the audio go behind the video.
808 g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
809 g_param_spec_int64 ("av-offset", "AV Offset",
810 "The synchronisation offset between audio and video in nanoseconds",
811 G_MININT64, G_MAXINT64, 0,
812 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
815 * GstQueue2:ring-buffer-max-size
817 * The maximum size of the ring buffer in bytes. If set to 0, the ring
818 * buffer is disabled. Default 0.
822 g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
823 g_param_spec_uint64 ("ring-buffer-max-size",
824 "Max. ring buffer size (bytes)",
825 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
826 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
827 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
831 * Set the role of the stream. This property is used by the platform policy subsystem
832 * to make policy decisions that affect the stream (for example routing and enforced
835 g_object_class_install_property (gobject_klass, PROP_ROLE,
836 g_param_spec_string ("role", "Stream role",
837 "Stream role for the platform policy sybsystem", NULL,
838 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
841 * GstPlayBin2::about-to-finish
842 * @playbin: a #GstPlayBin2
844 * This signal is emitted when the current uri is about to finish. You can
845 * set the uri and suburi to make sure that playback continues.
847 * This signal is emitted from the context of a GStreamer streaming thread.
849 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
850 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
852 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
853 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
856 * GstPlayBin2::video-changed
857 * @playbin: a #GstPlayBin2
859 * This signal is emitted whenever the number or order of the video
860 * streams has changed. The application will most likely want to select
861 * a new video stream.
863 * This signal is usually emitted from the context of a GStreamer streaming
864 * thread. You can use gst_message_new_application() and
865 * gst_element_post_message() to notify your application's main thread.
867 /* FIXME 0.11: turn video-changed signal into message? */
868 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
869 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
871 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
872 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
874 * GstPlayBin2::audio-changed
875 * @playbin: a #GstPlayBin2
877 * This signal is emitted whenever the number or order of the audio
878 * streams has changed. The application will most likely want to select
879 * a new audio stream.
881 * This signal may be emitted from the context of a GStreamer streaming thread.
882 * You can use gst_message_new_application() and gst_element_post_message()
883 * to notify your application's main thread.
885 /* FIXME 0.11: turn audio-changed signal into message? */
886 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
887 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
889 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
890 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
892 * GstPlayBin2::text-changed
893 * @playbin: a #GstPlayBin2
895 * This signal is emitted whenever the number or order of the text
896 * streams has changed. The application will most likely want to select
899 * This signal may be emitted from the context of a GStreamer streaming thread.
900 * You can use gst_message_new_application() and gst_element_post_message()
901 * to notify your application's main thread.
903 /* FIXME 0.11: turn text-changed signal into message? */
904 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
905 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
907 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
908 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
911 * GstPlayBin2::video-tags-changed
912 * @playbin: a #GstPlayBin2
913 * @stream: stream index with changed tags
915 * This signal is emitted whenever the tags of a video stream have changed.
916 * The application will most likely want to get the new tags.
918 * This signal may be emitted from the context of a GStreamer streaming thread.
919 * You can use gst_message_new_application() and gst_element_post_message()
920 * to notify your application's main thread.
924 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
925 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
927 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
928 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
931 * GstPlayBin2::audio-tags-changed
932 * @playbin: a #GstPlayBin2
933 * @stream: stream index with changed tags
935 * This signal is emitted whenever the tags of an audio stream have changed.
936 * The application will most likely want to get the new tags.
938 * This signal may be emitted from the context of a GStreamer streaming thread.
939 * You can use gst_message_new_application() and gst_element_post_message()
940 * to notify your application's main thread.
944 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
945 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
947 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
948 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
951 * GstPlayBin2::text-tags-changed
952 * @playbin: a #GstPlayBin2
953 * @stream: stream index with changed tags
955 * This signal is emitted whenever the tags of a text stream have changed.
956 * The application will most likely want to get the new tags.
958 * This signal may be emitted from the context of a GStreamer streaming thread.
959 * You can use gst_message_new_application() and gst_element_post_message()
960 * to notify your application's main thread.
964 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
965 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
967 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
968 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
971 * GstPlayBin2::source-setup:
972 * @playbin: a #GstPlayBin2
973 * @source: source element
975 * This signal is emitted after the source element has been created, so
976 * it can be configured by setting additional properties (e.g. set a
977 * proxy server for an http source, or set the device and read speed for
978 * an audio cd source). This is functionally equivalent to connecting to
979 * the notify::source signal, but more convenient.
981 * This signal is usually emitted from the context of a GStreamer streaming
986 gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
987 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
988 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
989 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
992 * GstPlayBin2::get-video-tags
993 * @playbin: a #GstPlayBin2
994 * @stream: a video stream number
996 * Action signal to retrieve the tags of a specific video stream number.
997 * This information can be used to select a stream.
999 * Returns: a GstTagList with tags or NULL when the stream number does not
1002 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
1003 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
1004 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1005 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
1006 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1008 * GstPlayBin2::get-audio-tags
1009 * @playbin: a #GstPlayBin2
1010 * @stream: an audio stream number
1012 * Action signal to retrieve the tags of a specific audio stream number.
1013 * This information can be used to select a stream.
1015 * Returns: a GstTagList with tags or NULL when the stream number does not
1018 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
1019 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
1020 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1021 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
1022 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1024 * GstPlayBin2::get-text-tags
1025 * @playbin: a #GstPlayBin2
1026 * @stream: a text stream number
1028 * Action signal to retrieve the tags of a specific text stream number.
1029 * This information can be used to select a stream.
1031 * Returns: a GstTagList with tags or NULL when the stream number does not
1034 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
1035 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
1036 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1037 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
1038 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1040 * GstPlayBin2::convert-frame
1041 * @playbin: a #GstPlayBin2
1042 * @caps: the target format of the frame
1044 * Action signal to retrieve the currently playing video frame in the format
1045 * specified by @caps.
1046 * If @caps is %NULL, no conversion will be performed and this function is
1047 * equivalent to the #GstPlayBin::frame property.
1049 * Returns: a #GstBuffer of the current video frame converted to #caps.
1050 * The caps on the buffer will describe the final layout of the buffer data.
1051 * %NULL is returned when no current buffer can be retrieved or when the
1052 * conversion failed.
1054 gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
1055 g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
1056 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1057 G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
1058 gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
1061 * GstPlayBin2::get-video-pad
1062 * @playbin: a #GstPlayBin2
1063 * @stream: a video stream number
1065 * Action signal to retrieve the stream-selector sinkpad for a specific
1067 * This pad can be used for notifications of caps changes, stream-specific
1070 * Returns: a #GstPad, or NULL when the stream number does not exist.
1072 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1073 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1074 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1075 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1076 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1078 * GstPlayBin2::get-audio-pad
1079 * @playbin: a #GstPlayBin2
1080 * @stream: an audio stream number
1082 * Action signal to retrieve the stream-selector sinkpad for a specific
1084 * This pad can be used for notifications of caps changes, stream-specific
1087 * Returns: a #GstPad, or NULL when the stream number does not exist.
1089 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1090 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1091 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1092 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1093 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1095 * GstPlayBin2::get-text-pad
1096 * @playbin: a #GstPlayBin2
1097 * @stream: a text stream number
1099 * Action signal to retrieve the stream-selector sinkpad for a specific
1101 * This pad can be used for notifications of caps changes, stream-specific
1104 * Returns: a #GstPad, or NULL when the stream number does not exist.
1106 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1107 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1108 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1109 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1110 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1112 klass->get_video_tags = gst_play_bin_get_video_tags;
1113 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1114 klass->get_text_tags = gst_play_bin_get_text_tags;
1116 klass->convert_frame = gst_play_bin_convert_frame;
1118 klass->get_video_pad = gst_play_bin_get_video_pad;
1119 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1120 klass->get_text_pad = gst_play_bin_get_text_pad;
1122 gst_element_class_set_details_simple (gstelement_klass,
1123 "Player Bin 2", "Generic/Bin/Player",
1124 "Autoplug and play media from an uri",
1125 "Wim Taymans <wim.taymans@gmail.com>");
1127 gstelement_klass->change_state =
1128 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1129 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1131 gstbin_klass->handle_message =
1132 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1136 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1140 /* store the array for the different channels */
1141 group->video_channels = g_ptr_array_new ();
1142 group->audio_channels = g_ptr_array_new ();
1143 group->text_channels = g_ptr_array_new ();
1144 group->lock = g_mutex_new ();
1145 /* init selectors. The selector is found by finding the first prefix that
1146 * matches the media. */
1147 group->playbin = playbin;
1148 /* If you add any items to these lists, check that media_list[] is defined
1149 * above to be large enough to hold MAX(items)+1, so as to accommodate a
1150 * NULL terminator (set when the memory is zeroed on allocation) */
1151 group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
1152 group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
1153 group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
1154 group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
1155 group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
1156 group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
1157 group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
1158 group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
1159 group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
1160 group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
1161 group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
1162 group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
1163 group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
1164 group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
1165 gst_subtitle_overlay_create_factory_caps;
1166 group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
1167 group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
1169 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1170 GstSourceSelect *select = &group->selector[n];
1171 select->sinkpad_delayed_event = NULL;
1172 select->sinkpad_data_probe = 0;
1177 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1181 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1182 GstSourceSelect *select = &group->selector[n];
1183 if (select->sinkpad && select->sinkpad_data_probe)
1184 gst_pad_remove_data_probe (select->sinkpad, select->sinkpad_data_probe);
1185 if (select->sinkpad_delayed_event)
1186 gst_event_unref (select->sinkpad_delayed_event);
1189 g_free (group->uri);
1190 g_free (group->suburi);
1191 g_ptr_array_free (group->video_channels, TRUE);
1192 g_ptr_array_free (group->audio_channels, TRUE);
1193 g_ptr_array_free (group->text_channels, TRUE);
1195 g_mutex_free (group->lock);
1196 if (group->audio_sink) {
1197 if (group->audio_sink != playbin->audio_sink)
1198 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1199 gst_object_unref (group->audio_sink);
1201 group->audio_sink = NULL;
1202 if (group->video_sink) {
1203 if (group->video_sink != playbin->video_sink)
1204 gst_element_set_state (group->video_sink, GST_STATE_NULL);
1205 gst_object_unref (group->video_sink);
1207 group->video_sink = NULL;
1209 g_list_free (group->stream_changed_pending);
1210 group->stream_changed_pending = NULL;
1212 if (group->stream_changed_pending_lock)
1213 g_mutex_free (group->stream_changed_pending_lock);
1214 group->stream_changed_pending_lock = NULL;
1218 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1220 g_object_notify (G_OBJECT (playbin), "volume");
1224 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1226 g_object_notify (G_OBJECT (playbin), "mute");
1229 /* Must be called with elements lock! */
1231 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1235 if (!playbin->elements ||
1236 playbin->elements_cookie !=
1237 gst_default_registry_get_feature_list_cookie ()) {
1238 if (playbin->elements)
1239 gst_plugin_feature_list_free (playbin->elements);
1241 gst_element_factory_list_get_elements
1242 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1244 gst_element_factory_list_get_elements
1245 (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1246 playbin->elements = g_list_concat (res, tmp);
1248 g_list_sort (playbin->elements, gst_plugin_feature_rank_compare_func);
1249 playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1254 gst_play_bin_init (GstPlayBin * playbin)
1256 g_static_rec_mutex_init (&playbin->lock);
1257 playbin->dyn_lock = g_mutex_new ();
1259 /* assume we can create a selector */
1260 playbin->have_selector = TRUE;
1263 playbin->curr_group = &playbin->groups[0];
1264 playbin->next_group = &playbin->groups[1];
1265 init_group (playbin, &playbin->groups[0]);
1266 init_group (playbin, &playbin->groups[1]);
1268 /* first filter out the interesting element factories */
1269 playbin->elements_lock = g_mutex_new ();
1272 playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1273 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1274 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1275 /* Connect to notify::volume and notify::mute signals for proxying */
1276 g_signal_connect (playbin->playsink, "notify::volume",
1277 G_CALLBACK (notify_volume_cb), playbin);
1278 g_signal_connect (playbin->playsink, "notify::mute",
1279 G_CALLBACK (notify_mute_cb), playbin);
1281 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1282 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1283 playbin->current_text = DEFAULT_CURRENT_TEXT;
1285 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1286 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1287 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1291 gst_play_bin_finalize (GObject * object)
1293 GstPlayBin *playbin;
1295 playbin = GST_PLAY_BIN (object);
1297 free_group (playbin, &playbin->groups[0]);
1298 free_group (playbin, &playbin->groups[1]);
1300 if (playbin->source)
1301 gst_object_unref (playbin->source);
1302 if (playbin->video_sink) {
1303 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1304 gst_object_unref (playbin->video_sink);
1306 if (playbin->audio_sink) {
1307 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1308 gst_object_unref (playbin->audio_sink);
1310 if (playbin->text_sink) {
1311 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1312 gst_object_unref (playbin->text_sink);
1315 if (playbin->elements)
1316 gst_plugin_feature_list_free (playbin->elements);
1318 g_static_rec_mutex_free (&playbin->lock);
1319 g_mutex_free (playbin->dyn_lock);
1320 g_mutex_free (playbin->elements_lock);
1322 G_OBJECT_CLASS (parent_class)->finalize (object);
1326 gst_playbin_uri_is_valid (GstPlayBin * playbin, const gchar * uri)
1330 GST_LOG_OBJECT (playbin, "checking uri '%s'", uri);
1332 /* this just checks the protocol */
1333 if (!gst_uri_is_valid (uri))
1336 for (c = uri; *c != '\0'; ++c) {
1337 if (!g_ascii_isprint (*c))
1347 GST_WARNING_OBJECT (playbin, "uri '%s' not valid, character #%u",
1348 uri, (guint) ((guintptr) c - (guintptr) uri));
1354 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1356 GstSourceGroup *group;
1359 g_warning ("cannot set NULL uri");
1363 if (!gst_playbin_uri_is_valid (playbin, uri)) {
1364 if (g_str_has_prefix (uri, "file:")) {
1365 GST_WARNING_OBJECT (playbin, "not entirely correct file URI '%s' - make "
1366 "sure to escape spaces and non-ASCII characters properly and specify "
1367 "an absolute path. Use gst_filename_to_uri() to convert filenames "
1370 /* GST_ERROR_OBJECT (playbin, "malformed URI '%s'", uri); */
1374 GST_PLAY_BIN_LOCK (playbin);
1375 group = playbin->next_group;
1377 GST_SOURCE_GROUP_LOCK (group);
1378 /* store the uri in the next group we will play */
1379 g_free (group->uri);
1380 group->uri = g_strdup (uri);
1381 group->valid = TRUE;
1382 GST_SOURCE_GROUP_UNLOCK (group);
1384 GST_DEBUG ("set new uri to %s", uri);
1385 GST_PLAY_BIN_UNLOCK (playbin);
1389 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1391 GstSourceGroup *group;
1393 GST_PLAY_BIN_LOCK (playbin);
1394 group = playbin->next_group;
1396 GST_SOURCE_GROUP_LOCK (group);
1397 g_free (group->suburi);
1398 group->suburi = g_strdup (suburi);
1399 GST_SOURCE_GROUP_UNLOCK (group);
1401 GST_DEBUG ("setting new .sub uri to %s", suburi);
1403 GST_PLAY_BIN_UNLOCK (playbin);
1407 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1409 gst_play_sink_set_flags (playbin->playsink, flags);
1410 gst_play_sink_reconfigure (playbin->playsink);
1414 gst_play_bin_get_flags (GstPlayBin * playbin)
1418 flags = gst_play_sink_get_flags (playbin->playsink);
1423 /* get the currently playing group or if nothing is playing, the next
1424 * group. Must be called with the PLAY_BIN_LOCK. */
1425 static GstSourceGroup *
1426 get_group (GstPlayBin * playbin)
1428 GstSourceGroup *result;
1430 if (!(result = playbin->curr_group))
1431 result = playbin->next_group;
1437 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1439 GstPad *sinkpad = NULL;
1440 GstSourceGroup *group;
1442 GST_PLAY_BIN_LOCK (playbin);
1443 group = get_group (playbin);
1444 if (stream < group->video_channels->len) {
1445 sinkpad = g_ptr_array_index (group->video_channels, stream);
1446 gst_object_ref (sinkpad);
1448 GST_PLAY_BIN_UNLOCK (playbin);
1454 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1456 GstPad *sinkpad = NULL;
1457 GstSourceGroup *group;
1459 GST_PLAY_BIN_LOCK (playbin);
1460 group = get_group (playbin);
1461 if (stream < group->audio_channels->len) {
1462 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1463 gst_object_ref (sinkpad);
1465 GST_PLAY_BIN_UNLOCK (playbin);
1471 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1473 GstPad *sinkpad = NULL;
1474 GstSourceGroup *group;
1476 GST_PLAY_BIN_LOCK (playbin);
1477 group = get_group (playbin);
1478 if (stream < group->text_channels->len) {
1479 sinkpad = g_ptr_array_index (group->text_channels, stream);
1480 gst_object_ref (sinkpad);
1482 GST_PLAY_BIN_UNLOCK (playbin);
1489 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1494 if (!channels || stream >= channels->len)
1497 sinkpad = g_ptr_array_index (channels, stream);
1498 g_object_get (sinkpad, "tags", &result, NULL);
1504 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1507 GstSourceGroup *group;
1509 GST_PLAY_BIN_LOCK (playbin);
1510 group = get_group (playbin);
1511 result = get_tags (playbin, group->video_channels, stream);
1512 GST_PLAY_BIN_UNLOCK (playbin);
1518 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1521 GstSourceGroup *group;
1523 GST_PLAY_BIN_LOCK (playbin);
1524 group = get_group (playbin);
1525 result = get_tags (playbin, group->audio_channels, stream);
1526 GST_PLAY_BIN_UNLOCK (playbin);
1532 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1535 GstSourceGroup *group;
1537 GST_PLAY_BIN_LOCK (playbin);
1538 group = get_group (playbin);
1539 result = get_tags (playbin, group->text_channels, stream);
1540 GST_PLAY_BIN_UNLOCK (playbin);
1546 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1548 return gst_play_sink_convert_frame (playbin->playsink, caps);
1551 /* Returns current stream number, or -1 if none has been selected yet */
1553 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1555 /* Internal API cleanup would make this easier... */
1557 GstPad *pad, *current;
1558 GstObject *selector = NULL;
1561 for (i = 0; i < channels->len; i++) {
1562 pad = g_ptr_array_index (channels, i);
1563 if ((selector = gst_pad_get_parent (pad))) {
1564 g_object_get (selector, "active-pad", ¤t, NULL);
1565 gst_object_unref (selector);
1567 if (pad == current) {
1568 gst_object_unref (current);
1574 gst_object_unref (current);
1582 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1584 GstSourceGroup *group;
1585 GPtrArray *channels;
1588 GST_PLAY_BIN_LOCK (playbin);
1590 GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1591 playbin->current_video, stream);
1593 group = get_group (playbin);
1594 if (!(channels = group->video_channels))
1597 if (stream == -1 || channels->len <= stream) {
1600 /* take channel from selected stream */
1601 sinkpad = g_ptr_array_index (channels, stream);
1605 gst_object_ref (sinkpad);
1606 GST_PLAY_BIN_UNLOCK (playbin);
1609 GstObject *selector;
1611 if ((selector = gst_pad_get_parent (sinkpad))) {
1612 /* activate the selected pad */
1613 g_object_set (selector, "active-pad", sinkpad, NULL);
1614 gst_object_unref (selector);
1616 gst_object_unref (sinkpad);
1622 GST_PLAY_BIN_UNLOCK (playbin);
1623 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1629 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1631 GstSourceGroup *group;
1632 GPtrArray *channels;
1635 GST_PLAY_BIN_LOCK (playbin);
1637 GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1638 playbin->current_audio, stream);
1640 group = get_group (playbin);
1641 if (!(channels = group->audio_channels))
1644 if (stream == -1 || channels->len <= stream) {
1647 /* take channel from selected stream */
1648 sinkpad = g_ptr_array_index (channels, stream);
1652 gst_object_ref (sinkpad);
1653 GST_PLAY_BIN_UNLOCK (playbin);
1656 GstObject *selector;
1658 if ((selector = gst_pad_get_parent (sinkpad))) {
1659 /* activate the selected pad */
1660 g_object_set (selector, "active-pad", sinkpad, NULL);
1661 gst_object_unref (selector);
1663 gst_object_unref (sinkpad);
1669 GST_PLAY_BIN_UNLOCK (playbin);
1670 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1676 _suburidecodebin_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
1678 GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
1682 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1684 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1687 if (it && gst_iterator_next (it, (gpointer) & sinkpad) == GST_ITERATOR_OK
1692 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1693 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1694 if (!gst_pad_send_event (sinkpad, event)) {
1696 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1697 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1698 if (!gst_pad_send_event (sinkpad, event))
1699 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1702 gst_object_unref (sinkpad);
1706 gst_iterator_free (it);
1710 gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
1713 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1714 gboolean done = FALSE;
1716 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1723 switch (gst_iterator_next (it, (gpointer) & sinkpad)) {
1724 case GST_ITERATOR_OK:
1725 gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
1727 gst_object_unref (sinkpad);
1729 case GST_ITERATOR_DONE:
1732 case GST_ITERATOR_RESYNC:
1733 gst_iterator_resync (it);
1735 case GST_ITERATOR_ERROR:
1740 gst_iterator_free (it);
1744 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1746 GstSourceGroup *group;
1747 GPtrArray *channels;
1750 GST_PLAY_BIN_LOCK (playbin);
1752 GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1753 playbin->current_text, stream);
1755 group = get_group (playbin);
1756 if (!(channels = group->text_channels))
1759 if (stream == -1 || channels->len <= stream) {
1762 /* take channel from selected stream */
1763 sinkpad = g_ptr_array_index (channels, stream);
1767 gst_object_ref (sinkpad);
1768 GST_PLAY_BIN_UNLOCK (playbin);
1771 GstObject *selector;
1773 if ((selector = gst_pad_get_parent (sinkpad))) {
1774 GstPad *old_sinkpad;
1776 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1778 if (old_sinkpad != sinkpad) {
1779 gboolean need_unblock, need_block, need_seek;
1780 GstPad *src, *peer = NULL, *oldpeer = NULL;
1781 GstElement *parent_element = NULL, *old_parent_element = NULL;
1783 /* Now check if we need to seek the suburidecodebin to the beginning
1784 * or if we need to block all suburidecodebin sinkpads or if we need
1785 * to unblock all suburidecodebin sinkpads
1788 peer = gst_pad_get_peer (sinkpad);
1790 oldpeer = gst_pad_get_peer (old_sinkpad);
1793 parent_element = gst_pad_get_parent_element (peer);
1795 old_parent_element = gst_pad_get_parent_element (oldpeer);
1797 need_block = (old_parent_element == group->suburidecodebin
1798 && parent_element != old_parent_element);
1799 need_unblock = (parent_element == group->suburidecodebin
1800 && parent_element != old_parent_element);
1801 need_seek = (parent_element == group->suburidecodebin);
1804 gst_object_unref (peer);
1806 gst_object_unref (oldpeer);
1808 gst_object_unref (parent_element);
1809 if (old_parent_element)
1810 gst_object_unref (old_parent_element);
1812 /* Block all suburidecodebin sinkpads */
1814 gst_play_bin_suburidecodebin_block (group->suburidecodebin, TRUE);
1816 /* activate the selected pad */
1817 g_object_set (selector, "active-pad", sinkpad, NULL);
1819 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1820 peer = gst_pad_get_peer (src);
1824 /* Flush the subtitle renderer to remove any
1825 * currently displayed subtitles. This event will
1826 * never travel outside subtitleoverlay!
1828 s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1829 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1830 gst_pad_send_event (peer, event);
1831 gst_object_unref (peer);
1833 gst_object_unref (src);
1835 /* Unblock pads if necessary */
1837 gst_play_bin_suburidecodebin_block (group->suburidecodebin, FALSE);
1839 /* seek to the beginning */
1841 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1843 gst_object_unref (selector);
1846 gst_object_unref (old_sinkpad);
1848 gst_object_unref (sinkpad);
1854 GST_PLAY_BIN_UNLOCK (playbin);
1860 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1861 const gchar * dbg, GstElement * sink)
1863 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1865 GST_PLAY_BIN_LOCK (playbin);
1866 if (*elem != sink) {
1871 gst_object_ref_sink (sink);
1875 gst_object_unref (old);
1877 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1878 GST_PLAY_BIN_UNLOCK (playbin);
1882 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1886 GST_PLAY_BIN_LOCK (playbin);
1888 /* set subtitles on all current and next decodebins. */
1889 if ((elem = playbin->groups[0].uridecodebin))
1890 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1891 if ((elem = playbin->groups[0].suburidecodebin))
1892 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1893 if ((elem = playbin->groups[1].uridecodebin))
1894 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1895 if ((elem = playbin->groups[1].suburidecodebin))
1896 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1898 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1899 GST_PLAY_BIN_UNLOCK (playbin);
1903 gst_play_bin_set_property (GObject * object, guint prop_id,
1904 const GValue * value, GParamSpec * pspec)
1906 GstPlayBin *playbin = GST_PLAY_BIN (object);
1910 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1913 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1916 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1918 case PROP_CURRENT_VIDEO:
1919 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1921 case PROP_CURRENT_AUDIO:
1922 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1924 case PROP_CURRENT_TEXT:
1925 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1927 case PROP_SUBTITLE_ENCODING:
1928 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1930 case PROP_VIDEO_SINK:
1931 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1932 g_value_get_object (value));
1934 case PROP_AUDIO_SINK:
1935 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1936 g_value_get_object (value));
1938 case PROP_VIS_PLUGIN:
1939 gst_play_sink_set_vis_plugin (playbin->playsink,
1940 g_value_get_object (value));
1942 case PROP_TEXT_SINK:
1943 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1944 g_value_get_object (value));
1947 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1950 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1952 case PROP_FONT_DESC:
1953 gst_play_sink_set_font_desc (playbin->playsink,
1954 g_value_get_string (value));
1956 case PROP_CONNECTION_SPEED:
1957 GST_PLAY_BIN_LOCK (playbin);
1958 playbin->connection_speed = g_value_get_uint (value) * 1000;
1959 GST_PLAY_BIN_UNLOCK (playbin);
1961 case PROP_BUFFER_SIZE:
1962 playbin->buffer_size = g_value_get_int (value);
1964 case PROP_BUFFER_DURATION:
1965 playbin->buffer_duration = g_value_get_int64 (value);
1967 case PROP_AV_OFFSET:
1968 gst_play_sink_set_av_offset (playbin->playsink,
1969 g_value_get_int64 (value));
1971 case PROP_RING_BUFFER_MAX_SIZE:
1972 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
1975 gst_child_proxy_set_property (GST_OBJECT_CAST(playbin->playsink),
1976 "policy::actual-policy::role", value);
1979 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1985 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1986 const gchar * dbg, GstPlaySinkType type)
1988 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
1990 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1991 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1992 dbg, sink, dbg, *elem);
1995 GST_PLAY_BIN_LOCK (playbin);
1997 gst_object_ref (sink);
1998 GST_PLAY_BIN_UNLOCK (playbin);
2005 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
2008 GstPlayBin *playbin = GST_PLAY_BIN (object);
2013 GstSourceGroup *group;
2015 GST_PLAY_BIN_LOCK (playbin);
2016 group = get_group (playbin);
2017 g_value_set_string (value, group->uri);
2018 GST_PLAY_BIN_UNLOCK (playbin);
2023 GstSourceGroup *group;
2025 GST_PLAY_BIN_LOCK (playbin);
2026 group = get_group (playbin);
2027 g_value_set_string (value, group->suburi);
2028 GST_PLAY_BIN_UNLOCK (playbin);
2033 GST_OBJECT_LOCK (playbin);
2034 g_value_set_object (value, playbin->source);
2035 GST_OBJECT_UNLOCK (playbin);
2039 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
2043 GstSourceGroup *group;
2046 GST_PLAY_BIN_LOCK (playbin);
2047 group = get_group (playbin);
2048 n_video = (group->video_channels ? group->video_channels->len : 0);
2049 g_value_set_int (value, n_video);
2050 GST_PLAY_BIN_UNLOCK (playbin);
2053 case PROP_CURRENT_VIDEO:
2054 GST_PLAY_BIN_LOCK (playbin);
2055 g_value_set_int (value, playbin->current_video);
2056 GST_PLAY_BIN_UNLOCK (playbin);
2060 GstSourceGroup *group;
2063 GST_PLAY_BIN_LOCK (playbin);
2064 group = get_group (playbin);
2065 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
2066 g_value_set_int (value, n_audio);
2067 GST_PLAY_BIN_UNLOCK (playbin);
2070 case PROP_CURRENT_AUDIO:
2071 GST_PLAY_BIN_LOCK (playbin);
2072 g_value_set_int (value, playbin->current_audio);
2073 GST_PLAY_BIN_UNLOCK (playbin);
2077 GstSourceGroup *group;
2080 GST_PLAY_BIN_LOCK (playbin);
2081 group = get_group (playbin);
2082 n_text = (group->text_channels ? group->text_channels->len : 0);
2083 g_value_set_int (value, n_text);
2084 GST_PLAY_BIN_UNLOCK (playbin);
2087 case PROP_CURRENT_TEXT:
2088 GST_PLAY_BIN_LOCK (playbin);
2089 g_value_set_int (value, playbin->current_text);
2090 GST_PLAY_BIN_UNLOCK (playbin);
2092 case PROP_SUBTITLE_ENCODING:
2093 GST_PLAY_BIN_LOCK (playbin);
2094 g_value_take_string (value,
2095 gst_play_sink_get_subtitle_encoding (playbin->playsink));
2096 GST_PLAY_BIN_UNLOCK (playbin);
2098 case PROP_VIDEO_SINK:
2099 g_value_take_object (value,
2100 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2101 "video", GST_PLAY_SINK_TYPE_VIDEO));
2103 case PROP_AUDIO_SINK:
2104 g_value_take_object (value,
2105 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2106 "audio", GST_PLAY_SINK_TYPE_AUDIO));
2108 case PROP_VIS_PLUGIN:
2109 g_value_take_object (value,
2110 gst_play_sink_get_vis_plugin (playbin->playsink));
2112 case PROP_TEXT_SINK:
2113 g_value_take_object (value,
2114 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2115 "text", GST_PLAY_SINK_TYPE_TEXT));
2118 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2121 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2124 gst_value_take_buffer (value,
2125 gst_play_sink_get_last_frame (playbin->playsink));
2127 case PROP_FONT_DESC:
2128 g_value_take_string (value,
2129 gst_play_sink_get_font_desc (playbin->playsink));
2131 case PROP_CONNECTION_SPEED:
2132 GST_PLAY_BIN_LOCK (playbin);
2133 g_value_set_uint (value, playbin->connection_speed / 1000);
2134 GST_PLAY_BIN_UNLOCK (playbin);
2136 case PROP_BUFFER_SIZE:
2137 GST_OBJECT_LOCK (playbin);
2138 g_value_set_int (value, playbin->buffer_size);
2139 GST_OBJECT_UNLOCK (playbin);
2141 case PROP_BUFFER_DURATION:
2142 GST_OBJECT_LOCK (playbin);
2143 g_value_set_int64 (value, playbin->buffer_duration);
2144 GST_OBJECT_UNLOCK (playbin);
2146 case PROP_AV_OFFSET:
2147 g_value_set_int64 (value,
2148 gst_play_sink_get_av_offset (playbin->playsink));
2150 case PROP_RING_BUFFER_MAX_SIZE:
2151 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2154 gst_child_proxy_get_property (GST_OBJECT_CAST (playbin->playsink),
2155 "policy::actual-policy::role", value);
2158 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2164 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2165 gboolean valid, GstQuery * query)
2171 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2172 gst_query_parse_duration (query, &fmt, &duration);
2174 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2175 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2176 playbin->duration[i].valid = valid;
2177 playbin->duration[i].format = fmt;
2178 playbin->duration[i].duration = valid ? duration : -1;
2185 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2187 const GstFormat formats[] =
2188 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2193 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2194 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2195 query = gst_query_new_duration (formats[i]);
2197 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2199 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2200 gst_query_unref (query);
2205 gst_play_bin_query (GstElement * element, GstQuery * query)
2207 GstPlayBin *playbin = GST_PLAY_BIN (element);
2210 /* During a group switch we shouldn't allow duration queries
2211 * because it's not clear if the old or new group's duration
2212 * is returned and if the sinks are already playing new data
2213 * or old data. See bug #585969
2215 * While we're at it, also don't do any other queries during
2216 * a group switch or any other event that causes topology changes
2217 * by taking the playbin lock in any case.
2219 GST_PLAY_BIN_LOCK (playbin);
2221 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2222 GstSourceGroup *group = playbin->curr_group;
2225 GST_SOURCE_GROUP_LOCK (group);
2226 if (group->stream_changed_pending_lock) {
2227 g_mutex_lock (group->stream_changed_pending_lock);
2228 pending = group->pending || group->stream_changed_pending;
2229 g_mutex_unlock (group->stream_changed_pending_lock);
2231 pending = group->pending;
2238 gst_query_parse_duration (query, &fmt, NULL);
2239 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2240 if (fmt == playbin->duration[i].format) {
2241 ret = playbin->duration[i].valid;
2242 gst_query_set_duration (query, fmt,
2243 (ret ? playbin->duration[i].duration : -1));
2247 /* if nothing cached yet, we might as well request duration,
2248 * such as during initial startup */
2250 GST_DEBUG_OBJECT (playbin,
2251 "Taking cached duration because of pending group switch: %d", ret);
2252 GST_SOURCE_GROUP_UNLOCK (group);
2253 GST_PLAY_BIN_UNLOCK (playbin);
2257 GST_SOURCE_GROUP_UNLOCK (group);
2260 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2262 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2263 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2264 GST_PLAY_BIN_UNLOCK (playbin);
2269 /* mime types we are not handling on purpose right now, don't post a
2270 * missing-plugin message for these */
2271 static const gchar *blacklisted_mimes[] = {
2276 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2278 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2279 GstSourceGroup *group;
2281 if (gst_is_missing_plugin_message (msg)) {
2285 detail = gst_missing_plugin_message_get_installer_detail (msg);
2286 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2287 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2288 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2289 gst_message_unref (msg);
2295 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2296 const GstStructure *s = gst_message_get_structure (msg);
2298 /* Drop all stream-changed messages except the last one */
2299 if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2300 guint32 seqnum = gst_message_get_seqnum (msg);
2303 group = playbin->curr_group;
2304 g_mutex_lock (group->stream_changed_pending_lock);
2305 for (l = group->stream_changed_pending; l;) {
2306 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2308 if (l_seqnum == seqnum) {
2311 group->stream_changed_pending =
2312 g_list_delete_link (group->stream_changed_pending, l_prev);
2313 if (group->stream_changed_pending) {
2314 gst_message_unref (msg);
2322 g_mutex_unlock (group->stream_changed_pending_lock);
2324 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2325 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2326 GstObject *src = GST_OBJECT_CAST (msg->src);
2328 /* Ignore async state changes from the uridecodebin children,
2329 * see bug #602000. */
2330 group = playbin->curr_group;
2331 if (src && (group = playbin->curr_group) &&
2332 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2333 || (group->suburidecodebin
2334 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2335 GST_DEBUG_OBJECT (playbin,
2336 "Ignoring async state change of uridecodebin: %s",
2337 GST_OBJECT_NAME (src));
2338 gst_message_unref (msg);
2341 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2342 /* If we get an error of the subtitle uridecodebin transform
2343 * them into warnings and disable the subtitles */
2344 group = playbin->curr_group;
2345 if (group && group->suburidecodebin) {
2346 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2347 (group->suburidecodebin)))) {
2349 gchar *debug = NULL;
2350 GstMessage *new_msg;
2352 gboolean done = FALSE;
2354 gst_message_parse_error (msg, &err, &debug);
2355 new_msg = gst_message_new_warning (msg->src, err, debug);
2357 gst_message_unref (msg);
2362 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2363 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2364 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2365 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2367 it = gst_element_iterate_src_pads (group->suburidecodebin);
2368 while (it && !done) {
2370 GstIteratorResult res;
2372 res = gst_iterator_next (it, (gpointer) & p);
2375 case GST_ITERATOR_DONE:
2378 case GST_ITERATOR_OK:
2379 pad_removed_cb (NULL, p, group);
2380 gst_object_unref (p);
2383 case GST_ITERATOR_RESYNC:
2384 gst_iterator_resync (it);
2386 case GST_ITERATOR_ERROR:
2392 gst_iterator_free (it);
2394 gst_object_ref (group->suburidecodebin);
2395 gst_bin_remove (bin, group->suburidecodebin);
2396 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2398 if (group->sub_pending) {
2399 group->sub_pending = FALSE;
2400 no_more_pads_cb (NULL, group);
2407 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2411 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2412 GstPlayBin * playbin)
2414 const gchar *property;
2415 GstSourceGroup *group;
2416 GstSourceSelect *select = NULL;
2419 GST_PLAY_BIN_LOCK (playbin);
2420 group = get_group (playbin);
2422 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2423 if (selector == G_OBJECT (group->selector[i].selector)) {
2424 select = &group->selector[i];
2428 /* We got a pad-change after our group got switched out; no need to notify */
2430 GST_PLAY_BIN_UNLOCK (playbin);
2434 switch (select->type) {
2435 case GST_PLAY_SINK_TYPE_VIDEO:
2436 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2437 property = "current-video";
2438 playbin->current_video = get_current_stream_number (playbin,
2439 group->video_channels);
2441 case GST_PLAY_SINK_TYPE_AUDIO:
2442 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2443 property = "current-audio";
2444 playbin->current_audio = get_current_stream_number (playbin,
2445 group->audio_channels);
2447 case GST_PLAY_SINK_TYPE_TEXT:
2448 property = "current-text";
2449 playbin->current_text = get_current_stream_number (playbin,
2450 group->text_channels);
2455 GST_PLAY_BIN_UNLOCK (playbin);
2458 g_object_notify (G_OBJECT (playbin), property);
2462 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
2465 GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
2468 /* this callback sends a delayed event once the pad becomes unblocked */
2470 stream_changed_data_probe (GstPad * pad, GstMiniObject * object, gpointer data)
2472 GstSourceSelect *select = (GstSourceSelect *) data;
2475 /* we need do this just once, so cleanup first */
2476 gst_pad_remove_data_probe (pad, select->sinkpad_data_probe);
2477 select->sinkpad_data_probe = 0;
2478 e = select->sinkpad_delayed_event;
2479 select->sinkpad_delayed_event = NULL;
2481 /* really, this should not happen */
2483 GST_WARNING ("Data probed called, but no delayed event");
2487 if (GST_IS_EVENT (object)
2488 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_NEWSEGMENT) {
2489 /* push the event first, then send the delayed one */
2490 gst_event_ref (GST_EVENT_CAST (object));
2491 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2492 gst_pad_send_event (pad, e);
2495 /* send delayed event, then allow the caller to go on */
2496 gst_pad_send_event (pad, e);
2501 /* helper function to lookup stuff in lists */
2503 array_has_value (const gchar * values[], const gchar * value, gboolean exact)
2507 for (i = 0; values[i]; i++) {
2508 if (exact && !strcmp (value, values[i]))
2510 if (!exact && g_str_has_prefix (value, values[i]))
2518 GstPlayBin *playbin;
2520 GstPlaySinkType type;
2524 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2526 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2529 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2530 " with stream id %d and type %d have changed",
2531 object, ntdata->stream_id, ntdata->type);
2533 switch (ntdata->type) {
2534 case GST_PLAY_SINK_TYPE_VIDEO:
2535 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2536 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2538 case GST_PLAY_SINK_TYPE_AUDIO:
2539 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2540 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2542 case GST_PLAY_SINK_TYPE_TEXT:
2543 signal = SIGNAL_TEXT_TAGS_CHANGED;
2551 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2555 /* this function is called when a new pad is added to decodebin. We check the
2556 * type of the pad and add it to the selector element of the group.
2559 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2561 GstPlayBin *playbin;
2563 const GstStructure *s;
2566 GstPadLinkReturn res;
2567 GstSourceSelect *select = NULL;
2569 gboolean changed = FALSE;
2571 playbin = group->playbin;
2573 caps = gst_pad_get_caps_reffed (pad);
2574 s = gst_caps_get_structure (caps, 0);
2575 name = gst_structure_get_name (s);
2577 GST_DEBUG_OBJECT (playbin,
2578 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2579 GST_DEBUG_PAD_NAME (pad), caps, group);
2581 /* major type of the pad, this determines the selector to use,
2582 try exact match first so we don't prematurely match video/
2583 for video/x-dvd-subpicture */
2584 for (pass = 0; !select && pass < 2; pass++) {
2585 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2586 if (array_has_value (group->selector[i].media_list, name, pass == 0)) {
2587 select = &group->selector[i];
2589 } else if (group->selector[i].get_media_caps) {
2590 GstCaps *media_caps = group->selector[i].get_media_caps ();
2592 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2593 select = &group->selector[i];
2594 gst_caps_unref (media_caps);
2597 gst_caps_unref (media_caps);
2601 /* no selector found for the media type, don't bother linking it to a
2602 * selector. This will leave the pad unlinked and thus ignored. */
2606 GST_SOURCE_GROUP_LOCK (group);
2607 if (select->selector == NULL && playbin->have_selector) {
2608 /* no selector, create one */
2609 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2610 select->selector = gst_element_factory_make ("input-selector", NULL);
2611 if (select->selector == NULL) {
2612 /* post the missing selector message only once */
2613 playbin->have_selector = FALSE;
2614 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2615 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2617 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2618 (_("Missing element '%s' - check your GStreamer installation."),
2619 "input-selector"), (NULL));
2621 g_object_set (select->selector, "sync-streams", TRUE, NULL);
2623 g_signal_connect (select->selector, "notify::active-pad",
2624 G_CALLBACK (selector_active_pad_changed), playbin);
2626 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2627 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2628 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2632 if (select->srcpad == NULL) {
2633 if (select->selector) {
2634 /* save source pad of the selector */
2635 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2637 /* no selector, use the pad as the source pad then */
2638 select->srcpad = gst_object_ref (pad);
2641 /* block the selector srcpad. It's possible that multiple decodebins start
2642 * pushing data into the selectors before we have a chance to collect all
2643 * streams and connect the sinks, resulting in not-linked errors. After we
2644 * configured the sinks we will unblock them all. */
2645 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2646 gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
2649 /* get sinkpad for the new stream */
2650 if (select->selector) {
2651 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2652 gulong notify_tags_handler = 0;
2653 NotifyTagsData *ntdata;
2655 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2656 GST_DEBUG_PAD_NAME (sinkpad));
2658 /* store the selector for the pad */
2659 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2661 /* connect to the notify::tags signal for our
2662 * own *-tags-changed signals
2664 ntdata = g_new0 (NotifyTagsData, 1);
2665 ntdata->playbin = playbin;
2666 ntdata->stream_id = select->channels->len;
2667 ntdata->type = select->type;
2669 notify_tags_handler =
2670 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2671 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2673 g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2674 (gpointer) (guintptr) notify_tags_handler);
2676 /* store the pad in the array */
2677 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2678 g_ptr_array_add (select->channels, sinkpad);
2680 res = gst_pad_link (pad, sinkpad);
2681 if (GST_PAD_LINK_FAILED (res))
2684 /* store selector pad so we can release it */
2685 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2688 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2689 GST_DEBUG_PAD_NAME (pad), select->selector);
2692 /* no selector, don't configure anything, we'll link the new pad directly to
2697 GST_SOURCE_GROUP_UNLOCK (group);
2701 gboolean always_ok = (decodebin == group->suburidecodebin);
2703 switch (select->type) {
2704 case GST_PLAY_SINK_TYPE_VIDEO:
2705 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2706 /* we want to return NOT_LINKED for unselected pads but only for pads
2707 * from the normal uridecodebin. This makes sure that subtitle streams
2708 * are not raced past audio/video from decodebin2's multiqueue.
2709 * For pads from suburidecodebin OK should always be returned, otherwise
2710 * it will most likely stop. */
2711 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2712 signal = SIGNAL_VIDEO_CHANGED;
2714 case GST_PLAY_SINK_TYPE_AUDIO:
2715 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2716 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2717 signal = SIGNAL_AUDIO_CHANGED;
2719 case GST_PLAY_SINK_TYPE_TEXT:
2720 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2721 signal = SIGNAL_TEXT_CHANGED;
2728 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2732 gst_caps_unref (caps);
2738 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2739 name, GST_DEBUG_PAD_NAME (pad));
2744 GST_ERROR_OBJECT (playbin,
2745 "failed to link pad %s:%s to selector, reason %d",
2746 GST_DEBUG_PAD_NAME (pad), res);
2747 GST_SOURCE_GROUP_UNLOCK (group);
2752 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2753 * the selector. This will make the selector select a new pad. */
2755 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2757 GstPlayBin *playbin;
2759 GstElement *selector;
2760 GstSourceSelect *select;
2762 playbin = group->playbin;
2764 GST_DEBUG_OBJECT (playbin,
2765 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2767 GST_SOURCE_GROUP_LOCK (group);
2768 /* get the selector sinkpad */
2769 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2772 if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2773 gulong notify_tags_handler;
2775 notify_tags_handler =
2776 (guintptr) g_object_get_data (G_OBJECT (peer),
2777 "playbin2.notify_tags_handler");
2778 if (notify_tags_handler != 0)
2779 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2780 g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2782 /* remove the pad from the array */
2783 g_ptr_array_remove (select->channels, peer);
2784 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2787 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2788 gst_pad_unlink (pad, peer);
2790 /* get selector, this can be NULL when the element is removing the pads
2791 * because it's being disposed. */
2792 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2794 gst_object_unref (peer);
2798 /* release the pad to the selector, this will make the selector choose a new
2800 gst_element_release_request_pad (selector, peer);
2801 gst_object_unref (peer);
2803 gst_object_unref (selector);
2804 GST_SOURCE_GROUP_UNLOCK (group);
2811 GST_DEBUG_OBJECT (playbin, "pad not linked");
2812 GST_SOURCE_GROUP_UNLOCK (group);
2817 GST_DEBUG_OBJECT (playbin, "selector not found");
2818 GST_SOURCE_GROUP_UNLOCK (group);
2823 /* we get called when all pads are available and we must connect the sinks to
2825 * The main purpose of the code is to see if we have video/audio and subtitles
2826 * and pick the right pipelines to display them.
2828 * The selectors installed on the group tell us about the presence of
2829 * audio/video and subtitle streams. This allows us to see if we need
2830 * visualisation, video or/and audio.
2833 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2835 GstPlayBin *playbin;
2836 GstPadLinkReturn res;
2840 playbin = group->playbin;
2842 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2844 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2846 GST_SOURCE_GROUP_LOCK (group);
2847 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2848 GstSourceSelect *select = &group->selector[i];
2850 /* check if the specific media type was detected and thus has a selector
2851 * created for it. If there is the media type, get a sinkpad from the sink
2852 * and link it. We only do this if we have not yet requested the sinkpad
2854 if (select->srcpad && select->sinkpad == NULL) {
2855 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2857 gst_play_sink_request_pad (playbin->playsink, select->type);
2859 res = gst_pad_link (select->srcpad, select->sinkpad);
2860 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2861 select->media_list[0], res);
2862 if (res != GST_PAD_LINK_OK) {
2863 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2864 ("Internal playbin error."),
2865 ("Failed to link selector to sink. Error %d", res));
2869 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2870 group->pending - 1);
2872 if (group->pending > 0)
2875 if (group->suburidecodebin == decodebin)
2876 group->sub_pending = FALSE;
2878 if (group->pending == 0) {
2879 /* we are the last group to complete, we will configure the output and then
2880 * signal the other waiters. */
2881 GST_LOG_OBJECT (playbin, "last group complete");
2884 GST_LOG_OBJECT (playbin, "have more pending groups");
2887 GST_SOURCE_GROUP_UNLOCK (group);
2890 /* if we have custom sinks, configure them now */
2891 GST_SOURCE_GROUP_LOCK (group);
2893 if (group->audio_sink) {
2894 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2896 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2900 if (group->video_sink) {
2901 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2903 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2907 if (playbin->text_sink) {
2908 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
2909 playbin->text_sink);
2910 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2911 playbin->text_sink);
2914 GST_SOURCE_GROUP_UNLOCK (group);
2916 /* signal the other decodebins that they can continue now. */
2917 GST_SOURCE_GROUP_LOCK (group);
2918 /* unblock all selectors */
2919 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2920 GstSourceSelect *select = &group->selector[i];
2922 /* All streamsynchronizer streams should see stream-changed message,
2923 * to arrange for blocking unblocking. */
2924 if (select->sinkpad) {
2930 s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2933 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2934 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2935 seqnum = gst_message_get_seqnum (msg);
2936 event = gst_event_new_sink_message (msg);
2937 g_mutex_lock (group->stream_changed_pending_lock);
2938 group->stream_changed_pending =
2939 g_list_prepend (group->stream_changed_pending,
2940 GUINT_TO_POINTER (seqnum));
2942 /* remove any data probe we might have, and replace */
2943 if (select->sinkpad_delayed_event)
2944 gst_event_unref (select->sinkpad_delayed_event);
2945 select->sinkpad_delayed_event = event;
2946 if (select->sinkpad_data_probe)
2947 gst_pad_remove_data_probe (select->sinkpad,
2948 select->sinkpad_data_probe);
2950 /* we go to the trouble of setting a probe on the pad to send
2951 the playbin2-stream-changed event as sending it here might
2952 find that the pad is blocked, so we'd block here, and the
2953 pad might not be linked yet. Additionally, sending it here
2954 apparently would be on the wrong thread */
2955 select->sinkpad_data_probe =
2956 gst_pad_add_data_probe (select->sinkpad,
2957 (GCallback) stream_changed_data_probe, (gpointer) select);
2959 g_mutex_unlock (group->stream_changed_pending_lock);
2960 gst_message_unref (msg);
2963 if (select->srcpad) {
2964 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2966 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2970 GST_SOURCE_GROUP_UNLOCK (group);
2973 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2979 GST_DEBUG ("ignoring, we are shutting down");
2980 /* Request a flushing pad from playsink that we then link to the selector.
2981 * Then we unblock the selectors so that they stop with a WRONG_STATE
2982 * instead of a NOT_LINKED error.
2984 GST_SOURCE_GROUP_LOCK (group);
2985 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2986 GstSourceSelect *select = &group->selector[i];
2988 if (select->srcpad) {
2989 if (select->sinkpad == NULL) {
2990 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2992 gst_play_sink_request_pad (playbin->playsink,
2993 GST_PLAY_SINK_TYPE_FLUSHING);
2994 res = gst_pad_link (select->srcpad, select->sinkpad);
2995 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2997 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2999 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
3003 GST_SOURCE_GROUP_UNLOCK (group);
3009 drained_cb (GstElement * decodebin, GstSourceGroup * group)
3011 GstPlayBin *playbin;
3013 playbin = group->playbin;
3015 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
3017 /* after this call, we should have a next group to activate or we EOS */
3018 g_signal_emit (G_OBJECT (playbin),
3019 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
3021 /* now activate the next group. If the app did not set a uri, this will
3022 * fail and we can do EOS */
3023 setup_next_source (playbin, GST_STATE_PAUSED);
3026 /* Like gst_element_factory_can_sink_any_caps() but doesn't
3027 * allow ANY caps on the sinkpad template */
3029 _factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps)
3031 const GList *templs;
3033 templs = gst_element_factory_get_static_pad_templates (factory);
3036 GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
3038 if (templ->direction == GST_PAD_SINK) {
3039 GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
3041 if (!gst_caps_is_any (templcaps)
3042 && gst_caps_can_intersect (templcaps, caps)) {
3043 gst_caps_unref (templcaps);
3046 gst_caps_unref (templcaps);
3048 templs = g_list_next (templs);
3054 /* Called when we must provide a list of factories to plug to @pad with @caps.
3055 * We first check if we have a sink that can handle the format and if we do, we
3056 * return NULL, to expose the pad. If we have no sink (or the sink does not
3057 * work), we return the list of elements that can connect. */
3058 static GValueArray *
3059 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
3060 GstCaps * caps, GstSourceGroup * group)
3062 GstPlayBin *playbin;
3063 GList *mylist, *tmp;
3064 GValueArray *result;
3066 playbin = group->playbin;
3068 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
3069 group, GST_DEBUG_PAD_NAME (pad), caps);
3071 /* filter out the elements based on the caps. */
3072 g_mutex_lock (playbin->elements_lock);
3073 gst_play_bin_update_elements_list (playbin);
3075 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
3077 g_mutex_unlock (playbin->elements_lock);
3079 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
3080 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
3082 /* 2 additional elements for the already set audio/video sinks */
3083 result = g_value_array_new (g_list_length (mylist) + 2);
3085 /* Check if we already have an audio/video sink and if this is the case
3086 * put it as the first element of the array */
3087 if (group->audio_sink) {
3088 GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
3090 if (factory && _factory_can_sink_caps (factory, caps)) {
3091 GValue val = { 0, };
3093 g_value_init (&val, G_TYPE_OBJECT);
3094 g_value_set_object (&val, factory);
3095 result = g_value_array_append (result, &val);
3096 g_value_unset (&val);
3100 if (group->video_sink) {
3101 GstElementFactory *factory = gst_element_get_factory (group->video_sink);
3103 if (factory && _factory_can_sink_caps (factory, caps)) {
3104 GValue val = { 0, };
3106 g_value_init (&val, G_TYPE_OBJECT);
3107 g_value_set_object (&val, factory);
3108 result = g_value_array_append (result, &val);
3109 g_value_unset (&val);
3113 for (tmp = mylist; tmp; tmp = tmp->next) {
3114 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
3115 GValue val = { 0, };
3117 if (group->audio_sink && gst_element_factory_list_is_type (factory,
3118 GST_ELEMENT_FACTORY_TYPE_SINK |
3119 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
3122 if (group->video_sink && gst_element_factory_list_is_type (factory,
3123 GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
3124 | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
3128 g_value_init (&val, G_TYPE_OBJECT);
3129 g_value_set_object (&val, factory);
3130 g_value_array_append (result, &val);
3131 g_value_unset (&val);
3133 gst_plugin_feature_list_free (mylist);
3138 /* autoplug-continue decides, if a pad has raw caps that can be exposed
3139 * directly or if further decoding is necessary. We use this to expose
3140 * supported subtitles directly */
3142 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
3143 * explicitly the caps it supports and if it claims to support ANY
3144 * caps it really should support everything */
3146 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
3147 GstSourceGroup * group)
3149 gboolean ret = TRUE;
3151 GstPad *sinkpad = NULL;
3153 GST_PLAY_BIN_LOCK (group->playbin);
3154 GST_SOURCE_GROUP_LOCK (group);
3156 if ((sink = group->playbin->text_sink))
3157 sinkpad = gst_element_get_static_pad (sink, "sink");
3161 /* Ignore errors here, if a custom sink fails to go
3162 * to READY things are wrong and will error out later
3164 if (GST_STATE (sink) < GST_STATE_READY)
3165 gst_element_set_state (sink, GST_STATE_READY);
3167 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3168 if (!gst_caps_is_any (sinkcaps))
3169 ret = !gst_pad_accept_caps (sinkpad, caps);
3170 gst_caps_unref (sinkcaps);
3171 gst_object_unref (sinkpad);
3173 GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3174 ret = !gst_caps_is_subset (caps, subcaps);
3175 gst_caps_unref (subcaps);
3177 /* If autoplugging can stop don't do additional checks */
3181 /* If this is from the subtitle uridecodebin we don't need to
3182 * check the audio and video sink */
3183 if (group->suburidecodebin
3184 && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3185 GST_OBJECT_CAST (group->suburidecodebin)))
3188 if ((sink = group->audio_sink)) {
3189 sinkpad = gst_element_get_static_pad (sink, "sink");
3193 /* Ignore errors here, if a custom sink fails to go
3194 * to READY things are wrong and will error out later
3196 if (GST_STATE (sink) < GST_STATE_READY)
3197 gst_element_set_state (sink, GST_STATE_READY);
3199 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3200 if (!gst_caps_is_any (sinkcaps))
3201 ret = !gst_pad_accept_caps (sinkpad, caps);
3202 gst_caps_unref (sinkcaps);
3203 gst_object_unref (sinkpad);
3209 if ((sink = group->video_sink)) {
3210 sinkpad = gst_element_get_static_pad (sink, "sink");
3214 /* Ignore errors here, if a custom sink fails to go
3215 * to READY things are wrong and will error out later
3217 if (GST_STATE (sink) < GST_STATE_READY)
3218 gst_element_set_state (sink, GST_STATE_READY);
3220 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3221 if (!gst_caps_is_any (sinkcaps))
3222 ret = !gst_pad_accept_caps (sinkpad, caps);
3223 gst_caps_unref (sinkcaps);
3224 gst_object_unref (sinkpad);
3229 GST_SOURCE_GROUP_UNLOCK (group);
3230 GST_PLAY_BIN_UNLOCK (group->playbin);
3232 GST_DEBUG_OBJECT (group->playbin,
3233 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3234 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3240 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3244 /* ... activate it ... We do this before adding it to the bin so that we
3245 * don't accidentally make it post error messages that will stop
3247 if (GST_STATE (sink) < GST_STATE_READY &&
3248 gst_element_set_state (sink,
3249 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3253 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3254 /* Got the sink pad, now let's see if the element actually does accept the
3255 * caps that we have */
3256 if (!gst_pad_accept_caps (sinkpad, caps)) {
3257 gst_object_unref (sinkpad);
3260 gst_object_unref (sinkpad);
3266 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw-int; "
3267 "audio/x-raw-float");
3268 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw-rgb; "
3269 "video/x-raw-yuv; " "video/x-raw-gray");
3271 /* We are asked to select an element. See if the next element to check
3272 * is a sink. If this is the case, we see if the sink works by setting it to
3273 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3274 * expose the raw pad so that we can setup the mixers. */
3275 static GstAutoplugSelectResult
3276 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3277 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3279 GstPlayBin *playbin;
3280 GstElement *element;
3282 GstPlaySinkType type;
3285 playbin = group->playbin;
3287 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3288 group, GST_DEBUG_PAD_NAME (pad), caps);
3290 GST_DEBUG_OBJECT (playbin, "checking factory %s",
3291 GST_PLUGIN_FEATURE_NAME (factory));
3293 /* if it's not a sink, we make sure the element is compatible with
3295 if (!gst_element_factory_list_is_type (factory,
3296 GST_ELEMENT_FACTORY_TYPE_SINK)) {
3297 gboolean isvideodec = gst_element_factory_list_is_type (factory,
3298 GST_ELEMENT_FACTORY_TYPE_DECODER |
3299 GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
3300 GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
3301 gboolean isaudiodec = gst_element_factory_list_is_type (factory,
3302 GST_ELEMENT_FACTORY_TYPE_DECODER |
3303 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
3305 /* If it is a decoder and we have a fixed sink for the media
3306 * type it outputs, check that the decoder is compatible with this sink */
3307 if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) {
3308 gboolean compatible = TRUE;
3314 sink = group->audio_sink;
3316 sink = group->video_sink;
3318 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3319 GstPlayFlags flags = gst_play_bin_get_flags (playbin);
3321 (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) :
3322 gst_static_caps_get (&raw_video_caps);
3324 caps = gst_pad_get_caps_reffed (sinkpad);
3326 /* If the sink supports raw audio/video, we first check
3327 * if the decoder could output any raw audio/video format
3328 * and assume it is compatible with the sink then. We don't
3329 * do a complete compatibility check here if converters
3330 * are plugged between the decoder and the sink because
3331 * the converters will convert between raw formats and
3332 * even if the decoder format is not supported by the decoder
3333 * a converter will convert it.
3335 * We assume here that the converters can convert between
3338 if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO)
3339 && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec
3340 && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO)
3341 && gst_caps_can_intersect (caps, raw_caps))) {
3342 compatible = gst_element_factory_can_src_any_caps (factory, raw_caps)
3343 || gst_element_factory_can_src_any_caps (factory, caps);
3345 compatible = gst_element_factory_can_src_any_caps (factory, caps);
3348 gst_object_unref (sinkpad);
3349 gst_caps_unref (caps);
3353 return GST_AUTOPLUG_SELECT_TRY;
3355 GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink",
3356 GST_PLUGIN_FEATURE_NAME (factory));
3358 return GST_AUTOPLUG_SELECT_SKIP;
3360 return GST_AUTOPLUG_SELECT_TRY;
3363 /* it's a sink, see if an instance of it actually works */
3364 GST_DEBUG_OBJECT (playbin, "we found a sink");
3366 klass = gst_element_factory_get_klass (factory);
3368 /* figure out the klass */
3369 if (strstr (klass, "Audio")) {
3370 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3371 type = GST_PLAY_SINK_TYPE_AUDIO;
3372 sinkp = &group->audio_sink;
3373 } else if (strstr (klass, "Video")) {
3374 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3375 type = GST_PLAY_SINK_TYPE_VIDEO;
3376 sinkp = &group->video_sink;
3378 /* unknown klass, skip this element */
3379 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3380 return GST_AUTOPLUG_SELECT_SKIP;
3383 /* if we are asked to do visualisations and it's an audio sink, skip the
3384 * element. We can only do visualisations with raw sinks */
3385 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3386 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3387 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3388 return GST_AUTOPLUG_SELECT_SKIP;
3392 /* now see if we already have a sink element */
3393 GST_SOURCE_GROUP_LOCK (group);
3395 GstElement *sink = gst_object_ref (*sinkp);
3397 if (sink_accepts_caps (sink, caps)) {
3398 GST_DEBUG_OBJECT (playbin,
3399 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3400 GST_ELEMENT_NAME (sink), caps);
3401 gst_object_unref (sink);
3402 GST_SOURCE_GROUP_UNLOCK (group);
3403 return GST_AUTOPLUG_SELECT_EXPOSE;
3405 GST_DEBUG_OBJECT (playbin,
3406 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3407 GST_ELEMENT_NAME (sink), caps);
3408 gst_object_unref (sink);
3409 GST_SOURCE_GROUP_UNLOCK (group);
3410 return GST_AUTOPLUG_SELECT_SKIP;
3413 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3415 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3416 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3417 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3418 GST_SOURCE_GROUP_UNLOCK (group);
3419 return GST_AUTOPLUG_SELECT_SKIP;
3422 /* Check if the selected sink actually supports the
3423 * caps and can be set to READY*/
3424 if (!sink_accepts_caps (element, caps)) {
3425 gst_element_set_state (element, GST_STATE_NULL);
3426 gst_object_unref (element);
3427 GST_SOURCE_GROUP_UNLOCK (group);
3428 return GST_AUTOPLUG_SELECT_SKIP;
3431 /* remember the sink in the group now, the element is floating, we take
3434 * store the sink in the group, we will configure it later when we
3435 * reconfigure the sink */
3436 GST_DEBUG_OBJECT (playbin, "remember sink");
3437 gst_object_ref_sink (element);
3439 GST_SOURCE_GROUP_UNLOCK (group);
3441 /* tell decodebin to expose the pad because we are going to use this
3443 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3445 return GST_AUTOPLUG_SELECT_EXPOSE;
3449 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3450 GstSourceGroup * group)
3452 GstPlayBin *playbin;
3455 playbin = group->playbin;
3457 g_object_get (group->uridecodebin, "source", &source, NULL);
3459 GST_OBJECT_LOCK (playbin);
3460 if (playbin->source)
3461 gst_object_unref (playbin->source);
3462 playbin->source = source;
3463 GST_OBJECT_UNLOCK (playbin);
3465 g_object_notify (G_OBJECT (playbin), "source");
3467 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3468 0, playbin->source);
3471 /* must be called with the group lock */
3473 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3476 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3478 if (group->uridecodebin)
3479 gst_element_set_locked_state (group->uridecodebin, locked);
3480 if (group->suburidecodebin)
3481 gst_element_set_locked_state (group->suburidecodebin, locked);
3486 /* must be called with PLAY_BIN_LOCK */
3488 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3490 GstElement *uridecodebin;
3491 GstElement *suburidecodebin = NULL;
3494 g_return_val_if_fail (group->valid, FALSE);
3495 g_return_val_if_fail (!group->active, FALSE);
3497 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3499 GST_SOURCE_GROUP_LOCK (group);
3501 /* First set up the custom sources */
3502 if (playbin->audio_sink)
3503 group->audio_sink = gst_object_ref (playbin->audio_sink);
3504 if (playbin->video_sink)
3505 group->video_sink = gst_object_ref (playbin->video_sink);
3507 g_list_free (group->stream_changed_pending);
3508 group->stream_changed_pending = NULL;
3509 if (!group->stream_changed_pending_lock)
3510 group->stream_changed_pending_lock = g_mutex_new ();
3512 if (group->uridecodebin) {
3513 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3514 uridecodebin = group->uridecodebin;
3515 gst_element_set_state (uridecodebin, GST_STATE_READY);
3516 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3518 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3519 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3522 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3523 group->uridecodebin = gst_object_ref (uridecodebin);
3526 flags = gst_play_sink_get_flags (playbin->playsink);
3528 g_object_set (uridecodebin,
3529 /* configure connection speed */
3530 "connection-speed", playbin->connection_speed / 1000,
3533 /* configure download buffering */
3534 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3535 /* configure buffering of demuxed/parsed data */
3536 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3537 /* configure buffering parameters */
3538 "buffer-duration", playbin->buffer_duration,
3539 "buffer-size", playbin->buffer_size,
3540 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3542 /* connect pads and other things */
3543 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3544 G_CALLBACK (pad_added_cb), group);
3545 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3546 G_CALLBACK (pad_removed_cb), group);
3547 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3548 G_CALLBACK (no_more_pads_cb), group);
3549 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3550 G_CALLBACK (notify_source_cb), group);
3552 /* we have 1 pending no-more-pads */
3555 /* is called when the uridecodebin is out of data and we can switch to the
3558 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3561 /* will be called when a new media type is found. We return a list of decoders
3562 * including sinks for decodebin to try */
3563 group->autoplug_factories_id =
3564 g_signal_connect (uridecodebin, "autoplug-factories",
3565 G_CALLBACK (autoplug_factories_cb), group);
3566 group->autoplug_select_id =
3567 g_signal_connect (uridecodebin, "autoplug-select",
3568 G_CALLBACK (autoplug_select_cb), group);
3569 group->autoplug_continue_id =
3570 g_signal_connect (uridecodebin, "autoplug-continue",
3571 G_CALLBACK (autoplug_continue_cb), group);
3573 if (group->suburi) {
3575 if (group->suburidecodebin) {
3576 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3577 suburidecodebin = group->suburidecodebin;
3578 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3579 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3581 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3582 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3583 if (!suburidecodebin)
3586 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3587 group->suburidecodebin = gst_object_ref (suburidecodebin);
3590 g_object_set (suburidecodebin,
3591 /* configure connection speed */
3592 "connection-speed", playbin->connection_speed,
3594 "uri", group->suburi, NULL);
3596 /* connect pads and other things */
3597 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3598 G_CALLBACK (pad_added_cb), group);
3599 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3600 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3601 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3602 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3604 group->sub_autoplug_continue_id =
3605 g_signal_connect (suburidecodebin, "autoplug-continue",
3606 G_CALLBACK (autoplug_continue_cb), group);
3608 /* we have 2 pending no-more-pads */
3610 group->sub_pending = TRUE;
3612 group->sub_pending = FALSE;
3615 /* release the group lock before setting the state of the decodebins, they
3616 * might fire signals in this thread that we need to handle with the
3617 * group_lock taken. */
3618 GST_SOURCE_GROUP_UNLOCK (group);
3620 if (suburidecodebin) {
3621 if (gst_element_set_state (suburidecodebin,
3622 target) == GST_STATE_CHANGE_FAILURE) {
3623 GST_DEBUG_OBJECT (playbin,
3624 "failed state change of subtitle uridecodebin");
3625 GST_SOURCE_GROUP_LOCK (group);
3627 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3628 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3629 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3630 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3631 /* Might already be removed because of an error message */
3632 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3633 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3634 if (group->sub_pending) {
3636 group->sub_pending = FALSE;
3638 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3639 GST_SOURCE_GROUP_UNLOCK (group);
3642 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3643 goto uridecodebin_failure;
3645 GST_SOURCE_GROUP_LOCK (group);
3646 /* alow state changes of the playbin2 affect the group elements now */
3647 group_set_locked_state_unlocked (playbin, group, FALSE);
3648 group->active = TRUE;
3649 GST_SOURCE_GROUP_UNLOCK (group);
3658 /* delete any custom sinks we might have */
3659 if (group->audio_sink) {
3660 /* If this is a automatically created sink set it to NULL */
3661 if (group->audio_sink != playbin->audio_sink)
3662 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3663 gst_object_unref (group->audio_sink);
3665 group->audio_sink = NULL;
3666 if (group->video_sink) {
3667 /* If this is a automatically created sink set it to NULL */
3668 if (group->video_sink != playbin->video_sink)
3669 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3670 gst_object_unref (group->video_sink);
3672 group->video_sink = NULL;
3674 GST_SOURCE_GROUP_UNLOCK (group);
3676 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3678 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3680 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3681 (_("Could not create \"uridecodebin\" element.")), (NULL));
3684 uridecodebin_failure:
3686 /* delete any custom sinks we might have */
3687 if (group->audio_sink) {
3688 /* If this is a automatically created sink set it to NULL */
3689 if (group->audio_sink != playbin->audio_sink)
3690 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3691 gst_object_unref (group->audio_sink);
3693 group->audio_sink = NULL;
3694 if (group->video_sink) {
3695 /* If this is a automatically created sink set it to NULL */
3696 if (group->video_sink != playbin->video_sink)
3697 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3698 gst_object_unref (group->video_sink);
3700 group->video_sink = NULL;
3702 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3707 /* unlink a group of uridecodebins from the sink.
3708 * must be called with PLAY_BIN_LOCK */
3710 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3714 g_return_val_if_fail (group->valid, FALSE);
3715 g_return_val_if_fail (group->active, FALSE);
3717 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3719 GST_SOURCE_GROUP_LOCK (group);
3720 group->active = FALSE;
3721 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3722 GstSourceSelect *select = &group->selector[i];
3724 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3726 if (select->srcpad) {
3727 if (select->sinkpad) {
3728 GST_LOG_OBJECT (playbin, "unlinking from sink");
3729 gst_pad_unlink (select->srcpad, select->sinkpad);
3732 GST_LOG_OBJECT (playbin, "release sink pad");
3733 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3734 select->sinkpad = NULL;
3737 gst_object_unref (select->srcpad);
3738 select->srcpad = NULL;
3741 if (select->selector) {
3744 /* release and unref requests pad from the selector */
3745 for (n = 0; n < select->channels->len; n++) {
3746 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3748 gst_element_release_request_pad (select->selector, sinkpad);
3749 gst_object_unref (sinkpad);
3751 g_ptr_array_set_size (select->channels, 0);
3753 gst_element_set_state (select->selector, GST_STATE_NULL);
3754 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3755 select->selector = NULL;
3758 /* delete any custom sinks we might have */
3759 if (group->audio_sink) {
3760 /* If this is a automatically created sink set it to NULL */
3761 if (group->audio_sink != playbin->audio_sink)
3762 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3763 gst_object_unref (group->audio_sink);
3765 group->audio_sink = NULL;
3766 if (group->video_sink) {
3767 /* If this is a automatically created sink set it to NULL */
3768 if (group->video_sink != playbin->video_sink)
3769 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3770 gst_object_unref (group->video_sink);
3772 group->video_sink = NULL;
3774 if (group->uridecodebin) {
3775 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3776 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3777 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3778 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3779 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3780 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3781 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3782 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3783 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3786 if (group->suburidecodebin) {
3787 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3788 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3789 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3790 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3792 /* Might already be removed because of errors */
3793 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3794 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3797 GST_SOURCE_GROUP_UNLOCK (group);
3802 /* setup the next group to play, this assumes the next_group is valid and
3803 * configured. It swaps out the current_group and activates the valid
3806 setup_next_source (GstPlayBin * playbin, GstState target)
3808 GstSourceGroup *new_group, *old_group;
3810 GST_DEBUG_OBJECT (playbin, "setup sources");
3812 /* see if there is a next group */
3813 GST_PLAY_BIN_LOCK (playbin);
3814 new_group = playbin->next_group;
3815 if (!new_group || !new_group->valid)
3818 /* first unlink the current source, if any */
3819 old_group = playbin->curr_group;
3820 if (old_group && old_group->valid && old_group->active) {
3821 gst_play_bin_update_cached_duration (playbin);
3822 /* unlink our pads with the sink */
3823 deactivate_group (playbin, old_group);
3824 old_group->valid = FALSE;
3827 /* swap old and new */
3828 playbin->curr_group = new_group;
3829 playbin->next_group = old_group;
3831 /* activate the new group */
3832 if (!activate_group (playbin, new_group, target))
3833 goto activate_failed;
3835 GST_PLAY_BIN_UNLOCK (playbin);
3842 GST_DEBUG_OBJECT (playbin, "no next group");
3843 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3844 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3845 GST_PLAY_BIN_UNLOCK (playbin);
3850 GST_DEBUG_OBJECT (playbin, "activate failed");
3851 GST_PLAY_BIN_UNLOCK (playbin);
3856 /* The group that is currently playing is copied again to the
3857 * next_group so that it will start playing the next time.
3860 save_current_group (GstPlayBin * playbin)
3862 GstSourceGroup *curr_group;
3864 GST_DEBUG_OBJECT (playbin, "save current group");
3866 /* see if there is a current group */
3867 GST_PLAY_BIN_LOCK (playbin);
3868 curr_group = playbin->curr_group;
3869 if (curr_group && curr_group->valid && curr_group->active) {
3870 /* unlink our pads with the sink */
3871 deactivate_group (playbin, curr_group);
3873 /* swap old and new */
3874 playbin->curr_group = playbin->next_group;
3875 playbin->next_group = curr_group;
3876 GST_PLAY_BIN_UNLOCK (playbin);
3881 /* clear the locked state from all groups. This function is called before a
3882 * state change to NULL is performed on them. */
3884 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3886 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3889 GST_PLAY_BIN_LOCK (playbin);
3890 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3891 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3892 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3893 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3894 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3895 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3896 GST_PLAY_BIN_UNLOCK (playbin);
3901 static GstStateChangeReturn
3902 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3904 GstStateChangeReturn ret;
3905 GstPlayBin *playbin;
3906 gboolean do_save = FALSE;
3908 playbin = GST_PLAY_BIN (element);
3910 switch (transition) {
3911 case GST_STATE_CHANGE_NULL_TO_READY:
3912 memset (&playbin->duration, 0, sizeof (playbin->duration));
3914 case GST_STATE_CHANGE_READY_TO_PAUSED:
3915 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3916 memset (&playbin->duration, 0, sizeof (playbin->duration));
3917 g_atomic_int_set (&playbin->shutdown, 0);
3919 if (!setup_next_source (playbin, GST_STATE_READY)) {
3920 ret = GST_STATE_CHANGE_FAILURE;
3924 case GST_STATE_CHANGE_PAUSED_TO_READY:
3926 /* FIXME unlock our waiting groups */
3927 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3928 g_atomic_int_set (&playbin->shutdown, 1);
3929 memset (&playbin->duration, 0, sizeof (playbin->duration));
3931 /* wait for all callbacks to end by taking the lock.
3932 * No dynamic (critical) new callbacks will
3933 * be able to happen as we set the shutdown flag. */
3934 GST_PLAY_BIN_DYN_LOCK (playbin);
3935 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3936 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3939 case GST_STATE_CHANGE_READY_TO_NULL:
3940 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3941 * an no state change PAUSED to READY passes here,
3942 * though it is a nice-to-have ... */
3943 if (!g_atomic_int_get (&playbin->shutdown)) {
3947 memset (&playbin->duration, 0, sizeof (playbin->duration));
3949 /* unlock so that all groups go to NULL */
3950 groups_set_locked_state (playbin, FALSE);
3956 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3957 if (ret == GST_STATE_CHANGE_FAILURE)
3960 switch (transition) {
3961 case GST_STATE_CHANGE_READY_TO_PAUSED:
3963 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3964 /* FIXME Release audio device when we implement that */
3966 case GST_STATE_CHANGE_PAUSED_TO_READY:
3967 save_current_group (playbin);
3969 case GST_STATE_CHANGE_READY_TO_NULL:
3973 /* also do missed state change down to READY */
3975 save_current_group (playbin);
3976 /* Deactive the groups, set the uridecodebins to NULL
3979 for (i = 0; i < 2; i++) {
3980 if (playbin->groups[i].active && playbin->groups[i].valid) {
3981 deactivate_group (playbin, &playbin->groups[i]);
3982 playbin->groups[i].valid = FALSE;
3985 if (playbin->groups[i].uridecodebin) {
3986 gst_element_set_state (playbin->groups[i].uridecodebin,
3988 gst_object_unref (playbin->groups[i].uridecodebin);
3989 playbin->groups[i].uridecodebin = NULL;
3992 if (playbin->groups[i].suburidecodebin) {
3993 gst_element_set_state (playbin->groups[i].suburidecodebin,
3995 gst_object_unref (playbin->groups[i].suburidecodebin);
3996 playbin->groups[i].suburidecodebin = NULL;
4000 /* Set our sinks back to NULL, they might not be child of playbin */
4001 if (playbin->audio_sink)
4002 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
4003 if (playbin->video_sink)
4004 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
4005 if (playbin->text_sink)
4006 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
4008 /* make sure the groups don't perform a state change anymore until we
4009 * enable them again */
4010 groups_set_locked_state (playbin, TRUE);
4022 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
4023 GstSourceGroup *curr_group;
4025 curr_group = playbin->curr_group;
4026 if (curr_group && curr_group->active && curr_group->valid) {
4027 /* unlink our pads with the sink */
4028 deactivate_group (playbin, curr_group);
4029 curr_group->valid = FALSE;
4032 /* Swap current and next group back */
4033 playbin->curr_group = playbin->next_group;
4034 playbin->next_group = curr_group;
4041 gst_play_bin2_plugin_init (GstPlugin * plugin)
4043 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
4045 return gst_element_register (plugin, "playbin2", GST_RANK_NONE,