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 pending_flush_finish; /* whether we are pending to send a custom
414 * subtitleoverlay-flush-subtitle-finish event
415 * on pad activation */
417 GstElement *audio_sink; /* configured audio sink, or NULL */
418 GstElement *video_sink; /* configured video sink, or NULL */
419 GstElement *text_sink; /* configured text sink, or NULL */
426 } duration[5]; /* cached durations */
428 guint64 ring_buffer_max_size; /* 0 means disabled */
431 struct _GstPlayBinClass
433 GstPipelineClass parent_class;
435 /* notify app that the current uri finished decoding and it is possible to
436 * queue a new one for gapless playback */
437 void (*about_to_finish) (GstPlayBin * playbin);
439 /* notify app that number of audio/video/text streams changed */
440 void (*video_changed) (GstPlayBin * playbin);
441 void (*audio_changed) (GstPlayBin * playbin);
442 void (*text_changed) (GstPlayBin * playbin);
444 /* notify app that the tags of audio/video/text streams changed */
445 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
446 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
447 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
449 /* get audio/video/text tags for a stream */
450 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
451 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
452 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
454 /* get the last video sample and convert it to the given caps */
455 GstSample *(*convert_sample) (GstPlayBin * playbin, GstCaps * caps);
457 /* get audio/video/text pad for a stream */
458 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
459 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
460 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
464 #define DEFAULT_URI NULL
465 #define DEFAULT_SUBURI NULL
466 #define DEFAULT_SOURCE NULL
467 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
468 GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_SOFT_COLORBALANCE
469 #define DEFAULT_N_VIDEO 0
470 #define DEFAULT_CURRENT_VIDEO -1
471 #define DEFAULT_N_AUDIO 0
472 #define DEFAULT_CURRENT_AUDIO -1
473 #define DEFAULT_N_TEXT 0
474 #define DEFAULT_CURRENT_TEXT -1
475 #define DEFAULT_SUBTITLE_ENCODING NULL
476 #define DEFAULT_AUDIO_SINK NULL
477 #define DEFAULT_VIDEO_SINK NULL
478 #define DEFAULT_VIS_PLUGIN NULL
479 #define DEFAULT_TEXT_SINK NULL
480 #define DEFAULT_VOLUME 1.0
481 #define DEFAULT_MUTE FALSE
482 #define DEFAULT_FRAME NULL
483 #define DEFAULT_FONT_DESC NULL
484 #define DEFAULT_CONNECTION_SPEED 0
485 #define DEFAULT_BUFFER_DURATION -1
486 #define DEFAULT_BUFFER_SIZE -1
487 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
504 PROP_SUBTITLE_ENCODING,
513 PROP_CONNECTION_SPEED,
515 PROP_BUFFER_DURATION,
517 PROP_RING_BUFFER_MAX_SIZE,
524 SIGNAL_ABOUT_TO_FINISH,
525 SIGNAL_CONVERT_SAMPLE,
526 SIGNAL_VIDEO_CHANGED,
527 SIGNAL_AUDIO_CHANGED,
529 SIGNAL_VIDEO_TAGS_CHANGED,
530 SIGNAL_AUDIO_TAGS_CHANGED,
531 SIGNAL_TEXT_TAGS_CHANGED,
532 SIGNAL_GET_VIDEO_TAGS,
533 SIGNAL_GET_AUDIO_TAGS,
534 SIGNAL_GET_TEXT_TAGS,
535 SIGNAL_GET_VIDEO_PAD,
536 SIGNAL_GET_AUDIO_PAD,
542 static void gst_play_bin_class_init (GstPlayBinClass * klass);
543 static void gst_play_bin_init (GstPlayBin * playbin);
544 static void gst_play_bin_finalize (GObject * object);
546 static void gst_play_bin_set_property (GObject * object, guint prop_id,
547 const GValue * value, GParamSpec * spec);
548 static void gst_play_bin_get_property (GObject * object, guint prop_id,
549 GValue * value, GParamSpec * spec);
551 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
552 GstStateChange transition);
554 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
555 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
557 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
559 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
561 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
564 static GstSample *gst_play_bin_convert_sample (GstPlayBin * playbin,
567 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
568 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
569 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
571 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
573 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
574 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
575 GstSourceGroup * group);
577 static void gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
578 GstElement * suburidecodebin, gboolean block);
579 static void gst_play_bin_suburidecodebin_seek_to_start (GstSourceGroup * group);
581 static GstElementClass *parent_class;
583 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
585 #define REMOVE_SIGNAL(obj,id) \
587 g_signal_handler_disconnect (obj, id); \
591 static void gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data);
592 static void gst_play_bin_navigation_init (gpointer g_iface,
593 gpointer g_iface_data);
594 static void gst_play_bin_colorbalance_init (gpointer g_iface,
595 gpointer g_iface_data);
598 gst_play_bin_get_type (void)
600 static GType gst_play_bin_type = 0;
602 if (!gst_play_bin_type) {
603 static const GTypeInfo gst_play_bin_info = {
604 sizeof (GstPlayBinClass),
607 (GClassInitFunc) gst_play_bin_class_init,
612 (GInstanceInitFunc) gst_play_bin_init,
615 static const GInterfaceInfo svol_info = {
618 static const GInterfaceInfo ov_info = {
619 gst_play_bin_overlay_init,
622 static const GInterfaceInfo nav_info = {
623 gst_play_bin_navigation_init,
626 static const GInterfaceInfo col_info = {
627 gst_play_bin_colorbalance_init,
631 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
632 "GstPlayBin", &gst_play_bin_info, 0);
634 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
636 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_VIDEO_OVERLAY,
638 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_NAVIGATION,
640 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_COLOR_BALANCE,
644 return gst_play_bin_type;
648 gst_play_bin_class_init (GstPlayBinClass * klass)
650 GObjectClass *gobject_klass;
651 GstElementClass *gstelement_klass;
652 GstBinClass *gstbin_klass;
654 gobject_klass = (GObjectClass *) klass;
655 gstelement_klass = (GstElementClass *) klass;
656 gstbin_klass = (GstBinClass *) klass;
658 parent_class = g_type_class_peek_parent (klass);
660 gobject_klass->set_property = gst_play_bin_set_property;
661 gobject_klass->get_property = gst_play_bin_get_property;
663 gobject_klass->finalize = gst_play_bin_finalize;
668 * Set the next URI that playbin will play. This property can be set from the
669 * about-to-finish signal to queue the next media file.
671 g_object_class_install_property (gobject_klass, PROP_URI,
672 g_param_spec_string ("uri", "URI", "URI of the media to play",
673 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
676 * GstPlayBin:current-uri
678 * The currently playing uri.
680 g_object_class_install_property (gobject_klass, PROP_CURRENT_URI,
681 g_param_spec_string ("current-uri", "Current URI",
682 "The currently playing URI", NULL,
683 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
688 * Set the next subtitle URI that playbin will play. This property can be
689 * set from the about-to-finish signal to queue the next subtitle media file.
691 g_object_class_install_property (gobject_klass, PROP_SUBURI,
692 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
693 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
696 * GstPlayBin:current-suburi
698 * The currently playing subtitle uri.
700 g_object_class_install_property (gobject_klass, PROP_CURRENT_SUBURI,
701 g_param_spec_string ("current-suburi", "Current .sub-URI",
702 "The currently playing URI of a subtitle",
703 NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
705 g_object_class_install_property (gobject_klass, PROP_SOURCE,
706 g_param_spec_object ("source", "Source", "Source element",
707 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
712 * Control the behaviour of playbin.
714 g_object_class_install_property (gobject_klass, PROP_FLAGS,
715 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
716 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
717 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
722 * Get the total number of available video streams.
724 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
725 g_param_spec_int ("n-video", "Number Video",
726 "Total number of video streams", 0, G_MAXINT, 0,
727 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
729 * GstPlayBin:current-video
731 * Get or set the currently playing video stream. By default the first video
732 * stream with data is played.
734 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
735 g_param_spec_int ("current-video", "Current Video",
736 "Currently playing video stream (-1 = auto)",
737 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
741 * Get the total number of available audio streams.
743 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
744 g_param_spec_int ("n-audio", "Number Audio",
745 "Total number of audio streams", 0, G_MAXINT, 0,
746 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
748 * GstPlayBin:current-audio
750 * Get or set the currently playing audio stream. By default the first audio
751 * stream with data is played.
753 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
754 g_param_spec_int ("current-audio", "Current audio",
755 "Currently playing audio stream (-1 = auto)",
756 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
760 * Get the total number of available subtitle streams.
762 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
763 g_param_spec_int ("n-text", "Number Text",
764 "Total number of text streams", 0, G_MAXINT, 0,
765 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
767 * GstPlayBin:current-text:
769 * Get or set the currently playing subtitle stream. By default the first
770 * subtitle stream with data is played.
772 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
773 g_param_spec_int ("current-text", "Current Text",
774 "Currently playing text stream (-1 = auto)",
775 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
777 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
778 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
779 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
780 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
781 "be checked for an encoding to use. If that is not set either, "
782 "ISO-8859-15 will be assumed.", NULL,
783 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
785 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
786 g_param_spec_object ("video-sink", "Video Sink",
787 "the video output element to use (NULL = default sink)",
788 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
789 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
790 g_param_spec_object ("audio-sink", "Audio Sink",
791 "the audio output element to use (NULL = default sink)",
792 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
793 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
794 g_param_spec_object ("vis-plugin", "Vis plugin",
795 "the visualization element to use (NULL = default)",
796 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
797 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
798 g_param_spec_object ("text-sink", "Text plugin",
799 "the text output element to use (NULL = default subtitleoverlay)",
800 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
805 * Get or set the current audio stream volume. 1.0 means 100%,
806 * 0.0 means mute. This uses a linear volume scale.
809 g_object_class_install_property (gobject_klass, PROP_VOLUME,
810 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
811 0.0, VOLUME_MAX_DOUBLE, 1.0,
812 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
813 g_object_class_install_property (gobject_klass, PROP_MUTE,
814 g_param_spec_boolean ("mute", "Mute",
815 "Mute the audio channel without changing the volume", FALSE,
816 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
820 * @playbin: a #GstPlayBin
822 * Get the currently rendered or prerolled sample in the video sink.
823 * The #GstCaps in the sample will describe the format of the buffer.
825 g_object_class_install_property (gobject_klass, PROP_SAMPLE,
826 g_param_spec_boxed ("sample", "Sample",
827 "The last sample (NULL = no video available)",
828 GST_TYPE_SAMPLE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
830 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
831 g_param_spec_string ("subtitle-font-desc",
832 "Subtitle font description",
833 "Pango font description of font "
834 "to be used for subtitle rendering", NULL,
835 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
837 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
838 g_param_spec_uint64 ("connection-speed", "Connection Speed",
839 "Network connection speed in kbps (0 = unknown)",
840 0, G_MAXUINT64 / 1000, DEFAULT_CONNECTION_SPEED,
841 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
843 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
844 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
845 "Buffer size when buffering network streams",
846 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
847 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
848 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
849 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
850 "Buffer duration when buffering network streams",
851 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
852 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
854 * GstPlayBin:av-offset:
856 * Control the synchronisation offset between the audio and video streams.
857 * Positive values make the audio ahead of the video and negative values make
858 * the audio go behind the video.
862 g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
863 g_param_spec_int64 ("av-offset", "AV Offset",
864 "The synchronisation offset between audio and video in nanoseconds",
865 G_MININT64, G_MAXINT64, 0,
866 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
869 * GstQueue2:ring-buffer-max-size
871 * The maximum size of the ring buffer in bytes. If set to 0, the ring
872 * buffer is disabled. Default 0.
876 g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
877 g_param_spec_uint64 ("ring-buffer-max-size",
878 "Max. ring buffer size (bytes)",
879 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
880 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
881 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
884 * GstPlayBin::about-to-finish
885 * @playbin: a #GstPlayBin
887 * This signal is emitted when the current uri is about to finish. You can
888 * set the uri and suburi to make sure that playback continues.
890 * This signal is emitted from the context of a GStreamer streaming thread.
892 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
893 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
895 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
896 g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
899 * GstPlayBin::video-changed
900 * @playbin: a #GstPlayBin
902 * This signal is emitted whenever the number or order of the video
903 * streams has changed. The application will most likely want to select
904 * a new video stream.
906 * This signal is usually emitted from the context of a GStreamer streaming
907 * thread. You can use gst_message_new_application() and
908 * gst_element_post_message() to notify your application's main thread.
910 /* FIXME 0.11: turn video-changed signal into message? */
911 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
912 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
914 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
915 g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
917 * GstPlayBin::audio-changed
918 * @playbin: a #GstPlayBin
920 * This signal is emitted whenever the number or order of the audio
921 * streams has changed. The application will most likely want to select
922 * a new audio stream.
924 * This signal may be emitted from the context of a GStreamer streaming thread.
925 * You can use gst_message_new_application() and gst_element_post_message()
926 * to notify your application's main thread.
928 /* FIXME 0.11: turn audio-changed signal into message? */
929 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
930 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
932 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
933 g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
935 * GstPlayBin::text-changed
936 * @playbin: a #GstPlayBin
938 * This signal is emitted whenever the number or order of the text
939 * streams has changed. The application will most likely want to select
942 * This signal may be emitted from the context of a GStreamer streaming thread.
943 * You can use gst_message_new_application() and gst_element_post_message()
944 * to notify your application's main thread.
946 /* FIXME 0.11: turn text-changed signal into message? */
947 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
948 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
950 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
951 g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
954 * GstPlayBin::video-tags-changed
955 * @playbin: a #GstPlayBin
956 * @stream: stream index with changed tags
958 * This signal is emitted whenever the tags of a video stream have changed.
959 * The application will most likely want to get the new tags.
961 * This signal may be emitted from the context of a GStreamer streaming thread.
962 * You can use gst_message_new_application() and gst_element_post_message()
963 * to notify your application's main thread.
967 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
968 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
970 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
971 g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
974 * GstPlayBin::audio-tags-changed
975 * @playbin: a #GstPlayBin
976 * @stream: stream index with changed tags
978 * This signal is emitted whenever the tags of an audio stream have changed.
979 * The application will most likely want to get the new tags.
981 * This signal may be emitted from the context of a GStreamer streaming thread.
982 * You can use gst_message_new_application() and gst_element_post_message()
983 * to notify your application's main thread.
987 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
988 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
990 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
991 g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
994 * GstPlayBin::text-tags-changed
995 * @playbin: a #GstPlayBin
996 * @stream: stream index with changed tags
998 * This signal is emitted whenever the tags of a text stream have changed.
999 * The application will most likely want to get the new tags.
1001 * This signal may be emitted from the context of a GStreamer streaming thread.
1002 * You can use gst_message_new_application() and gst_element_post_message()
1003 * to notify your application's main thread.
1007 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
1008 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
1010 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
1011 g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
1014 * GstPlayBin::source-setup:
1015 * @playbin: a #GstPlayBin
1016 * @source: source element
1018 * This signal is emitted after the source element has been created, so
1019 * it can be configured by setting additional properties (e.g. set a
1020 * proxy server for an http source, or set the device and read speed for
1021 * an audio cd source). This is functionally equivalent to connecting to
1022 * the notify::source signal, but more convenient.
1024 * This signal is usually emitted from the context of a GStreamer streaming
1029 gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
1030 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
1031 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1032 g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
1035 * GstPlayBin::get-video-tags
1036 * @playbin: a #GstPlayBin
1037 * @stream: a video stream number
1039 * Action signal to retrieve the tags of a specific video stream number.
1040 * This information can be used to select a stream.
1042 * Returns: a GstTagList with tags or NULL when the stream number does not
1045 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
1046 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
1047 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1048 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
1049 g_cclosure_marshal_generic, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1051 * GstPlayBin::get-audio-tags
1052 * @playbin: a #GstPlayBin
1053 * @stream: an audio stream number
1055 * Action signal to retrieve the tags of a specific audio stream number.
1056 * This information can be used to select a stream.
1058 * Returns: a GstTagList with tags or NULL when the stream number does not
1061 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
1062 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
1063 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1064 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
1065 g_cclosure_marshal_generic, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1067 * GstPlayBin::get-text-tags
1068 * @playbin: a #GstPlayBin
1069 * @stream: a text stream number
1071 * Action signal to retrieve the tags of a specific text stream number.
1072 * This information can be used to select a stream.
1074 * Returns: a GstTagList with tags or NULL when the stream number does not
1077 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
1078 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
1079 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1080 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
1081 g_cclosure_marshal_generic, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1083 * GstPlayBin::convert-sample
1084 * @playbin: a #GstPlayBin
1085 * @caps: the target format of the frame
1087 * Action signal to retrieve the currently playing video frame in the format
1088 * specified by @caps.
1089 * If @caps is %NULL, no conversion will be performed and this function is
1090 * equivalent to the #GstPlayBin::frame property.
1092 * Returns: a #GstBuffer of the current video frame converted to #caps.
1093 * The caps on the buffer will describe the final layout of the buffer data.
1094 * %NULL is returned when no current buffer can be retrieved or when the
1095 * conversion failed.
1097 gst_play_bin_signals[SIGNAL_CONVERT_SAMPLE] =
1098 g_signal_new ("convert-sample", G_TYPE_FROM_CLASS (klass),
1099 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1100 G_STRUCT_OFFSET (GstPlayBinClass, convert_sample), NULL, NULL,
1101 g_cclosure_marshal_generic, GST_TYPE_SAMPLE, 1, GST_TYPE_CAPS);
1104 * GstPlayBin::get-video-pad
1105 * @playbin: a #GstPlayBin
1106 * @stream: a video stream number
1108 * Action signal to retrieve the stream-selector sinkpad for a specific
1110 * This pad can be used for notifications of caps changes, stream-specific
1113 * Returns: a #GstPad, or NULL when the stream number does not exist.
1115 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1116 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1117 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1118 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1119 g_cclosure_marshal_generic, GST_TYPE_PAD, 1, G_TYPE_INT);
1121 * GstPlayBin::get-audio-pad
1122 * @playbin: a #GstPlayBin
1123 * @stream: an audio stream number
1125 * Action signal to retrieve the stream-selector sinkpad for a specific
1127 * This pad can be used for notifications of caps changes, stream-specific
1130 * Returns: a #GstPad, or NULL when the stream number does not exist.
1132 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1133 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1134 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1135 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1136 g_cclosure_marshal_generic, GST_TYPE_PAD, 1, G_TYPE_INT);
1138 * GstPlayBin::get-text-pad
1139 * @playbin: a #GstPlayBin
1140 * @stream: a text stream number
1142 * Action signal to retrieve the stream-selector sinkpad for a specific
1144 * This pad can be used for notifications of caps changes, stream-specific
1147 * Returns: a #GstPad, or NULL when the stream number does not exist.
1149 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1150 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1151 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1152 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1153 g_cclosure_marshal_generic, GST_TYPE_PAD, 1, G_TYPE_INT);
1155 klass->get_video_tags = gst_play_bin_get_video_tags;
1156 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1157 klass->get_text_tags = gst_play_bin_get_text_tags;
1159 klass->convert_sample = gst_play_bin_convert_sample;
1161 klass->get_video_pad = gst_play_bin_get_video_pad;
1162 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1163 klass->get_text_pad = gst_play_bin_get_text_pad;
1165 gst_element_class_set_static_metadata (gstelement_klass,
1166 "Player Bin 2", "Generic/Bin/Player",
1167 "Autoplug and play media from an uri",
1168 "Wim Taymans <wim.taymans@gmail.com>");
1170 gstelement_klass->change_state =
1171 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1172 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1174 gstbin_klass->handle_message =
1175 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1179 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1183 /* store the array for the different channels */
1184 group->video_channels = g_ptr_array_new ();
1185 group->audio_channels = g_ptr_array_new ();
1186 group->text_channels = g_ptr_array_new ();
1187 g_mutex_init (&group->lock);
1188 /* init selectors. The selector is found by finding the first prefix that
1189 * matches the media. */
1190 group->playbin = playbin;
1191 /* If you add any items to these lists, check that media_list[] is defined
1192 * above to be large enough to hold MAX(items)+1, so as to accommodate a
1193 * NULL terminator (set when the memory is zeroed on allocation) */
1194 group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
1195 group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
1196 group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
1197 group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
1198 group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
1199 group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
1200 group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
1201 group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
1202 group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
1203 group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
1204 group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
1205 group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
1206 group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
1207 group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
1208 gst_subtitle_overlay_create_factory_caps;
1209 group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
1210 group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
1212 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1213 GstSourceSelect *select = &group->selector[n];
1214 select->sinkpad_delayed_event = NULL;
1215 select->sinkpad_data_probe = 0;
1220 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1224 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1225 GstSourceSelect *select = &group->selector[n];
1226 if (select->sinkpad && select->sinkpad_data_probe)
1227 gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
1228 if (select->sinkpad_delayed_event)
1229 gst_event_unref (select->sinkpad_delayed_event);
1232 g_free (group->uri);
1233 g_free (group->suburi);
1234 g_ptr_array_free (group->video_channels, TRUE);
1235 g_ptr_array_free (group->audio_channels, TRUE);
1236 g_ptr_array_free (group->text_channels, TRUE);
1238 g_mutex_clear (&group->lock);
1239 if (group->audio_sink) {
1240 if (group->audio_sink != playbin->audio_sink)
1241 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1242 gst_object_unref (group->audio_sink);
1244 group->audio_sink = NULL;
1245 if (group->video_sink) {
1246 if (group->video_sink != playbin->video_sink)
1247 gst_element_set_state (group->video_sink, GST_STATE_NULL);
1248 gst_object_unref (group->video_sink);
1250 group->video_sink = NULL;
1252 g_list_free (group->stream_changed_pending);
1253 group->stream_changed_pending = NULL;
1255 if (group->stream_changed_pending_lock.p)
1256 g_mutex_clear (&group->stream_changed_pending_lock);
1257 group->stream_changed_pending_lock.p = NULL;
1259 g_slist_free (group->suburi_flushes_to_drop);
1260 group->suburi_flushes_to_drop = NULL;
1262 if (group->suburi_flushes_to_drop_lock.p)
1263 g_mutex_clear (&group->suburi_flushes_to_drop_lock);
1264 group->suburi_flushes_to_drop_lock.p = NULL;
1268 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1270 g_object_notify (G_OBJECT (playbin), "volume");
1274 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1276 g_object_notify (G_OBJECT (playbin), "mute");
1280 colorbalance_value_changed_cb (GstColorBalance * balance,
1281 GstColorBalanceChannel * channel, gint value, GstPlayBin * playbin)
1283 gst_color_balance_value_changed (GST_COLOR_BALANCE (playbin), channel, value);
1287 compare_factories_func (gconstpointer p1, gconstpointer p2)
1289 GstPluginFeature *f1, *f2;
1293 f1 = (GstPluginFeature *) p1;
1294 f2 = (GstPluginFeature *) p2;
1296 s1 = gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (f1),
1297 GST_ELEMENT_FACTORY_TYPE_SINK);
1298 s2 = gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (f2),
1299 GST_ELEMENT_FACTORY_TYPE_SINK);
1306 diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
1310 diff = strcmp (GST_OBJECT_NAME (f2), GST_OBJECT_NAME (f1));
1315 /* Must be called with elements lock! */
1317 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1322 cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
1323 if (!playbin->elements || playbin->elements_cookie != cookie) {
1324 if (playbin->elements)
1325 gst_plugin_feature_list_free (playbin->elements);
1327 gst_element_factory_list_get_elements
1328 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1330 gst_element_factory_list_get_elements
1331 (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1332 playbin->elements = g_list_concat (res, tmp);
1333 playbin->elements = g_list_sort (playbin->elements, compare_factories_func);
1334 playbin->elements_cookie = cookie;
1339 gst_play_bin_init (GstPlayBin * playbin)
1341 g_rec_mutex_init (&playbin->lock);
1342 g_mutex_init (&playbin->dyn_lock);
1344 /* assume we can create a selector */
1345 playbin->have_selector = TRUE;
1348 playbin->curr_group = &playbin->groups[0];
1349 playbin->next_group = &playbin->groups[1];
1350 init_group (playbin, &playbin->groups[0]);
1351 init_group (playbin, &playbin->groups[1]);
1353 /* first filter out the interesting element factories */
1354 g_mutex_init (&playbin->elements_lock);
1358 g_object_new (GST_TYPE_PLAY_SINK, "name", "playsink", "send-event-mode",
1360 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1361 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1362 /* Connect to notify::volume and notify::mute signals for proxying */
1363 g_signal_connect (playbin->playsink, "notify::volume",
1364 G_CALLBACK (notify_volume_cb), playbin);
1365 g_signal_connect (playbin->playsink, "notify::mute",
1366 G_CALLBACK (notify_mute_cb), playbin);
1367 g_signal_connect (playbin->playsink, "value-changed",
1368 G_CALLBACK (colorbalance_value_changed_cb), playbin);
1370 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1371 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1372 playbin->current_text = DEFAULT_CURRENT_TEXT;
1374 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1375 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1376 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1380 gst_play_bin_finalize (GObject * object)
1382 GstPlayBin *playbin;
1384 playbin = GST_PLAY_BIN (object);
1386 free_group (playbin, &playbin->groups[0]);
1387 free_group (playbin, &playbin->groups[1]);
1389 if (playbin->source)
1390 gst_object_unref (playbin->source);
1391 if (playbin->video_sink) {
1392 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1393 gst_object_unref (playbin->video_sink);
1395 if (playbin->audio_sink) {
1396 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1397 gst_object_unref (playbin->audio_sink);
1399 if (playbin->text_sink) {
1400 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1401 gst_object_unref (playbin->text_sink);
1404 if (playbin->elements)
1405 gst_plugin_feature_list_free (playbin->elements);
1407 g_rec_mutex_clear (&playbin->lock);
1408 g_mutex_clear (&playbin->dyn_lock);
1409 g_mutex_clear (&playbin->elements_lock);
1411 G_OBJECT_CLASS (parent_class)->finalize (object);
1415 gst_playbin_uri_is_valid (GstPlayBin * playbin, const gchar * uri)
1419 GST_LOG_OBJECT (playbin, "checking uri '%s'", uri);
1421 /* this just checks the protocol */
1422 if (!gst_uri_is_valid (uri))
1425 for (c = uri; *c != '\0'; ++c) {
1426 if (!g_ascii_isprint (*c))
1436 GST_WARNING_OBJECT (playbin, "uri '%s' not valid, character #%u",
1437 uri, (guint) ((guintptr) c - (guintptr) uri));
1443 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1445 GstSourceGroup *group;
1448 g_warning ("cannot set NULL uri");
1452 if (!gst_playbin_uri_is_valid (playbin, uri)) {
1453 if (g_str_has_prefix (uri, "file:")) {
1454 GST_WARNING_OBJECT (playbin, "not entirely correct file URI '%s' - make "
1455 "sure to escape spaces and non-ASCII characters properly and specify "
1456 "an absolute path. Use gst_filename_to_uri() to convert filenames "
1459 /* GST_ERROR_OBJECT (playbin, "malformed URI '%s'", uri); */
1463 GST_PLAY_BIN_LOCK (playbin);
1464 group = playbin->next_group;
1466 GST_SOURCE_GROUP_LOCK (group);
1467 /* store the uri in the next group we will play */
1468 g_free (group->uri);
1469 group->uri = g_strdup (uri);
1470 group->valid = TRUE;
1471 GST_SOURCE_GROUP_UNLOCK (group);
1473 GST_DEBUG ("set new uri to %s", uri);
1474 GST_PLAY_BIN_UNLOCK (playbin);
1478 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1480 GstSourceGroup *group;
1482 GST_PLAY_BIN_LOCK (playbin);
1483 group = playbin->next_group;
1485 GST_SOURCE_GROUP_LOCK (group);
1486 g_free (group->suburi);
1487 group->suburi = g_strdup (suburi);
1488 GST_SOURCE_GROUP_UNLOCK (group);
1490 GST_DEBUG ("setting new .sub uri to %s", suburi);
1492 GST_PLAY_BIN_UNLOCK (playbin);
1496 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1498 gst_play_sink_set_flags (playbin->playsink, flags);
1499 gst_play_sink_reconfigure (playbin->playsink);
1503 gst_play_bin_get_flags (GstPlayBin * playbin)
1507 flags = gst_play_sink_get_flags (playbin->playsink);
1512 /* get the currently playing group or if nothing is playing, the next
1513 * group. Must be called with the PLAY_BIN_LOCK. */
1514 static GstSourceGroup *
1515 get_group (GstPlayBin * playbin)
1517 GstSourceGroup *result;
1519 if (!(result = playbin->curr_group))
1520 result = playbin->next_group;
1526 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1528 GstPad *sinkpad = NULL;
1529 GstSourceGroup *group;
1531 GST_PLAY_BIN_LOCK (playbin);
1532 group = get_group (playbin);
1533 if (stream < group->video_channels->len) {
1534 sinkpad = g_ptr_array_index (group->video_channels, stream);
1535 gst_object_ref (sinkpad);
1537 GST_PLAY_BIN_UNLOCK (playbin);
1543 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1545 GstPad *sinkpad = NULL;
1546 GstSourceGroup *group;
1548 GST_PLAY_BIN_LOCK (playbin);
1549 group = get_group (playbin);
1550 if (stream < group->audio_channels->len) {
1551 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1552 gst_object_ref (sinkpad);
1554 GST_PLAY_BIN_UNLOCK (playbin);
1560 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1562 GstPad *sinkpad = NULL;
1563 GstSourceGroup *group;
1565 GST_PLAY_BIN_LOCK (playbin);
1566 group = get_group (playbin);
1567 if (stream < group->text_channels->len) {
1568 sinkpad = g_ptr_array_index (group->text_channels, stream);
1569 gst_object_ref (sinkpad);
1571 GST_PLAY_BIN_UNLOCK (playbin);
1578 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1583 if (!channels || stream >= channels->len)
1586 sinkpad = g_ptr_array_index (channels, stream);
1587 g_object_get (sinkpad, "tags", &result, NULL);
1593 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1596 GstSourceGroup *group;
1598 GST_PLAY_BIN_LOCK (playbin);
1599 group = get_group (playbin);
1600 result = get_tags (playbin, group->video_channels, stream);
1601 GST_PLAY_BIN_UNLOCK (playbin);
1607 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1610 GstSourceGroup *group;
1612 GST_PLAY_BIN_LOCK (playbin);
1613 group = get_group (playbin);
1614 result = get_tags (playbin, group->audio_channels, stream);
1615 GST_PLAY_BIN_UNLOCK (playbin);
1621 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1624 GstSourceGroup *group;
1626 GST_PLAY_BIN_LOCK (playbin);
1627 group = get_group (playbin);
1628 result = get_tags (playbin, group->text_channels, stream);
1629 GST_PLAY_BIN_UNLOCK (playbin);
1635 gst_play_bin_convert_sample (GstPlayBin * playbin, GstCaps * caps)
1637 return gst_play_sink_convert_sample (playbin->playsink, caps);
1640 /* Returns current stream number, or -1 if none has been selected yet */
1642 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1644 /* Internal API cleanup would make this easier... */
1646 GstPad *pad, *current;
1647 GstObject *selector = NULL;
1650 for (i = 0; i < channels->len; i++) {
1651 pad = g_ptr_array_index (channels, i);
1652 if ((selector = gst_pad_get_parent (pad))) {
1653 g_object_get (selector, "active-pad", ¤t, NULL);
1654 gst_object_unref (selector);
1656 if (pad == current) {
1657 gst_object_unref (current);
1663 gst_object_unref (current);
1671 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1673 GstSourceGroup *group;
1674 GPtrArray *channels;
1677 GST_PLAY_BIN_LOCK (playbin);
1679 GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1680 playbin->current_video, stream);
1682 group = get_group (playbin);
1683 if (!(channels = group->video_channels))
1686 if (stream == -1 || channels->len <= stream) {
1689 /* take channel from selected stream */
1690 sinkpad = g_ptr_array_index (channels, stream);
1694 gst_object_ref (sinkpad);
1695 GST_PLAY_BIN_UNLOCK (playbin);
1698 GstObject *selector;
1700 if ((selector = gst_pad_get_parent (sinkpad))) {
1701 /* activate the selected pad */
1702 g_object_set (selector, "active-pad", sinkpad, NULL);
1703 gst_object_unref (selector);
1705 gst_object_unref (sinkpad);
1711 GST_PLAY_BIN_UNLOCK (playbin);
1712 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1718 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1720 GstSourceGroup *group;
1721 GPtrArray *channels;
1724 GST_PLAY_BIN_LOCK (playbin);
1726 GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1727 playbin->current_audio, stream);
1729 group = get_group (playbin);
1730 if (!(channels = group->audio_channels))
1733 if (stream == -1 || channels->len <= stream) {
1736 /* take channel from selected stream */
1737 sinkpad = g_ptr_array_index (channels, stream);
1741 gst_object_ref (sinkpad);
1742 GST_PLAY_BIN_UNLOCK (playbin);
1745 GstObject *selector;
1747 if ((selector = gst_pad_get_parent (sinkpad))) {
1748 /* activate the selected pad */
1749 g_object_set (selector, "active-pad", sinkpad, NULL);
1750 gst_object_unref (selector);
1752 gst_object_unref (sinkpad);
1758 GST_PLAY_BIN_UNLOCK (playbin);
1759 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1765 gst_play_bin_suburidecodebin_seek_to_start (GstSourceGroup * group)
1767 GstElement *suburidecodebin = group->suburidecodebin;
1768 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1770 GValue item = { 0, };
1772 if (it && gst_iterator_next (it, &item) == GST_ITERATOR_OK
1773 && ((sinkpad = g_value_get_object (&item)) != NULL)) {
1778 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_FLUSH,
1779 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1780 seqnum = gst_event_get_seqnum (event);
1782 /* store the seqnum to drop flushes from this seek later */
1783 g_mutex_lock (&group->suburi_flushes_to_drop_lock);
1784 group->suburi_flushes_to_drop =
1785 g_slist_append (group->suburi_flushes_to_drop,
1786 GUINT_TO_POINTER (seqnum));
1787 g_mutex_unlock (&group->suburi_flushes_to_drop_lock);
1789 if (!gst_pad_send_event (sinkpad, event)) {
1791 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1792 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1793 gst_event_set_seqnum (event, seqnum);
1794 if (!gst_pad_send_event (sinkpad, event)) {
1795 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1797 g_mutex_lock (&group->suburi_flushes_to_drop_lock);
1798 group->suburi_flushes_to_drop =
1799 g_slist_remove (group->suburi_flushes_to_drop,
1800 GUINT_TO_POINTER (seqnum));
1801 g_mutex_unlock (&group->suburi_flushes_to_drop_lock);
1805 g_value_unset (&item);
1809 gst_iterator_free (it);
1813 gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
1814 GstElement * suburidecodebin, gboolean block)
1816 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1817 gboolean done = FALSE;
1818 GValue item = { 0, };
1820 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1827 switch (gst_iterator_next (it, &item)) {
1828 case GST_ITERATOR_OK:
1829 sinkpad = g_value_get_object (&item);
1832 gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1834 } else if (group->block_id) {
1835 gst_pad_remove_probe (sinkpad, group->block_id);
1836 group->block_id = 0;
1838 g_value_reset (&item);
1840 case GST_ITERATOR_DONE:
1843 case GST_ITERATOR_RESYNC:
1844 gst_iterator_resync (it);
1846 case GST_ITERATOR_ERROR:
1851 g_value_unset (&item);
1852 gst_iterator_free (it);
1856 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1858 GstSourceGroup *group;
1859 GPtrArray *channels;
1862 GST_PLAY_BIN_LOCK (playbin);
1864 GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1865 playbin->current_text, stream);
1867 group = get_group (playbin);
1868 if (!(channels = group->text_channels))
1871 if (stream == -1 || channels->len <= stream) {
1874 /* take channel from selected stream */
1875 sinkpad = g_ptr_array_index (channels, stream);
1879 gst_object_ref (sinkpad);
1880 GST_PLAY_BIN_UNLOCK (playbin);
1883 GstObject *selector;
1885 if ((selector = gst_pad_get_parent (sinkpad))) {
1886 GstPad *old_sinkpad;
1888 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1890 if (old_sinkpad != sinkpad) {
1891 gboolean need_unblock, need_block, need_seek;
1892 GstPad *src, *peer = NULL, *oldpeer = NULL;
1893 GstElement *parent_element = NULL, *old_parent_element = NULL;
1895 /* Now check if we need to seek the suburidecodebin to the beginning
1896 * or if we need to block all suburidecodebin sinkpads or if we need
1897 * to unblock all suburidecodebin sinkpads
1900 peer = gst_pad_get_peer (sinkpad);
1902 oldpeer = gst_pad_get_peer (old_sinkpad);
1905 parent_element = gst_pad_get_parent_element (peer);
1907 old_parent_element = gst_pad_get_parent_element (oldpeer);
1909 need_block = (old_parent_element == group->suburidecodebin
1910 && parent_element != old_parent_element);
1911 need_unblock = (parent_element == group->suburidecodebin
1912 && parent_element != old_parent_element);
1913 need_seek = (parent_element == group->suburidecodebin);
1916 gst_object_unref (peer);
1918 gst_object_unref (oldpeer);
1920 gst_object_unref (parent_element);
1921 if (old_parent_element)
1922 gst_object_unref (old_parent_element);
1924 /* Block all suburidecodebin sinkpads */
1926 gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1929 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1930 peer = gst_pad_get_peer (src);
1934 /* Flush the subtitle renderer to remove any
1935 * currently displayed subtitles. This event will
1936 * never travel outside subtitleoverlay!
1938 s = gst_structure_new_empty ("subtitleoverlay-flush-subtitle");
1939 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1940 gst_pad_send_event (peer, event);
1941 playbin->pending_flush_finish = TRUE;
1942 gst_object_unref (peer);
1944 gst_object_unref (src);
1946 /* activate the selected pad */
1947 g_object_set (selector, "active-pad", sinkpad, NULL);
1949 /* Unblock pads if necessary */
1951 gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1954 /* seek to the beginning */
1956 gst_play_bin_suburidecodebin_seek_to_start (group);
1958 gst_object_unref (selector);
1961 gst_object_unref (old_sinkpad);
1963 gst_object_unref (sinkpad);
1969 GST_PLAY_BIN_UNLOCK (playbin);
1975 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1976 const gchar * dbg, GstElement * sink)
1978 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1980 GST_PLAY_BIN_LOCK (playbin);
1981 if (*elem != sink) {
1986 gst_object_ref_sink (sink);
1990 gst_object_unref (old);
1992 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1993 GST_PLAY_BIN_UNLOCK (playbin);
1997 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
2001 GST_PLAY_BIN_LOCK (playbin);
2003 /* set subtitles on all current and next decodebins. */
2004 if ((elem = playbin->groups[0].uridecodebin))
2005 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
2006 if ((elem = playbin->groups[0].suburidecodebin))
2007 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
2008 if ((elem = playbin->groups[1].uridecodebin))
2009 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
2010 if ((elem = playbin->groups[1].suburidecodebin))
2011 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
2013 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
2014 GST_PLAY_BIN_UNLOCK (playbin);
2018 gst_play_bin_set_property (GObject * object, guint prop_id,
2019 const GValue * value, GParamSpec * pspec)
2021 GstPlayBin *playbin = GST_PLAY_BIN (object);
2025 gst_play_bin_set_uri (playbin, g_value_get_string (value));
2028 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
2031 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
2033 case PROP_CURRENT_VIDEO:
2034 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
2036 case PROP_CURRENT_AUDIO:
2037 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
2039 case PROP_CURRENT_TEXT:
2040 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
2042 case PROP_SUBTITLE_ENCODING:
2043 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
2045 case PROP_VIDEO_SINK:
2046 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
2047 g_value_get_object (value));
2049 case PROP_AUDIO_SINK:
2050 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
2051 g_value_get_object (value));
2053 case PROP_VIS_PLUGIN:
2054 gst_play_sink_set_vis_plugin (playbin->playsink,
2055 g_value_get_object (value));
2057 case PROP_TEXT_SINK:
2058 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
2059 g_value_get_object (value));
2062 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
2065 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
2067 case PROP_FONT_DESC:
2068 gst_play_sink_set_font_desc (playbin->playsink,
2069 g_value_get_string (value));
2071 case PROP_CONNECTION_SPEED:
2072 GST_PLAY_BIN_LOCK (playbin);
2073 playbin->connection_speed = g_value_get_uint64 (value) * 1000;
2074 GST_PLAY_BIN_UNLOCK (playbin);
2076 case PROP_BUFFER_SIZE:
2077 playbin->buffer_size = g_value_get_int (value);
2079 case PROP_BUFFER_DURATION:
2080 playbin->buffer_duration = g_value_get_int64 (value);
2082 case PROP_AV_OFFSET:
2083 gst_play_sink_set_av_offset (playbin->playsink,
2084 g_value_get_int64 (value));
2086 case PROP_RING_BUFFER_MAX_SIZE:
2087 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
2090 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2096 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
2097 const gchar * dbg, GstPlaySinkType type)
2099 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
2101 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
2102 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
2103 dbg, sink, dbg, *elem);
2106 GST_PLAY_BIN_LOCK (playbin);
2108 gst_object_ref (sink);
2109 GST_PLAY_BIN_UNLOCK (playbin);
2116 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
2119 GstPlayBin *playbin = GST_PLAY_BIN (object);
2124 GstSourceGroup *group;
2126 GST_PLAY_BIN_LOCK (playbin);
2127 group = playbin->next_group;
2128 g_value_set_string (value, group->uri);
2129 GST_PLAY_BIN_UNLOCK (playbin);
2133 case PROP_CURRENT_URI:
2135 GstSourceGroup *group;
2137 GST_PLAY_BIN_LOCK (playbin);
2138 group = get_group (playbin);
2139 g_value_set_string (value, group->uri);
2140 GST_PLAY_BIN_UNLOCK (playbin);
2145 GstSourceGroup *group;
2147 GST_PLAY_BIN_LOCK (playbin);
2148 group = playbin->next_group;
2149 g_value_set_string (value, group->suburi);
2150 GST_PLAY_BIN_UNLOCK (playbin);
2153 case PROP_CURRENT_SUBURI:
2155 GstSourceGroup *group;
2157 GST_PLAY_BIN_LOCK (playbin);
2158 group = get_group (playbin);
2159 g_value_set_string (value, group->suburi);
2160 GST_PLAY_BIN_UNLOCK (playbin);
2165 GST_OBJECT_LOCK (playbin);
2166 g_value_set_object (value, playbin->source);
2167 GST_OBJECT_UNLOCK (playbin);
2171 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
2175 GstSourceGroup *group;
2178 GST_PLAY_BIN_LOCK (playbin);
2179 group = get_group (playbin);
2180 n_video = (group->video_channels ? group->video_channels->len : 0);
2181 g_value_set_int (value, n_video);
2182 GST_PLAY_BIN_UNLOCK (playbin);
2185 case PROP_CURRENT_VIDEO:
2186 GST_PLAY_BIN_LOCK (playbin);
2187 g_value_set_int (value, playbin->current_video);
2188 GST_PLAY_BIN_UNLOCK (playbin);
2192 GstSourceGroup *group;
2195 GST_PLAY_BIN_LOCK (playbin);
2196 group = get_group (playbin);
2197 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
2198 g_value_set_int (value, n_audio);
2199 GST_PLAY_BIN_UNLOCK (playbin);
2202 case PROP_CURRENT_AUDIO:
2203 GST_PLAY_BIN_LOCK (playbin);
2204 g_value_set_int (value, playbin->current_audio);
2205 GST_PLAY_BIN_UNLOCK (playbin);
2209 GstSourceGroup *group;
2212 GST_PLAY_BIN_LOCK (playbin);
2213 group = get_group (playbin);
2214 n_text = (group->text_channels ? group->text_channels->len : 0);
2215 g_value_set_int (value, n_text);
2216 GST_PLAY_BIN_UNLOCK (playbin);
2219 case PROP_CURRENT_TEXT:
2220 GST_PLAY_BIN_LOCK (playbin);
2221 g_value_set_int (value, playbin->current_text);
2222 GST_PLAY_BIN_UNLOCK (playbin);
2224 case PROP_SUBTITLE_ENCODING:
2225 GST_PLAY_BIN_LOCK (playbin);
2226 g_value_take_string (value,
2227 gst_play_sink_get_subtitle_encoding (playbin->playsink));
2228 GST_PLAY_BIN_UNLOCK (playbin);
2230 case PROP_VIDEO_SINK:
2231 g_value_take_object (value,
2232 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2233 "video", GST_PLAY_SINK_TYPE_VIDEO));
2235 case PROP_AUDIO_SINK:
2236 g_value_take_object (value,
2237 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2238 "audio", GST_PLAY_SINK_TYPE_AUDIO));
2240 case PROP_VIS_PLUGIN:
2241 g_value_take_object (value,
2242 gst_play_sink_get_vis_plugin (playbin->playsink));
2244 case PROP_TEXT_SINK:
2245 g_value_take_object (value,
2246 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2247 "text", GST_PLAY_SINK_TYPE_TEXT));
2250 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2253 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2256 gst_value_take_sample (value,
2257 gst_play_sink_get_last_sample (playbin->playsink));
2259 case PROP_FONT_DESC:
2260 g_value_take_string (value,
2261 gst_play_sink_get_font_desc (playbin->playsink));
2263 case PROP_CONNECTION_SPEED:
2264 GST_PLAY_BIN_LOCK (playbin);
2265 g_value_set_uint64 (value, playbin->connection_speed / 1000);
2266 GST_PLAY_BIN_UNLOCK (playbin);
2268 case PROP_BUFFER_SIZE:
2269 GST_OBJECT_LOCK (playbin);
2270 g_value_set_int (value, playbin->buffer_size);
2271 GST_OBJECT_UNLOCK (playbin);
2273 case PROP_BUFFER_DURATION:
2274 GST_OBJECT_LOCK (playbin);
2275 g_value_set_int64 (value, playbin->buffer_duration);
2276 GST_OBJECT_UNLOCK (playbin);
2278 case PROP_AV_OFFSET:
2279 g_value_set_int64 (value,
2280 gst_play_sink_get_av_offset (playbin->playsink));
2282 case PROP_RING_BUFFER_MAX_SIZE:
2283 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2286 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2292 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2293 gboolean valid, GstQuery * query)
2299 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2300 gst_query_parse_duration (query, &fmt, &duration);
2302 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2303 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2304 playbin->duration[i].valid = valid;
2305 playbin->duration[i].format = fmt;
2306 playbin->duration[i].duration = valid ? duration : -1;
2313 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2315 const GstFormat formats[] =
2316 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2321 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2322 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2323 query = gst_query_new_duration (formats[i]);
2325 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2327 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2328 gst_query_unref (query);
2333 gst_play_bin_query (GstElement * element, GstQuery * query)
2335 GstPlayBin *playbin = GST_PLAY_BIN (element);
2338 /* During a group switch we shouldn't allow duration queries
2339 * because it's not clear if the old or new group's duration
2340 * is returned and if the sinks are already playing new data
2341 * or old data. See bug #585969
2343 * While we're at it, also don't do any other queries during
2344 * a group switch or any other event that causes topology changes
2345 * by taking the playbin lock in any case.
2347 GST_PLAY_BIN_LOCK (playbin);
2349 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2350 GstSourceGroup *group = playbin->curr_group;
2353 GST_SOURCE_GROUP_LOCK (group);
2354 if (group->stream_changed_pending_lock.p) {
2355 g_mutex_lock (&group->stream_changed_pending_lock);
2356 pending = group->pending || group->stream_changed_pending;
2357 g_mutex_unlock (&group->stream_changed_pending_lock);
2359 pending = group->pending;
2366 gst_query_parse_duration (query, &fmt, NULL);
2367 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2368 if (fmt == playbin->duration[i].format) {
2369 ret = playbin->duration[i].valid;
2370 gst_query_set_duration (query, fmt,
2371 (ret ? playbin->duration[i].duration : -1));
2375 /* if nothing cached yet, we might as well request duration,
2376 * such as during initial startup */
2378 GST_DEBUG_OBJECT (playbin,
2379 "Taking cached duration because of pending group switch: %d", ret);
2380 GST_SOURCE_GROUP_UNLOCK (group);
2381 GST_PLAY_BIN_UNLOCK (playbin);
2385 GST_SOURCE_GROUP_UNLOCK (group);
2388 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2390 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2391 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2392 GST_PLAY_BIN_UNLOCK (playbin);
2397 /* mime types we are not handling on purpose right now, don't post a
2398 * missing-plugin message for these */
2399 static const gchar *blacklisted_mimes[] = {
2404 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2406 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2407 GstSourceGroup *group;
2409 if (gst_is_missing_plugin_message (msg)) {
2413 detail = gst_missing_plugin_message_get_installer_detail (msg);
2414 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2415 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2416 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2417 gst_message_unref (msg);
2423 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2424 const GstStructure *s = gst_message_get_structure (msg);
2426 /* Drop all stream-changed messages except the last one */
2427 if (strcmp ("playbin-stream-changed", gst_structure_get_name (s)) == 0) {
2428 guint32 seqnum = gst_message_get_seqnum (msg);
2431 group = playbin->curr_group;
2432 g_mutex_lock (&group->stream_changed_pending_lock);
2433 for (l = group->stream_changed_pending; l;) {
2434 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2436 if (l_seqnum == seqnum) {
2439 group->stream_changed_pending =
2440 g_list_delete_link (group->stream_changed_pending, l_prev);
2441 if (group->stream_changed_pending) {
2442 gst_message_unref (msg);
2450 g_mutex_unlock (&group->stream_changed_pending_lock);
2452 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2453 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2454 GstObject *src = GST_OBJECT_CAST (msg->src);
2456 /* Ignore async state changes from the uridecodebin children,
2457 * see bug #602000. */
2458 group = playbin->curr_group;
2459 if (src && (group = playbin->curr_group) &&
2460 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2461 || (group->suburidecodebin
2462 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2463 GST_DEBUG_OBJECT (playbin,
2464 "Ignoring async state change of uridecodebin: %s",
2465 GST_OBJECT_NAME (src));
2466 gst_message_unref (msg);
2469 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2470 /* If we get an error of the subtitle uridecodebin transform
2471 * them into warnings and disable the subtitles */
2472 group = playbin->curr_group;
2473 if (group && group->suburidecodebin) {
2474 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2475 (group->suburidecodebin)))) {
2477 gchar *debug = NULL;
2478 GstMessage *new_msg;
2480 gboolean done = FALSE;
2481 GValue item = { 0, };
2483 gst_message_parse_error (msg, &err, &debug);
2484 new_msg = gst_message_new_warning (msg->src, err, debug);
2486 gst_message_unref (msg);
2491 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2492 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2493 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2494 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2496 it = gst_element_iterate_src_pads (group->suburidecodebin);
2497 while (it && !done) {
2499 GstIteratorResult res;
2501 res = gst_iterator_next (it, &item);
2504 case GST_ITERATOR_DONE:
2507 case GST_ITERATOR_OK:
2508 p = g_value_get_object (&item);
2509 pad_removed_cb (NULL, p, group);
2510 g_value_reset (&item);
2513 case GST_ITERATOR_RESYNC:
2514 gst_iterator_resync (it);
2516 case GST_ITERATOR_ERROR:
2521 g_value_unset (&item);
2523 gst_iterator_free (it);
2525 gst_object_ref (group->suburidecodebin);
2526 gst_bin_remove (bin, group->suburidecodebin);
2527 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2529 if (group->sub_pending) {
2530 group->sub_pending = FALSE;
2531 no_more_pads_cb (NULL, group);
2538 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2542 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2543 GstPlayBin * playbin)
2545 const gchar *property;
2546 GstSourceGroup *group;
2547 GstSourceSelect *select = NULL;
2550 GST_PLAY_BIN_LOCK (playbin);
2551 group = get_group (playbin);
2553 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2554 if (selector == G_OBJECT (group->selector[i].selector)) {
2555 select = &group->selector[i];
2559 /* We got a pad-change after our group got switched out; no need to notify */
2561 GST_PLAY_BIN_UNLOCK (playbin);
2565 switch (select->type) {
2566 case GST_PLAY_SINK_TYPE_VIDEO:
2567 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2568 property = "current-video";
2569 playbin->current_video = get_current_stream_number (playbin,
2570 group->video_channels);
2572 case GST_PLAY_SINK_TYPE_AUDIO:
2573 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2574 property = "current-audio";
2575 playbin->current_audio = get_current_stream_number (playbin,
2576 group->audio_channels);
2578 case GST_PLAY_SINK_TYPE_TEXT:
2579 property = "current-text";
2580 playbin->current_text = get_current_stream_number (playbin,
2581 group->text_channels);
2583 if (playbin->pending_flush_finish) {
2588 playbin->pending_flush_finish = FALSE;
2589 GST_PLAY_BIN_UNLOCK (playbin);
2591 /* Flush the subtitle renderer to remove any
2592 * currently displayed subtitles. This event will
2593 * never travel outside subtitleoverlay!
2595 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
2596 peer = gst_pad_get_peer (src);
2597 s = gst_structure_new_empty ("subtitleoverlay-flush-subtitle-finish");
2598 ev = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
2599 gst_pad_send_event (peer, ev);
2600 gst_object_unref (peer);
2601 gst_object_unref (src);
2609 GST_PLAY_BIN_UNLOCK (playbin);
2613 g_object_notify (G_OBJECT (playbin), property);
2616 /* this callback sends a delayed event once the pad becomes unblocked */
2617 static GstPadProbeReturn
2618 stream_changed_data_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
2620 GstMiniObject *object = GST_PAD_PROBE_INFO_DATA (info);
2621 GstSourceSelect *select = (GstSourceSelect *) data;
2624 /* we need do this just once, so cleanup first */
2625 gst_pad_remove_probe (pad, select->sinkpad_data_probe);
2626 select->sinkpad_data_probe = 0;
2627 e = select->sinkpad_delayed_event;
2628 select->sinkpad_delayed_event = NULL;
2630 /* really, this should not happen */
2632 GST_WARNING ("Data probed called, but no delayed event");
2633 return GST_PAD_PROBE_OK;
2636 if (GST_IS_EVENT (object)
2637 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_SEGMENT) {
2638 /* push the event first, then send the delayed one */
2639 gst_event_ref (GST_EVENT_CAST (object));
2640 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2641 gst_pad_send_event (pad, e);
2642 return GST_PAD_PROBE_DROP;
2644 /* send delayed event, then allow the caller to go on */
2645 gst_pad_send_event (pad, e);
2646 return GST_PAD_PROBE_OK;
2650 static GstPadProbeReturn
2651 _suburidecodebin_event_probe (GstPad * pad, GstPadProbeInfo * info,
2654 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2655 GstSourceGroup *group = udata;
2656 GstEvent *event = GST_PAD_PROBE_INFO_DATA (info);
2658 switch (GST_EVENT_TYPE (event)) {
2659 case GST_EVENT_FLUSH_START:
2660 case GST_EVENT_FLUSH_STOP:
2662 guint32 seqnum = gst_event_get_seqnum (event);
2663 GSList *item = g_slist_find (group->suburi_flushes_to_drop,
2664 GUINT_TO_POINTER (seqnum));
2666 ret = GST_PAD_PROBE_DROP; /* this is from subtitle seek only, drop it */
2667 if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2668 group->suburi_flushes_to_drop =
2669 g_slist_delete_link (group->suburi_flushes_to_drop, item);
2679 /* helper function to lookup stuff in lists */
2681 array_has_value (const gchar * values[], const gchar * value, gboolean exact)
2685 for (i = 0; values[i]; i++) {
2686 if (exact && !strcmp (value, values[i]))
2688 if (!exact && g_str_has_prefix (value, values[i]))
2696 GstPlayBin *playbin;
2698 GstPlaySinkType type;
2702 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2704 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2707 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2708 " with stream id %d and type %d have changed",
2709 object, ntdata->stream_id, ntdata->type);
2711 switch (ntdata->type) {
2712 case GST_PLAY_SINK_TYPE_VIDEO:
2713 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2714 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2716 case GST_PLAY_SINK_TYPE_AUDIO:
2717 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2718 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2720 case GST_PLAY_SINK_TYPE_TEXT:
2721 signal = SIGNAL_TEXT_TAGS_CHANGED;
2729 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2733 /* this function is called when a new pad is added to decodebin. We check the
2734 * type of the pad and add it to the selector element of the group.
2737 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2739 GstPlayBin *playbin;
2741 const GstStructure *s;
2744 GstPadLinkReturn res;
2745 GstSourceSelect *select = NULL;
2747 gboolean changed = FALSE;
2749 playbin = group->playbin;
2751 caps = gst_pad_query_caps (pad, NULL);
2752 s = gst_caps_get_structure (caps, 0);
2753 name = gst_structure_get_name (s);
2755 GST_DEBUG_OBJECT (playbin,
2756 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2757 GST_DEBUG_PAD_NAME (pad), caps, group);
2759 /* major type of the pad, this determines the selector to use,
2760 try exact match first so we don't prematurely match video/
2761 for video/x-dvd-subpicture */
2762 for (pass = 0; !select && pass < 2; pass++) {
2763 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2764 if (array_has_value (group->selector[i].media_list, name, pass == 0)) {
2765 select = &group->selector[i];
2767 } else if (group->selector[i].get_media_caps) {
2768 GstCaps *media_caps = group->selector[i].get_media_caps ();
2770 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2771 select = &group->selector[i];
2772 gst_caps_unref (media_caps);
2775 gst_caps_unref (media_caps);
2779 /* no selector found for the media type, don't bother linking it to a
2780 * selector. This will leave the pad unlinked and thus ignored. */
2784 GST_SOURCE_GROUP_LOCK (group);
2785 if (select->selector == NULL && playbin->have_selector) {
2786 /* no selector, create one */
2787 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2788 select->selector = gst_element_factory_make ("input-selector", NULL);
2789 if (select->selector == NULL) {
2790 /* post the missing selector message only once */
2791 playbin->have_selector = FALSE;
2792 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2793 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2795 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2796 (_("Missing element '%s' - check your GStreamer installation."),
2797 "input-selector"), (NULL));
2799 g_object_set (select->selector, "sync-streams", TRUE, NULL);
2801 g_signal_connect (select->selector, "notify::active-pad",
2802 G_CALLBACK (selector_active_pad_changed), playbin);
2804 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2805 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2806 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2810 if (select->srcpad == NULL) {
2811 if (select->selector) {
2812 /* save source pad of the selector */
2813 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2815 /* no selector, use the pad as the source pad then */
2816 select->srcpad = gst_object_ref (pad);
2819 /* block the selector srcpad. It's possible that multiple decodebins start
2820 * pushing data into the selectors before we have a chance to collect all
2821 * streams and connect the sinks, resulting in not-linked errors. After we
2822 * configured the sinks we will unblock them all. */
2823 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2825 gst_pad_add_probe (select->srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2829 /* get sinkpad for the new stream */
2830 if (select->selector) {
2831 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink_%u"))) {
2832 gulong notify_tags_handler = 0;
2833 NotifyTagsData *ntdata;
2835 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2836 GST_DEBUG_PAD_NAME (sinkpad));
2838 /* store the selector for the pad */
2839 g_object_set_data (G_OBJECT (sinkpad), "playbin.select", select);
2841 /* connect to the notify::tags signal for our
2842 * own *-tags-changed signals
2844 ntdata = g_new0 (NotifyTagsData, 1);
2845 ntdata->playbin = playbin;
2846 ntdata->stream_id = select->channels->len;
2847 ntdata->type = select->type;
2849 notify_tags_handler =
2850 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2851 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2853 g_object_set_data (G_OBJECT (sinkpad), "playbin.notify_tags_handler",
2854 (gpointer) (guintptr) notify_tags_handler);
2856 /* store the pad in the array */
2857 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2858 g_ptr_array_add (select->channels, sinkpad);
2860 res = gst_pad_link (pad, sinkpad);
2861 if (GST_PAD_LINK_FAILED (res))
2864 /* store selector pad so we can release it */
2865 g_object_set_data (G_OBJECT (pad), "playbin.sinkpad", sinkpad);
2868 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2869 GST_DEBUG_PAD_NAME (pad), select->selector);
2872 /* no selector, don't configure anything, we'll link the new pad directly to
2877 /* store the selector for the pad */
2878 g_object_set_data (G_OBJECT (pad), "playbin2.select", select);
2880 GST_SOURCE_GROUP_UNLOCK (group);
2882 if (decodebin == group->suburidecodebin) {
2883 /* TODO store the probe id */
2884 /* to avoid propagating flushes from suburi specific seeks */
2885 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
2886 _suburidecodebin_event_probe, group, NULL);
2891 gboolean always_ok = (decodebin == group->suburidecodebin);
2893 switch (select->type) {
2894 case GST_PLAY_SINK_TYPE_VIDEO:
2895 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2896 /* we want to return NOT_LINKED for unselected pads but only for pads
2897 * from the normal uridecodebin. This makes sure that subtitle streams
2898 * are not raced past audio/video from decodebin's multiqueue.
2899 * For pads from suburidecodebin OK should always be returned, otherwise
2900 * it will most likely stop. */
2901 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2902 signal = SIGNAL_VIDEO_CHANGED;
2904 case GST_PLAY_SINK_TYPE_AUDIO:
2905 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2906 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2907 signal = SIGNAL_AUDIO_CHANGED;
2909 case GST_PLAY_SINK_TYPE_TEXT:
2910 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2911 signal = SIGNAL_TEXT_CHANGED;
2918 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2922 gst_caps_unref (caps);
2928 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2929 name, GST_DEBUG_PAD_NAME (pad));
2934 GST_ERROR_OBJECT (playbin,
2935 "failed to link pad %s:%s to selector, reason %d",
2936 GST_DEBUG_PAD_NAME (pad), res);
2937 GST_SOURCE_GROUP_UNLOCK (group);
2942 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2943 * the selector. This will make the selector select a new pad. */
2945 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2947 GstPlayBin *playbin;
2949 GstElement *selector;
2950 GstSourceSelect *select;
2952 playbin = group->playbin;
2954 GST_DEBUG_OBJECT (playbin,
2955 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2957 GST_SOURCE_GROUP_LOCK (group);
2959 if ((select = g_object_get_data (G_OBJECT (pad), "playbin2.select"))) {
2960 g_assert (select->selector == NULL);
2961 g_assert (select->srcpad == pad);
2962 gst_object_unref (pad);
2963 select->srcpad = NULL;
2967 /* get the selector sinkpad */
2968 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin.sinkpad")))
2971 if ((select = g_object_get_data (G_OBJECT (peer), "playbin.select"))) {
2972 gulong notify_tags_handler;
2974 notify_tags_handler =
2975 (guintptr) g_object_get_data (G_OBJECT (peer),
2976 "playbin.notify_tags_handler");
2977 if (notify_tags_handler != 0)
2978 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2979 g_object_set_data (G_OBJECT (peer), "playbin.notify_tags_handler", NULL);
2981 /* remove the pad from the array */
2982 g_ptr_array_remove (select->channels, peer);
2983 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2985 if (!select->channels->len && select->selector) {
2986 GST_DEBUG_OBJECT (playbin, "all selector sinkpads removed");
2987 GST_DEBUG_OBJECT (playbin, "removing selector %p", select->selector);
2988 gst_object_unref (select->srcpad);
2989 select->srcpad = NULL;
2990 gst_element_set_state (select->selector, GST_STATE_NULL);
2991 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
2992 select->selector = NULL;
2996 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2997 gst_pad_unlink (pad, peer);
2999 /* get selector, this can be NULL when the element is removing the pads
3000 * because it's being disposed. */
3001 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
3003 gst_object_unref (peer);
3007 /* release the pad to the selector, this will make the selector choose a new
3009 gst_element_release_request_pad (selector, peer);
3010 gst_object_unref (peer);
3012 gst_object_unref (selector);
3014 GST_SOURCE_GROUP_UNLOCK (group);
3021 GST_DEBUG_OBJECT (playbin, "pad not linked");
3022 GST_SOURCE_GROUP_UNLOCK (group);
3027 GST_DEBUG_OBJECT (playbin, "selector not found");
3028 GST_SOURCE_GROUP_UNLOCK (group);
3033 /* we get called when all pads are available and we must connect the sinks to
3035 * The main purpose of the code is to see if we have video/audio and subtitles
3036 * and pick the right pipelines to display them.
3038 * The selectors installed on the group tell us about the presence of
3039 * audio/video and subtitle streams. This allows us to see if we need
3040 * visualisation, video or/and audio.
3043 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
3045 GstPlayBin *playbin;
3046 GstPadLinkReturn res;
3050 playbin = group->playbin;
3052 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
3054 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
3056 GST_SOURCE_GROUP_LOCK (group);
3057 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3058 GstSourceSelect *select = &group->selector[i];
3060 /* check if the specific media type was detected and thus has a selector
3061 * created for it. If there is the media type, get a sinkpad from the sink
3062 * and link it. We only do this if we have not yet requested the sinkpad
3064 if (select->srcpad && select->sinkpad == NULL) {
3065 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
3067 gst_play_sink_request_pad (playbin->playsink, select->type);
3068 } else if (select->srcpad && select->sinkpad) {
3069 GST_DEBUG_OBJECT (playbin, "refreshing new sink pad %d", select->type);
3070 gst_play_sink_refresh_pad (playbin->playsink, select->sinkpad,
3072 } else if (select->sinkpad && select->srcpad == NULL) {
3073 GST_DEBUG_OBJECT (playbin, "releasing sink pad %d", select->type);
3074 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3075 select->sinkpad = NULL;
3077 if (select->sinkpad && select->srcpad &&
3078 !gst_pad_is_linked (select->srcpad)) {
3079 res = gst_pad_link (select->srcpad, select->sinkpad);
3080 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
3081 select->media_list[0], res);
3082 if (res != GST_PAD_LINK_OK) {
3083 GST_ELEMENT_ERROR (playbin, CORE, PAD,
3084 ("Internal playbin error."),
3085 ("Failed to link selector to sink. Error %d", res));
3089 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
3090 group->pending - 1);
3092 if (group->pending > 0)
3095 if (group->suburidecodebin == decodebin)
3096 group->sub_pending = FALSE;
3098 if (group->pending == 0) {
3099 /* we are the last group to complete, we will configure the output and then
3100 * signal the other waiters. */
3101 GST_LOG_OBJECT (playbin, "last group complete");
3104 GST_LOG_OBJECT (playbin, "have more pending groups");
3107 GST_SOURCE_GROUP_UNLOCK (group);
3110 /* if we have custom sinks, configure them now */
3111 GST_SOURCE_GROUP_LOCK (group);
3113 if (group->audio_sink) {
3114 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
3116 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
3120 if (group->video_sink) {
3121 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
3123 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
3127 if (playbin->text_sink) {
3128 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
3129 playbin->text_sink);
3130 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
3131 playbin->text_sink);
3134 GST_SOURCE_GROUP_UNLOCK (group);
3136 /* signal the other decodebins that they can continue now. */
3137 GST_SOURCE_GROUP_LOCK (group);
3138 /* unblock all selectors */
3139 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3140 GstSourceSelect *select = &group->selector[i];
3142 /* All streamsynchronizer streams should see stream-changed message,
3143 * to arrange for blocking unblocking. */
3144 if (select->sinkpad) {
3150 s = gst_structure_new ("playbin-stream-changed", "uri", G_TYPE_STRING,
3153 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
3154 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
3155 seqnum = gst_message_get_seqnum (msg);
3156 event = gst_event_new_sink_message ("GstPlaybin", msg);
3157 g_mutex_lock (&group->stream_changed_pending_lock);
3158 group->stream_changed_pending =
3159 g_list_prepend (group->stream_changed_pending,
3160 GUINT_TO_POINTER (seqnum));
3162 /* remove any data probe we might have, and replace */
3163 if (select->sinkpad_delayed_event)
3164 gst_event_unref (select->sinkpad_delayed_event);
3165 select->sinkpad_delayed_event = event;
3166 if (select->sinkpad_data_probe)
3167 gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
3169 /* we go to the trouble of setting a probe on the pad to send
3170 the playbin-stream-changed event as sending it here might
3171 find that the pad is blocked, so we'd block here, and the
3172 pad might not be linked yet. Additionally, sending it here
3173 apparently would be on the wrong thread */
3174 select->sinkpad_data_probe =
3175 gst_pad_add_probe (select->sinkpad,
3176 GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
3177 stream_changed_data_probe, (gpointer) select, NULL);
3179 g_mutex_unlock (&group->stream_changed_pending_lock);
3180 gst_message_unref (msg);
3183 if (select->srcpad) {
3184 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
3186 if (select->block_id) {
3187 gst_pad_remove_probe (select->srcpad, select->block_id);
3188 select->block_id = 0;
3192 GST_SOURCE_GROUP_UNLOCK (group);
3195 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
3201 GST_DEBUG ("ignoring, we are shutting down");
3202 /* Request a flushing pad from playsink that we then link to the selector.
3203 * Then we unblock the selectors so that they stop with a WRONG_STATE
3204 * instead of a NOT_LINKED error.
3206 GST_SOURCE_GROUP_LOCK (group);
3207 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3208 GstSourceSelect *select = &group->selector[i];
3210 if (select->srcpad) {
3211 if (select->sinkpad == NULL) {
3212 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
3214 gst_play_sink_request_pad (playbin->playsink,
3215 GST_PLAY_SINK_TYPE_FLUSHING);
3216 res = gst_pad_link (select->srcpad, select->sinkpad);
3217 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
3219 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
3221 if (select->block_id) {
3222 gst_pad_remove_probe (select->srcpad, select->block_id);
3223 select->block_id = 0;
3227 GST_SOURCE_GROUP_UNLOCK (group);
3233 drained_cb (GstElement * decodebin, GstSourceGroup * group)
3235 GstPlayBin *playbin;
3237 playbin = group->playbin;
3239 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
3241 /* after this call, we should have a next group to activate or we EOS */
3242 g_signal_emit (G_OBJECT (playbin),
3243 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
3245 /* now activate the next group. If the app did not set a uri, this will
3246 * fail and we can do EOS */
3247 setup_next_source (playbin, GST_STATE_PAUSED);
3250 /* Like gst_element_factory_can_sink_any_caps() but doesn't
3251 * allow ANY caps on the sinkpad template */
3253 _factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps)
3255 const GList *templs;
3257 templs = gst_element_factory_get_static_pad_templates (factory);
3260 GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
3262 if (templ->direction == GST_PAD_SINK) {
3263 GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
3265 if (!gst_caps_is_any (templcaps)
3266 && gst_caps_can_intersect (templcaps, caps)) {
3267 gst_caps_unref (templcaps);
3270 gst_caps_unref (templcaps);
3272 templs = g_list_next (templs);
3278 /* Called when we must provide a list of factories to plug to @pad with @caps.
3279 * We first check if we have a sink that can handle the format and if we do, we
3280 * return NULL, to expose the pad. If we have no sink (or the sink does not
3281 * work), we return the list of elements that can connect. */
3282 static GValueArray *
3283 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
3284 GstCaps * caps, GstSourceGroup * group)
3286 GstPlayBin *playbin;
3287 GList *mylist, *tmp;
3288 GValueArray *result;
3290 playbin = group->playbin;
3292 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
3293 group, GST_DEBUG_PAD_NAME (pad), caps);
3295 /* filter out the elements based on the caps. */
3296 g_mutex_lock (&playbin->elements_lock);
3297 gst_play_bin_update_elements_list (playbin);
3299 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
3301 g_mutex_unlock (&playbin->elements_lock);
3303 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
3304 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
3306 /* 2 additional elements for the already set audio/video sinks */
3307 result = g_value_array_new (g_list_length (mylist) + 2);
3309 /* Check if we already have an audio/video sink and if this is the case
3310 * put it as the first element of the array */
3311 if (group->audio_sink) {
3312 GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
3314 if (factory && _factory_can_sink_caps (factory, caps)) {
3315 GValue val = { 0, };
3317 g_value_init (&val, G_TYPE_OBJECT);
3318 g_value_set_object (&val, factory);
3319 result = g_value_array_append (result, &val);
3320 g_value_unset (&val);
3324 if (group->video_sink) {
3325 GstElementFactory *factory = gst_element_get_factory (group->video_sink);
3327 if (factory && _factory_can_sink_caps (factory, caps)) {
3328 GValue val = { 0, };
3330 g_value_init (&val, G_TYPE_OBJECT);
3331 g_value_set_object (&val, factory);
3332 result = g_value_array_append (result, &val);
3333 g_value_unset (&val);
3337 for (tmp = mylist; tmp; tmp = tmp->next) {
3338 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
3339 GValue val = { 0, };
3341 if (group->audio_sink && gst_element_factory_list_is_type (factory,
3342 GST_ELEMENT_FACTORY_TYPE_SINK |
3343 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
3346 if (group->video_sink && gst_element_factory_list_is_type (factory,
3347 GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
3348 | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
3352 g_value_init (&val, G_TYPE_OBJECT);
3353 g_value_set_object (&val, factory);
3354 g_value_array_append (result, &val);
3355 g_value_unset (&val);
3357 gst_plugin_feature_list_free (mylist);
3362 /* autoplug-continue decides, if a pad has raw caps that can be exposed
3363 * directly or if further decoding is necessary. We use this to expose
3364 * supported subtitles directly */
3366 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
3367 * explicitly the caps it supports and if it claims to support ANY
3368 * caps it really should support everything */
3370 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
3371 GstSourceGroup * group)
3373 gboolean ret = TRUE;
3375 GstPad *sinkpad = NULL;
3377 GST_SOURCE_GROUP_LOCK (group);
3379 if ((sink = group->playbin->text_sink))
3380 sinkpad = gst_element_get_static_pad (sink, "sink");
3384 /* Ignore errors here, if a custom sink fails to go
3385 * to READY things are wrong and will error out later
3387 if (GST_STATE (sink) < GST_STATE_READY)
3388 gst_element_set_state (sink, GST_STATE_READY);
3390 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3391 if (!gst_caps_is_any (sinkcaps))
3392 ret = !gst_pad_query_accept_caps (sinkpad, caps);
3393 gst_caps_unref (sinkcaps);
3394 gst_object_unref (sinkpad);
3396 GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3397 ret = !gst_caps_is_subset (caps, subcaps);
3398 gst_caps_unref (subcaps);
3400 /* If autoplugging can stop don't do additional checks */
3404 /* If this is from the subtitle uridecodebin we don't need to
3405 * check the audio and video sink */
3406 if (group->suburidecodebin
3407 && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3408 GST_OBJECT_CAST (group->suburidecodebin)))
3411 if ((sink = group->audio_sink)) {
3412 sinkpad = gst_element_get_static_pad (sink, "sink");
3416 /* Ignore errors here, if a custom sink fails to go
3417 * to READY things are wrong and will error out later
3419 if (GST_STATE (sink) < GST_STATE_READY)
3420 gst_element_set_state (sink, GST_STATE_READY);
3422 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3423 if (!gst_caps_is_any (sinkcaps))
3424 ret = !gst_pad_query_accept_caps (sinkpad, caps);
3425 gst_caps_unref (sinkcaps);
3426 gst_object_unref (sinkpad);
3432 if ((sink = group->video_sink)) {
3433 sinkpad = gst_element_get_static_pad (sink, "sink");
3437 /* Ignore errors here, if a custom sink fails to go
3438 * to READY things are wrong and will error out later
3440 if (GST_STATE (sink) < GST_STATE_READY)
3441 gst_element_set_state (sink, GST_STATE_READY);
3443 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3444 if (!gst_caps_is_any (sinkcaps))
3445 ret = !gst_pad_query_accept_caps (sinkpad, caps);
3446 gst_caps_unref (sinkcaps);
3447 gst_object_unref (sinkpad);
3452 GST_SOURCE_GROUP_UNLOCK (group);
3454 GST_DEBUG_OBJECT (group->playbin,
3455 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3456 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3462 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3466 /* ... activate it ... We do this before adding it to the bin so that we
3467 * don't accidentally make it post error messages that will stop
3469 if (GST_STATE (sink) < GST_STATE_READY &&
3470 gst_element_set_state (sink,
3471 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3475 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3476 /* Got the sink pad, now let's see if the element actually does accept the
3477 * caps that we have */
3478 if (!gst_pad_query_accept_caps (sinkpad, caps)) {
3479 gst_object_unref (sinkpad);
3482 gst_object_unref (sinkpad);
3488 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw");
3489 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw");
3491 /* We are asked to select an element. See if the next element to check
3492 * is a sink. If this is the case, we see if the sink works by setting it to
3493 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3494 * expose the raw pad so that we can setup the mixers. */
3495 static GstAutoplugSelectResult
3496 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3497 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3499 GstPlayBin *playbin;
3500 GstElement *element;
3502 GstPlaySinkType type;
3505 playbin = group->playbin;
3507 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3508 group, GST_DEBUG_PAD_NAME (pad), caps);
3510 GST_DEBUG_OBJECT (playbin, "checking factory %s", GST_OBJECT_NAME (factory));
3512 /* if it's not a sink, we make sure the element is compatible with
3514 if (!gst_element_factory_list_is_type (factory,
3515 GST_ELEMENT_FACTORY_TYPE_SINK)) {
3516 gboolean isvideodec = gst_element_factory_list_is_type (factory,
3517 GST_ELEMENT_FACTORY_TYPE_DECODER |
3518 GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
3519 GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
3520 gboolean isaudiodec = gst_element_factory_list_is_type (factory,
3521 GST_ELEMENT_FACTORY_TYPE_DECODER |
3522 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
3524 /* If it is a decoder and we have a fixed sink for the media
3525 * type it outputs, check that the decoder is compatible with this sink */
3526 if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) {
3527 gboolean compatible = TRUE;
3533 sink = group->audio_sink;
3535 sink = group->video_sink;
3537 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3538 GstPlayFlags flags = gst_play_bin_get_flags (playbin);
3540 (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) :
3541 gst_static_caps_get (&raw_video_caps);
3543 caps = gst_pad_query_caps (sinkpad, NULL);
3545 /* If the sink supports raw audio/video, we first check
3546 * if the decoder could output any raw audio/video format
3547 * and assume it is compatible with the sink then. We don't
3548 * do a complete compatibility check here if converters
3549 * are plugged between the decoder and the sink because
3550 * the converters will convert between raw formats and
3551 * even if the decoder format is not supported by the decoder
3552 * a converter will convert it.
3554 * We assume here that the converters can convert between
3557 if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO)
3558 && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec
3559 && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO)
3560 && gst_caps_can_intersect (caps, raw_caps))) {
3561 compatible = gst_element_factory_can_src_any_caps (factory, raw_caps)
3562 || gst_element_factory_can_src_any_caps (factory, caps);
3564 compatible = gst_element_factory_can_src_any_caps (factory, caps);
3567 gst_object_unref (sinkpad);
3568 gst_caps_unref (caps);
3572 return GST_AUTOPLUG_SELECT_TRY;
3574 GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink",
3575 GST_OBJECT_NAME (factory));
3577 return GST_AUTOPLUG_SELECT_SKIP;
3579 return GST_AUTOPLUG_SELECT_TRY;
3582 /* it's a sink, see if an instance of it actually works */
3583 GST_DEBUG_OBJECT (playbin, "we found a sink");
3585 klass = gst_element_factory_get_klass (factory);
3587 /* figure out the klass */
3588 if (strstr (klass, "Audio")) {
3589 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3590 type = GST_PLAY_SINK_TYPE_AUDIO;
3591 sinkp = &group->audio_sink;
3592 } else if (strstr (klass, "Video")) {
3593 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3594 type = GST_PLAY_SINK_TYPE_VIDEO;
3595 sinkp = &group->video_sink;
3597 /* unknown klass, skip this element */
3598 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3599 return GST_AUTOPLUG_SELECT_SKIP;
3602 /* if we are asked to do visualisations and it's an audio sink, skip the
3603 * element. We can only do visualisations with raw sinks */
3604 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3605 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3606 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3607 return GST_AUTOPLUG_SELECT_SKIP;
3611 /* now see if we already have a sink element */
3612 GST_SOURCE_GROUP_LOCK (group);
3614 GstElement *sink = gst_object_ref (*sinkp);
3616 if (sink_accepts_caps (sink, caps)) {
3617 GST_DEBUG_OBJECT (playbin,
3618 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3619 GST_ELEMENT_NAME (sink), caps);
3620 gst_object_unref (sink);
3621 GST_SOURCE_GROUP_UNLOCK (group);
3622 return GST_AUTOPLUG_SELECT_EXPOSE;
3624 GST_DEBUG_OBJECT (playbin,
3625 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3626 GST_ELEMENT_NAME (sink), caps);
3627 gst_object_unref (sink);
3628 GST_SOURCE_GROUP_UNLOCK (group);
3629 return GST_AUTOPLUG_SELECT_SKIP;
3632 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3634 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3635 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3636 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3637 GST_SOURCE_GROUP_UNLOCK (group);
3638 return GST_AUTOPLUG_SELECT_SKIP;
3641 /* Check if the selected sink actually supports the
3642 * caps and can be set to READY*/
3643 if (!sink_accepts_caps (element, caps)) {
3644 gst_element_set_state (element, GST_STATE_NULL);
3645 gst_object_unref (element);
3646 GST_SOURCE_GROUP_UNLOCK (group);
3647 return GST_AUTOPLUG_SELECT_SKIP;
3650 /* remember the sink in the group now, the element is floating, we take
3653 * store the sink in the group, we will configure it later when we
3654 * reconfigure the sink */
3655 GST_DEBUG_OBJECT (playbin, "remember sink");
3656 gst_object_ref_sink (element);
3658 GST_SOURCE_GROUP_UNLOCK (group);
3660 /* tell decodebin to expose the pad because we are going to use this
3662 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3664 return GST_AUTOPLUG_SELECT_EXPOSE;
3668 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3669 GstSourceGroup * group)
3671 GstPlayBin *playbin;
3674 playbin = group->playbin;
3676 g_object_get (group->uridecodebin, "source", &source, NULL);
3678 GST_OBJECT_LOCK (playbin);
3679 if (playbin->source)
3680 gst_object_unref (playbin->source);
3681 playbin->source = source;
3682 GST_OBJECT_UNLOCK (playbin);
3684 g_object_notify (G_OBJECT (playbin), "source");
3686 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3687 0, playbin->source);
3690 /* must be called with the group lock */
3692 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3695 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3697 if (group->uridecodebin)
3698 gst_element_set_locked_state (group->uridecodebin, locked);
3699 if (group->suburidecodebin)
3700 gst_element_set_locked_state (group->suburidecodebin, locked);
3705 /* must be called with PLAY_BIN_LOCK */
3707 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3709 GstElement *uridecodebin;
3710 GstElement *suburidecodebin = NULL;
3713 g_return_val_if_fail (group->valid, FALSE);
3714 g_return_val_if_fail (!group->active, FALSE);
3716 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3718 GST_SOURCE_GROUP_LOCK (group);
3720 /* First set up the custom sources */
3721 if (playbin->audio_sink)
3722 group->audio_sink = gst_object_ref (playbin->audio_sink);
3723 if (playbin->video_sink)
3724 group->video_sink = gst_object_ref (playbin->video_sink);
3726 g_list_free (group->stream_changed_pending);
3727 group->stream_changed_pending = NULL;
3728 if (!group->stream_changed_pending_lock.p)
3729 g_mutex_init (&group->stream_changed_pending_lock);
3731 g_slist_free (group->suburi_flushes_to_drop);
3732 group->suburi_flushes_to_drop = NULL;
3733 if (!group->suburi_flushes_to_drop_lock.p)
3734 g_mutex_init (&group->suburi_flushes_to_drop_lock);
3736 if (group->uridecodebin) {
3737 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3738 uridecodebin = group->uridecodebin;
3739 gst_element_set_state (uridecodebin, GST_STATE_READY);
3740 /* no need to take extra ref, we already have one
3741 * and the bin will add one since it is no longer floating,
3742 * as it was at least added once before (below) */
3743 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3745 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3746 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3749 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3750 group->uridecodebin = gst_object_ref (uridecodebin);
3753 flags = gst_play_sink_get_flags (playbin->playsink);
3755 g_object_set (uridecodebin,
3756 /* configure connection speed */
3757 "connection-speed", playbin->connection_speed / 1000,
3760 /* configure download buffering */
3761 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3762 /* configure buffering of demuxed/parsed data */
3763 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3764 /* configure buffering parameters */
3765 "buffer-duration", playbin->buffer_duration,
3766 "buffer-size", playbin->buffer_size,
3767 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3769 /* connect pads and other things */
3770 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3771 G_CALLBACK (pad_added_cb), group);
3772 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3773 G_CALLBACK (pad_removed_cb), group);
3774 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3775 G_CALLBACK (no_more_pads_cb), group);
3776 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3777 G_CALLBACK (notify_source_cb), group);
3779 /* we have 1 pending no-more-pads */
3782 /* is called when the uridecodebin is out of data and we can switch to the
3785 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3788 /* will be called when a new media type is found. We return a list of decoders
3789 * including sinks for decodebin to try */
3790 group->autoplug_factories_id =
3791 g_signal_connect (uridecodebin, "autoplug-factories",
3792 G_CALLBACK (autoplug_factories_cb), group);
3793 group->autoplug_select_id =
3794 g_signal_connect (uridecodebin, "autoplug-select",
3795 G_CALLBACK (autoplug_select_cb), group);
3796 group->autoplug_continue_id =
3797 g_signal_connect (uridecodebin, "autoplug-continue",
3798 G_CALLBACK (autoplug_continue_cb), group);
3800 if (group->suburi) {
3802 if (group->suburidecodebin) {
3803 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3804 suburidecodebin = group->suburidecodebin;
3805 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3806 /* no need to take extra ref, we already have one
3807 * and the bin will add one since it is no longer floating,
3808 * as it was at least added once before (below) */
3809 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3811 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3812 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3813 if (!suburidecodebin)
3816 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3817 group->suburidecodebin = gst_object_ref (suburidecodebin);
3820 g_object_set (suburidecodebin,
3821 /* configure connection speed */
3822 "connection-speed", playbin->connection_speed,
3824 "uri", group->suburi, NULL);
3826 /* connect pads and other things */
3827 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3828 G_CALLBACK (pad_added_cb), group);
3829 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3830 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3831 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3832 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3834 group->sub_autoplug_continue_id =
3835 g_signal_connect (suburidecodebin, "autoplug-continue",
3836 G_CALLBACK (autoplug_continue_cb), group);
3838 /* we have 2 pending no-more-pads */
3840 group->sub_pending = TRUE;
3842 group->sub_pending = FALSE;
3845 /* release the group lock before setting the state of the decodebins, they
3846 * might fire signals in this thread that we need to handle with the
3847 * group_lock taken. */
3848 GST_SOURCE_GROUP_UNLOCK (group);
3850 if (suburidecodebin) {
3851 if (gst_element_set_state (suburidecodebin,
3852 target) == GST_STATE_CHANGE_FAILURE) {
3853 GST_DEBUG_OBJECT (playbin,
3854 "failed state change of subtitle uridecodebin");
3855 GST_SOURCE_GROUP_LOCK (group);
3857 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3858 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3859 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3860 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3861 /* Might already be removed because of an error message */
3862 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3863 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3864 if (group->sub_pending) {
3866 group->sub_pending = FALSE;
3868 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3869 GST_SOURCE_GROUP_UNLOCK (group);
3872 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3873 goto uridecodebin_failure;
3875 GST_SOURCE_GROUP_LOCK (group);
3876 /* alow state changes of the playbin affect the group elements now */
3877 group_set_locked_state_unlocked (playbin, group, FALSE);
3878 group->active = TRUE;
3879 GST_SOURCE_GROUP_UNLOCK (group);
3888 /* delete any custom sinks we might have */
3889 if (group->audio_sink) {
3890 /* If this is a automatically created sink set it to NULL */
3891 if (group->audio_sink != playbin->audio_sink)
3892 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3893 gst_object_unref (group->audio_sink);
3895 group->audio_sink = NULL;
3896 if (group->video_sink) {
3897 /* If this is a automatically created sink set it to NULL */
3898 if (group->video_sink != playbin->video_sink)
3899 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3900 gst_object_unref (group->video_sink);
3902 group->video_sink = NULL;
3904 GST_SOURCE_GROUP_UNLOCK (group);
3906 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3908 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3910 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3911 (_("Could not create \"uridecodebin\" element.")), (NULL));
3914 uridecodebin_failure:
3916 /* delete any custom sinks we might have */
3917 if (group->audio_sink) {
3918 /* If this is a automatically created sink set it to NULL */
3919 if (group->audio_sink != playbin->audio_sink)
3920 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3921 gst_object_unref (group->audio_sink);
3923 group->audio_sink = NULL;
3924 if (group->video_sink) {
3925 /* If this is a automatically created sink set it to NULL */
3926 if (group->video_sink != playbin->video_sink)
3927 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3928 gst_object_unref (group->video_sink);
3930 group->video_sink = NULL;
3932 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3937 /* unlink a group of uridecodebins from the sink.
3938 * must be called with PLAY_BIN_LOCK */
3940 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3944 g_return_val_if_fail (group->valid, FALSE);
3945 g_return_val_if_fail (group->active, FALSE);
3947 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3949 GST_SOURCE_GROUP_LOCK (group);
3950 group->active = FALSE;
3951 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3952 GstSourceSelect *select = &group->selector[i];
3954 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3956 if (select->srcpad) {
3957 if (select->sinkpad) {
3958 GST_LOG_OBJECT (playbin, "unlinking from sink");
3959 gst_pad_unlink (select->srcpad, select->sinkpad);
3962 GST_LOG_OBJECT (playbin, "release sink pad");
3963 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3964 select->sinkpad = NULL;
3967 gst_object_unref (select->srcpad);
3968 select->srcpad = NULL;
3971 if (select->selector) {
3974 /* release and unref requests pad from the selector */
3975 for (n = 0; n < select->channels->len; n++) {
3976 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3978 gst_element_release_request_pad (select->selector, sinkpad);
3979 gst_object_unref (sinkpad);
3981 g_ptr_array_set_size (select->channels, 0);
3983 gst_element_set_state (select->selector, GST_STATE_NULL);
3984 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3985 select->selector = NULL;
3988 /* delete any custom sinks we might have */
3989 if (group->audio_sink) {
3990 /* If this is a automatically created sink set it to NULL */
3991 if (group->audio_sink != playbin->audio_sink)
3992 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3993 gst_object_unref (group->audio_sink);
3995 group->audio_sink = NULL;
3996 if (group->video_sink) {
3997 /* If this is a automatically created sink set it to NULL */
3998 if (group->video_sink != playbin->video_sink)
3999 gst_element_set_state (group->video_sink, GST_STATE_NULL);
4000 gst_object_unref (group->video_sink);
4002 group->video_sink = NULL;
4004 if (group->uridecodebin) {
4005 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
4006 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
4007 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
4008 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
4009 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
4010 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
4011 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
4012 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
4013 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
4016 if (group->suburidecodebin) {
4017 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
4018 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
4019 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
4020 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
4022 /* Might already be removed because of errors */
4023 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
4024 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
4027 GST_SOURCE_GROUP_UNLOCK (group);
4032 /* setup the next group to play, this assumes the next_group is valid and
4033 * configured. It swaps out the current_group and activates the valid
4036 setup_next_source (GstPlayBin * playbin, GstState target)
4038 GstSourceGroup *new_group, *old_group;
4040 GST_DEBUG_OBJECT (playbin, "setup sources");
4042 /* see if there is a next group */
4043 GST_PLAY_BIN_LOCK (playbin);
4044 new_group = playbin->next_group;
4045 if (!new_group || !new_group->valid)
4048 /* first unlink the current source, if any */
4049 old_group = playbin->curr_group;
4050 if (old_group && old_group->valid && old_group->active) {
4051 gst_play_bin_update_cached_duration (playbin);
4052 /* unlink our pads with the sink */
4053 deactivate_group (playbin, old_group);
4054 old_group->valid = FALSE;
4057 /* swap old and new */
4058 playbin->curr_group = new_group;
4059 playbin->next_group = old_group;
4061 /* activate the new group */
4062 if (!activate_group (playbin, new_group, target))
4063 goto activate_failed;
4065 GST_PLAY_BIN_UNLOCK (playbin);
4072 GST_DEBUG_OBJECT (playbin, "no next group");
4073 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
4074 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
4075 GST_PLAY_BIN_UNLOCK (playbin);
4080 GST_DEBUG_OBJECT (playbin, "activate failed");
4081 GST_PLAY_BIN_UNLOCK (playbin);
4086 /* The group that is currently playing is copied again to the
4087 * next_group so that it will start playing the next time.
4090 save_current_group (GstPlayBin * playbin)
4092 GstSourceGroup *curr_group;
4094 GST_DEBUG_OBJECT (playbin, "save current group");
4096 /* see if there is a current group */
4097 GST_PLAY_BIN_LOCK (playbin);
4098 curr_group = playbin->curr_group;
4099 if (curr_group && curr_group->valid && curr_group->active) {
4100 /* unlink our pads with the sink */
4101 deactivate_group (playbin, curr_group);
4103 /* swap old and new */
4104 playbin->curr_group = playbin->next_group;
4105 playbin->next_group = curr_group;
4106 GST_PLAY_BIN_UNLOCK (playbin);
4111 /* clear the locked state from all groups. This function is called before a
4112 * state change to NULL is performed on them. */
4114 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
4116 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
4119 GST_PLAY_BIN_LOCK (playbin);
4120 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
4121 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
4122 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
4123 GST_SOURCE_GROUP_LOCK (playbin->next_group);
4124 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
4125 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
4126 GST_PLAY_BIN_UNLOCK (playbin);
4131 static GstStateChangeReturn
4132 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
4134 GstStateChangeReturn ret;
4135 GstPlayBin *playbin;
4136 gboolean do_save = FALSE;
4138 playbin = GST_PLAY_BIN (element);
4140 switch (transition) {
4141 case GST_STATE_CHANGE_NULL_TO_READY:
4142 memset (&playbin->duration, 0, sizeof (playbin->duration));
4144 case GST_STATE_CHANGE_READY_TO_PAUSED:
4145 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
4146 memset (&playbin->duration, 0, sizeof (playbin->duration));
4147 g_atomic_int_set (&playbin->shutdown, 0);
4149 if (!setup_next_source (playbin, GST_STATE_READY)) {
4150 ret = GST_STATE_CHANGE_FAILURE;
4154 case GST_STATE_CHANGE_PAUSED_TO_READY:
4156 /* FIXME unlock our waiting groups */
4157 GST_LOG_OBJECT (playbin, "setting shutdown flag");
4158 g_atomic_int_set (&playbin->shutdown, 1);
4159 memset (&playbin->duration, 0, sizeof (playbin->duration));
4161 /* wait for all callbacks to end by taking the lock.
4162 * No dynamic (critical) new callbacks will
4163 * be able to happen as we set the shutdown flag. */
4164 GST_PLAY_BIN_DYN_LOCK (playbin);
4165 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
4166 GST_PLAY_BIN_DYN_UNLOCK (playbin);
4169 case GST_STATE_CHANGE_READY_TO_NULL:
4170 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
4171 * an no state change PAUSED to READY passes here,
4172 * though it is a nice-to-have ... */
4173 if (!g_atomic_int_get (&playbin->shutdown)) {
4177 memset (&playbin->duration, 0, sizeof (playbin->duration));
4179 /* unlock so that all groups go to NULL */
4180 groups_set_locked_state (playbin, FALSE);
4186 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4187 if (ret == GST_STATE_CHANGE_FAILURE)
4190 switch (transition) {
4191 case GST_STATE_CHANGE_READY_TO_PAUSED:
4193 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4194 /* FIXME Release audio device when we implement that */
4196 case GST_STATE_CHANGE_PAUSED_TO_READY:
4197 save_current_group (playbin);
4199 case GST_STATE_CHANGE_READY_TO_NULL:
4203 /* also do missed state change down to READY */
4205 save_current_group (playbin);
4206 /* Deactive the groups, set the uridecodebins to NULL
4209 for (i = 0; i < 2; i++) {
4210 if (playbin->groups[i].active && playbin->groups[i].valid) {
4211 deactivate_group (playbin, &playbin->groups[i]);
4212 playbin->groups[i].valid = FALSE;
4215 if (playbin->groups[i].uridecodebin) {
4216 gst_element_set_state (playbin->groups[i].uridecodebin,
4218 gst_object_unref (playbin->groups[i].uridecodebin);
4219 playbin->groups[i].uridecodebin = NULL;
4222 if (playbin->groups[i].suburidecodebin) {
4223 gst_element_set_state (playbin->groups[i].suburidecodebin,
4225 gst_object_unref (playbin->groups[i].suburidecodebin);
4226 playbin->groups[i].suburidecodebin = NULL;
4230 /* Set our sinks back to NULL, they might not be child of playbin */
4231 if (playbin->audio_sink)
4232 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
4233 if (playbin->video_sink)
4234 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
4235 if (playbin->text_sink)
4236 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
4238 /* make sure the groups don't perform a state change anymore until we
4239 * enable them again */
4240 groups_set_locked_state (playbin, TRUE);
4252 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
4253 GstSourceGroup *curr_group;
4255 curr_group = playbin->curr_group;
4256 if (curr_group && curr_group->active && curr_group->valid) {
4257 /* unlink our pads with the sink */
4258 deactivate_group (playbin, curr_group);
4259 curr_group->valid = FALSE;
4262 /* Swap current and next group back */
4263 playbin->curr_group = playbin->next_group;
4264 playbin->next_group = curr_group;
4271 gst_play_bin_overlay_expose (GstVideoOverlay * overlay)
4273 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4275 gst_video_overlay_expose (GST_VIDEO_OVERLAY (playbin->playsink));
4279 gst_play_bin_overlay_handle_events (GstVideoOverlay * overlay,
4280 gboolean handle_events)
4282 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4284 gst_video_overlay_handle_events (GST_VIDEO_OVERLAY (playbin->playsink),
4289 gst_play_bin_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x,
4290 gint y, gint width, gint height)
4292 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4294 gst_video_overlay_set_render_rectangle (GST_VIDEO_OVERLAY (playbin->playsink),
4295 x, y, width, height);
4299 gst_play_bin_overlay_set_window_handle (GstVideoOverlay * overlay,
4302 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4304 gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (playbin->playsink),
4309 gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data)
4311 GstVideoOverlayInterface *iface = (GstVideoOverlayInterface *) g_iface;
4312 iface->expose = gst_play_bin_overlay_expose;
4313 iface->handle_events = gst_play_bin_overlay_handle_events;
4314 iface->set_render_rectangle = gst_play_bin_overlay_set_render_rectangle;
4315 iface->set_window_handle = gst_play_bin_overlay_set_window_handle;
4319 gst_play_bin_navigation_send_event (GstNavigation * navigation,
4320 GstStructure * structure)
4322 GstPlayBin *playbin = GST_PLAY_BIN (navigation);
4324 gst_navigation_send_event (GST_NAVIGATION (playbin->playsink), structure);
4328 gst_play_bin_navigation_init (gpointer g_iface, gpointer g_iface_data)
4330 GstNavigationInterface *iface = (GstNavigationInterface *) g_iface;
4332 iface->send_event = gst_play_bin_navigation_send_event;
4335 static const GList *
4336 gst_play_bin_colorbalance_list_channels (GstColorBalance * balance)
4338 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4341 gst_color_balance_list_channels (GST_COLOR_BALANCE (playbin->playsink));
4345 gst_play_bin_colorbalance_set_value (GstColorBalance * balance,
4346 GstColorBalanceChannel * channel, gint value)
4348 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4350 gst_color_balance_set_value (GST_COLOR_BALANCE (playbin->playsink), channel,
4355 gst_play_bin_colorbalance_get_value (GstColorBalance * balance,
4356 GstColorBalanceChannel * channel)
4358 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4360 return gst_color_balance_get_value (GST_COLOR_BALANCE (playbin->playsink),
4364 static GstColorBalanceType
4365 gst_play_bin_colorbalance_get_balance_type (GstColorBalance * balance)
4367 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4370 gst_color_balance_get_balance_type (GST_COLOR_BALANCE
4371 (playbin->playsink));
4375 gst_play_bin_colorbalance_init (gpointer g_iface, gpointer g_iface_data)
4377 GstColorBalanceInterface *iface = (GstColorBalanceInterface *) g_iface;
4379 iface->list_channels = gst_play_bin_colorbalance_list_channels;
4380 iface->set_value = gst_play_bin_colorbalance_set_value;
4381 iface->get_value = gst_play_bin_colorbalance_get_value;
4382 iface->get_balance_type = gst_play_bin_colorbalance_get_balance_type;
4386 gst_play_bin2_plugin_init (GstPlugin * plugin)
4388 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin", 0, "play bin");
4390 return gst_element_register (plugin, "playbin", GST_RANK_NONE,