2 * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
3 * Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * SECTION:element-playbin
24 * Playbin provides a stand-alone everything-in-one abstraction for an
25 * audio and/or video player.
27 * Playbin can handle both audio and video files and features
30 * automatic file type recognition and based on that automatic
31 * selection and usage of the right audio/video/subtitle demuxers/decoders
34 * visualisations for audio files
37 * subtitle support for video files. Subtitles can be store in external
41 * stream selection between different video/audio/subtitles streams
44 * meta info (tag) extraction
47 * easy access to the last video sample
50 * buffering when playing streams over a network
53 * volume control with mute option
58 * <title>Usage</title>
60 * A playbin element can be created just like any other element using
61 * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin:uri
62 * property. This must be an absolute URI, relative file paths are not allowed.
63 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
65 * Playbin is a #GstPipeline. It will notify the application of everything
66 * that's happening (errors, end of stream, tags found, state changes, etc.)
67 * by posting messages on its #GstBus. The application needs to watch the
70 * Playback can be initiated by setting the element to PLAYING state using
71 * gst_element_set_state(). Note that the state change will take place in
72 * the background in a separate thread, when the function returns playback
73 * is probably not happening yet and any errors might not have occured yet.
74 * Applications using playbin should ideally be written to deal with things
75 * completely asynchroneous.
77 * When playback has finished (an EOS message has been received on the bus)
78 * or an error has occured (an ERROR message has been received on the bus) or
79 * the user wants to play a different track, playbin should be set back to
80 * READY or NULL state, then the #GstPlayBin:uri property should be set to the
81 * new location and then playbin be set to PLAYING state again.
83 * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
84 * on the playbin element. Again, the seek will not be executed
85 * instantaneously, but will be done in a background thread. When the seek
86 * call returns the seek will most likely still be in process. An application
87 * may wait for the seek to finish (or fail) using gst_element_get_state() with
88 * -1 as the timeout, but this will block the user interface and is not
91 * Applications may query the current position and duration of the stream
92 * via gst_element_query_position() and gst_element_query_duration() and
93 * setting the format passed to GST_FORMAT_TIME. If the query was successful,
94 * the duration or position will have been returned in units of nanoseconds.
98 * <title>Advanced Usage: specifying the audio and video sink</title>
100 * By default, if no audio sink or video sink has been specified via the
101 * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property, playbin will use the autoaudiosink
102 * and autovideosink elements to find the first-best available output method.
103 * This should work in most cases, but is not always desirable. Often either
104 * the user or application might want to specify more explicitly what to use
105 * for audio and video output.
107 * If the application wants more control over how audio or video should be
108 * output, it may create the audio/video sink elements itself (for example
109 * using gst_element_factory_make()) and provide them to playbin using the
110 * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property.
112 * GNOME-based applications, for example, will usually want to create
113 * gconfaudiosink and gconfvideosink elements and make playbin use those,
114 * so that output happens to whatever the user has configured in the GNOME
115 * Multimedia System Selector configuration dialog.
117 * The sink elements do not necessarily need to be ready-made sinks. It is
118 * possible to create container elements that look like a sink to playbin,
119 * but in reality contain a number of custom elements linked together. This
120 * can be achieved by creating a #GstBin and putting elements in there and
121 * linking them, and then creating a sink #GstGhostPad for the bin and pointing
122 * it to the sink pad of the first element within the bin. This can be used
123 * for a number of purposes, for example to force output to a particular
124 * format or to modify or observe the data before it is output.
126 * It is also possible to 'suppress' audio and/or video output by using
127 * 'fakesink' elements (or capture it from there using the fakesink element's
128 * "handoff" signal, which, nota bene, is fired from the streaming thread!).
132 * <title>Retrieving Tags and Other Meta Data</title>
134 * Most of the common meta data (artist, title, etc.) can be retrieved by
135 * watching for TAG messages on the pipeline's bus (see above).
137 * Other more specific meta information like width/height/framerate of video
138 * streams or samplerate/number of channels of audio streams can be obtained
139 * from the negotiated caps on the sink pads of the sinks.
143 * <title>Buffering</title>
144 * Playbin handles buffering automatically for the most part, but applications
145 * need to handle parts of the buffering process as well. Whenever playbin is
146 * buffering, it will post BUFFERING messages on the bus with a percentage
147 * value that shows the progress of the buffering process. Applications need
148 * to set playbin to PLAYING or PAUSED state in response to these messages.
149 * They may also want to convey the buffering progress to the user in some
150 * way. Here is how to extract the percentage information from the message
151 * (requires GStreamer >= 0.10.11):
153 * switch (GST_MESSAGE_TYPE (msg)) {
154 * case GST_MESSAGE_BUFFERING: {
156 * gst_message_parse_buffering (msg, &percent);
157 * g_print ("Buffering (%%u percent done)", percent);
163 * Note that applications should keep/set the pipeline in the PAUSED state when
164 * a BUFFERING message is received with a buffer percent value < 100 and set
165 * the pipeline back to PLAYING state when a BUFFERING message with a value
166 * of 100 percent is received (if PLAYING is the desired state, that is).
169 * <title>Embedding the video window in your application</title>
170 * By default, playbin (or rather the video sinks used) will create their own
171 * window. Applications will usually want to force output to a window of their
172 * own, however. This can be done using the #GstVideoOverlay interface, which most
173 * video sinks implement. See the documentation there for more details.
176 * <title>Specifying which CD/DVD device to use</title>
177 * The device to use for CDs/DVDs needs to be set on the source element
178 * playbin creates before it is opened. The most generic way of doing this
179 * is to connect to playbin's "source-setup" (or "notify::source") signal,
180 * which will be emitted by playbin2 when it has created the source element
181 * for a particular URI. In the signal callback you can check if the source
182 * element has a "device" property and set it appropriately. In some cases
183 * the device can also be set as part of the URI, but it depends on the
184 * elements involved if this will work or not. For example, for DVD menu
185 * playback, the following syntax might work (if the resindvd plugin is used):
186 * dvd://[/path/to/device]
189 * <title>Handling redirects</title>
191 * Some elements may post 'redirect' messages on the bus to tell the
192 * application to open another location. These are element messages containing
193 * a structure named 'redirect' along with a 'new-location' field of string
194 * type. The new location may be a relative or an absolute URI. Examples
195 * for such redirects can be found in many quicktime movie trailers.
199 * <title>Examples</title>
201 * gst-launch -v playbin2 uri=file:///path/to/somefile.avi
202 * ]| This will play back the given AVI video file, given that the video and
203 * audio decoders required to decode the content are installed. Since no
204 * special audio sink or video sink is supplied (not possible via gst-launch),
205 * playbin will try to find a suitable audio and video sink automatically
206 * using the autoaudiosink and autovideosink elements.
208 * gst-launch -v playbin2 uri=cdda://4
209 * ]| This will play back track 4 on an audio CD in your disc drive (assuming
210 * the drive is detected automatically by the plugin).
212 * gst-launch -v playbin2 uri=dvd://
213 * ]| This will play back the DVD in your disc drive (assuming
214 * the drive is detected automatically by the plugin).
218 /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
219 * with newer GLib versions (>= 2.31.0) */
220 #define GLIB_DISABLE_DEPRECATION_WARNINGS
229 #include <gst/gst-i18n-plugin.h>
230 #include <gst/pbutils/pbutils.h>
231 #include <gst/audio/streamvolume.h>
232 #include <gst/video/videooverlay.h>
233 #include <gst/video/navigation.h>
234 #include <gst/video/colorbalance.h>
235 #include "gstplay-enum.h"
236 #include "gstplayback.h"
237 #include "gstplaysink.h"
238 #include "gstsubtitleoverlay.h"
239 #include "gst/glib-compat-private.h"
240 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
241 #define GST_CAT_DEFAULT gst_play_bin_debug
243 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type())
244 #define GST_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
245 #define GST_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
246 #define GST_IS_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
247 #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
249 #define VOLUME_MAX_DOUBLE 10.0
251 typedef struct _GstPlayBin GstPlayBin;
252 typedef struct _GstPlayBinClass GstPlayBinClass;
253 typedef struct _GstSourceGroup GstSourceGroup;
254 typedef struct _GstSourceSelect GstSourceSelect;
256 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
258 /* has the info for a selector and provides the link to the sink */
259 struct _GstSourceSelect
261 const gchar *media_list[8]; /* the media types for the selector */
262 SourceSelectGetMediaCapsFunc get_media_caps; /* more complex caps for the selector */
263 GstPlaySinkType type; /* the sink pad type of the selector */
265 GstElement *selector; /* the selector */
267 GstPad *srcpad; /* the source pad of the selector */
268 GstPad *sinkpad; /* the sinkpad of the sink when the selector
271 GstEvent *sinkpad_delayed_event;
272 gulong sinkpad_data_probe;
276 #define GST_SOURCE_GROUP_GET_LOCK(group) (&((GstSourceGroup*)(group))->lock)
277 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
278 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
282 PLAYBIN_STREAM_AUDIO = 0,
283 PLAYBIN_STREAM_VIDEO,
288 /* a structure to hold the objects for decoding a uri and the subtitle uri
290 struct _GstSourceGroup
296 gboolean valid; /* the group has valid info to start playback */
297 gboolean active; /* the group is active */
302 GValueArray *streaminfo;
305 GPtrArray *video_channels; /* links to selector pads */
306 GPtrArray *audio_channels; /* links to selector pads */
307 GPtrArray *text_channels; /* links to selector pads */
309 GstElement *audio_sink; /* autoplugged audio and video sinks */
310 GstElement *video_sink;
312 /* uridecodebins for uri and subtitle uri */
313 GstElement *uridecodebin;
314 GstElement *suburidecodebin;
316 gboolean sub_pending;
319 gulong pad_removed_id;
320 gulong no_more_pads_id;
321 gulong notify_source_id;
323 gulong autoplug_factories_id;
324 gulong autoplug_select_id;
325 gulong autoplug_continue_id;
327 gulong sub_pad_added_id;
328 gulong sub_pad_removed_id;
329 gulong sub_no_more_pads_id;
330 gulong sub_autoplug_continue_id;
334 GMutex stream_changed_pending_lock;
335 GList *stream_changed_pending;
337 /* to prevent that suburidecodebin seek flushes disrupt playback */
338 GMutex suburi_flushes_to_drop_lock;
339 GSList *suburi_flushes_to_drop;
341 /* selectors for different streams */
342 GstSourceSelect selector[PLAYBIN_STREAM_LAST];
345 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
346 #define GST_PLAY_BIN_LOCK(bin) (g_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
347 #define GST_PLAY_BIN_UNLOCK(bin) (g_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
349 /* lock to protect dynamic callbacks, like no-more-pads */
350 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock (&(bin)->dyn_lock)
351 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock (&(bin)->dyn_lock)
353 /* lock for shutdown */
354 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
356 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
358 GST_PLAY_BIN_DYN_LOCK (bin); \
359 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
360 GST_PLAY_BIN_DYN_UNLOCK (bin); \
365 /* unlock for shutdown */
366 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
367 GST_PLAY_BIN_DYN_UNLOCK (bin); \
372 * playbin element structure
378 GRecMutex lock; /* to protect group switching */
380 /* the groups, we use a double buffer to switch between current and next */
381 GstSourceGroup groups[2]; /* array with group info */
382 GstSourceGroup *curr_group; /* pointer to the currently playing group */
383 GstSourceGroup *next_group; /* pointer to the next group */
386 guint64 connection_speed; /* connection speed in bits/sec (0 = unknown) */
387 gint current_video; /* the currently selected stream */
388 gint current_audio; /* the currently selected stream */
389 gint current_text; /* the currently selected stream */
391 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
392 guint buffer_size; /* When buffering, the max buffer size (bytes) */
395 GstPlaySink *playsink;
397 /* the last activated source */
400 /* lock protecting dynamic adding/removing */
402 /* if we are shutting down or not */
405 GMutex elements_lock;
406 guint32 elements_cookie;
407 GList *elements; /* factories we can use for selecting elements */
409 gboolean have_selector; /* set to FALSE when we fail to create an
410 * input-selector, so that we only post a
413 gboolean video_pending_flush_finish; /* whether we are pending to send a custom
414 * custom-video-flush-finish event
415 * on pad activation */
416 gboolean audio_pending_flush_finish; /* whether we are pending to send a custom
417 * custom-audio-flush-finish event
418 * on pad activation */
419 gboolean text_pending_flush_finish; /* whether we are pending to send a custom
420 * custom-subtitle-flush-finish event
421 * on pad activation */
423 GstElement *audio_sink; /* configured audio sink, or NULL */
424 GstElement *video_sink; /* configured video sink, or NULL */
425 GstElement *text_sink; /* configured text sink, or NULL */
432 } duration[5]; /* cached durations */
434 guint64 ring_buffer_max_size; /* 0 means disabled */
437 struct _GstPlayBinClass
439 GstPipelineClass parent_class;
441 /* notify app that the current uri finished decoding and it is possible to
442 * queue a new one for gapless playback */
443 void (*about_to_finish) (GstPlayBin * playbin);
445 /* notify app that number of audio/video/text streams changed */
446 void (*video_changed) (GstPlayBin * playbin);
447 void (*audio_changed) (GstPlayBin * playbin);
448 void (*text_changed) (GstPlayBin * playbin);
450 /* notify app that the tags of audio/video/text streams changed */
451 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
452 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
453 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
455 /* get audio/video/text tags for a stream */
456 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
457 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
458 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
460 /* get the last video sample and convert it to the given caps */
461 GstSample *(*convert_sample) (GstPlayBin * playbin, GstCaps * caps);
463 /* get audio/video/text pad for a stream */
464 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
465 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
466 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
470 #define DEFAULT_URI NULL
471 #define DEFAULT_SUBURI NULL
472 #define DEFAULT_SOURCE NULL
473 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
474 GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_SOFT_COLORBALANCE
475 #define DEFAULT_N_VIDEO 0
476 #define DEFAULT_CURRENT_VIDEO -1
477 #define DEFAULT_N_AUDIO 0
478 #define DEFAULT_CURRENT_AUDIO -1
479 #define DEFAULT_N_TEXT 0
480 #define DEFAULT_CURRENT_TEXT -1
481 #define DEFAULT_SUBTITLE_ENCODING NULL
482 #define DEFAULT_AUDIO_SINK NULL
483 #define DEFAULT_VIDEO_SINK NULL
484 #define DEFAULT_VIS_PLUGIN NULL
485 #define DEFAULT_TEXT_SINK NULL
486 #define DEFAULT_VOLUME 1.0
487 #define DEFAULT_MUTE FALSE
488 #define DEFAULT_FRAME NULL
489 #define DEFAULT_FONT_DESC NULL
490 #define DEFAULT_CONNECTION_SPEED 0
491 #define DEFAULT_BUFFER_DURATION -1
492 #define DEFAULT_BUFFER_SIZE -1
493 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
510 PROP_SUBTITLE_ENCODING,
519 PROP_CONNECTION_SPEED,
521 PROP_BUFFER_DURATION,
523 PROP_RING_BUFFER_MAX_SIZE,
530 SIGNAL_ABOUT_TO_FINISH,
531 SIGNAL_CONVERT_SAMPLE,
532 SIGNAL_VIDEO_CHANGED,
533 SIGNAL_AUDIO_CHANGED,
535 SIGNAL_VIDEO_TAGS_CHANGED,
536 SIGNAL_AUDIO_TAGS_CHANGED,
537 SIGNAL_TEXT_TAGS_CHANGED,
538 SIGNAL_GET_VIDEO_TAGS,
539 SIGNAL_GET_AUDIO_TAGS,
540 SIGNAL_GET_TEXT_TAGS,
541 SIGNAL_GET_VIDEO_PAD,
542 SIGNAL_GET_AUDIO_PAD,
548 static void gst_play_bin_class_init (GstPlayBinClass * klass);
549 static void gst_play_bin_init (GstPlayBin * playbin);
550 static void gst_play_bin_finalize (GObject * object);
552 static void gst_play_bin_set_property (GObject * object, guint prop_id,
553 const GValue * value, GParamSpec * spec);
554 static void gst_play_bin_get_property (GObject * object, guint prop_id,
555 GValue * value, GParamSpec * spec);
557 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
558 GstStateChange transition);
560 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
561 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
563 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
565 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
567 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
570 static GstSample *gst_play_bin_convert_sample (GstPlayBin * playbin,
573 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
574 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
575 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
577 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
579 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
580 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
581 GstSourceGroup * group);
583 static void gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
584 GstElement * suburidecodebin, gboolean block);
585 static void gst_play_bin_suburidecodebin_seek_to_start (GstSourceGroup * group);
587 static GstElementClass *parent_class;
589 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
591 #define REMOVE_SIGNAL(obj,id) \
593 g_signal_handler_disconnect (obj, id); \
597 static void gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data);
598 static void gst_play_bin_navigation_init (gpointer g_iface,
599 gpointer g_iface_data);
600 static void gst_play_bin_colorbalance_init (gpointer g_iface,
601 gpointer g_iface_data);
604 gst_play_bin_get_type (void)
606 static GType gst_play_bin_type = 0;
608 if (!gst_play_bin_type) {
609 static const GTypeInfo gst_play_bin_info = {
610 sizeof (GstPlayBinClass),
613 (GClassInitFunc) gst_play_bin_class_init,
618 (GInstanceInitFunc) gst_play_bin_init,
621 static const GInterfaceInfo svol_info = {
624 static const GInterfaceInfo ov_info = {
625 gst_play_bin_overlay_init,
628 static const GInterfaceInfo nav_info = {
629 gst_play_bin_navigation_init,
632 static const GInterfaceInfo col_info = {
633 gst_play_bin_colorbalance_init,
637 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
638 "GstPlayBin", &gst_play_bin_info, 0);
640 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
642 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_VIDEO_OVERLAY,
644 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_NAVIGATION,
646 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_COLOR_BALANCE,
650 return gst_play_bin_type;
654 gst_play_bin_class_init (GstPlayBinClass * klass)
656 GObjectClass *gobject_klass;
657 GstElementClass *gstelement_klass;
658 GstBinClass *gstbin_klass;
660 gobject_klass = (GObjectClass *) klass;
661 gstelement_klass = (GstElementClass *) klass;
662 gstbin_klass = (GstBinClass *) klass;
664 parent_class = g_type_class_peek_parent (klass);
666 gobject_klass->set_property = gst_play_bin_set_property;
667 gobject_klass->get_property = gst_play_bin_get_property;
669 gobject_klass->finalize = gst_play_bin_finalize;
674 * Set the next URI that playbin will play. This property can be set from the
675 * about-to-finish signal to queue the next media file.
677 g_object_class_install_property (gobject_klass, PROP_URI,
678 g_param_spec_string ("uri", "URI", "URI of the media to play",
679 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
682 * GstPlayBin:current-uri
684 * The currently playing uri.
686 g_object_class_install_property (gobject_klass, PROP_CURRENT_URI,
687 g_param_spec_string ("current-uri", "Current URI",
688 "The currently playing URI", NULL,
689 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
694 * Set the next subtitle URI that playbin will play. This property can be
695 * set from the about-to-finish signal to queue the next subtitle media file.
697 g_object_class_install_property (gobject_klass, PROP_SUBURI,
698 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
699 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
702 * GstPlayBin:current-suburi
704 * The currently playing subtitle uri.
706 g_object_class_install_property (gobject_klass, PROP_CURRENT_SUBURI,
707 g_param_spec_string ("current-suburi", "Current .sub-URI",
708 "The currently playing URI of a subtitle",
709 NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
711 g_object_class_install_property (gobject_klass, PROP_SOURCE,
712 g_param_spec_object ("source", "Source", "Source element",
713 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
718 * Control the behaviour of playbin.
720 g_object_class_install_property (gobject_klass, PROP_FLAGS,
721 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
722 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
723 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
728 * Get the total number of available video streams.
730 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
731 g_param_spec_int ("n-video", "Number Video",
732 "Total number of video streams", 0, G_MAXINT, 0,
733 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
735 * GstPlayBin:current-video
737 * Get or set the currently playing video stream. By default the first video
738 * stream with data is played.
740 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
741 g_param_spec_int ("current-video", "Current Video",
742 "Currently playing video stream (-1 = auto)",
743 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
747 * Get the total number of available audio streams.
749 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
750 g_param_spec_int ("n-audio", "Number Audio",
751 "Total number of audio streams", 0, G_MAXINT, 0,
752 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
754 * GstPlayBin:current-audio
756 * Get or set the currently playing audio stream. By default the first audio
757 * stream with data is played.
759 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
760 g_param_spec_int ("current-audio", "Current audio",
761 "Currently playing audio stream (-1 = auto)",
762 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
766 * Get the total number of available subtitle streams.
768 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
769 g_param_spec_int ("n-text", "Number Text",
770 "Total number of text streams", 0, G_MAXINT, 0,
771 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
773 * GstPlayBin:current-text:
775 * Get or set the currently playing subtitle stream. By default the first
776 * subtitle stream with data is played.
778 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
779 g_param_spec_int ("current-text", "Current Text",
780 "Currently playing text stream (-1 = auto)",
781 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
783 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
784 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
785 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
786 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
787 "be checked for an encoding to use. If that is not set either, "
788 "ISO-8859-15 will be assumed.", NULL,
789 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
791 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
792 g_param_spec_object ("video-sink", "Video Sink",
793 "the video output element to use (NULL = default sink)",
794 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
795 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
796 g_param_spec_object ("audio-sink", "Audio Sink",
797 "the audio output element to use (NULL = default sink)",
798 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
799 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
800 g_param_spec_object ("vis-plugin", "Vis plugin",
801 "the visualization element to use (NULL = default)",
802 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
803 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
804 g_param_spec_object ("text-sink", "Text plugin",
805 "the text output element to use (NULL = default subtitleoverlay)",
806 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
811 * Get or set the current audio stream volume. 1.0 means 100%,
812 * 0.0 means mute. This uses a linear volume scale.
815 g_object_class_install_property (gobject_klass, PROP_VOLUME,
816 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
817 0.0, VOLUME_MAX_DOUBLE, 1.0,
818 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
819 g_object_class_install_property (gobject_klass, PROP_MUTE,
820 g_param_spec_boolean ("mute", "Mute",
821 "Mute the audio channel without changing the volume", FALSE,
822 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
826 * @playbin: a #GstPlayBin
828 * Get the currently rendered or prerolled sample in the video sink.
829 * The #GstCaps in the sample will describe the format of the buffer.
831 g_object_class_install_property (gobject_klass, PROP_SAMPLE,
832 g_param_spec_boxed ("sample", "Sample",
833 "The last sample (NULL = no video available)",
834 GST_TYPE_SAMPLE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
836 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
837 g_param_spec_string ("subtitle-font-desc",
838 "Subtitle font description",
839 "Pango font description of font "
840 "to be used for subtitle rendering", NULL,
841 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
843 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
844 g_param_spec_uint64 ("connection-speed", "Connection Speed",
845 "Network connection speed in kbps (0 = unknown)",
846 0, G_MAXUINT64 / 1000, DEFAULT_CONNECTION_SPEED,
847 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
849 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
850 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
851 "Buffer size when buffering network streams",
852 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
853 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
854 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
855 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
856 "Buffer duration when buffering network streams",
857 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
858 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
860 * GstPlayBin:av-offset:
862 * Control the synchronisation offset between the audio and video streams.
863 * Positive values make the audio ahead of the video and negative values make
864 * the audio go behind the video.
868 g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
869 g_param_spec_int64 ("av-offset", "AV Offset",
870 "The synchronisation offset between audio and video in nanoseconds",
871 G_MININT64, G_MAXINT64, 0,
872 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
875 * GstQueue2:ring-buffer-max-size
877 * The maximum size of the ring buffer in bytes. If set to 0, the ring
878 * buffer is disabled. Default 0.
882 g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
883 g_param_spec_uint64 ("ring-buffer-max-size",
884 "Max. ring buffer size (bytes)",
885 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
886 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
887 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
890 * GstPlayBin::about-to-finish
891 * @playbin: a #GstPlayBin
893 * This signal is emitted when the current uri is about to finish. You can
894 * set the uri and suburi to make sure that playback continues.
896 * This signal is emitted from the context of a GStreamer streaming thread.
898 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
899 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
901 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
902 g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
905 * GstPlayBin::video-changed
906 * @playbin: a #GstPlayBin
908 * This signal is emitted whenever the number or order of the video
909 * streams has changed. The application will most likely want to select
910 * a new video stream.
912 * This signal is usually emitted from the context of a GStreamer streaming
913 * thread. You can use gst_message_new_application() and
914 * gst_element_post_message() to notify your application's main thread.
916 /* FIXME 0.11: turn video-changed signal into message? */
917 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
918 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
920 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
921 g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
923 * GstPlayBin::audio-changed
924 * @playbin: a #GstPlayBin
926 * This signal is emitted whenever the number or order of the audio
927 * streams has changed. The application will most likely want to select
928 * a new audio stream.
930 * This signal may be emitted from the context of a GStreamer streaming thread.
931 * You can use gst_message_new_application() and gst_element_post_message()
932 * to notify your application's main thread.
934 /* FIXME 0.11: turn audio-changed signal into message? */
935 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
936 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
938 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
939 g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
941 * GstPlayBin::text-changed
942 * @playbin: a #GstPlayBin
944 * This signal is emitted whenever the number or order of the text
945 * streams has changed. The application will most likely want to select
948 * This signal may be emitted from the context of a GStreamer streaming thread.
949 * You can use gst_message_new_application() and gst_element_post_message()
950 * to notify your application's main thread.
952 /* FIXME 0.11: turn text-changed signal into message? */
953 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
954 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
956 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
957 g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
960 * GstPlayBin::video-tags-changed
961 * @playbin: a #GstPlayBin
962 * @stream: stream index with changed tags
964 * This signal is emitted whenever the tags of a video stream have changed.
965 * The application will most likely want to get the new tags.
967 * This signal may be emitted from the context of a GStreamer streaming thread.
968 * You can use gst_message_new_application() and gst_element_post_message()
969 * to notify your application's main thread.
973 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
974 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
976 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
977 g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
980 * GstPlayBin::audio-tags-changed
981 * @playbin: a #GstPlayBin
982 * @stream: stream index with changed tags
984 * This signal is emitted whenever the tags of an audio stream have changed.
985 * The application will most likely want to get the new tags.
987 * This signal may be emitted from the context of a GStreamer streaming thread.
988 * You can use gst_message_new_application() and gst_element_post_message()
989 * to notify your application's main thread.
993 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
994 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
996 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
997 g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
1000 * GstPlayBin::text-tags-changed
1001 * @playbin: a #GstPlayBin
1002 * @stream: stream index with changed tags
1004 * This signal is emitted whenever the tags of a text stream have changed.
1005 * The application will most likely want to get the new tags.
1007 * This signal may be emitted from the context of a GStreamer streaming thread.
1008 * You can use gst_message_new_application() and gst_element_post_message()
1009 * to notify your application's main thread.
1013 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
1014 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
1016 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
1017 g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
1020 * GstPlayBin::source-setup:
1021 * @playbin: a #GstPlayBin
1022 * @source: source element
1024 * This signal is emitted after the source element has been created, so
1025 * it can be configured by setting additional properties (e.g. set a
1026 * proxy server for an http source, or set the device and read speed for
1027 * an audio cd source). This is functionally equivalent to connecting to
1028 * the notify::source signal, but more convenient.
1030 * This signal is usually emitted from the context of a GStreamer streaming
1035 gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
1036 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
1037 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1038 g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
1041 * GstPlayBin::get-video-tags
1042 * @playbin: a #GstPlayBin
1043 * @stream: a video stream number
1045 * Action signal to retrieve the tags of a specific video stream number.
1046 * This information can be used to select a stream.
1048 * Returns: a GstTagList with tags or NULL when the stream number does not
1051 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
1052 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
1053 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1054 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
1055 g_cclosure_marshal_generic, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1057 * GstPlayBin::get-audio-tags
1058 * @playbin: a #GstPlayBin
1059 * @stream: an audio stream number
1061 * Action signal to retrieve the tags of a specific audio stream number.
1062 * This information can be used to select a stream.
1064 * Returns: a GstTagList with tags or NULL when the stream number does not
1067 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
1068 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
1069 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1070 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
1071 g_cclosure_marshal_generic, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1073 * GstPlayBin::get-text-tags
1074 * @playbin: a #GstPlayBin
1075 * @stream: a text stream number
1077 * Action signal to retrieve the tags of a specific text stream number.
1078 * This information can be used to select a stream.
1080 * Returns: a GstTagList with tags or NULL when the stream number does not
1083 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
1084 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
1085 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1086 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
1087 g_cclosure_marshal_generic, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1089 * GstPlayBin::convert-sample
1090 * @playbin: a #GstPlayBin
1091 * @caps: the target format of the frame
1093 * Action signal to retrieve the currently playing video frame in the format
1094 * specified by @caps.
1095 * If @caps is %NULL, no conversion will be performed and this function is
1096 * equivalent to the #GstPlayBin::frame property.
1098 * Returns: a #GstBuffer of the current video frame converted to #caps.
1099 * The caps on the buffer will describe the final layout of the buffer data.
1100 * %NULL is returned when no current buffer can be retrieved or when the
1101 * conversion failed.
1103 gst_play_bin_signals[SIGNAL_CONVERT_SAMPLE] =
1104 g_signal_new ("convert-sample", G_TYPE_FROM_CLASS (klass),
1105 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1106 G_STRUCT_OFFSET (GstPlayBinClass, convert_sample), NULL, NULL,
1107 g_cclosure_marshal_generic, GST_TYPE_SAMPLE, 1, GST_TYPE_CAPS);
1110 * GstPlayBin::get-video-pad
1111 * @playbin: a #GstPlayBin
1112 * @stream: a video stream number
1114 * Action signal to retrieve the stream-selector sinkpad for a specific
1116 * This pad can be used for notifications of caps changes, stream-specific
1119 * Returns: a #GstPad, or NULL when the stream number does not exist.
1121 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1122 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1123 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1124 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1125 g_cclosure_marshal_generic, GST_TYPE_PAD, 1, G_TYPE_INT);
1127 * GstPlayBin::get-audio-pad
1128 * @playbin: a #GstPlayBin
1129 * @stream: an audio stream number
1131 * Action signal to retrieve the stream-selector sinkpad for a specific
1133 * This pad can be used for notifications of caps changes, stream-specific
1136 * Returns: a #GstPad, or NULL when the stream number does not exist.
1138 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1139 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1140 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1141 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1142 g_cclosure_marshal_generic, GST_TYPE_PAD, 1, G_TYPE_INT);
1144 * GstPlayBin::get-text-pad
1145 * @playbin: a #GstPlayBin
1146 * @stream: a text stream number
1148 * Action signal to retrieve the stream-selector sinkpad for a specific
1150 * This pad can be used for notifications of caps changes, stream-specific
1153 * Returns: a #GstPad, or NULL when the stream number does not exist.
1155 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1156 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1157 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1158 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1159 g_cclosure_marshal_generic, GST_TYPE_PAD, 1, G_TYPE_INT);
1161 klass->get_video_tags = gst_play_bin_get_video_tags;
1162 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1163 klass->get_text_tags = gst_play_bin_get_text_tags;
1165 klass->convert_sample = gst_play_bin_convert_sample;
1167 klass->get_video_pad = gst_play_bin_get_video_pad;
1168 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1169 klass->get_text_pad = gst_play_bin_get_text_pad;
1171 gst_element_class_set_static_metadata (gstelement_klass,
1172 "Player Bin 2", "Generic/Bin/Player",
1173 "Autoplug and play media from an uri",
1174 "Wim Taymans <wim.taymans@gmail.com>");
1176 gstelement_klass->change_state =
1177 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1178 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1180 gstbin_klass->handle_message =
1181 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1185 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1189 /* store the array for the different channels */
1190 group->video_channels = g_ptr_array_new ();
1191 group->audio_channels = g_ptr_array_new ();
1192 group->text_channels = g_ptr_array_new ();
1193 g_mutex_init (&group->lock);
1194 /* init selectors. The selector is found by finding the first prefix that
1195 * matches the media. */
1196 group->playbin = playbin;
1197 /* If you add any items to these lists, check that media_list[] is defined
1198 * above to be large enough to hold MAX(items)+1, so as to accommodate a
1199 * NULL terminator (set when the memory is zeroed on allocation) */
1200 group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
1201 group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
1202 group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
1203 group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
1204 group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
1205 group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
1206 group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
1207 group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
1208 group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
1209 group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
1210 group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
1211 group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
1212 group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
1213 group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
1214 gst_subtitle_overlay_create_factory_caps;
1215 group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
1216 group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
1218 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1219 GstSourceSelect *select = &group->selector[n];
1220 select->sinkpad_delayed_event = NULL;
1221 select->sinkpad_data_probe = 0;
1226 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1230 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1231 GstSourceSelect *select = &group->selector[n];
1232 if (select->sinkpad && select->sinkpad_data_probe)
1233 gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
1234 if (select->sinkpad_delayed_event)
1235 gst_event_unref (select->sinkpad_delayed_event);
1238 g_free (group->uri);
1239 g_free (group->suburi);
1240 g_ptr_array_free (group->video_channels, TRUE);
1241 g_ptr_array_free (group->audio_channels, TRUE);
1242 g_ptr_array_free (group->text_channels, TRUE);
1244 g_mutex_clear (&group->lock);
1245 if (group->audio_sink) {
1246 if (group->audio_sink != playbin->audio_sink)
1247 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1248 gst_object_unref (group->audio_sink);
1250 group->audio_sink = NULL;
1251 if (group->video_sink) {
1252 if (group->video_sink != playbin->video_sink)
1253 gst_element_set_state (group->video_sink, GST_STATE_NULL);
1254 gst_object_unref (group->video_sink);
1256 group->video_sink = NULL;
1258 g_list_free (group->stream_changed_pending);
1259 group->stream_changed_pending = NULL;
1261 if (group->stream_changed_pending_lock.p)
1262 g_mutex_clear (&group->stream_changed_pending_lock);
1263 group->stream_changed_pending_lock.p = NULL;
1265 g_slist_free (group->suburi_flushes_to_drop);
1266 group->suburi_flushes_to_drop = NULL;
1268 if (group->suburi_flushes_to_drop_lock.p)
1269 g_mutex_clear (&group->suburi_flushes_to_drop_lock);
1270 group->suburi_flushes_to_drop_lock.p = NULL;
1274 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1276 g_object_notify (G_OBJECT (playbin), "volume");
1280 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1282 g_object_notify (G_OBJECT (playbin), "mute");
1286 colorbalance_value_changed_cb (GstColorBalance * balance,
1287 GstColorBalanceChannel * channel, gint value, GstPlayBin * playbin)
1289 gst_color_balance_value_changed (GST_COLOR_BALANCE (playbin), channel, value);
1293 compare_factories_func (gconstpointer p1, gconstpointer p2)
1295 GstPluginFeature *f1, *f2;
1299 f1 = (GstPluginFeature *) p1;
1300 f2 = (GstPluginFeature *) p2;
1302 s1 = gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (f1),
1303 GST_ELEMENT_FACTORY_TYPE_SINK);
1304 s2 = gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (f2),
1305 GST_ELEMENT_FACTORY_TYPE_SINK);
1312 diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
1316 diff = strcmp (GST_OBJECT_NAME (f2), GST_OBJECT_NAME (f1));
1321 /* Must be called with elements lock! */
1323 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1328 cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
1329 if (!playbin->elements || playbin->elements_cookie != cookie) {
1330 if (playbin->elements)
1331 gst_plugin_feature_list_free (playbin->elements);
1333 gst_element_factory_list_get_elements
1334 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1336 gst_element_factory_list_get_elements
1337 (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1338 playbin->elements = g_list_concat (res, tmp);
1339 playbin->elements = g_list_sort (playbin->elements, compare_factories_func);
1340 playbin->elements_cookie = cookie;
1345 gst_play_bin_init (GstPlayBin * playbin)
1347 g_rec_mutex_init (&playbin->lock);
1348 g_mutex_init (&playbin->dyn_lock);
1350 /* assume we can create a selector */
1351 playbin->have_selector = TRUE;
1354 playbin->curr_group = &playbin->groups[0];
1355 playbin->next_group = &playbin->groups[1];
1356 init_group (playbin, &playbin->groups[0]);
1357 init_group (playbin, &playbin->groups[1]);
1359 /* first filter out the interesting element factories */
1360 g_mutex_init (&playbin->elements_lock);
1364 g_object_new (GST_TYPE_PLAY_SINK, "name", "playsink", "send-event-mode",
1366 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1367 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1368 /* Connect to notify::volume and notify::mute signals for proxying */
1369 g_signal_connect (playbin->playsink, "notify::volume",
1370 G_CALLBACK (notify_volume_cb), playbin);
1371 g_signal_connect (playbin->playsink, "notify::mute",
1372 G_CALLBACK (notify_mute_cb), playbin);
1373 g_signal_connect (playbin->playsink, "value-changed",
1374 G_CALLBACK (colorbalance_value_changed_cb), playbin);
1376 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1377 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1378 playbin->current_text = DEFAULT_CURRENT_TEXT;
1380 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1381 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1382 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1386 gst_play_bin_finalize (GObject * object)
1388 GstPlayBin *playbin;
1390 playbin = GST_PLAY_BIN (object);
1392 free_group (playbin, &playbin->groups[0]);
1393 free_group (playbin, &playbin->groups[1]);
1395 if (playbin->source)
1396 gst_object_unref (playbin->source);
1397 if (playbin->video_sink) {
1398 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1399 gst_object_unref (playbin->video_sink);
1401 if (playbin->audio_sink) {
1402 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1403 gst_object_unref (playbin->audio_sink);
1405 if (playbin->text_sink) {
1406 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1407 gst_object_unref (playbin->text_sink);
1410 if (playbin->elements)
1411 gst_plugin_feature_list_free (playbin->elements);
1413 g_rec_mutex_clear (&playbin->lock);
1414 g_mutex_clear (&playbin->dyn_lock);
1415 g_mutex_clear (&playbin->elements_lock);
1417 G_OBJECT_CLASS (parent_class)->finalize (object);
1421 gst_playbin_uri_is_valid (GstPlayBin * playbin, const gchar * uri)
1425 GST_LOG_OBJECT (playbin, "checking uri '%s'", uri);
1427 /* this just checks the protocol */
1428 if (!gst_uri_is_valid (uri))
1431 for (c = uri; *c != '\0'; ++c) {
1432 if (!g_ascii_isprint (*c))
1442 GST_WARNING_OBJECT (playbin, "uri '%s' not valid, character #%u",
1443 uri, (guint) ((guintptr) c - (guintptr) uri));
1449 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1451 GstSourceGroup *group;
1454 g_warning ("cannot set NULL uri");
1458 if (!gst_playbin_uri_is_valid (playbin, uri)) {
1459 if (g_str_has_prefix (uri, "file:")) {
1460 GST_WARNING_OBJECT (playbin, "not entirely correct file URI '%s' - make "
1461 "sure to escape spaces and non-ASCII characters properly and specify "
1462 "an absolute path. Use gst_filename_to_uri() to convert filenames "
1465 /* GST_ERROR_OBJECT (playbin, "malformed URI '%s'", uri); */
1469 GST_PLAY_BIN_LOCK (playbin);
1470 group = playbin->next_group;
1472 GST_SOURCE_GROUP_LOCK (group);
1473 /* store the uri in the next group we will play */
1474 g_free (group->uri);
1475 group->uri = g_strdup (uri);
1476 group->valid = TRUE;
1477 GST_SOURCE_GROUP_UNLOCK (group);
1479 GST_DEBUG ("set new uri to %s", uri);
1480 GST_PLAY_BIN_UNLOCK (playbin);
1484 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1486 GstSourceGroup *group;
1488 GST_PLAY_BIN_LOCK (playbin);
1489 group = playbin->next_group;
1491 GST_SOURCE_GROUP_LOCK (group);
1492 g_free (group->suburi);
1493 group->suburi = g_strdup (suburi);
1494 GST_SOURCE_GROUP_UNLOCK (group);
1496 GST_DEBUG ("setting new .sub uri to %s", suburi);
1498 GST_PLAY_BIN_UNLOCK (playbin);
1502 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1504 gst_play_sink_set_flags (playbin->playsink, flags);
1505 gst_play_sink_reconfigure (playbin->playsink);
1509 gst_play_bin_get_flags (GstPlayBin * playbin)
1513 flags = gst_play_sink_get_flags (playbin->playsink);
1518 /* get the currently playing group or if nothing is playing, the next
1519 * group. Must be called with the PLAY_BIN_LOCK. */
1520 static GstSourceGroup *
1521 get_group (GstPlayBin * playbin)
1523 GstSourceGroup *result;
1525 if (!(result = playbin->curr_group))
1526 result = playbin->next_group;
1532 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1534 GstPad *sinkpad = NULL;
1535 GstSourceGroup *group;
1537 GST_PLAY_BIN_LOCK (playbin);
1538 group = get_group (playbin);
1539 if (stream < group->video_channels->len) {
1540 sinkpad = g_ptr_array_index (group->video_channels, stream);
1541 gst_object_ref (sinkpad);
1543 GST_PLAY_BIN_UNLOCK (playbin);
1549 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1551 GstPad *sinkpad = NULL;
1552 GstSourceGroup *group;
1554 GST_PLAY_BIN_LOCK (playbin);
1555 group = get_group (playbin);
1556 if (stream < group->audio_channels->len) {
1557 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1558 gst_object_ref (sinkpad);
1560 GST_PLAY_BIN_UNLOCK (playbin);
1566 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1568 GstPad *sinkpad = NULL;
1569 GstSourceGroup *group;
1571 GST_PLAY_BIN_LOCK (playbin);
1572 group = get_group (playbin);
1573 if (stream < group->text_channels->len) {
1574 sinkpad = g_ptr_array_index (group->text_channels, stream);
1575 gst_object_ref (sinkpad);
1577 GST_PLAY_BIN_UNLOCK (playbin);
1584 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1589 if (!channels || stream >= channels->len)
1592 sinkpad = g_ptr_array_index (channels, stream);
1593 g_object_get (sinkpad, "tags", &result, NULL);
1599 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1602 GstSourceGroup *group;
1604 GST_PLAY_BIN_LOCK (playbin);
1605 group = get_group (playbin);
1606 result = get_tags (playbin, group->video_channels, stream);
1607 GST_PLAY_BIN_UNLOCK (playbin);
1613 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1616 GstSourceGroup *group;
1618 GST_PLAY_BIN_LOCK (playbin);
1619 group = get_group (playbin);
1620 result = get_tags (playbin, group->audio_channels, stream);
1621 GST_PLAY_BIN_UNLOCK (playbin);
1627 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1630 GstSourceGroup *group;
1632 GST_PLAY_BIN_LOCK (playbin);
1633 group = get_group (playbin);
1634 result = get_tags (playbin, group->text_channels, stream);
1635 GST_PLAY_BIN_UNLOCK (playbin);
1641 gst_play_bin_convert_sample (GstPlayBin * playbin, GstCaps * caps)
1643 return gst_play_sink_convert_sample (playbin->playsink, caps);
1646 /* Returns current stream number, or -1 if none has been selected yet */
1648 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1650 /* Internal API cleanup would make this easier... */
1652 GstPad *pad, *current;
1653 GstObject *selector = NULL;
1656 for (i = 0; i < channels->len; i++) {
1657 pad = g_ptr_array_index (channels, i);
1658 if ((selector = gst_pad_get_parent (pad))) {
1659 g_object_get (selector, "active-pad", ¤t, NULL);
1660 gst_object_unref (selector);
1662 if (pad == current) {
1663 gst_object_unref (current);
1669 gst_object_unref (current);
1677 gst_playbin2_send_custom_event (GstObject * selector, const gchar * event_name)
1683 gboolean ret = FALSE;
1685 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1686 peer = gst_pad_get_peer (src);
1688 s = gst_structure_new_empty (event_name);
1689 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1690 gst_pad_send_event (peer, event);
1691 gst_object_unref (peer);
1694 gst_object_unref (src);
1699 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1701 GstSourceGroup *group;
1702 GPtrArray *channels;
1705 GST_PLAY_BIN_LOCK (playbin);
1707 GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1708 playbin->current_video, stream);
1710 group = get_group (playbin);
1711 if (!(channels = group->video_channels))
1714 if (stream == -1 || channels->len <= stream) {
1717 /* take channel from selected stream */
1718 sinkpad = g_ptr_array_index (channels, stream);
1722 gst_object_ref (sinkpad);
1723 GST_PLAY_BIN_UNLOCK (playbin);
1726 GstObject *selector;
1728 if ((selector = gst_pad_get_parent (sinkpad))) {
1729 GstPad *old_sinkpad;
1731 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1733 if (old_sinkpad != sinkpad) {
1734 if (gst_playbin2_send_custom_event (selector,
1735 "playsink-custom-video-flush"))
1736 playbin->video_pending_flush_finish = TRUE;
1738 /* activate the selected pad */
1739 g_object_set (selector, "active-pad", sinkpad, NULL);
1742 gst_object_unref (selector);
1744 gst_object_unref (sinkpad);
1750 GST_PLAY_BIN_UNLOCK (playbin);
1751 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1757 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1759 GstSourceGroup *group;
1760 GPtrArray *channels;
1763 GST_PLAY_BIN_LOCK (playbin);
1765 GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1766 playbin->current_audio, stream);
1768 group = get_group (playbin);
1769 if (!(channels = group->audio_channels))
1772 if (stream == -1 || channels->len <= stream) {
1775 /* take channel from selected stream */
1776 sinkpad = g_ptr_array_index (channels, stream);
1780 gst_object_ref (sinkpad);
1781 GST_PLAY_BIN_UNLOCK (playbin);
1784 GstObject *selector;
1786 if ((selector = gst_pad_get_parent (sinkpad))) {
1787 GstPad *old_sinkpad;
1789 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1791 if (old_sinkpad != sinkpad) {
1792 if (gst_playbin2_send_custom_event (selector,
1793 "playsink-custom-audio-flush"))
1794 playbin->audio_pending_flush_finish = TRUE;
1796 /* activate the selected pad */
1797 g_object_set (selector, "active-pad", sinkpad, NULL);
1799 gst_object_unref (selector);
1801 gst_object_unref (sinkpad);
1807 GST_PLAY_BIN_UNLOCK (playbin);
1808 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1814 gst_play_bin_suburidecodebin_seek_to_start (GstSourceGroup * group)
1816 GstElement *suburidecodebin = group->suburidecodebin;
1817 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1819 GValue item = { 0, };
1821 if (it && gst_iterator_next (it, &item) == GST_ITERATOR_OK
1822 && ((sinkpad = g_value_get_object (&item)) != NULL)) {
1827 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_FLUSH,
1828 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1829 seqnum = gst_event_get_seqnum (event);
1831 /* store the seqnum to drop flushes from this seek later */
1832 g_mutex_lock (&group->suburi_flushes_to_drop_lock);
1833 group->suburi_flushes_to_drop =
1834 g_slist_append (group->suburi_flushes_to_drop,
1835 GUINT_TO_POINTER (seqnum));
1836 g_mutex_unlock (&group->suburi_flushes_to_drop_lock);
1838 if (!gst_pad_send_event (sinkpad, event)) {
1840 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1841 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1842 gst_event_set_seqnum (event, seqnum);
1843 if (!gst_pad_send_event (sinkpad, event)) {
1844 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1846 g_mutex_lock (&group->suburi_flushes_to_drop_lock);
1847 group->suburi_flushes_to_drop =
1848 g_slist_remove (group->suburi_flushes_to_drop,
1849 GUINT_TO_POINTER (seqnum));
1850 g_mutex_unlock (&group->suburi_flushes_to_drop_lock);
1854 g_value_unset (&item);
1858 gst_iterator_free (it);
1862 gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
1863 GstElement * suburidecodebin, gboolean block)
1865 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1866 gboolean done = FALSE;
1867 GValue item = { 0, };
1869 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1876 switch (gst_iterator_next (it, &item)) {
1877 case GST_ITERATOR_OK:
1878 sinkpad = g_value_get_object (&item);
1881 gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1883 } else if (group->block_id) {
1884 gst_pad_remove_probe (sinkpad, group->block_id);
1885 group->block_id = 0;
1887 g_value_reset (&item);
1889 case GST_ITERATOR_DONE:
1892 case GST_ITERATOR_RESYNC:
1893 gst_iterator_resync (it);
1895 case GST_ITERATOR_ERROR:
1900 g_value_unset (&item);
1901 gst_iterator_free (it);
1905 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1907 GstSourceGroup *group;
1908 GPtrArray *channels;
1911 GST_PLAY_BIN_LOCK (playbin);
1913 GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1914 playbin->current_text, stream);
1916 group = get_group (playbin);
1917 if (!(channels = group->text_channels))
1920 if (stream == -1 || channels->len <= stream) {
1923 /* take channel from selected stream */
1924 sinkpad = g_ptr_array_index (channels, stream);
1928 gst_object_ref (sinkpad);
1929 GST_PLAY_BIN_UNLOCK (playbin);
1932 GstObject *selector;
1934 if ((selector = gst_pad_get_parent (sinkpad))) {
1935 GstPad *old_sinkpad;
1937 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1939 if (old_sinkpad != sinkpad) {
1940 gboolean need_unblock, need_block, need_seek;
1941 GstPad *peer = NULL, *oldpeer = NULL;
1942 GstElement *parent_element = NULL, *old_parent_element = NULL;
1944 /* Now check if we need to seek the suburidecodebin to the beginning
1945 * or if we need to block all suburidecodebin sinkpads or if we need
1946 * to unblock all suburidecodebin sinkpads
1949 peer = gst_pad_get_peer (sinkpad);
1951 oldpeer = gst_pad_get_peer (old_sinkpad);
1954 parent_element = gst_pad_get_parent_element (peer);
1956 old_parent_element = gst_pad_get_parent_element (oldpeer);
1958 need_block = (old_parent_element == group->suburidecodebin
1959 && parent_element != old_parent_element);
1960 need_unblock = (parent_element == group->suburidecodebin
1961 && parent_element != old_parent_element);
1962 need_seek = (parent_element == group->suburidecodebin);
1965 gst_object_unref (peer);
1967 gst_object_unref (oldpeer);
1969 gst_object_unref (parent_element);
1970 if (old_parent_element)
1971 gst_object_unref (old_parent_element);
1973 /* Block all suburidecodebin sinkpads */
1975 gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1978 if (gst_playbin2_send_custom_event (selector,
1979 "playsink-custom-subtitle-flush"))
1980 playbin->text_pending_flush_finish = TRUE;
1982 /* activate the selected pad */
1983 g_object_set (selector, "active-pad", sinkpad, NULL);
1985 /* Unblock pads if necessary */
1987 gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1990 /* seek to the beginning */
1992 gst_play_bin_suburidecodebin_seek_to_start (group);
1994 gst_object_unref (selector);
1997 gst_object_unref (old_sinkpad);
1999 gst_object_unref (sinkpad);
2005 GST_PLAY_BIN_UNLOCK (playbin);
2011 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
2012 const gchar * dbg, GstElement * sink)
2014 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
2016 GST_PLAY_BIN_LOCK (playbin);
2017 if (*elem != sink) {
2022 gst_object_ref_sink (sink);
2026 gst_object_unref (old);
2028 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
2029 GST_PLAY_BIN_UNLOCK (playbin);
2033 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
2037 GST_PLAY_BIN_LOCK (playbin);
2039 /* set subtitles on all current and next decodebins. */
2040 if ((elem = playbin->groups[0].uridecodebin))
2041 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
2042 if ((elem = playbin->groups[0].suburidecodebin))
2043 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
2044 if ((elem = playbin->groups[1].uridecodebin))
2045 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
2046 if ((elem = playbin->groups[1].suburidecodebin))
2047 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
2049 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
2050 GST_PLAY_BIN_UNLOCK (playbin);
2054 gst_play_bin_set_property (GObject * object, guint prop_id,
2055 const GValue * value, GParamSpec * pspec)
2057 GstPlayBin *playbin = GST_PLAY_BIN (object);
2061 gst_play_bin_set_uri (playbin, g_value_get_string (value));
2064 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
2067 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
2069 case PROP_CURRENT_VIDEO:
2070 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
2072 case PROP_CURRENT_AUDIO:
2073 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
2075 case PROP_CURRENT_TEXT:
2076 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
2078 case PROP_SUBTITLE_ENCODING:
2079 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
2081 case PROP_VIDEO_SINK:
2082 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
2083 g_value_get_object (value));
2085 case PROP_AUDIO_SINK:
2086 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
2087 g_value_get_object (value));
2089 case PROP_VIS_PLUGIN:
2090 gst_play_sink_set_vis_plugin (playbin->playsink,
2091 g_value_get_object (value));
2093 case PROP_TEXT_SINK:
2094 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
2095 g_value_get_object (value));
2098 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
2101 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
2103 case PROP_FONT_DESC:
2104 gst_play_sink_set_font_desc (playbin->playsink,
2105 g_value_get_string (value));
2107 case PROP_CONNECTION_SPEED:
2108 GST_PLAY_BIN_LOCK (playbin);
2109 playbin->connection_speed = g_value_get_uint64 (value) * 1000;
2110 GST_PLAY_BIN_UNLOCK (playbin);
2112 case PROP_BUFFER_SIZE:
2113 playbin->buffer_size = g_value_get_int (value);
2115 case PROP_BUFFER_DURATION:
2116 playbin->buffer_duration = g_value_get_int64 (value);
2118 case PROP_AV_OFFSET:
2119 gst_play_sink_set_av_offset (playbin->playsink,
2120 g_value_get_int64 (value));
2122 case PROP_RING_BUFFER_MAX_SIZE:
2123 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
2126 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2132 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
2133 const gchar * dbg, GstPlaySinkType type)
2135 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
2137 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
2138 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
2139 dbg, sink, dbg, *elem);
2142 GST_PLAY_BIN_LOCK (playbin);
2144 gst_object_ref (sink);
2145 GST_PLAY_BIN_UNLOCK (playbin);
2152 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
2155 GstPlayBin *playbin = GST_PLAY_BIN (object);
2160 GstSourceGroup *group;
2162 GST_PLAY_BIN_LOCK (playbin);
2163 group = playbin->next_group;
2164 g_value_set_string (value, group->uri);
2165 GST_PLAY_BIN_UNLOCK (playbin);
2169 case PROP_CURRENT_URI:
2171 GstSourceGroup *group;
2173 GST_PLAY_BIN_LOCK (playbin);
2174 group = get_group (playbin);
2175 g_value_set_string (value, group->uri);
2176 GST_PLAY_BIN_UNLOCK (playbin);
2181 GstSourceGroup *group;
2183 GST_PLAY_BIN_LOCK (playbin);
2184 group = playbin->next_group;
2185 g_value_set_string (value, group->suburi);
2186 GST_PLAY_BIN_UNLOCK (playbin);
2189 case PROP_CURRENT_SUBURI:
2191 GstSourceGroup *group;
2193 GST_PLAY_BIN_LOCK (playbin);
2194 group = get_group (playbin);
2195 g_value_set_string (value, group->suburi);
2196 GST_PLAY_BIN_UNLOCK (playbin);
2201 GST_OBJECT_LOCK (playbin);
2202 g_value_set_object (value, playbin->source);
2203 GST_OBJECT_UNLOCK (playbin);
2207 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
2211 GstSourceGroup *group;
2214 GST_PLAY_BIN_LOCK (playbin);
2215 group = get_group (playbin);
2216 n_video = (group->video_channels ? group->video_channels->len : 0);
2217 g_value_set_int (value, n_video);
2218 GST_PLAY_BIN_UNLOCK (playbin);
2221 case PROP_CURRENT_VIDEO:
2222 GST_PLAY_BIN_LOCK (playbin);
2223 g_value_set_int (value, playbin->current_video);
2224 GST_PLAY_BIN_UNLOCK (playbin);
2228 GstSourceGroup *group;
2231 GST_PLAY_BIN_LOCK (playbin);
2232 group = get_group (playbin);
2233 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
2234 g_value_set_int (value, n_audio);
2235 GST_PLAY_BIN_UNLOCK (playbin);
2238 case PROP_CURRENT_AUDIO:
2239 GST_PLAY_BIN_LOCK (playbin);
2240 g_value_set_int (value, playbin->current_audio);
2241 GST_PLAY_BIN_UNLOCK (playbin);
2245 GstSourceGroup *group;
2248 GST_PLAY_BIN_LOCK (playbin);
2249 group = get_group (playbin);
2250 n_text = (group->text_channels ? group->text_channels->len : 0);
2251 g_value_set_int (value, n_text);
2252 GST_PLAY_BIN_UNLOCK (playbin);
2255 case PROP_CURRENT_TEXT:
2256 GST_PLAY_BIN_LOCK (playbin);
2257 g_value_set_int (value, playbin->current_text);
2258 GST_PLAY_BIN_UNLOCK (playbin);
2260 case PROP_SUBTITLE_ENCODING:
2261 GST_PLAY_BIN_LOCK (playbin);
2262 g_value_take_string (value,
2263 gst_play_sink_get_subtitle_encoding (playbin->playsink));
2264 GST_PLAY_BIN_UNLOCK (playbin);
2266 case PROP_VIDEO_SINK:
2267 g_value_take_object (value,
2268 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2269 "video", GST_PLAY_SINK_TYPE_VIDEO));
2271 case PROP_AUDIO_SINK:
2272 g_value_take_object (value,
2273 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2274 "audio", GST_PLAY_SINK_TYPE_AUDIO));
2276 case PROP_VIS_PLUGIN:
2277 g_value_take_object (value,
2278 gst_play_sink_get_vis_plugin (playbin->playsink));
2280 case PROP_TEXT_SINK:
2281 g_value_take_object (value,
2282 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2283 "text", GST_PLAY_SINK_TYPE_TEXT));
2286 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2289 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2292 gst_value_take_sample (value,
2293 gst_play_sink_get_last_sample (playbin->playsink));
2295 case PROP_FONT_DESC:
2296 g_value_take_string (value,
2297 gst_play_sink_get_font_desc (playbin->playsink));
2299 case PROP_CONNECTION_SPEED:
2300 GST_PLAY_BIN_LOCK (playbin);
2301 g_value_set_uint64 (value, playbin->connection_speed / 1000);
2302 GST_PLAY_BIN_UNLOCK (playbin);
2304 case PROP_BUFFER_SIZE:
2305 GST_OBJECT_LOCK (playbin);
2306 g_value_set_int (value, playbin->buffer_size);
2307 GST_OBJECT_UNLOCK (playbin);
2309 case PROP_BUFFER_DURATION:
2310 GST_OBJECT_LOCK (playbin);
2311 g_value_set_int64 (value, playbin->buffer_duration);
2312 GST_OBJECT_UNLOCK (playbin);
2314 case PROP_AV_OFFSET:
2315 g_value_set_int64 (value,
2316 gst_play_sink_get_av_offset (playbin->playsink));
2318 case PROP_RING_BUFFER_MAX_SIZE:
2319 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2322 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2328 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2329 gboolean valid, GstQuery * query)
2335 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2336 gst_query_parse_duration (query, &fmt, &duration);
2338 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2339 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2340 playbin->duration[i].valid = valid;
2341 playbin->duration[i].format = fmt;
2342 playbin->duration[i].duration = valid ? duration : -1;
2349 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2351 const GstFormat formats[] =
2352 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2357 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2358 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2359 query = gst_query_new_duration (formats[i]);
2361 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2363 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2364 gst_query_unref (query);
2369 gst_play_bin_query (GstElement * element, GstQuery * query)
2371 GstPlayBin *playbin = GST_PLAY_BIN (element);
2374 /* During a group switch we shouldn't allow duration queries
2375 * because it's not clear if the old or new group's duration
2376 * is returned and if the sinks are already playing new data
2377 * or old data. See bug #585969
2379 * While we're at it, also don't do any other queries during
2380 * a group switch or any other event that causes topology changes
2381 * by taking the playbin lock in any case.
2383 GST_PLAY_BIN_LOCK (playbin);
2385 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2386 GstSourceGroup *group = playbin->curr_group;
2389 GST_SOURCE_GROUP_LOCK (group);
2390 if (group->stream_changed_pending_lock.p) {
2391 g_mutex_lock (&group->stream_changed_pending_lock);
2392 pending = group->pending || group->stream_changed_pending;
2393 g_mutex_unlock (&group->stream_changed_pending_lock);
2395 pending = group->pending;
2402 gst_query_parse_duration (query, &fmt, NULL);
2403 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2404 if (fmt == playbin->duration[i].format) {
2405 ret = playbin->duration[i].valid;
2406 gst_query_set_duration (query, fmt,
2407 (ret ? playbin->duration[i].duration : -1));
2411 /* if nothing cached yet, we might as well request duration,
2412 * such as during initial startup */
2414 GST_DEBUG_OBJECT (playbin,
2415 "Taking cached duration because of pending group switch: %d", ret);
2416 GST_SOURCE_GROUP_UNLOCK (group);
2417 GST_PLAY_BIN_UNLOCK (playbin);
2421 GST_SOURCE_GROUP_UNLOCK (group);
2424 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2426 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2427 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2428 GST_PLAY_BIN_UNLOCK (playbin);
2433 /* mime types we are not handling on purpose right now, don't post a
2434 * missing-plugin message for these */
2435 static const gchar *blacklisted_mimes[] = {
2440 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2442 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2443 GstSourceGroup *group;
2445 if (gst_is_missing_plugin_message (msg)) {
2449 detail = gst_missing_plugin_message_get_installer_detail (msg);
2450 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2451 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2452 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2453 gst_message_unref (msg);
2459 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2460 const GstStructure *s = gst_message_get_structure (msg);
2462 /* Drop all stream-changed messages except the last one */
2463 if (strcmp ("playbin-stream-changed", gst_structure_get_name (s)) == 0) {
2464 guint32 seqnum = gst_message_get_seqnum (msg);
2467 group = playbin->curr_group;
2468 g_mutex_lock (&group->stream_changed_pending_lock);
2469 for (l = group->stream_changed_pending; l;) {
2470 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2472 if (l_seqnum == seqnum) {
2475 group->stream_changed_pending =
2476 g_list_delete_link (group->stream_changed_pending, l_prev);
2477 if (group->stream_changed_pending) {
2478 gst_message_unref (msg);
2486 g_mutex_unlock (&group->stream_changed_pending_lock);
2488 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2489 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2490 GstObject *src = GST_OBJECT_CAST (msg->src);
2492 /* Ignore async state changes from the uridecodebin children,
2493 * see bug #602000. */
2494 group = playbin->curr_group;
2495 if (src && (group = playbin->curr_group) &&
2496 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2497 || (group->suburidecodebin
2498 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2499 GST_DEBUG_OBJECT (playbin,
2500 "Ignoring async state change of uridecodebin: %s",
2501 GST_OBJECT_NAME (src));
2502 gst_message_unref (msg);
2505 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2506 /* If we get an error of the subtitle uridecodebin transform
2507 * them into warnings and disable the subtitles */
2508 group = playbin->curr_group;
2509 if (group && group->suburidecodebin) {
2510 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2511 (group->suburidecodebin)))) {
2513 gchar *debug = NULL;
2514 GstMessage *new_msg;
2516 gboolean done = FALSE;
2517 GValue item = { 0, };
2519 gst_message_parse_error (msg, &err, &debug);
2520 new_msg = gst_message_new_warning (msg->src, err, debug);
2522 gst_message_unref (msg);
2527 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2528 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2529 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2530 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2532 it = gst_element_iterate_src_pads (group->suburidecodebin);
2533 while (it && !done) {
2535 GstIteratorResult res;
2537 res = gst_iterator_next (it, &item);
2540 case GST_ITERATOR_DONE:
2543 case GST_ITERATOR_OK:
2544 p = g_value_get_object (&item);
2545 pad_removed_cb (NULL, p, group);
2546 g_value_reset (&item);
2549 case GST_ITERATOR_RESYNC:
2550 gst_iterator_resync (it);
2552 case GST_ITERATOR_ERROR:
2557 g_value_unset (&item);
2559 gst_iterator_free (it);
2561 gst_object_ref (group->suburidecodebin);
2562 gst_bin_remove (bin, group->suburidecodebin);
2563 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2565 if (group->sub_pending) {
2566 group->sub_pending = FALSE;
2567 no_more_pads_cb (NULL, group);
2574 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2578 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2579 GstPlayBin * playbin)
2581 const gchar *property;
2582 GstSourceGroup *group;
2583 GstSourceSelect *select = NULL;
2586 GST_PLAY_BIN_LOCK (playbin);
2587 group = get_group (playbin);
2589 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2590 if (selector == G_OBJECT (group->selector[i].selector)) {
2591 select = &group->selector[i];
2595 /* We got a pad-change after our group got switched out; no need to notify */
2597 GST_PLAY_BIN_UNLOCK (playbin);
2601 switch (select->type) {
2602 case GST_PLAY_SINK_TYPE_VIDEO:
2603 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2604 property = "current-video";
2605 playbin->current_video = get_current_stream_number (playbin,
2606 group->video_channels);
2608 if (playbin->video_pending_flush_finish) {
2609 playbin->video_pending_flush_finish = FALSE;
2610 GST_PLAY_BIN_UNLOCK (playbin);
2611 gst_playbin2_send_custom_event (GST_OBJECT (selector),
2612 "playsink-custom-video-flush-finish");
2616 case GST_PLAY_SINK_TYPE_AUDIO:
2617 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2618 property = "current-audio";
2619 playbin->current_audio = get_current_stream_number (playbin,
2620 group->audio_channels);
2622 if (playbin->audio_pending_flush_finish) {
2623 playbin->audio_pending_flush_finish = FALSE;
2624 GST_PLAY_BIN_UNLOCK (playbin);
2625 gst_playbin2_send_custom_event (GST_OBJECT (selector),
2626 "playsink-custom-audio-flush-finish");
2630 case GST_PLAY_SINK_TYPE_TEXT:
2631 property = "current-text";
2632 playbin->current_text = get_current_stream_number (playbin,
2633 group->text_channels);
2635 if (playbin->text_pending_flush_finish) {
2636 playbin->text_pending_flush_finish = FALSE;
2637 GST_PLAY_BIN_UNLOCK (playbin);
2638 gst_playbin2_send_custom_event (GST_OBJECT (selector),
2639 "playsink-custom-subtitle-flush-finish");
2646 GST_PLAY_BIN_UNLOCK (playbin);
2650 g_object_notify (G_OBJECT (playbin), property);
2653 /* this callback sends a delayed event once the pad becomes unblocked */
2654 static GstPadProbeReturn
2655 stream_changed_data_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
2657 GstMiniObject *object = GST_PAD_PROBE_INFO_DATA (info);
2658 GstSourceSelect *select = (GstSourceSelect *) data;
2661 /* we need do this just once, so cleanup first */
2662 gst_pad_remove_probe (pad, select->sinkpad_data_probe);
2663 select->sinkpad_data_probe = 0;
2664 e = select->sinkpad_delayed_event;
2665 select->sinkpad_delayed_event = NULL;
2667 /* really, this should not happen */
2669 GST_WARNING ("Data probed called, but no delayed event");
2670 return GST_PAD_PROBE_OK;
2673 if (GST_IS_EVENT (object)
2674 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_SEGMENT) {
2675 /* push the event first, then send the delayed one */
2676 gst_event_ref (GST_EVENT_CAST (object));
2677 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2678 gst_pad_send_event (pad, e);
2679 return GST_PAD_PROBE_DROP;
2681 /* send delayed event, then allow the caller to go on */
2682 gst_pad_send_event (pad, e);
2683 return GST_PAD_PROBE_OK;
2687 static GstPadProbeReturn
2688 _suburidecodebin_event_probe (GstPad * pad, GstPadProbeInfo * info,
2691 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2692 GstSourceGroup *group = udata;
2693 GstEvent *event = GST_PAD_PROBE_INFO_DATA (info);
2695 switch (GST_EVENT_TYPE (event)) {
2696 case GST_EVENT_FLUSH_START:
2697 case GST_EVENT_FLUSH_STOP:
2699 guint32 seqnum = gst_event_get_seqnum (event);
2700 GSList *item = g_slist_find (group->suburi_flushes_to_drop,
2701 GUINT_TO_POINTER (seqnum));
2703 ret = GST_PAD_PROBE_DROP; /* this is from subtitle seek only, drop it */
2704 if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2705 group->suburi_flushes_to_drop =
2706 g_slist_delete_link (group->suburi_flushes_to_drop, item);
2716 /* helper function to lookup stuff in lists */
2718 array_has_value (const gchar * values[], const gchar * value, gboolean exact)
2722 for (i = 0; values[i]; i++) {
2723 if (exact && !strcmp (value, values[i]))
2725 if (!exact && g_str_has_prefix (value, values[i]))
2733 GstPlayBin *playbin;
2735 GstPlaySinkType type;
2739 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2741 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2744 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2745 " with stream id %d and type %d have changed",
2746 object, ntdata->stream_id, ntdata->type);
2748 switch (ntdata->type) {
2749 case GST_PLAY_SINK_TYPE_VIDEO:
2750 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2751 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2753 case GST_PLAY_SINK_TYPE_AUDIO:
2754 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2755 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2757 case GST_PLAY_SINK_TYPE_TEXT:
2758 signal = SIGNAL_TEXT_TAGS_CHANGED;
2766 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2770 /* this function is called when a new pad is added to decodebin. We check the
2771 * type of the pad and add it to the selector element of the group.
2774 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2776 GstPlayBin *playbin;
2778 const GstStructure *s;
2781 GstPadLinkReturn res;
2782 GstSourceSelect *select = NULL;
2784 gboolean changed = FALSE;
2786 playbin = group->playbin;
2788 caps = gst_pad_query_caps (pad, NULL);
2789 s = gst_caps_get_structure (caps, 0);
2790 name = gst_structure_get_name (s);
2792 GST_DEBUG_OBJECT (playbin,
2793 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2794 GST_DEBUG_PAD_NAME (pad), caps, group);
2796 /* major type of the pad, this determines the selector to use,
2797 try exact match first so we don't prematurely match video/
2798 for video/x-dvd-subpicture */
2799 for (pass = 0; !select && pass < 2; pass++) {
2800 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2801 if (array_has_value (group->selector[i].media_list, name, pass == 0)) {
2802 select = &group->selector[i];
2804 } else if (group->selector[i].get_media_caps) {
2805 GstCaps *media_caps = group->selector[i].get_media_caps ();
2807 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2808 select = &group->selector[i];
2809 gst_caps_unref (media_caps);
2812 gst_caps_unref (media_caps);
2816 /* no selector found for the media type, don't bother linking it to a
2817 * selector. This will leave the pad unlinked and thus ignored. */
2821 GST_SOURCE_GROUP_LOCK (group);
2822 if (select->selector == NULL && playbin->have_selector) {
2823 /* no selector, create one */
2824 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2825 select->selector = gst_element_factory_make ("input-selector", NULL);
2826 if (select->selector == NULL) {
2827 /* post the missing selector message only once */
2828 playbin->have_selector = FALSE;
2829 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2830 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2832 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2833 (_("Missing element '%s' - check your GStreamer installation."),
2834 "input-selector"), (NULL));
2836 /* sync-mode=1, use clock */
2837 if (select->type == GST_PLAY_SINK_TYPE_TEXT)
2838 g_object_set (select->selector, "sync-streams", TRUE,
2839 "sync-mode", 1, "cache-buffers", TRUE, NULL);
2841 g_object_set (select->selector, "sync-streams", TRUE, NULL);
2843 g_signal_connect (select->selector, "notify::active-pad",
2844 G_CALLBACK (selector_active_pad_changed), playbin);
2846 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2847 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2848 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2852 if (select->srcpad == NULL) {
2853 if (select->selector) {
2854 /* save source pad of the selector */
2855 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2857 /* no selector, use the pad as the source pad then */
2858 select->srcpad = gst_object_ref (pad);
2861 /* block the selector srcpad. It's possible that multiple decodebins start
2862 * pushing data into the selectors before we have a chance to collect all
2863 * streams and connect the sinks, resulting in not-linked errors. After we
2864 * configured the sinks we will unblock them all. */
2865 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2867 gst_pad_add_probe (select->srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2871 /* get sinkpad for the new stream */
2872 if (select->selector) {
2873 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink_%u"))) {
2874 gulong notify_tags_handler = 0;
2875 NotifyTagsData *ntdata;
2877 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2878 GST_DEBUG_PAD_NAME (sinkpad));
2880 /* store the selector for the pad */
2881 g_object_set_data (G_OBJECT (sinkpad), "playbin.select", select);
2883 /* connect to the notify::tags signal for our
2884 * own *-tags-changed signals
2886 ntdata = g_new0 (NotifyTagsData, 1);
2887 ntdata->playbin = playbin;
2888 ntdata->stream_id = select->channels->len;
2889 ntdata->type = select->type;
2891 notify_tags_handler =
2892 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2893 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2895 g_object_set_data (G_OBJECT (sinkpad), "playbin.notify_tags_handler",
2896 (gpointer) (guintptr) notify_tags_handler);
2898 /* store the pad in the array */
2899 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2900 g_ptr_array_add (select->channels, sinkpad);
2902 res = gst_pad_link (pad, sinkpad);
2903 if (GST_PAD_LINK_FAILED (res))
2906 /* store selector pad so we can release it */
2907 g_object_set_data (G_OBJECT (pad), "playbin.sinkpad", sinkpad);
2910 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2911 GST_DEBUG_PAD_NAME (pad), select->selector);
2914 /* no selector, don't configure anything, we'll link the new pad directly to
2919 /* store the selector for the pad */
2920 g_object_set_data (G_OBJECT (pad), "playbin2.select", select);
2922 GST_SOURCE_GROUP_UNLOCK (group);
2924 if (decodebin == group->suburidecodebin) {
2925 /* TODO store the probe id */
2926 /* to avoid propagating flushes from suburi specific seeks */
2927 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
2928 _suburidecodebin_event_probe, group, NULL);
2933 gboolean always_ok = (decodebin == group->suburidecodebin);
2935 switch (select->type) {
2936 case GST_PLAY_SINK_TYPE_VIDEO:
2937 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2938 /* we want to return NOT_LINKED for unselected pads but only for pads
2939 * from the normal uridecodebin. This makes sure that subtitle streams
2940 * are not raced past audio/video from decodebin's multiqueue.
2941 * For pads from suburidecodebin OK should always be returned, otherwise
2942 * it will most likely stop. */
2943 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2944 signal = SIGNAL_VIDEO_CHANGED;
2946 case GST_PLAY_SINK_TYPE_AUDIO:
2947 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2948 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2949 signal = SIGNAL_AUDIO_CHANGED;
2951 case GST_PLAY_SINK_TYPE_TEXT:
2952 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2953 signal = SIGNAL_TEXT_CHANGED;
2960 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2964 gst_caps_unref (caps);
2970 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2971 name, GST_DEBUG_PAD_NAME (pad));
2976 GST_ERROR_OBJECT (playbin,
2977 "failed to link pad %s:%s to selector, reason %d",
2978 GST_DEBUG_PAD_NAME (pad), res);
2979 GST_SOURCE_GROUP_UNLOCK (group);
2984 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2985 * the selector. This will make the selector select a new pad. */
2987 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2989 GstPlayBin *playbin;
2991 GstElement *selector;
2992 GstSourceSelect *select;
2994 playbin = group->playbin;
2996 GST_DEBUG_OBJECT (playbin,
2997 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2999 GST_SOURCE_GROUP_LOCK (group);
3001 if ((select = g_object_get_data (G_OBJECT (pad), "playbin2.select"))) {
3002 g_assert (select->selector == NULL);
3003 g_assert (select->srcpad == pad);
3004 gst_object_unref (pad);
3005 select->srcpad = NULL;
3009 /* get the selector sinkpad */
3010 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin.sinkpad")))
3013 if ((select = g_object_get_data (G_OBJECT (peer), "playbin.select"))) {
3014 gulong notify_tags_handler;
3016 notify_tags_handler =
3017 (guintptr) g_object_get_data (G_OBJECT (peer),
3018 "playbin.notify_tags_handler");
3019 if (notify_tags_handler != 0)
3020 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
3021 g_object_set_data (G_OBJECT (peer), "playbin.notify_tags_handler", NULL);
3023 /* remove the pad from the array */
3024 g_ptr_array_remove (select->channels, peer);
3025 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
3027 if (!select->channels->len && select->selector) {
3028 GST_DEBUG_OBJECT (playbin, "all selector sinkpads removed");
3029 GST_DEBUG_OBJECT (playbin, "removing selector %p", select->selector);
3030 gst_object_unref (select->srcpad);
3031 select->srcpad = NULL;
3032 gst_element_set_state (select->selector, GST_STATE_NULL);
3033 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3034 select->selector = NULL;
3038 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
3039 gst_pad_unlink (pad, peer);
3041 /* get selector, this can be NULL when the element is removing the pads
3042 * because it's being disposed. */
3043 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
3045 gst_object_unref (peer);
3049 /* release the pad to the selector, this will make the selector choose a new
3051 gst_element_release_request_pad (selector, peer);
3052 gst_object_unref (peer);
3054 gst_object_unref (selector);
3056 GST_SOURCE_GROUP_UNLOCK (group);
3063 GST_DEBUG_OBJECT (playbin, "pad not linked");
3064 GST_SOURCE_GROUP_UNLOCK (group);
3069 GST_DEBUG_OBJECT (playbin, "selector not found");
3070 GST_SOURCE_GROUP_UNLOCK (group);
3075 /* we get called when all pads are available and we must connect the sinks to
3077 * The main purpose of the code is to see if we have video/audio and subtitles
3078 * and pick the right pipelines to display them.
3080 * The selectors installed on the group tell us about the presence of
3081 * audio/video and subtitle streams. This allows us to see if we need
3082 * visualisation, video or/and audio.
3085 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
3087 GstPlayBin *playbin;
3088 GstPadLinkReturn res;
3092 playbin = group->playbin;
3094 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
3096 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
3098 GST_SOURCE_GROUP_LOCK (group);
3099 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3100 GstSourceSelect *select = &group->selector[i];
3102 /* check if the specific media type was detected and thus has a selector
3103 * created for it. If there is the media type, get a sinkpad from the sink
3104 * and link it. We only do this if we have not yet requested the sinkpad
3106 if (select->srcpad && select->sinkpad == NULL) {
3107 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
3109 gst_play_sink_request_pad (playbin->playsink, select->type);
3110 } else if (select->srcpad && select->sinkpad) {
3111 GST_DEBUG_OBJECT (playbin, "refreshing new sink pad %d", select->type);
3112 gst_play_sink_refresh_pad (playbin->playsink, select->sinkpad,
3114 } else if (select->sinkpad && select->srcpad == NULL) {
3115 GST_DEBUG_OBJECT (playbin, "releasing sink pad %d", select->type);
3116 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3117 select->sinkpad = NULL;
3119 if (select->sinkpad && select->srcpad &&
3120 !gst_pad_is_linked (select->srcpad)) {
3121 res = gst_pad_link (select->srcpad, select->sinkpad);
3122 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
3123 select->media_list[0], res);
3124 if (res != GST_PAD_LINK_OK) {
3125 GST_ELEMENT_ERROR (playbin, CORE, PAD,
3126 ("Internal playbin error."),
3127 ("Failed to link selector to sink. Error %d", res));
3131 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
3132 group->pending - 1);
3134 if (group->pending > 0)
3137 if (group->suburidecodebin == decodebin)
3138 group->sub_pending = FALSE;
3140 if (group->pending == 0) {
3141 /* we are the last group to complete, we will configure the output and then
3142 * signal the other waiters. */
3143 GST_LOG_OBJECT (playbin, "last group complete");
3146 GST_LOG_OBJECT (playbin, "have more pending groups");
3149 GST_SOURCE_GROUP_UNLOCK (group);
3152 /* if we have custom sinks, configure them now */
3153 GST_SOURCE_GROUP_LOCK (group);
3155 if (group->audio_sink) {
3156 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
3158 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
3162 if (group->video_sink) {
3163 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
3165 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
3169 if (playbin->text_sink) {
3170 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
3171 playbin->text_sink);
3172 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
3173 playbin->text_sink);
3176 GST_SOURCE_GROUP_UNLOCK (group);
3178 /* signal the other decodebins that they can continue now. */
3179 GST_SOURCE_GROUP_LOCK (group);
3180 /* unblock all selectors */
3181 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3182 GstSourceSelect *select = &group->selector[i];
3184 /* All streamsynchronizer streams should see stream-changed message,
3185 * to arrange for blocking unblocking. */
3186 if (select->sinkpad) {
3192 s = gst_structure_new ("playbin-stream-changed", "uri", G_TYPE_STRING,
3195 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
3196 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
3197 seqnum = gst_message_get_seqnum (msg);
3198 event = gst_event_new_sink_message ("GstPlaybin", msg);
3199 g_mutex_lock (&group->stream_changed_pending_lock);
3200 group->stream_changed_pending =
3201 g_list_prepend (group->stream_changed_pending,
3202 GUINT_TO_POINTER (seqnum));
3204 /* remove any data probe we might have, and replace */
3205 if (select->sinkpad_delayed_event)
3206 gst_event_unref (select->sinkpad_delayed_event);
3207 select->sinkpad_delayed_event = event;
3208 if (select->sinkpad_data_probe)
3209 gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
3211 /* we go to the trouble of setting a probe on the pad to send
3212 the playbin-stream-changed event as sending it here might
3213 find that the pad is blocked, so we'd block here, and the
3214 pad might not be linked yet. Additionally, sending it here
3215 apparently would be on the wrong thread */
3216 select->sinkpad_data_probe =
3217 gst_pad_add_probe (select->sinkpad,
3218 GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
3219 stream_changed_data_probe, (gpointer) select, NULL);
3221 g_mutex_unlock (&group->stream_changed_pending_lock);
3222 gst_message_unref (msg);
3225 if (select->srcpad) {
3226 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
3228 if (select->block_id) {
3229 gst_pad_remove_probe (select->srcpad, select->block_id);
3230 select->block_id = 0;
3234 GST_SOURCE_GROUP_UNLOCK (group);
3237 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
3243 GST_DEBUG ("ignoring, we are shutting down");
3244 /* Request a flushing pad from playsink that we then link to the selector.
3245 * Then we unblock the selectors so that they stop with a WRONG_STATE
3246 * instead of a NOT_LINKED error.
3248 GST_SOURCE_GROUP_LOCK (group);
3249 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3250 GstSourceSelect *select = &group->selector[i];
3252 if (select->srcpad) {
3253 if (select->sinkpad == NULL) {
3254 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
3256 gst_play_sink_request_pad (playbin->playsink,
3257 GST_PLAY_SINK_TYPE_FLUSHING);
3258 res = gst_pad_link (select->srcpad, select->sinkpad);
3259 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
3261 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
3263 if (select->block_id) {
3264 gst_pad_remove_probe (select->srcpad, select->block_id);
3265 select->block_id = 0;
3269 GST_SOURCE_GROUP_UNLOCK (group);
3275 drained_cb (GstElement * decodebin, GstSourceGroup * group)
3277 GstPlayBin *playbin;
3279 playbin = group->playbin;
3281 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
3283 /* after this call, we should have a next group to activate or we EOS */
3284 g_signal_emit (G_OBJECT (playbin),
3285 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
3287 /* now activate the next group. If the app did not set a uri, this will
3288 * fail and we can do EOS */
3289 setup_next_source (playbin, GST_STATE_PAUSED);
3292 /* Like gst_element_factory_can_sink_any_caps() but doesn't
3293 * allow ANY caps on the sinkpad template */
3295 _factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps)
3297 const GList *templs;
3299 templs = gst_element_factory_get_static_pad_templates (factory);
3302 GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
3304 if (templ->direction == GST_PAD_SINK) {
3305 GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
3307 if (!gst_caps_is_any (templcaps)
3308 && gst_caps_can_intersect (templcaps, caps)) {
3309 gst_caps_unref (templcaps);
3312 gst_caps_unref (templcaps);
3314 templs = g_list_next (templs);
3320 /* Called when we must provide a list of factories to plug to @pad with @caps.
3321 * We first check if we have a sink that can handle the format and if we do, we
3322 * return NULL, to expose the pad. If we have no sink (or the sink does not
3323 * work), we return the list of elements that can connect. */
3324 static GValueArray *
3325 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
3326 GstCaps * caps, GstSourceGroup * group)
3328 GstPlayBin *playbin;
3329 GList *mylist, *tmp;
3330 GValueArray *result;
3332 playbin = group->playbin;
3334 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
3335 group, GST_DEBUG_PAD_NAME (pad), caps);
3337 /* filter out the elements based on the caps. */
3338 g_mutex_lock (&playbin->elements_lock);
3339 gst_play_bin_update_elements_list (playbin);
3341 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
3343 g_mutex_unlock (&playbin->elements_lock);
3345 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
3346 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
3348 /* 2 additional elements for the already set audio/video sinks */
3349 result = g_value_array_new (g_list_length (mylist) + 2);
3351 /* Check if we already have an audio/video sink and if this is the case
3352 * put it as the first element of the array */
3353 if (group->audio_sink) {
3354 GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
3356 if (factory && _factory_can_sink_caps (factory, caps)) {
3357 GValue val = { 0, };
3359 g_value_init (&val, G_TYPE_OBJECT);
3360 g_value_set_object (&val, factory);
3361 result = g_value_array_append (result, &val);
3362 g_value_unset (&val);
3366 if (group->video_sink) {
3367 GstElementFactory *factory = gst_element_get_factory (group->video_sink);
3369 if (factory && _factory_can_sink_caps (factory, caps)) {
3370 GValue val = { 0, };
3372 g_value_init (&val, G_TYPE_OBJECT);
3373 g_value_set_object (&val, factory);
3374 result = g_value_array_append (result, &val);
3375 g_value_unset (&val);
3379 for (tmp = mylist; tmp; tmp = tmp->next) {
3380 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
3381 GValue val = { 0, };
3383 if (group->audio_sink && gst_element_factory_list_is_type (factory,
3384 GST_ELEMENT_FACTORY_TYPE_SINK |
3385 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
3388 if (group->video_sink && gst_element_factory_list_is_type (factory,
3389 GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
3390 | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
3394 g_value_init (&val, G_TYPE_OBJECT);
3395 g_value_set_object (&val, factory);
3396 g_value_array_append (result, &val);
3397 g_value_unset (&val);
3399 gst_plugin_feature_list_free (mylist);
3404 /* autoplug-continue decides, if a pad has raw caps that can be exposed
3405 * directly or if further decoding is necessary. We use this to expose
3406 * supported subtitles directly */
3408 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
3409 * explicitly the caps it supports and if it claims to support ANY
3410 * caps it really should support everything */
3412 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
3413 GstSourceGroup * group)
3415 gboolean ret = TRUE;
3417 GstPad *sinkpad = NULL;
3419 GST_SOURCE_GROUP_LOCK (group);
3421 if ((sink = group->playbin->text_sink))
3422 sinkpad = gst_element_get_static_pad (sink, "sink");
3426 /* Ignore errors here, if a custom sink fails to go
3427 * to READY things are wrong and will error out later
3429 if (GST_STATE (sink) < GST_STATE_READY)
3430 gst_element_set_state (sink, GST_STATE_READY);
3432 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3433 if (!gst_caps_is_any (sinkcaps))
3434 ret = !gst_pad_query_accept_caps (sinkpad, caps);
3435 gst_caps_unref (sinkcaps);
3436 gst_object_unref (sinkpad);
3438 GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3439 ret = !gst_caps_is_subset (caps, subcaps);
3440 gst_caps_unref (subcaps);
3442 /* If autoplugging can stop don't do additional checks */
3446 /* If this is from the subtitle uridecodebin we don't need to
3447 * check the audio and video sink */
3448 if (group->suburidecodebin
3449 && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3450 GST_OBJECT_CAST (group->suburidecodebin)))
3453 if ((sink = group->audio_sink)) {
3454 sinkpad = gst_element_get_static_pad (sink, "sink");
3458 /* Ignore errors here, if a custom sink fails to go
3459 * to READY things are wrong and will error out later
3461 if (GST_STATE (sink) < GST_STATE_READY)
3462 gst_element_set_state (sink, GST_STATE_READY);
3464 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3465 if (!gst_caps_is_any (sinkcaps))
3466 ret = !gst_pad_query_accept_caps (sinkpad, caps);
3467 gst_caps_unref (sinkcaps);
3468 gst_object_unref (sinkpad);
3474 if ((sink = group->video_sink)) {
3475 sinkpad = gst_element_get_static_pad (sink, "sink");
3479 /* Ignore errors here, if a custom sink fails to go
3480 * to READY things are wrong and will error out later
3482 if (GST_STATE (sink) < GST_STATE_READY)
3483 gst_element_set_state (sink, GST_STATE_READY);
3485 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3486 if (!gst_caps_is_any (sinkcaps))
3487 ret = !gst_pad_query_accept_caps (sinkpad, caps);
3488 gst_caps_unref (sinkcaps);
3489 gst_object_unref (sinkpad);
3494 GST_SOURCE_GROUP_UNLOCK (group);
3496 GST_DEBUG_OBJECT (group->playbin,
3497 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3498 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3504 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3508 /* ... activate it ... We do this before adding it to the bin so that we
3509 * don't accidentally make it post error messages that will stop
3511 if (GST_STATE (sink) < GST_STATE_READY &&
3512 gst_element_set_state (sink,
3513 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3517 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3518 /* Got the sink pad, now let's see if the element actually does accept the
3519 * caps that we have */
3520 if (!gst_pad_query_accept_caps (sinkpad, caps)) {
3521 gst_object_unref (sinkpad);
3524 gst_object_unref (sinkpad);
3530 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw");
3531 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw");
3533 /* We are asked to select an element. See if the next element to check
3534 * is a sink. If this is the case, we see if the sink works by setting it to
3535 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3536 * expose the raw pad so that we can setup the mixers. */
3537 static GstAutoplugSelectResult
3538 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3539 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3541 GstPlayBin *playbin;
3542 GstElement *element;
3544 GstPlaySinkType type;
3547 playbin = group->playbin;
3549 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3550 group, GST_DEBUG_PAD_NAME (pad), caps);
3552 GST_DEBUG_OBJECT (playbin, "checking factory %s", GST_OBJECT_NAME (factory));
3554 /* if it's not a sink, we make sure the element is compatible with
3556 if (!gst_element_factory_list_is_type (factory,
3557 GST_ELEMENT_FACTORY_TYPE_SINK)) {
3558 gboolean isvideodec = gst_element_factory_list_is_type (factory,
3559 GST_ELEMENT_FACTORY_TYPE_DECODER |
3560 GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
3561 GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
3562 gboolean isaudiodec = gst_element_factory_list_is_type (factory,
3563 GST_ELEMENT_FACTORY_TYPE_DECODER |
3564 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
3566 /* If it is a decoder and we have a fixed sink for the media
3567 * type it outputs, check that the decoder is compatible with this sink */
3568 if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) {
3569 gboolean compatible = TRUE;
3575 sink = group->audio_sink;
3577 sink = group->video_sink;
3579 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3580 GstPlayFlags flags = gst_play_bin_get_flags (playbin);
3582 (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) :
3583 gst_static_caps_get (&raw_video_caps);
3585 caps = gst_pad_query_caps (sinkpad, NULL);
3587 /* If the sink supports raw audio/video, we first check
3588 * if the decoder could output any raw audio/video format
3589 * and assume it is compatible with the sink then. We don't
3590 * do a complete compatibility check here if converters
3591 * are plugged between the decoder and the sink because
3592 * the converters will convert between raw formats and
3593 * even if the decoder format is not supported by the decoder
3594 * a converter will convert it.
3596 * We assume here that the converters can convert between
3599 if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO)
3600 && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec
3601 && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO)
3602 && gst_caps_can_intersect (caps, raw_caps))) {
3603 compatible = gst_element_factory_can_src_any_caps (factory, raw_caps)
3604 || gst_element_factory_can_src_any_caps (factory, caps);
3606 compatible = gst_element_factory_can_src_any_caps (factory, caps);
3609 gst_object_unref (sinkpad);
3610 gst_caps_unref (caps);
3614 return GST_AUTOPLUG_SELECT_TRY;
3616 GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink",
3617 GST_OBJECT_NAME (factory));
3619 return GST_AUTOPLUG_SELECT_SKIP;
3621 return GST_AUTOPLUG_SELECT_TRY;
3624 /* it's a sink, see if an instance of it actually works */
3625 GST_DEBUG_OBJECT (playbin, "we found a sink");
3627 klass = gst_element_factory_get_klass (factory);
3629 /* figure out the klass */
3630 if (strstr (klass, "Audio")) {
3631 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3632 type = GST_PLAY_SINK_TYPE_AUDIO;
3633 sinkp = &group->audio_sink;
3634 } else if (strstr (klass, "Video")) {
3635 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3636 type = GST_PLAY_SINK_TYPE_VIDEO;
3637 sinkp = &group->video_sink;
3639 /* unknown klass, skip this element */
3640 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3641 return GST_AUTOPLUG_SELECT_SKIP;
3644 /* if we are asked to do visualisations and it's an audio sink, skip the
3645 * element. We can only do visualisations with raw sinks */
3646 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3647 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3648 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3649 return GST_AUTOPLUG_SELECT_SKIP;
3653 /* now see if we already have a sink element */
3654 GST_SOURCE_GROUP_LOCK (group);
3656 GstElement *sink = gst_object_ref (*sinkp);
3658 if (sink_accepts_caps (sink, caps)) {
3659 GST_DEBUG_OBJECT (playbin,
3660 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3661 GST_ELEMENT_NAME (sink), caps);
3662 gst_object_unref (sink);
3663 GST_SOURCE_GROUP_UNLOCK (group);
3664 return GST_AUTOPLUG_SELECT_EXPOSE;
3666 GST_DEBUG_OBJECT (playbin,
3667 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3668 GST_ELEMENT_NAME (sink), caps);
3669 gst_object_unref (sink);
3670 GST_SOURCE_GROUP_UNLOCK (group);
3671 return GST_AUTOPLUG_SELECT_SKIP;
3674 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3676 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3677 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3678 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3679 GST_SOURCE_GROUP_UNLOCK (group);
3680 return GST_AUTOPLUG_SELECT_SKIP;
3683 /* Check if the selected sink actually supports the
3684 * caps and can be set to READY*/
3685 if (!sink_accepts_caps (element, caps)) {
3686 gst_element_set_state (element, GST_STATE_NULL);
3687 gst_object_unref (element);
3688 GST_SOURCE_GROUP_UNLOCK (group);
3689 return GST_AUTOPLUG_SELECT_SKIP;
3692 /* remember the sink in the group now, the element is floating, we take
3695 * store the sink in the group, we will configure it later when we
3696 * reconfigure the sink */
3697 GST_DEBUG_OBJECT (playbin, "remember sink");
3698 gst_object_ref_sink (element);
3700 GST_SOURCE_GROUP_UNLOCK (group);
3702 /* tell decodebin to expose the pad because we are going to use this
3704 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3706 return GST_AUTOPLUG_SELECT_EXPOSE;
3710 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3711 GstSourceGroup * group)
3713 GstPlayBin *playbin;
3716 playbin = group->playbin;
3718 g_object_get (group->uridecodebin, "source", &source, NULL);
3720 GST_OBJECT_LOCK (playbin);
3721 if (playbin->source)
3722 gst_object_unref (playbin->source);
3723 playbin->source = source;
3724 GST_OBJECT_UNLOCK (playbin);
3726 g_object_notify (G_OBJECT (playbin), "source");
3728 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3729 0, playbin->source);
3732 /* must be called with the group lock */
3734 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3737 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3739 if (group->uridecodebin)
3740 gst_element_set_locked_state (group->uridecodebin, locked);
3741 if (group->suburidecodebin)
3742 gst_element_set_locked_state (group->suburidecodebin, locked);
3747 /* must be called with PLAY_BIN_LOCK */
3749 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3751 GstElement *uridecodebin;
3752 GstElement *suburidecodebin = NULL;
3755 g_return_val_if_fail (group->valid, FALSE);
3756 g_return_val_if_fail (!group->active, FALSE);
3758 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3760 GST_SOURCE_GROUP_LOCK (group);
3762 /* First set up the custom sources */
3763 if (playbin->audio_sink)
3764 group->audio_sink = gst_object_ref (playbin->audio_sink);
3765 if (playbin->video_sink)
3766 group->video_sink = gst_object_ref (playbin->video_sink);
3768 g_list_free (group->stream_changed_pending);
3769 group->stream_changed_pending = NULL;
3770 if (!group->stream_changed_pending_lock.p)
3771 g_mutex_init (&group->stream_changed_pending_lock);
3773 g_slist_free (group->suburi_flushes_to_drop);
3774 group->suburi_flushes_to_drop = NULL;
3775 if (!group->suburi_flushes_to_drop_lock.p)
3776 g_mutex_init (&group->suburi_flushes_to_drop_lock);
3778 if (group->uridecodebin) {
3779 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3780 uridecodebin = group->uridecodebin;
3781 gst_element_set_state (uridecodebin, GST_STATE_READY);
3782 /* no need to take extra ref, we already have one
3783 * and the bin will add one since it is no longer floating,
3784 * as it was at least added once before (below) */
3785 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3787 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3788 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3791 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3792 group->uridecodebin = gst_object_ref (uridecodebin);
3795 flags = gst_play_sink_get_flags (playbin->playsink);
3797 g_object_set (uridecodebin,
3798 /* configure connection speed */
3799 "connection-speed", playbin->connection_speed / 1000,
3802 /* configure download buffering */
3803 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3804 /* configure buffering of demuxed/parsed data */
3805 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3806 /* configure buffering parameters */
3807 "buffer-duration", playbin->buffer_duration,
3808 "buffer-size", playbin->buffer_size,
3809 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3811 /* connect pads and other things */
3812 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3813 G_CALLBACK (pad_added_cb), group);
3814 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3815 G_CALLBACK (pad_removed_cb), group);
3816 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3817 G_CALLBACK (no_more_pads_cb), group);
3818 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3819 G_CALLBACK (notify_source_cb), group);
3821 /* we have 1 pending no-more-pads */
3824 /* is called when the uridecodebin is out of data and we can switch to the
3827 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3830 /* will be called when a new media type is found. We return a list of decoders
3831 * including sinks for decodebin to try */
3832 group->autoplug_factories_id =
3833 g_signal_connect (uridecodebin, "autoplug-factories",
3834 G_CALLBACK (autoplug_factories_cb), group);
3835 group->autoplug_select_id =
3836 g_signal_connect (uridecodebin, "autoplug-select",
3837 G_CALLBACK (autoplug_select_cb), group);
3838 group->autoplug_continue_id =
3839 g_signal_connect (uridecodebin, "autoplug-continue",
3840 G_CALLBACK (autoplug_continue_cb), group);
3842 if (group->suburi) {
3844 if (group->suburidecodebin) {
3845 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3846 suburidecodebin = group->suburidecodebin;
3847 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3848 /* no need to take extra ref, we already have one
3849 * and the bin will add one since it is no longer floating,
3850 * as it was at least added once before (below) */
3851 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3853 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3854 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3855 if (!suburidecodebin)
3858 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3859 group->suburidecodebin = gst_object_ref (suburidecodebin);
3862 g_object_set (suburidecodebin,
3863 /* configure connection speed */
3864 "connection-speed", playbin->connection_speed,
3866 "uri", group->suburi, NULL);
3868 /* connect pads and other things */
3869 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3870 G_CALLBACK (pad_added_cb), group);
3871 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3872 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3873 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3874 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3876 group->sub_autoplug_continue_id =
3877 g_signal_connect (suburidecodebin, "autoplug-continue",
3878 G_CALLBACK (autoplug_continue_cb), group);
3880 /* we have 2 pending no-more-pads */
3882 group->sub_pending = TRUE;
3884 group->sub_pending = FALSE;
3887 /* release the group lock before setting the state of the decodebins, they
3888 * might fire signals in this thread that we need to handle with the
3889 * group_lock taken. */
3890 GST_SOURCE_GROUP_UNLOCK (group);
3892 if (suburidecodebin) {
3893 if (gst_element_set_state (suburidecodebin,
3894 target) == GST_STATE_CHANGE_FAILURE) {
3895 GST_DEBUG_OBJECT (playbin,
3896 "failed state change of subtitle uridecodebin");
3897 GST_SOURCE_GROUP_LOCK (group);
3899 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3900 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3901 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3902 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3903 /* Might already be removed because of an error message */
3904 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3905 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3906 if (group->sub_pending) {
3908 group->sub_pending = FALSE;
3910 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3911 GST_SOURCE_GROUP_UNLOCK (group);
3914 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3915 goto uridecodebin_failure;
3917 GST_SOURCE_GROUP_LOCK (group);
3918 /* alow state changes of the playbin affect the group elements now */
3919 group_set_locked_state_unlocked (playbin, group, FALSE);
3920 group->active = TRUE;
3921 GST_SOURCE_GROUP_UNLOCK (group);
3930 /* delete any custom sinks we might have */
3931 if (group->audio_sink) {
3932 /* If this is a automatically created sink set it to NULL */
3933 if (group->audio_sink != playbin->audio_sink)
3934 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3935 gst_object_unref (group->audio_sink);
3937 group->audio_sink = NULL;
3938 if (group->video_sink) {
3939 /* If this is a automatically created sink set it to NULL */
3940 if (group->video_sink != playbin->video_sink)
3941 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3942 gst_object_unref (group->video_sink);
3944 group->video_sink = NULL;
3946 GST_SOURCE_GROUP_UNLOCK (group);
3948 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3950 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3952 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3953 (_("Could not create \"uridecodebin\" element.")), (NULL));
3956 uridecodebin_failure:
3958 /* delete any custom sinks we might have */
3959 if (group->audio_sink) {
3960 /* If this is a automatically created sink set it to NULL */
3961 if (group->audio_sink != playbin->audio_sink)
3962 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3963 gst_object_unref (group->audio_sink);
3965 group->audio_sink = NULL;
3966 if (group->video_sink) {
3967 /* If this is a automatically created sink set it to NULL */
3968 if (group->video_sink != playbin->video_sink)
3969 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3970 gst_object_unref (group->video_sink);
3972 group->video_sink = NULL;
3974 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3979 /* unlink a group of uridecodebins from the sink.
3980 * must be called with PLAY_BIN_LOCK */
3982 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3986 g_return_val_if_fail (group->valid, FALSE);
3987 g_return_val_if_fail (group->active, FALSE);
3989 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3991 GST_SOURCE_GROUP_LOCK (group);
3992 group->active = FALSE;
3993 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3994 GstSourceSelect *select = &group->selector[i];
3996 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3998 if (select->srcpad) {
3999 if (select->sinkpad) {
4000 GST_LOG_OBJECT (playbin, "unlinking from sink");
4001 gst_pad_unlink (select->srcpad, select->sinkpad);
4004 GST_LOG_OBJECT (playbin, "release sink pad");
4005 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
4006 select->sinkpad = NULL;
4009 gst_object_unref (select->srcpad);
4010 select->srcpad = NULL;
4013 if (select->selector) {
4016 /* release and unref requests pad from the selector */
4017 for (n = 0; n < select->channels->len; n++) {
4018 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
4020 gst_element_release_request_pad (select->selector, sinkpad);
4021 gst_object_unref (sinkpad);
4023 g_ptr_array_set_size (select->channels, 0);
4025 gst_element_set_state (select->selector, GST_STATE_NULL);
4026 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
4027 select->selector = NULL;
4030 /* delete any custom sinks we might have */
4031 if (group->audio_sink) {
4032 /* If this is a automatically created sink set it to NULL */
4033 if (group->audio_sink != playbin->audio_sink)
4034 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
4035 gst_object_unref (group->audio_sink);
4037 group->audio_sink = NULL;
4038 if (group->video_sink) {
4039 /* If this is a automatically created sink set it to NULL */
4040 if (group->video_sink != playbin->video_sink)
4041 gst_element_set_state (group->video_sink, GST_STATE_NULL);
4042 gst_object_unref (group->video_sink);
4044 group->video_sink = NULL;
4046 if (group->uridecodebin) {
4047 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
4048 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
4049 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
4050 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
4051 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
4052 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
4053 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
4054 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
4055 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
4058 if (group->suburidecodebin) {
4059 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
4060 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
4061 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
4062 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
4064 /* Might already be removed because of errors */
4065 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
4066 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
4069 GST_SOURCE_GROUP_UNLOCK (group);
4074 /* setup the next group to play, this assumes the next_group is valid and
4075 * configured. It swaps out the current_group and activates the valid
4078 setup_next_source (GstPlayBin * playbin, GstState target)
4080 GstSourceGroup *new_group, *old_group;
4082 GST_DEBUG_OBJECT (playbin, "setup sources");
4084 /* see if there is a next group */
4085 GST_PLAY_BIN_LOCK (playbin);
4086 new_group = playbin->next_group;
4087 if (!new_group || !new_group->valid)
4090 /* first unlink the current source, if any */
4091 old_group = playbin->curr_group;
4092 if (old_group && old_group->valid && old_group->active) {
4093 gst_play_bin_update_cached_duration (playbin);
4094 /* unlink our pads with the sink */
4095 deactivate_group (playbin, old_group);
4096 old_group->valid = FALSE;
4099 /* swap old and new */
4100 playbin->curr_group = new_group;
4101 playbin->next_group = old_group;
4103 /* activate the new group */
4104 if (!activate_group (playbin, new_group, target))
4105 goto activate_failed;
4107 GST_PLAY_BIN_UNLOCK (playbin);
4114 GST_DEBUG_OBJECT (playbin, "no next group");
4115 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
4116 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
4117 GST_PLAY_BIN_UNLOCK (playbin);
4122 GST_DEBUG_OBJECT (playbin, "activate failed");
4123 GST_PLAY_BIN_UNLOCK (playbin);
4128 /* The group that is currently playing is copied again to the
4129 * next_group so that it will start playing the next time.
4132 save_current_group (GstPlayBin * playbin)
4134 GstSourceGroup *curr_group;
4136 GST_DEBUG_OBJECT (playbin, "save current group");
4138 /* see if there is a current group */
4139 GST_PLAY_BIN_LOCK (playbin);
4140 curr_group = playbin->curr_group;
4141 if (curr_group && curr_group->valid && curr_group->active) {
4142 /* unlink our pads with the sink */
4143 deactivate_group (playbin, curr_group);
4145 /* swap old and new */
4146 playbin->curr_group = playbin->next_group;
4147 playbin->next_group = curr_group;
4148 GST_PLAY_BIN_UNLOCK (playbin);
4153 /* clear the locked state from all groups. This function is called before a
4154 * state change to NULL is performed on them. */
4156 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
4158 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
4161 GST_PLAY_BIN_LOCK (playbin);
4162 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
4163 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
4164 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
4165 GST_SOURCE_GROUP_LOCK (playbin->next_group);
4166 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
4167 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
4168 GST_PLAY_BIN_UNLOCK (playbin);
4173 static GstStateChangeReturn
4174 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
4176 GstStateChangeReturn ret;
4177 GstPlayBin *playbin;
4178 gboolean do_save = FALSE;
4180 playbin = GST_PLAY_BIN (element);
4182 switch (transition) {
4183 case GST_STATE_CHANGE_NULL_TO_READY:
4184 memset (&playbin->duration, 0, sizeof (playbin->duration));
4186 case GST_STATE_CHANGE_READY_TO_PAUSED:
4187 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
4188 memset (&playbin->duration, 0, sizeof (playbin->duration));
4189 g_atomic_int_set (&playbin->shutdown, 0);
4191 if (!setup_next_source (playbin, GST_STATE_READY)) {
4192 ret = GST_STATE_CHANGE_FAILURE;
4196 case GST_STATE_CHANGE_PAUSED_TO_READY:
4198 /* FIXME unlock our waiting groups */
4199 GST_LOG_OBJECT (playbin, "setting shutdown flag");
4200 g_atomic_int_set (&playbin->shutdown, 1);
4201 memset (&playbin->duration, 0, sizeof (playbin->duration));
4203 /* wait for all callbacks to end by taking the lock.
4204 * No dynamic (critical) new callbacks will
4205 * be able to happen as we set the shutdown flag. */
4206 GST_PLAY_BIN_DYN_LOCK (playbin);
4207 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
4208 GST_PLAY_BIN_DYN_UNLOCK (playbin);
4211 case GST_STATE_CHANGE_READY_TO_NULL:
4212 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
4213 * an no state change PAUSED to READY passes here,
4214 * though it is a nice-to-have ... */
4215 if (!g_atomic_int_get (&playbin->shutdown)) {
4219 memset (&playbin->duration, 0, sizeof (playbin->duration));
4221 /* unlock so that all groups go to NULL */
4222 groups_set_locked_state (playbin, FALSE);
4228 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4229 if (ret == GST_STATE_CHANGE_FAILURE)
4232 switch (transition) {
4233 case GST_STATE_CHANGE_READY_TO_PAUSED:
4235 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4236 /* FIXME Release audio device when we implement that */
4238 case GST_STATE_CHANGE_PAUSED_TO_READY:
4239 save_current_group (playbin);
4241 case GST_STATE_CHANGE_READY_TO_NULL:
4245 /* also do missed state change down to READY */
4247 save_current_group (playbin);
4248 /* Deactive the groups, set the uridecodebins to NULL
4251 for (i = 0; i < 2; i++) {
4252 if (playbin->groups[i].active && playbin->groups[i].valid) {
4253 deactivate_group (playbin, &playbin->groups[i]);
4254 playbin->groups[i].valid = FALSE;
4257 if (playbin->groups[i].uridecodebin) {
4258 gst_element_set_state (playbin->groups[i].uridecodebin,
4260 gst_object_unref (playbin->groups[i].uridecodebin);
4261 playbin->groups[i].uridecodebin = NULL;
4264 if (playbin->groups[i].suburidecodebin) {
4265 gst_element_set_state (playbin->groups[i].suburidecodebin,
4267 gst_object_unref (playbin->groups[i].suburidecodebin);
4268 playbin->groups[i].suburidecodebin = NULL;
4272 /* Set our sinks back to NULL, they might not be child of playbin */
4273 if (playbin->audio_sink)
4274 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
4275 if (playbin->video_sink)
4276 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
4277 if (playbin->text_sink)
4278 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
4280 /* make sure the groups don't perform a state change anymore until we
4281 * enable them again */
4282 groups_set_locked_state (playbin, TRUE);
4294 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
4295 GstSourceGroup *curr_group;
4297 curr_group = playbin->curr_group;
4298 if (curr_group && curr_group->active && curr_group->valid) {
4299 /* unlink our pads with the sink */
4300 deactivate_group (playbin, curr_group);
4301 curr_group->valid = FALSE;
4304 /* Swap current and next group back */
4305 playbin->curr_group = playbin->next_group;
4306 playbin->next_group = curr_group;
4313 gst_play_bin_overlay_expose (GstVideoOverlay * overlay)
4315 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4317 gst_video_overlay_expose (GST_VIDEO_OVERLAY (playbin->playsink));
4321 gst_play_bin_overlay_handle_events (GstVideoOverlay * overlay,
4322 gboolean handle_events)
4324 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4326 gst_video_overlay_handle_events (GST_VIDEO_OVERLAY (playbin->playsink),
4331 gst_play_bin_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x,
4332 gint y, gint width, gint height)
4334 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4336 gst_video_overlay_set_render_rectangle (GST_VIDEO_OVERLAY (playbin->playsink),
4337 x, y, width, height);
4341 gst_play_bin_overlay_set_window_handle (GstVideoOverlay * overlay,
4344 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4346 gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (playbin->playsink),
4351 gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data)
4353 GstVideoOverlayInterface *iface = (GstVideoOverlayInterface *) g_iface;
4354 iface->expose = gst_play_bin_overlay_expose;
4355 iface->handle_events = gst_play_bin_overlay_handle_events;
4356 iface->set_render_rectangle = gst_play_bin_overlay_set_render_rectangle;
4357 iface->set_window_handle = gst_play_bin_overlay_set_window_handle;
4361 gst_play_bin_navigation_send_event (GstNavigation * navigation,
4362 GstStructure * structure)
4364 GstPlayBin *playbin = GST_PLAY_BIN (navigation);
4366 gst_navigation_send_event (GST_NAVIGATION (playbin->playsink), structure);
4370 gst_play_bin_navigation_init (gpointer g_iface, gpointer g_iface_data)
4372 GstNavigationInterface *iface = (GstNavigationInterface *) g_iface;
4374 iface->send_event = gst_play_bin_navigation_send_event;
4377 static const GList *
4378 gst_play_bin_colorbalance_list_channels (GstColorBalance * balance)
4380 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4383 gst_color_balance_list_channels (GST_COLOR_BALANCE (playbin->playsink));
4387 gst_play_bin_colorbalance_set_value (GstColorBalance * balance,
4388 GstColorBalanceChannel * channel, gint value)
4390 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4392 gst_color_balance_set_value (GST_COLOR_BALANCE (playbin->playsink), channel,
4397 gst_play_bin_colorbalance_get_value (GstColorBalance * balance,
4398 GstColorBalanceChannel * channel)
4400 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4402 return gst_color_balance_get_value (GST_COLOR_BALANCE (playbin->playsink),
4406 static GstColorBalanceType
4407 gst_play_bin_colorbalance_get_balance_type (GstColorBalance * balance)
4409 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4412 gst_color_balance_get_balance_type (GST_COLOR_BALANCE
4413 (playbin->playsink));
4417 gst_play_bin_colorbalance_init (gpointer g_iface, gpointer g_iface_data)
4419 GstColorBalanceInterface *iface = (GstColorBalanceInterface *) g_iface;
4421 iface->list_channels = gst_play_bin_colorbalance_list_channels;
4422 iface->set_value = gst_play_bin_colorbalance_set_value;
4423 iface->get_value = gst_play_bin_colorbalance_get_value;
4424 iface->get_balance_type = gst_play_bin_colorbalance_get_balance_type;
4428 gst_play_bin2_plugin_init (GstPlugin * plugin)
4430 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin", 0, "play bin");
4432 return gst_element_register (plugin, "playbin", GST_RANK_NONE,