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 frame
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 #GstXOverlay 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 only way to do this at the moment
179 * is to connect to playbin's "notify::source" signal, which will be emitted
180 * by playbin when it has created the source element for a particular URI.
181 * In the signal callback you can check if the source element has a "device"
182 * property and set it appropriately. In future ways might be added to specify
183 * the device as part of the URI, but at the time of writing this is not
187 * <title>Handling redirects</title>
189 * Some elements may post 'redirect' messages on the bus to tell the
190 * application to open another location. These are element messages containing
191 * a structure named 'redirect' along with a 'new-location' field of string
192 * type. The new location may be a relative or an absolute URI. Examples
193 * for such redirects can be found in many quicktime movie trailers.
197 * <title>Examples</title>
199 * gst-launch -v playbin uri=file:///path/to/somefile.avi
200 * ]| This will play back the given AVI video file, given that the video and
201 * audio decoders required to decode the content are installed. Since no
202 * special audio sink or video sink is supplied (not possible via gst-launch),
203 * playbin will try to find a suitable audio and video sink automatically
204 * using the autoaudiosink and autovideosink elements.
206 * gst-launch -v playbin uri=cdda://4
207 * ]| This will play back track 4 on an audio CD in your disc drive (assuming
208 * the drive is detected automatically by the plugin).
210 * gst-launch -v playbin uri=dvd://1
211 * ]| This will play back title 1 of a DVD in your disc drive (assuming
212 * the drive is detected automatically by the plugin).
223 #include <gst/gst-i18n-plugin.h>
224 #include <gst/pbutils/pbutils.h>
225 #include <gst/interfaces/streamvolume.h>
227 #include "gstplay-enum.h"
228 #include "gstplay-marshal.h"
229 #include "gstplayback.h"
230 #include "gstplaysink.h"
231 #include "gstsubtitleoverlay.h"
233 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
234 #define GST_CAT_DEFAULT gst_play_bin_debug
236 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type())
237 #define GST_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
238 #define GST_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
239 #define GST_IS_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
240 #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
242 #define VOLUME_MAX_DOUBLE 10.0
244 typedef struct _GstPlayBin GstPlayBin;
245 typedef struct _GstPlayBinClass GstPlayBinClass;
246 typedef struct _GstSourceGroup GstSourceGroup;
247 typedef struct _GstSourceSelect GstSourceSelect;
249 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
251 /* has the info for a selector and provides the link to the sink */
252 struct _GstSourceSelect
254 const gchar *media_list[8]; /* the media types for the selector */
255 SourceSelectGetMediaCapsFunc get_media_caps; /* more complex caps for the selector */
256 GstPlaySinkType type; /* the sink pad type of the selector */
258 GstElement *selector; /* the selector */
260 GstPad *srcpad; /* the source pad of the selector */
261 GstPad *sinkpad; /* the sinkpad of the sink when the selector
264 GstEvent *sinkpad_delayed_event;
265 gulong sinkpad_data_probe;
269 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
270 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
271 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
275 PLAYBIN_STREAM_AUDIO = 0,
276 PLAYBIN_STREAM_VIDEO,
281 /* a structure to hold the objects for decoding a uri and the subtitle uri
283 struct _GstSourceGroup
289 gboolean valid; /* the group has valid info to start playback */
290 gboolean active; /* the group is active */
295 GValueArray *streaminfo;
298 GPtrArray *video_channels; /* links to selector pads */
299 GPtrArray *audio_channels; /* links to selector pads */
300 GPtrArray *text_channels; /* links to selector pads */
302 GstElement *audio_sink; /* autoplugged audio and video sinks */
303 GstElement *video_sink;
305 /* uridecodebins for uri and subtitle uri */
306 GstElement *uridecodebin;
307 GstElement *suburidecodebin;
309 gboolean sub_pending;
312 gulong pad_removed_id;
313 gulong no_more_pads_id;
314 gulong notify_source_id;
316 gulong autoplug_factories_id;
317 gulong autoplug_select_id;
318 gulong autoplug_continue_id;
320 gulong sub_pad_added_id;
321 gulong sub_pad_removed_id;
322 gulong sub_no_more_pads_id;
323 gulong sub_autoplug_continue_id;
327 GMutex *stream_changed_pending_lock;
328 GList *stream_changed_pending;
330 /* selectors for different streams */
331 GstSourceSelect selector[PLAYBIN_STREAM_LAST];
334 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
335 #define GST_PLAY_BIN_LOCK(bin) (g_static_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
336 #define GST_PLAY_BIN_UNLOCK(bin) (g_static_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
338 /* lock to protect dynamic callbacks, like no-more-pads */
339 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->dyn_lock)
340 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->dyn_lock)
342 /* lock for shutdown */
343 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
345 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
347 GST_PLAY_BIN_DYN_LOCK (bin); \
348 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
349 GST_PLAY_BIN_DYN_UNLOCK (bin); \
354 /* unlock for shutdown */
355 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
356 GST_PLAY_BIN_DYN_UNLOCK (bin); \
361 * playbin element structure
367 GStaticRecMutex lock; /* to protect group switching */
369 /* the groups, we use a double buffer to switch between current and next */
370 GstSourceGroup groups[2]; /* array with group info */
371 GstSourceGroup *curr_group; /* pointer to the currently playing group */
372 GstSourceGroup *next_group; /* pointer to the next group */
375 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
376 gint current_video; /* the currently selected stream */
377 gint current_audio; /* the currently selected stream */
378 gint current_text; /* the currently selected stream */
380 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
381 guint buffer_size; /* When buffering, the max buffer size (bytes) */
384 GstPlaySink *playsink;
386 /* the last activated source */
389 /* lock protecting dynamic adding/removing */
391 /* if we are shutting down or not */
394 GMutex *elements_lock;
395 guint32 elements_cookie;
396 GList *elements; /* factories we can use for selecting elements */
398 gboolean have_selector; /* set to FALSE when we fail to create an
399 * input-selector, so that we only post a
402 GstElement *audio_sink; /* configured audio sink, or NULL */
403 GstElement *video_sink; /* configured video sink, or NULL */
404 GstElement *text_sink; /* configured text sink, or NULL */
411 } duration[5]; /* cached durations */
413 guint64 ring_buffer_max_size; /* 0 means disabled */
416 struct _GstPlayBinClass
418 GstPipelineClass parent_class;
420 /* notify app that the current uri finished decoding and it is possible to
421 * queue a new one for gapless playback */
422 void (*about_to_finish) (GstPlayBin * playbin);
424 /* notify app that number of audio/video/text streams changed */
425 void (*video_changed) (GstPlayBin * playbin);
426 void (*audio_changed) (GstPlayBin * playbin);
427 void (*text_changed) (GstPlayBin * playbin);
429 /* notify app that the tags of audio/video/text streams changed */
430 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
431 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
432 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
434 /* get audio/video/text tags for a stream */
435 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
436 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
437 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
439 /* get the last video frame and convert it to the given caps */
440 GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
442 /* get audio/video/text pad for a stream */
443 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
444 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
445 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
449 #define DEFAULT_URI NULL
450 #define DEFAULT_SUBURI NULL
451 #define DEFAULT_SOURCE NULL
452 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
453 GST_PLAY_FLAG_SOFT_VOLUME
454 #define DEFAULT_N_VIDEO 0
455 #define DEFAULT_CURRENT_VIDEO -1
456 #define DEFAULT_N_AUDIO 0
457 #define DEFAULT_CURRENT_AUDIO -1
458 #define DEFAULT_N_TEXT 0
459 #define DEFAULT_CURRENT_TEXT -1
460 #define DEFAULT_SUBTITLE_ENCODING NULL
461 #define DEFAULT_AUDIO_SINK NULL
462 #define DEFAULT_VIDEO_SINK NULL
463 #define DEFAULT_VIS_PLUGIN NULL
464 #define DEFAULT_TEXT_SINK NULL
465 #define DEFAULT_VOLUME 1.0
466 #define DEFAULT_MUTE FALSE
467 #define DEFAULT_FRAME NULL
468 #define DEFAULT_FONT_DESC NULL
469 #define DEFAULT_CONNECTION_SPEED 0
470 #define DEFAULT_BUFFER_DURATION -1
471 #define DEFAULT_BUFFER_SIZE -1
472 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
487 PROP_SUBTITLE_ENCODING,
496 PROP_CONNECTION_SPEED,
498 PROP_BUFFER_DURATION,
500 PROP_RING_BUFFER_MAX_SIZE,
507 SIGNAL_ABOUT_TO_FINISH,
508 SIGNAL_CONVERT_FRAME,
509 SIGNAL_VIDEO_CHANGED,
510 SIGNAL_AUDIO_CHANGED,
512 SIGNAL_VIDEO_TAGS_CHANGED,
513 SIGNAL_AUDIO_TAGS_CHANGED,
514 SIGNAL_TEXT_TAGS_CHANGED,
515 SIGNAL_GET_VIDEO_TAGS,
516 SIGNAL_GET_AUDIO_TAGS,
517 SIGNAL_GET_TEXT_TAGS,
518 SIGNAL_GET_VIDEO_PAD,
519 SIGNAL_GET_AUDIO_PAD,
525 static void gst_play_bin_class_init (GstPlayBinClass * klass);
526 static void gst_play_bin_init (GstPlayBin * playbin);
527 static void gst_play_bin_finalize (GObject * object);
529 static void gst_play_bin_set_property (GObject * object, guint prop_id,
530 const GValue * value, GParamSpec * spec);
531 static void gst_play_bin_get_property (GObject * object, guint prop_id,
532 GValue * value, GParamSpec * spec);
534 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
535 GstStateChange transition);
537 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
538 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
540 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
542 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
544 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
547 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
550 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
551 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
552 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
554 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
556 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
557 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
558 GstSourceGroup * group);
560 static void gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
561 GstElement * suburidecodebin, gboolean block);
562 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
565 static GstElementClass *parent_class;
567 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
569 #define REMOVE_SIGNAL(obj,id) \
571 g_signal_handler_disconnect (obj, id); \
576 gst_play_bin_get_type (void)
578 static GType gst_play_bin_type = 0;
580 if (!gst_play_bin_type) {
581 static const GTypeInfo gst_play_bin_info = {
582 sizeof (GstPlayBinClass),
585 (GClassInitFunc) gst_play_bin_class_init,
590 (GInstanceInitFunc) gst_play_bin_init,
593 static const GInterfaceInfo svol_info = {
597 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
598 "GstPlayBin", &gst_play_bin_info, 0);
600 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
604 return gst_play_bin_type;
608 gst_play_bin_class_init (GstPlayBinClass * klass)
610 GObjectClass *gobject_klass;
611 GstElementClass *gstelement_klass;
612 GstBinClass *gstbin_klass;
614 gobject_klass = (GObjectClass *) klass;
615 gstelement_klass = (GstElementClass *) klass;
616 gstbin_klass = (GstBinClass *) klass;
618 parent_class = g_type_class_peek_parent (klass);
620 gobject_klass->set_property = gst_play_bin_set_property;
621 gobject_klass->get_property = gst_play_bin_get_property;
623 gobject_klass->finalize = gst_play_bin_finalize;
628 * Set the next URI that playbin will play. This property can be set from the
629 * about-to-finish signal to queue the next media file.
631 g_object_class_install_property (gobject_klass, PROP_URI,
632 g_param_spec_string ("uri", "URI", "URI of the media to play",
633 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
638 * Set the next subtitle URI that playbin will play. This property can be
639 * set from the about-to-finish signal to queue the next subtitle media file.
641 g_object_class_install_property (gobject_klass, PROP_SUBURI,
642 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
643 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
645 g_object_class_install_property (gobject_klass, PROP_SOURCE,
646 g_param_spec_object ("source", "Source", "Source element",
647 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
652 * Control the behaviour of playbin.
654 g_object_class_install_property (gobject_klass, PROP_FLAGS,
655 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
656 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
657 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
662 * Get the total number of available video streams.
664 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
665 g_param_spec_int ("n-video", "Number Video",
666 "Total number of video streams", 0, G_MAXINT, 0,
667 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
669 * GstPlayBin:current-video
671 * Get or set the currently playing video stream. By default the first video
672 * stream with data is played.
674 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
675 g_param_spec_int ("current-video", "Current Video",
676 "Currently playing video stream (-1 = auto)",
677 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
681 * Get the total number of available audio streams.
683 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
684 g_param_spec_int ("n-audio", "Number Audio",
685 "Total number of audio streams", 0, G_MAXINT, 0,
686 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
688 * GstPlayBin:current-audio
690 * Get or set the currently playing audio stream. By default the first audio
691 * stream with data is played.
693 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
694 g_param_spec_int ("current-audio", "Current audio",
695 "Currently playing audio stream (-1 = auto)",
696 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
700 * Get the total number of available subtitle streams.
702 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
703 g_param_spec_int ("n-text", "Number Text",
704 "Total number of text streams", 0, G_MAXINT, 0,
705 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
707 * GstPlayBin:current-text:
709 * Get or set the currently playing subtitle stream. By default the first
710 * subtitle stream with data is played.
712 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
713 g_param_spec_int ("current-text", "Current Text",
714 "Currently playing text stream (-1 = auto)",
715 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
717 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
718 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
719 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
720 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
721 "be checked for an encoding to use. If that is not set either, "
722 "ISO-8859-15 will be assumed.", NULL,
723 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
725 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
726 g_param_spec_object ("video-sink", "Video Sink",
727 "the video output element to use (NULL = default sink)",
728 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
729 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
730 g_param_spec_object ("audio-sink", "Audio Sink",
731 "the audio output element to use (NULL = default sink)",
732 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
733 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
734 g_param_spec_object ("vis-plugin", "Vis plugin",
735 "the visualization element to use (NULL = default)",
736 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
737 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
738 g_param_spec_object ("text-sink", "Text plugin",
739 "the text output element to use (NULL = default textoverlay)",
740 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
745 * Get or set the current audio stream volume. 1.0 means 100%,
746 * 0.0 means mute. This uses a linear volume scale.
749 g_object_class_install_property (gobject_klass, PROP_VOLUME,
750 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
751 0.0, VOLUME_MAX_DOUBLE, 1.0,
752 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
753 g_object_class_install_property (gobject_klass, PROP_MUTE,
754 g_param_spec_boolean ("mute", "Mute",
755 "Mute the audio channel without changing the volume", FALSE,
756 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
760 * @playbin: a #GstPlayBin
762 * Get the currently rendered or prerolled frame in the video sink.
763 * The #GstCaps on the buffer will describe the format of the buffer.
765 g_object_class_install_property (gobject_klass, PROP_FRAME,
766 g_param_spec_boxed ("frame", "Frame",
767 "The last frame (NULL = no video available)",
768 GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
769 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
770 g_param_spec_string ("subtitle-font-desc",
771 "Subtitle font description",
772 "Pango font description of font "
773 "to be used for subtitle rendering", NULL,
774 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
776 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
777 g_param_spec_uint ("connection-speed", "Connection Speed",
778 "Network connection speed in kbps (0 = unknown)",
779 0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
780 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
782 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
783 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
784 "Buffer size when buffering network streams",
785 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
786 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
787 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
788 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
789 "Buffer duration when buffering network streams",
790 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
791 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
793 * GstPlayBin:av-offset:
795 * Control the synchronisation offset between the audio and video streams.
796 * Positive values make the audio ahead of the video and negative values make
797 * the audio go behind the video.
801 g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
802 g_param_spec_int64 ("av-offset", "AV Offset",
803 "The synchronisation offset between audio and video in nanoseconds",
804 G_MININT64, G_MAXINT64, 0,
805 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
808 * GstQueue2:ring-buffer-max-size
810 * The maximum size of the ring buffer in bytes. If set to 0, the ring
811 * buffer is disabled. Default 0.
815 g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
816 g_param_spec_uint64 ("ring-buffer-max-size",
817 "Max. ring buffer size (bytes)",
818 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
819 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
820 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
823 * GstPlayBin::about-to-finish
824 * @playbin: a #GstPlayBin
826 * This signal is emitted when the current uri is about to finish. You can
827 * set the uri and suburi to make sure that playback continues.
829 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
830 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
832 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
833 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
836 * GstPlayBin::video-changed
837 * @playbin: a #GstPlayBin
839 * This signal is emitted whenever the number or order of the video
840 * streams has changed. The application will most likely want to select
841 * a new video stream.
843 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
844 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
846 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
847 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
849 * GstPlayBin::audio-changed
850 * @playbin: a #GstPlayBin
852 * This signal is emitted whenever the number or order of the audio
853 * streams has changed. The application will most likely want to select
854 * a new audio stream.
856 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
857 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
859 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
860 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
862 * GstPlayBin::text-changed
863 * @playbin: a #GstPlayBin
865 * This signal is emitted whenever the number or order of the text
866 * streams has changed. The application will most likely want to select
869 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
870 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
872 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
873 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
876 * GstPlayBin::video-tags-changed
877 * @playbin: a #GstPlayBin
878 * @stream: stream index with changed tags
880 * This signal is emitted whenever the tags of a video stream have changed.
881 * The application will most likely want to get the new tags.
885 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
886 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
888 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
889 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
892 * GstPlayBin::audio-tags-changed
893 * @playbin: a #GstPlayBin
894 * @stream: stream index with changed tags
896 * This signal is emitted whenever the tags of an audio stream have changed.
897 * The application will most likely want to get the new tags.
901 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
902 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
904 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
905 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
908 * GstPlayBin::text-tags-changed
909 * @playbin: a #GstPlayBin
910 * @stream: stream index with changed tags
912 * This signal is emitted whenever the tags of a text stream have changed.
913 * The application will most likely want to get the new tags.
917 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
918 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
920 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
921 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
924 * GstPlayBin::source-setup:
925 * @playbin: a #GstPlayBin
926 * @source: source element
928 * This signal is emitted after the source element has been created, so
929 * it can be configured by setting additional properties (e.g. set a
930 * proxy server for an http source, or set the device and read speed for
931 * an audio cd source). This is functionally equivalent to connecting to
932 * the notify::source signal, but more convenient.
936 gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
937 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
938 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
939 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
942 * GstPlayBin::get-video-tags
943 * @playbin: a #GstPlayBin
944 * @stream: a video stream number
946 * Action signal to retrieve the tags of a specific video stream number.
947 * This information can be used to select a stream.
949 * Returns: a GstTagList with tags or NULL when the stream number does not
952 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
953 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
954 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
955 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
956 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
958 * GstPlayBin::get-audio-tags
959 * @playbin: a #GstPlayBin
960 * @stream: an audio stream number
962 * Action signal to retrieve the tags of a specific audio stream number.
963 * This information can be used to select a stream.
965 * Returns: a GstTagList with tags or NULL when the stream number does not
968 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
969 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
970 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
971 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
972 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
974 * GstPlayBin::get-text-tags
975 * @playbin: a #GstPlayBin
976 * @stream: a text stream number
978 * Action signal to retrieve the tags of a specific text stream number.
979 * This information can be used to select a stream.
981 * Returns: a GstTagList with tags or NULL when the stream number does not
984 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
985 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
986 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
987 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
988 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
990 * GstPlayBin::convert-frame
991 * @playbin: a #GstPlayBin
992 * @caps: the target format of the frame
994 * Action signal to retrieve the currently playing video frame in the format
995 * specified by @caps.
996 * If @caps is %NULL, no conversion will be performed and this function is
997 * equivalent to the #GstPlayBin::frame property.
999 * Returns: a #GstBuffer of the current video frame converted to #caps.
1000 * The caps on the buffer will describe the final layout of the buffer data.
1001 * %NULL is returned when no current buffer can be retrieved or when the
1002 * conversion failed.
1004 gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
1005 g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
1006 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1007 G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
1008 gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
1011 * GstPlayBin::get-video-pad
1012 * @playbin: a #GstPlayBin
1013 * @stream: a video stream number
1015 * Action signal to retrieve the stream-selector sinkpad for a specific
1017 * This pad can be used for notifications of caps changes, stream-specific
1020 * Returns: a #GstPad, or NULL when the stream number does not exist.
1022 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1023 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1024 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1025 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1026 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1028 * GstPlayBin::get-audio-pad
1029 * @playbin: a #GstPlayBin
1030 * @stream: an audio stream number
1032 * Action signal to retrieve the stream-selector sinkpad for a specific
1034 * This pad can be used for notifications of caps changes, stream-specific
1037 * Returns: a #GstPad, or NULL when the stream number does not exist.
1039 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1040 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1041 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1042 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1043 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1045 * GstPlayBin::get-text-pad
1046 * @playbin: a #GstPlayBin
1047 * @stream: a text stream number
1049 * Action signal to retrieve the stream-selector sinkpad for a specific
1051 * This pad can be used for notifications of caps changes, stream-specific
1054 * Returns: a #GstPad, or NULL when the stream number does not exist.
1056 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1057 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1058 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1059 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1060 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1062 klass->get_video_tags = gst_play_bin_get_video_tags;
1063 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1064 klass->get_text_tags = gst_play_bin_get_text_tags;
1066 klass->convert_frame = gst_play_bin_convert_frame;
1068 klass->get_video_pad = gst_play_bin_get_video_pad;
1069 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1070 klass->get_text_pad = gst_play_bin_get_text_pad;
1072 gst_element_class_set_details_simple (gstelement_klass,
1073 "Player Bin 2", "Generic/Bin/Player",
1074 "Autoplug and play media from an uri",
1075 "Wim Taymans <wim.taymans@gmail.com>");
1077 gstelement_klass->change_state =
1078 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1079 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1081 gstbin_klass->handle_message =
1082 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1086 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1090 /* store the array for the different channels */
1091 group->video_channels = g_ptr_array_new ();
1092 group->audio_channels = g_ptr_array_new ();
1093 group->text_channels = g_ptr_array_new ();
1094 group->lock = g_mutex_new ();
1095 /* init selectors. The selector is found by finding the first prefix that
1096 * matches the media. */
1097 group->playbin = playbin;
1098 /* If you add any items to these lists, check that media_list[] is defined
1099 * above to be large enough to hold MAX(items)+1, so as to accomodate a
1100 * NULL terminator (set when the memory is zeroed on allocation) */
1101 group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
1102 group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
1103 group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
1104 group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
1105 group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
1106 group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
1107 group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
1108 group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
1109 group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
1110 group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
1111 group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
1112 group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
1113 group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
1114 group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
1115 gst_subtitle_overlay_create_factory_caps;
1116 group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
1117 group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
1119 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1120 GstSourceSelect *select = &group->selector[n];
1121 select->sinkpad_delayed_event = NULL;
1122 select->sinkpad_data_probe = 0;
1127 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1131 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1132 GstSourceSelect *select = &group->selector[n];
1133 if (select->sinkpad && select->sinkpad_data_probe)
1134 gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
1135 if (select->sinkpad_delayed_event)
1136 gst_event_unref (select->sinkpad_delayed_event);
1139 g_free (group->uri);
1140 g_free (group->suburi);
1141 g_ptr_array_free (group->video_channels, TRUE);
1142 g_ptr_array_free (group->audio_channels, TRUE);
1143 g_ptr_array_free (group->text_channels, TRUE);
1145 g_mutex_free (group->lock);
1146 if (group->audio_sink) {
1147 if (group->audio_sink != playbin->audio_sink)
1148 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1149 gst_object_unref (group->audio_sink);
1151 group->audio_sink = NULL;
1152 if (group->video_sink) {
1153 if (group->video_sink != playbin->video_sink)
1154 gst_element_set_state (group->video_sink, GST_STATE_NULL);
1155 gst_object_unref (group->video_sink);
1157 group->video_sink = NULL;
1159 g_list_free (group->stream_changed_pending);
1160 group->stream_changed_pending = NULL;
1162 if (group->stream_changed_pending_lock)
1163 g_mutex_free (group->stream_changed_pending_lock);
1164 group->stream_changed_pending_lock = NULL;
1168 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1170 g_object_notify (G_OBJECT (playbin), "volume");
1174 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1176 g_object_notify (G_OBJECT (playbin), "mute");
1179 /* Must be called with elements lock! */
1181 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1185 if (!playbin->elements ||
1186 playbin->elements_cookie !=
1187 gst_default_registry_get_feature_list_cookie ()) {
1188 if (playbin->elements)
1189 gst_plugin_feature_list_free (playbin->elements);
1191 gst_element_factory_list_get_elements
1192 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1194 gst_element_factory_list_get_elements
1195 (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1196 playbin->elements = g_list_concat (res, tmp);
1198 g_list_sort (playbin->elements, gst_plugin_feature_rank_compare_func);
1199 playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1204 gst_play_bin_init (GstPlayBin * playbin)
1206 g_static_rec_mutex_init (&playbin->lock);
1207 playbin->dyn_lock = g_mutex_new ();
1209 /* assume we can create a selector */
1210 playbin->have_selector = TRUE;
1213 playbin->curr_group = &playbin->groups[0];
1214 playbin->next_group = &playbin->groups[1];
1215 init_group (playbin, &playbin->groups[0]);
1216 init_group (playbin, &playbin->groups[1]);
1218 /* first filter out the interesting element factories */
1219 playbin->elements_lock = g_mutex_new ();
1222 playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1223 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1224 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1225 /* Connect to notify::volume and notify::mute signals for proxying */
1226 g_signal_connect (playbin->playsink, "notify::volume",
1227 G_CALLBACK (notify_volume_cb), playbin);
1228 g_signal_connect (playbin->playsink, "notify::mute",
1229 G_CALLBACK (notify_mute_cb), playbin);
1231 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1232 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1233 playbin->current_text = DEFAULT_CURRENT_TEXT;
1235 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1236 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1237 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1241 gst_play_bin_finalize (GObject * object)
1243 GstPlayBin *playbin;
1245 playbin = GST_PLAY_BIN (object);
1247 free_group (playbin, &playbin->groups[0]);
1248 free_group (playbin, &playbin->groups[1]);
1250 if (playbin->source)
1251 gst_object_unref (playbin->source);
1252 if (playbin->video_sink) {
1253 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1254 gst_object_unref (playbin->video_sink);
1256 if (playbin->audio_sink) {
1257 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1258 gst_object_unref (playbin->audio_sink);
1260 if (playbin->text_sink) {
1261 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1262 gst_object_unref (playbin->text_sink);
1265 if (playbin->elements)
1266 gst_plugin_feature_list_free (playbin->elements);
1268 g_static_rec_mutex_free (&playbin->lock);
1269 g_mutex_free (playbin->dyn_lock);
1270 g_mutex_free (playbin->elements_lock);
1272 G_OBJECT_CLASS (parent_class)->finalize (object);
1276 gst_playbin_uri_is_valid (GstPlayBin * playbin, const gchar * uri)
1280 GST_LOG_OBJECT (playbin, "checking uri '%s'", uri);
1282 /* this just checks the protocol */
1283 if (!gst_uri_is_valid (uri))
1286 for (c = uri; *c != '\0'; ++c) {
1287 if (!g_ascii_isprint (*c))
1297 GST_WARNING_OBJECT (playbin, "uri '%s' not valid, character #%u",
1298 uri, (guint) ((guintptr) c - (guintptr) uri));
1304 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1306 GstSourceGroup *group;
1309 g_warning ("cannot set NULL uri");
1313 if (!gst_playbin_uri_is_valid (playbin, uri)) {
1314 if (g_str_has_prefix (uri, "file:")) {
1315 GST_ERROR_OBJECT (playbin, "malformed file URI '%s' - make sure to "
1316 "escape spaces and non-ASCII characters properly and specify an "
1317 "absolute path. Use gst_filename_to_uri() to convert filenames "
1320 GST_ERROR_OBJECT (playbin, "malformed URI '%s'", uri);
1324 GST_PLAY_BIN_LOCK (playbin);
1325 group = playbin->next_group;
1327 GST_SOURCE_GROUP_LOCK (group);
1328 /* store the uri in the next group we will play */
1329 g_free (group->uri);
1330 group->uri = g_strdup (uri);
1331 group->valid = TRUE;
1332 GST_SOURCE_GROUP_UNLOCK (group);
1334 GST_DEBUG ("set new uri to %s", uri);
1335 GST_PLAY_BIN_UNLOCK (playbin);
1339 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1341 GstSourceGroup *group;
1343 GST_PLAY_BIN_LOCK (playbin);
1344 group = playbin->next_group;
1346 GST_SOURCE_GROUP_LOCK (group);
1347 g_free (group->suburi);
1348 group->suburi = g_strdup (suburi);
1349 GST_SOURCE_GROUP_UNLOCK (group);
1351 GST_DEBUG ("setting new .sub uri to %s", suburi);
1353 GST_PLAY_BIN_UNLOCK (playbin);
1357 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1359 gst_play_sink_set_flags (playbin->playsink, flags);
1360 gst_play_sink_reconfigure (playbin->playsink);
1364 gst_play_bin_get_flags (GstPlayBin * playbin)
1368 flags = gst_play_sink_get_flags (playbin->playsink);
1373 /* get the currently playing group or if nothing is playing, the next
1374 * group. Must be called with the PLAY_BIN_LOCK. */
1375 static GstSourceGroup *
1376 get_group (GstPlayBin * playbin)
1378 GstSourceGroup *result;
1380 if (!(result = playbin->curr_group))
1381 result = playbin->next_group;
1387 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1389 GstPad *sinkpad = NULL;
1390 GstSourceGroup *group;
1392 GST_PLAY_BIN_LOCK (playbin);
1393 group = get_group (playbin);
1394 if (stream < group->video_channels->len) {
1395 sinkpad = g_ptr_array_index (group->video_channels, stream);
1396 gst_object_ref (sinkpad);
1398 GST_PLAY_BIN_UNLOCK (playbin);
1404 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1406 GstPad *sinkpad = NULL;
1407 GstSourceGroup *group;
1409 GST_PLAY_BIN_LOCK (playbin);
1410 group = get_group (playbin);
1411 if (stream < group->audio_channels->len) {
1412 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1413 gst_object_ref (sinkpad);
1415 GST_PLAY_BIN_UNLOCK (playbin);
1421 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1423 GstPad *sinkpad = NULL;
1424 GstSourceGroup *group;
1426 GST_PLAY_BIN_LOCK (playbin);
1427 group = get_group (playbin);
1428 if (stream < group->text_channels->len) {
1429 sinkpad = g_ptr_array_index (group->text_channels, stream);
1430 gst_object_ref (sinkpad);
1432 GST_PLAY_BIN_UNLOCK (playbin);
1439 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1444 if (!channels || stream >= channels->len)
1447 sinkpad = g_ptr_array_index (channels, stream);
1448 g_object_get (sinkpad, "tags", &result, NULL);
1454 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1457 GstSourceGroup *group;
1459 GST_PLAY_BIN_LOCK (playbin);
1460 group = get_group (playbin);
1461 result = get_tags (playbin, group->video_channels, stream);
1462 GST_PLAY_BIN_UNLOCK (playbin);
1468 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1471 GstSourceGroup *group;
1473 GST_PLAY_BIN_LOCK (playbin);
1474 group = get_group (playbin);
1475 result = get_tags (playbin, group->audio_channels, stream);
1476 GST_PLAY_BIN_UNLOCK (playbin);
1482 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1485 GstSourceGroup *group;
1487 GST_PLAY_BIN_LOCK (playbin);
1488 group = get_group (playbin);
1489 result = get_tags (playbin, group->text_channels, stream);
1490 GST_PLAY_BIN_UNLOCK (playbin);
1496 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1498 return gst_play_sink_convert_frame (playbin->playsink, caps);
1501 /* Returns current stream number, or -1 if none has been selected yet */
1503 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1505 /* Internal API cleanup would make this easier... */
1507 GstPad *pad, *current;
1508 GstObject *selector = NULL;
1511 for (i = 0; i < channels->len; i++) {
1512 pad = g_ptr_array_index (channels, i);
1513 if ((selector = gst_pad_get_parent (pad))) {
1514 g_object_get (selector, "active-pad", ¤t, NULL);
1515 gst_object_unref (selector);
1517 if (pad == current) {
1518 gst_object_unref (current);
1524 gst_object_unref (current);
1532 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1534 GstSourceGroup *group;
1535 GPtrArray *channels;
1538 GST_PLAY_BIN_LOCK (playbin);
1540 GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1541 playbin->current_video, stream);
1543 group = get_group (playbin);
1544 if (!(channels = group->video_channels))
1547 if (stream == -1 || channels->len <= stream) {
1550 /* take channel from selected stream */
1551 sinkpad = g_ptr_array_index (channels, stream);
1555 gst_object_ref (sinkpad);
1556 GST_PLAY_BIN_UNLOCK (playbin);
1559 GstObject *selector;
1561 if ((selector = gst_pad_get_parent (sinkpad))) {
1562 /* activate the selected pad */
1563 g_object_set (selector, "active-pad", sinkpad, NULL);
1564 gst_object_unref (selector);
1566 gst_object_unref (sinkpad);
1572 GST_PLAY_BIN_UNLOCK (playbin);
1573 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1579 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1581 GstSourceGroup *group;
1582 GPtrArray *channels;
1585 GST_PLAY_BIN_LOCK (playbin);
1587 GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1588 playbin->current_audio, stream);
1590 group = get_group (playbin);
1591 if (!(channels = group->audio_channels))
1594 if (stream == -1 || channels->len <= stream) {
1597 /* take channel from selected stream */
1598 sinkpad = g_ptr_array_index (channels, stream);
1602 gst_object_ref (sinkpad);
1603 GST_PLAY_BIN_UNLOCK (playbin);
1606 GstObject *selector;
1608 if ((selector = gst_pad_get_parent (sinkpad))) {
1609 /* activate the selected pad */
1610 g_object_set (selector, "active-pad", sinkpad, NULL);
1611 gst_object_unref (selector);
1613 gst_object_unref (sinkpad);
1619 GST_PLAY_BIN_UNLOCK (playbin);
1620 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1626 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1628 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1630 GValue item = { 0, };
1632 if (it && gst_iterator_next (it, &item) == GST_ITERATOR_OK
1633 && ((sinkpad = g_value_get_object (&item)) != NULL)) {
1637 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1638 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1639 if (!gst_pad_send_event (sinkpad, event)) {
1641 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1642 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1643 if (!gst_pad_send_event (sinkpad, event))
1644 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1647 g_value_unset (&item);
1651 gst_iterator_free (it);
1655 gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
1656 GstElement * suburidecodebin, gboolean block)
1658 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1659 gboolean done = FALSE;
1660 GValue item = { 0, };
1662 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1669 switch (gst_iterator_next (it, &item)) {
1670 case GST_ITERATOR_OK:
1671 sinkpad = g_value_get_object (&item);
1674 gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1676 } else if (group->block_id) {
1677 gst_pad_remove_probe (sinkpad, group->block_id);
1678 group->block_id = 0;
1680 g_value_reset (&item);
1682 case GST_ITERATOR_DONE:
1685 case GST_ITERATOR_RESYNC:
1686 gst_iterator_resync (it);
1688 case GST_ITERATOR_ERROR:
1693 g_value_unset (&item);
1694 gst_iterator_free (it);
1698 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1700 GstSourceGroup *group;
1701 GPtrArray *channels;
1704 GST_PLAY_BIN_LOCK (playbin);
1706 GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1707 playbin->current_text, stream);
1709 group = get_group (playbin);
1710 if (!(channels = group->text_channels))
1713 if (stream == -1 || channels->len <= stream) {
1716 /* take channel from selected stream */
1717 sinkpad = g_ptr_array_index (channels, stream);
1721 gst_object_ref (sinkpad);
1722 GST_PLAY_BIN_UNLOCK (playbin);
1725 GstObject *selector;
1727 if ((selector = gst_pad_get_parent (sinkpad))) {
1728 GstPad *old_sinkpad;
1730 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1732 if (old_sinkpad != sinkpad) {
1733 gboolean need_unblock, need_block, need_seek;
1734 GstPad *src, *peer = NULL, *oldpeer = NULL;
1735 GstElement *parent_element = NULL, *old_parent_element = NULL;
1737 /* Now check if we need to seek the suburidecodebin to the beginning
1738 * or if we need to block all suburidecodebin sinkpads or if we need
1739 * to unblock all suburidecodebin sinkpads
1742 peer = gst_pad_get_peer (sinkpad);
1744 oldpeer = gst_pad_get_peer (old_sinkpad);
1747 parent_element = gst_pad_get_parent_element (peer);
1749 old_parent_element = gst_pad_get_parent_element (oldpeer);
1751 need_block = (old_parent_element == group->suburidecodebin
1752 && parent_element != old_parent_element);
1753 need_unblock = (parent_element == group->suburidecodebin
1754 && parent_element != old_parent_element);
1755 need_seek = (parent_element == group->suburidecodebin);
1758 gst_object_unref (peer);
1760 gst_object_unref (oldpeer);
1762 gst_object_unref (parent_element);
1763 if (old_parent_element)
1764 gst_object_unref (old_parent_element);
1766 /* Block all suburidecodebin sinkpads */
1768 gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1771 /* activate the selected pad */
1772 g_object_set (selector, "active-pad", sinkpad, NULL);
1774 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1775 peer = gst_pad_get_peer (src);
1779 /* Flush the subtitle renderer to remove any
1780 * currently displayed subtitles. This event will
1781 * never travel outside subtitleoverlay!
1783 s = gst_structure_new_empty ("subtitleoverlay-flush-subtitle");
1784 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1785 gst_pad_send_event (peer, event);
1786 gst_object_unref (peer);
1788 gst_object_unref (src);
1790 /* Unblock pads if necessary */
1792 gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1795 /* seek to the beginning */
1797 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1799 gst_object_unref (selector);
1802 gst_object_unref (old_sinkpad);
1804 gst_object_unref (sinkpad);
1810 GST_PLAY_BIN_UNLOCK (playbin);
1816 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1817 const gchar * dbg, GstElement * sink)
1819 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1821 GST_PLAY_BIN_LOCK (playbin);
1822 if (*elem != sink) {
1827 gst_object_ref_sink (sink);
1831 gst_object_unref (old);
1833 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1834 GST_PLAY_BIN_UNLOCK (playbin);
1838 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1842 GST_PLAY_BIN_LOCK (playbin);
1844 /* set subtitles on all current and next decodebins. */
1845 if ((elem = playbin->groups[0].uridecodebin))
1846 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1847 if ((elem = playbin->groups[0].suburidecodebin))
1848 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1849 if ((elem = playbin->groups[1].uridecodebin))
1850 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1851 if ((elem = playbin->groups[1].suburidecodebin))
1852 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1854 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1855 GST_PLAY_BIN_UNLOCK (playbin);
1859 gst_play_bin_set_property (GObject * object, guint prop_id,
1860 const GValue * value, GParamSpec * pspec)
1862 GstPlayBin *playbin = GST_PLAY_BIN (object);
1866 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1869 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1872 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1874 case PROP_CURRENT_VIDEO:
1875 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1877 case PROP_CURRENT_AUDIO:
1878 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1880 case PROP_CURRENT_TEXT:
1881 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1883 case PROP_SUBTITLE_ENCODING:
1884 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1886 case PROP_VIDEO_SINK:
1887 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1888 g_value_get_object (value));
1890 case PROP_AUDIO_SINK:
1891 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1892 g_value_get_object (value));
1894 case PROP_VIS_PLUGIN:
1895 gst_play_sink_set_vis_plugin (playbin->playsink,
1896 g_value_get_object (value));
1898 case PROP_TEXT_SINK:
1899 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1900 g_value_get_object (value));
1903 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1906 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1908 case PROP_FONT_DESC:
1909 gst_play_sink_set_font_desc (playbin->playsink,
1910 g_value_get_string (value));
1912 case PROP_CONNECTION_SPEED:
1913 GST_PLAY_BIN_LOCK (playbin);
1914 playbin->connection_speed = g_value_get_uint (value) * 1000;
1915 GST_PLAY_BIN_UNLOCK (playbin);
1917 case PROP_BUFFER_SIZE:
1918 playbin->buffer_size = g_value_get_int (value);
1920 case PROP_BUFFER_DURATION:
1921 playbin->buffer_duration = g_value_get_int64 (value);
1923 case PROP_AV_OFFSET:
1924 gst_play_sink_set_av_offset (playbin->playsink,
1925 g_value_get_int64 (value));
1927 case PROP_RING_BUFFER_MAX_SIZE:
1928 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
1931 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1937 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1938 const gchar * dbg, GstPlaySinkType type)
1940 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
1942 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1943 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1944 dbg, sink, dbg, *elem);
1947 GST_PLAY_BIN_LOCK (playbin);
1949 gst_object_ref (sink);
1950 GST_PLAY_BIN_UNLOCK (playbin);
1957 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1960 GstPlayBin *playbin = GST_PLAY_BIN (object);
1965 GstSourceGroup *group;
1967 GST_PLAY_BIN_LOCK (playbin);
1968 group = get_group (playbin);
1969 g_value_set_string (value, group->uri);
1970 GST_PLAY_BIN_UNLOCK (playbin);
1975 GstSourceGroup *group;
1977 GST_PLAY_BIN_LOCK (playbin);
1978 group = get_group (playbin);
1979 g_value_set_string (value, group->suburi);
1980 GST_PLAY_BIN_UNLOCK (playbin);
1985 GST_OBJECT_LOCK (playbin);
1986 g_value_set_object (value, playbin->source);
1987 GST_OBJECT_UNLOCK (playbin);
1991 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
1995 GstSourceGroup *group;
1998 GST_PLAY_BIN_LOCK (playbin);
1999 group = get_group (playbin);
2000 n_video = (group->video_channels ? group->video_channels->len : 0);
2001 g_value_set_int (value, n_video);
2002 GST_PLAY_BIN_UNLOCK (playbin);
2005 case PROP_CURRENT_VIDEO:
2006 GST_PLAY_BIN_LOCK (playbin);
2007 g_value_set_int (value, playbin->current_video);
2008 GST_PLAY_BIN_UNLOCK (playbin);
2012 GstSourceGroup *group;
2015 GST_PLAY_BIN_LOCK (playbin);
2016 group = get_group (playbin);
2017 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
2018 g_value_set_int (value, n_audio);
2019 GST_PLAY_BIN_UNLOCK (playbin);
2022 case PROP_CURRENT_AUDIO:
2023 GST_PLAY_BIN_LOCK (playbin);
2024 g_value_set_int (value, playbin->current_audio);
2025 GST_PLAY_BIN_UNLOCK (playbin);
2029 GstSourceGroup *group;
2032 GST_PLAY_BIN_LOCK (playbin);
2033 group = get_group (playbin);
2034 n_text = (group->text_channels ? group->text_channels->len : 0);
2035 g_value_set_int (value, n_text);
2036 GST_PLAY_BIN_UNLOCK (playbin);
2039 case PROP_CURRENT_TEXT:
2040 GST_PLAY_BIN_LOCK (playbin);
2041 g_value_set_int (value, playbin->current_text);
2042 GST_PLAY_BIN_UNLOCK (playbin);
2044 case PROP_SUBTITLE_ENCODING:
2045 GST_PLAY_BIN_LOCK (playbin);
2046 g_value_take_string (value,
2047 gst_play_sink_get_subtitle_encoding (playbin->playsink));
2048 GST_PLAY_BIN_UNLOCK (playbin);
2050 case PROP_VIDEO_SINK:
2051 g_value_take_object (value,
2052 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2053 "video", GST_PLAY_SINK_TYPE_VIDEO));
2055 case PROP_AUDIO_SINK:
2056 g_value_take_object (value,
2057 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2058 "audio", GST_PLAY_SINK_TYPE_AUDIO));
2060 case PROP_VIS_PLUGIN:
2061 g_value_take_object (value,
2062 gst_play_sink_get_vis_plugin (playbin->playsink));
2064 case PROP_TEXT_SINK:
2065 g_value_take_object (value,
2066 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2067 "text", GST_PLAY_SINK_TYPE_TEXT));
2070 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2073 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2076 gst_value_take_buffer (value,
2077 gst_play_sink_get_last_frame (playbin->playsink));
2079 case PROP_FONT_DESC:
2080 g_value_take_string (value,
2081 gst_play_sink_get_font_desc (playbin->playsink));
2083 case PROP_CONNECTION_SPEED:
2084 GST_PLAY_BIN_LOCK (playbin);
2085 g_value_set_uint (value, playbin->connection_speed / 1000);
2086 GST_PLAY_BIN_UNLOCK (playbin);
2088 case PROP_BUFFER_SIZE:
2089 GST_OBJECT_LOCK (playbin);
2090 g_value_set_int (value, playbin->buffer_size);
2091 GST_OBJECT_UNLOCK (playbin);
2093 case PROP_BUFFER_DURATION:
2094 GST_OBJECT_LOCK (playbin);
2095 g_value_set_int64 (value, playbin->buffer_duration);
2096 GST_OBJECT_UNLOCK (playbin);
2098 case PROP_AV_OFFSET:
2099 g_value_set_int64 (value,
2100 gst_play_sink_get_av_offset (playbin->playsink));
2102 case PROP_RING_BUFFER_MAX_SIZE:
2103 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2106 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2112 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2113 gboolean valid, GstQuery * query)
2119 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2120 gst_query_parse_duration (query, &fmt, &duration);
2122 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2123 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2124 playbin->duration[i].valid = valid;
2125 playbin->duration[i].format = fmt;
2126 playbin->duration[i].duration = valid ? duration : -1;
2133 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2135 const GstFormat formats[] =
2136 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2141 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2142 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2143 query = gst_query_new_duration (formats[i]);
2145 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2147 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2148 gst_query_unref (query);
2153 gst_play_bin_query (GstElement * element, GstQuery * query)
2155 GstPlayBin *playbin = GST_PLAY_BIN (element);
2158 /* During a group switch we shouldn't allow duration queries
2159 * because it's not clear if the old or new group's duration
2160 * is returned and if the sinks are already playing new data
2161 * or old data. See bug #585969
2163 * While we're at it, also don't do any other queries during
2164 * a group switch or any other event that causes topology changes
2165 * by taking the playbin lock in any case.
2167 GST_PLAY_BIN_LOCK (playbin);
2169 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2170 GstSourceGroup *group = playbin->curr_group;
2173 GST_SOURCE_GROUP_LOCK (group);
2174 if (group->stream_changed_pending_lock) {
2175 g_mutex_lock (group->stream_changed_pending_lock);
2176 pending = group->pending || group->stream_changed_pending;
2177 g_mutex_unlock (group->stream_changed_pending_lock);
2179 pending = group->pending;
2186 gst_query_parse_duration (query, &fmt, NULL);
2187 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2188 if (fmt == playbin->duration[i].format) {
2189 ret = playbin->duration[i].valid;
2190 gst_query_set_duration (query, fmt,
2191 (ret ? playbin->duration[i].duration : -1));
2195 /* if nothing cached yet, we might as well request duration,
2196 * such as during initial startup */
2198 GST_DEBUG_OBJECT (playbin,
2199 "Taking cached duration because of pending group switch: %d", ret);
2200 GST_SOURCE_GROUP_UNLOCK (group);
2201 GST_PLAY_BIN_UNLOCK (playbin);
2205 GST_SOURCE_GROUP_UNLOCK (group);
2208 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2210 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2211 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2212 GST_PLAY_BIN_UNLOCK (playbin);
2217 /* mime types we are not handling on purpose right now, don't post a
2218 * missing-plugin message for these */
2219 static const gchar *blacklisted_mimes[] = {
2224 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2226 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2227 GstSourceGroup *group;
2229 if (gst_is_missing_plugin_message (msg)) {
2233 detail = gst_missing_plugin_message_get_installer_detail (msg);
2234 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2235 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2236 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2237 gst_message_unref (msg);
2243 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2244 const GstStructure *s = gst_message_get_structure (msg);
2246 /* Drop all stream-changed messages except the last one */
2247 if (strcmp ("playbin-stream-changed", gst_structure_get_name (s)) == 0) {
2248 guint32 seqnum = gst_message_get_seqnum (msg);
2251 group = playbin->curr_group;
2252 g_mutex_lock (group->stream_changed_pending_lock);
2253 for (l = group->stream_changed_pending; l;) {
2254 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2256 if (l_seqnum == seqnum) {
2259 group->stream_changed_pending =
2260 g_list_delete_link (group->stream_changed_pending, l_prev);
2261 if (group->stream_changed_pending) {
2262 gst_message_unref (msg);
2270 g_mutex_unlock (group->stream_changed_pending_lock);
2272 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2273 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2274 GstObject *src = GST_OBJECT_CAST (msg->src);
2276 /* Ignore async state changes from the uridecodebin children,
2277 * see bug #602000. */
2278 group = playbin->curr_group;
2279 if (src && (group = playbin->curr_group) &&
2280 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2281 || (group->suburidecodebin
2282 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2283 GST_DEBUG_OBJECT (playbin,
2284 "Ignoring async state change of uridecodebin: %s",
2285 GST_OBJECT_NAME (src));
2286 gst_message_unref (msg);
2289 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2290 /* If we get an error of the subtitle uridecodebin transform
2291 * them into warnings and disable the subtitles */
2292 group = playbin->curr_group;
2293 if (group && group->suburidecodebin) {
2294 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2295 (group->suburidecodebin)))) {
2297 gchar *debug = NULL;
2298 GstMessage *new_msg;
2300 gboolean done = FALSE;
2301 GValue item = { 0, };
2303 gst_message_parse_error (msg, &err, &debug);
2304 new_msg = gst_message_new_warning (msg->src, err, debug);
2306 gst_message_unref (msg);
2311 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2312 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2313 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2314 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2316 it = gst_element_iterate_src_pads (group->suburidecodebin);
2317 while (it && !done) {
2319 GstIteratorResult res;
2321 res = gst_iterator_next (it, &item);
2324 case GST_ITERATOR_DONE:
2327 case GST_ITERATOR_OK:
2328 p = g_value_get_object (&item);
2329 pad_removed_cb (NULL, p, group);
2330 g_value_reset (&item);
2333 case GST_ITERATOR_RESYNC:
2334 gst_iterator_resync (it);
2336 case GST_ITERATOR_ERROR:
2341 g_value_unset (&item);
2343 gst_iterator_free (it);
2345 gst_object_ref (group->suburidecodebin);
2346 gst_bin_remove (bin, group->suburidecodebin);
2347 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2349 if (group->sub_pending) {
2350 group->sub_pending = FALSE;
2351 no_more_pads_cb (NULL, group);
2358 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2362 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2363 GstPlayBin * playbin)
2365 const gchar *property;
2366 GstSourceGroup *group;
2367 GstSourceSelect *select = NULL;
2370 GST_PLAY_BIN_LOCK (playbin);
2371 group = get_group (playbin);
2373 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2374 if (selector == G_OBJECT (group->selector[i].selector)) {
2375 select = &group->selector[i];
2379 /* We got a pad-change after our group got switched out; no need to notify */
2381 GST_PLAY_BIN_UNLOCK (playbin);
2385 switch (select->type) {
2386 case GST_PLAY_SINK_TYPE_VIDEO:
2387 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2388 property = "current-video";
2389 playbin->current_video = get_current_stream_number (playbin,
2390 group->video_channels);
2392 case GST_PLAY_SINK_TYPE_AUDIO:
2393 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2394 property = "current-audio";
2395 playbin->current_audio = get_current_stream_number (playbin,
2396 group->audio_channels);
2398 case GST_PLAY_SINK_TYPE_TEXT:
2399 property = "current-text";
2400 playbin->current_text = get_current_stream_number (playbin,
2401 group->text_channels);
2406 GST_PLAY_BIN_UNLOCK (playbin);
2409 g_object_notify (G_OBJECT (playbin), property);
2412 /* this callback sends a delayed event once the pad becomes unblocked */
2413 static GstPadProbeReturn
2414 stream_changed_data_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
2416 GstMiniObject *object = GST_PAD_PROBE_INFO_DATA (info);
2417 GstSourceSelect *select = (GstSourceSelect *) data;
2420 /* we need do this just once, so cleanup first */
2421 gst_pad_remove_probe (pad, select->sinkpad_data_probe);
2422 select->sinkpad_data_probe = 0;
2423 e = select->sinkpad_delayed_event;
2424 select->sinkpad_delayed_event = NULL;
2426 /* really, this should not happen */
2428 GST_WARNING ("Data probed called, but no delayed event");
2429 return GST_PAD_PROBE_OK;
2432 if (GST_IS_EVENT (object)
2433 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_SEGMENT) {
2434 /* push the event first, then send the delayed one */
2435 gst_event_ref (GST_EVENT_CAST (object));
2436 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2437 gst_pad_send_event (pad, e);
2438 return GST_PAD_PROBE_DROP;
2440 /* send delayed event, then allow the caller to go on */
2441 gst_pad_send_event (pad, e);
2442 return GST_PAD_PROBE_OK;
2446 /* helper function to lookup stuff in lists */
2448 array_has_value (const gchar * values[], const gchar * value, gboolean exact)
2452 for (i = 0; values[i]; i++) {
2453 if (exact && !strcmp (value, values[i]))
2455 if (!exact && g_str_has_prefix (value, values[i]))
2463 GstPlayBin *playbin;
2465 GstPlaySinkType type;
2469 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2471 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2474 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2475 " with stream id %d and type %d have changed",
2476 object, ntdata->stream_id, ntdata->type);
2478 switch (ntdata->type) {
2479 case GST_PLAY_SINK_TYPE_VIDEO:
2480 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2481 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2483 case GST_PLAY_SINK_TYPE_AUDIO:
2484 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2485 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2487 case GST_PLAY_SINK_TYPE_TEXT:
2488 signal = SIGNAL_TEXT_TAGS_CHANGED;
2496 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2500 /* this function is called when a new pad is added to decodebin. We check the
2501 * type of the pad and add it to the selector element of the group.
2504 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2506 GstPlayBin *playbin;
2508 const GstStructure *s;
2511 GstPadLinkReturn res;
2512 GstSourceSelect *select = NULL;
2514 gboolean changed = FALSE;
2516 playbin = group->playbin;
2518 caps = gst_pad_query_caps (pad, NULL);
2519 s = gst_caps_get_structure (caps, 0);
2520 name = gst_structure_get_name (s);
2522 GST_DEBUG_OBJECT (playbin,
2523 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2524 GST_DEBUG_PAD_NAME (pad), caps, group);
2526 /* major type of the pad, this determines the selector to use,
2527 try exact match first so we don't prematurely match video/
2528 for video/x-dvd-subpicture */
2529 for (pass = 0; !select && pass < 2; pass++) {
2530 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2531 if (array_has_value (group->selector[i].media_list, name, pass == 0)) {
2532 select = &group->selector[i];
2534 } else if (group->selector[i].get_media_caps) {
2535 GstCaps *media_caps = group->selector[i].get_media_caps ();
2537 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2538 select = &group->selector[i];
2539 gst_caps_unref (media_caps);
2542 gst_caps_unref (media_caps);
2546 /* no selector found for the media type, don't bother linking it to a
2547 * selector. This will leave the pad unlinked and thus ignored. */
2551 GST_SOURCE_GROUP_LOCK (group);
2552 if (select->selector == NULL && playbin->have_selector) {
2553 /* no selector, create one */
2554 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2555 select->selector = gst_element_factory_make ("input-selector", NULL);
2556 if (select->selector == NULL) {
2557 /* post the missing selector message only once */
2558 playbin->have_selector = FALSE;
2559 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2560 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2562 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2563 (_("Missing element '%s' - check your GStreamer installation."),
2564 "input-selector"), (NULL));
2566 g_object_set (select->selector, "sync-streams", TRUE, NULL);
2568 g_signal_connect (select->selector, "notify::active-pad",
2569 G_CALLBACK (selector_active_pad_changed), playbin);
2571 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2572 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2573 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2577 if (select->srcpad == NULL) {
2578 if (select->selector) {
2579 /* save source pad of the selector */
2580 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2582 /* no selector, use the pad as the source pad then */
2583 select->srcpad = gst_object_ref (pad);
2586 /* block the selector srcpad. It's possible that multiple decodebins start
2587 * pushing data into the selectors before we have a chance to collect all
2588 * streams and connect the sinks, resulting in not-linked errors. After we
2589 * configured the sinks we will unblock them all. */
2590 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2592 gst_pad_add_probe (select->srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2596 /* get sinkpad for the new stream */
2597 if (select->selector) {
2598 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink_%u"))) {
2599 gulong notify_tags_handler = 0;
2600 NotifyTagsData *ntdata;
2602 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2603 GST_DEBUG_PAD_NAME (sinkpad));
2605 /* store the selector for the pad */
2606 g_object_set_data (G_OBJECT (sinkpad), "playbin.select", select);
2608 /* connect to the notify::tags signal for our
2609 * own *-tags-changed signals
2611 ntdata = g_new0 (NotifyTagsData, 1);
2612 ntdata->playbin = playbin;
2613 ntdata->stream_id = select->channels->len;
2614 ntdata->type = select->type;
2616 notify_tags_handler =
2617 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2618 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2620 g_object_set_data (G_OBJECT (sinkpad), "playbin.notify_tags_handler",
2621 (gpointer) (guintptr) notify_tags_handler);
2623 /* store the pad in the array */
2624 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2625 g_ptr_array_add (select->channels, sinkpad);
2627 res = gst_pad_link (pad, sinkpad);
2628 if (GST_PAD_LINK_FAILED (res))
2631 /* store selector pad so we can release it */
2632 g_object_set_data (G_OBJECT (pad), "playbin.sinkpad", sinkpad);
2635 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2636 GST_DEBUG_PAD_NAME (pad), select->selector);
2639 /* no selector, don't configure anything, we'll link the new pad directly to
2644 GST_SOURCE_GROUP_UNLOCK (group);
2648 gboolean always_ok = (decodebin == group->suburidecodebin);
2650 switch (select->type) {
2651 case GST_PLAY_SINK_TYPE_VIDEO:
2652 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2653 /* we want to return NOT_LINKED for unselected pads but only for pads
2654 * from the normal uridecodebin. This makes sure that subtitle streams
2655 * are not raced past audio/video from decodebin's multiqueue.
2656 * For pads from suburidecodebin OK should always be returned, otherwise
2657 * it will most likely stop. */
2658 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2659 signal = SIGNAL_VIDEO_CHANGED;
2661 case GST_PLAY_SINK_TYPE_AUDIO:
2662 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2663 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2664 signal = SIGNAL_AUDIO_CHANGED;
2666 case GST_PLAY_SINK_TYPE_TEXT:
2667 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2668 signal = SIGNAL_TEXT_CHANGED;
2675 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2679 gst_caps_unref (caps);
2685 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2686 name, GST_DEBUG_PAD_NAME (pad));
2691 GST_ERROR_OBJECT (playbin,
2692 "failed to link pad %s:%s to selector, reason %d",
2693 GST_DEBUG_PAD_NAME (pad), res);
2694 GST_SOURCE_GROUP_UNLOCK (group);
2699 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2700 * the selector. This will make the selector select a new pad. */
2702 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2704 GstPlayBin *playbin;
2706 GstElement *selector;
2707 GstSourceSelect *select;
2709 playbin = group->playbin;
2711 GST_DEBUG_OBJECT (playbin,
2712 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2714 GST_SOURCE_GROUP_LOCK (group);
2715 /* get the selector sinkpad */
2716 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin.sinkpad")))
2719 if ((select = g_object_get_data (G_OBJECT (peer), "playbin.select"))) {
2720 gulong notify_tags_handler;
2722 notify_tags_handler =
2723 (guintptr) g_object_get_data (G_OBJECT (peer),
2724 "playbin.notify_tags_handler");
2725 if (notify_tags_handler != 0)
2726 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2727 g_object_set_data (G_OBJECT (peer), "playbin.notify_tags_handler", NULL);
2729 /* remove the pad from the array */
2730 g_ptr_array_remove (select->channels, peer);
2731 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2734 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2735 gst_pad_unlink (pad, peer);
2737 /* get selector, this can be NULL when the element is removing the pads
2738 * because it's being disposed. */
2739 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2741 gst_object_unref (peer);
2745 /* release the pad to the selector, this will make the selector choose a new
2747 gst_element_release_request_pad (selector, peer);
2748 gst_object_unref (peer);
2750 gst_object_unref (selector);
2751 GST_SOURCE_GROUP_UNLOCK (group);
2758 GST_DEBUG_OBJECT (playbin, "pad not linked");
2759 GST_SOURCE_GROUP_UNLOCK (group);
2764 GST_DEBUG_OBJECT (playbin, "selector not found");
2765 GST_SOURCE_GROUP_UNLOCK (group);
2770 /* we get called when all pads are available and we must connect the sinks to
2772 * The main purpose of the code is to see if we have video/audio and subtitles
2773 * and pick the right pipelines to display them.
2775 * The selectors installed on the group tell us about the presence of
2776 * audio/video and subtitle streams. This allows us to see if we need
2777 * visualisation, video or/and audio.
2780 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2782 GstPlayBin *playbin;
2783 GstPadLinkReturn res;
2787 playbin = group->playbin;
2789 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2791 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2793 GST_SOURCE_GROUP_LOCK (group);
2794 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2795 GstSourceSelect *select = &group->selector[i];
2797 /* check if the specific media type was detected and thus has a selector
2798 * created for it. If there is the media type, get a sinkpad from the sink
2799 * and link it. We only do this if we have not yet requested the sinkpad
2801 if (select->srcpad && select->sinkpad == NULL) {
2802 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2804 gst_play_sink_request_pad (playbin->playsink, select->type);
2806 res = gst_pad_link (select->srcpad, select->sinkpad);
2807 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2808 select->media_list[0], res);
2809 if (res != GST_PAD_LINK_OK) {
2810 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2811 ("Internal playbin error."),
2812 ("Failed to link selector to sink. Error %d", res));
2816 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2817 group->pending - 1);
2819 if (group->pending > 0)
2822 if (group->suburidecodebin == decodebin)
2823 group->sub_pending = FALSE;
2825 if (group->pending == 0) {
2826 /* we are the last group to complete, we will configure the output and then
2827 * signal the other waiters. */
2828 GST_LOG_OBJECT (playbin, "last group complete");
2831 GST_LOG_OBJECT (playbin, "have more pending groups");
2834 GST_SOURCE_GROUP_UNLOCK (group);
2837 /* if we have custom sinks, configure them now */
2838 GST_SOURCE_GROUP_LOCK (group);
2840 if (group->audio_sink) {
2841 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2843 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2847 if (group->video_sink) {
2848 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2850 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2854 if (playbin->text_sink) {
2855 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
2856 playbin->text_sink);
2857 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2858 playbin->text_sink);
2861 GST_SOURCE_GROUP_UNLOCK (group);
2863 /* signal the other decodebins that they can continue now. */
2864 GST_SOURCE_GROUP_LOCK (group);
2865 /* unblock all selectors */
2866 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2867 GstSourceSelect *select = &group->selector[i];
2869 /* All streamsynchronizer streams should see stream-changed message,
2870 * to arrange for blocking unblocking. */
2871 if (select->sinkpad) {
2877 s = gst_structure_new ("playbin-stream-changed", "uri", G_TYPE_STRING,
2880 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2881 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2882 seqnum = gst_message_get_seqnum (msg);
2883 event = gst_event_new_sink_message (msg);
2884 g_mutex_lock (group->stream_changed_pending_lock);
2885 group->stream_changed_pending =
2886 g_list_prepend (group->stream_changed_pending,
2887 GUINT_TO_POINTER (seqnum));
2889 /* remove any data probe we might have, and replace */
2890 if (select->sinkpad_delayed_event)
2891 gst_event_unref (select->sinkpad_delayed_event);
2892 select->sinkpad_delayed_event = event;
2893 if (select->sinkpad_data_probe)
2894 gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
2896 /* we go to the trouble of setting a probe on the pad to send
2897 the playbin-stream-changed event as sending it here might
2898 find that the pad is blocked, so we'd block here, and the
2899 pad might not be linked yet. Additionally, sending it here
2900 apparently would be on the wrong thread */
2901 select->sinkpad_data_probe =
2902 gst_pad_add_probe (select->sinkpad,
2903 GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
2904 stream_changed_data_probe, (gpointer) select, NULL);
2906 g_mutex_unlock (group->stream_changed_pending_lock);
2907 gst_message_unref (msg);
2910 if (select->srcpad) {
2911 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2913 if (select->block_id) {
2914 gst_pad_remove_probe (select->srcpad, select->block_id);
2915 select->block_id = 0;
2919 GST_SOURCE_GROUP_UNLOCK (group);
2922 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2928 GST_DEBUG ("ignoring, we are shutting down");
2929 /* Request a flushing pad from playsink that we then link to the selector.
2930 * Then we unblock the selectors so that they stop with a WRONG_STATE
2931 * instead of a NOT_LINKED error.
2933 GST_SOURCE_GROUP_LOCK (group);
2934 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2935 GstSourceSelect *select = &group->selector[i];
2937 if (select->srcpad) {
2938 if (select->sinkpad == NULL) {
2939 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2941 gst_play_sink_request_pad (playbin->playsink,
2942 GST_PLAY_SINK_TYPE_FLUSHING);
2943 res = gst_pad_link (select->srcpad, select->sinkpad);
2944 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2946 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2948 if (select->block_id) {
2949 gst_pad_remove_probe (select->srcpad, select->block_id);
2950 select->block_id = 0;
2954 GST_SOURCE_GROUP_UNLOCK (group);
2960 drained_cb (GstElement * decodebin, GstSourceGroup * group)
2962 GstPlayBin *playbin;
2964 playbin = group->playbin;
2966 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
2968 /* after this call, we should have a next group to activate or we EOS */
2969 g_signal_emit (G_OBJECT (playbin),
2970 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
2972 /* now activate the next group. If the app did not set a uri, this will
2973 * fail and we can do EOS */
2974 setup_next_source (playbin, GST_STATE_PAUSED);
2977 /* Like gst_element_factory_can_sink_any_caps() but doesn't
2978 * allow ANY caps on the sinkpad template */
2980 _factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps)
2982 const GList *templs;
2984 templs = gst_element_factory_get_static_pad_templates (factory);
2987 GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
2989 if (templ->direction == GST_PAD_SINK) {
2990 GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
2992 if (!gst_caps_is_any (templcaps)
2993 && gst_caps_can_intersect (templcaps, caps)) {
2994 gst_caps_unref (templcaps);
2997 gst_caps_unref (templcaps);
2999 templs = g_list_next (templs);
3005 /* Called when we must provide a list of factories to plug to @pad with @caps.
3006 * We first check if we have a sink that can handle the format and if we do, we
3007 * return NULL, to expose the pad. If we have no sink (or the sink does not
3008 * work), we return the list of elements that can connect. */
3009 static GValueArray *
3010 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
3011 GstCaps * caps, GstSourceGroup * group)
3013 GstPlayBin *playbin;
3014 GList *mylist, *tmp;
3015 GValueArray *result;
3017 playbin = group->playbin;
3019 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
3020 group, GST_DEBUG_PAD_NAME (pad), caps);
3022 /* filter out the elements based on the caps. */
3023 g_mutex_lock (playbin->elements_lock);
3024 gst_play_bin_update_elements_list (playbin);
3026 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
3028 g_mutex_unlock (playbin->elements_lock);
3030 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
3031 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
3033 /* 2 additional elements for the already set audio/video sinks */
3034 result = g_value_array_new (g_list_length (mylist) + 2);
3036 /* Check if we already have an audio/video sink and if this is the case
3037 * put it as the first element of the array */
3038 if (group->audio_sink) {
3039 GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
3041 if (factory && _factory_can_sink_caps (factory, caps)) {
3042 GValue val = { 0, };
3044 g_value_init (&val, G_TYPE_OBJECT);
3045 g_value_set_object (&val, factory);
3046 result = g_value_array_append (result, &val);
3047 g_value_unset (&val);
3051 if (group->video_sink) {
3052 GstElementFactory *factory = gst_element_get_factory (group->video_sink);
3054 if (factory && _factory_can_sink_caps (factory, caps)) {
3055 GValue val = { 0, };
3057 g_value_init (&val, G_TYPE_OBJECT);
3058 g_value_set_object (&val, factory);
3059 result = g_value_array_append (result, &val);
3060 g_value_unset (&val);
3064 for (tmp = mylist; tmp; tmp = tmp->next) {
3065 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
3066 GValue val = { 0, };
3068 if (group->audio_sink && gst_element_factory_list_is_type (factory,
3069 GST_ELEMENT_FACTORY_TYPE_SINK |
3070 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
3073 if (group->video_sink && gst_element_factory_list_is_type (factory,
3074 GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
3075 | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
3079 g_value_init (&val, G_TYPE_OBJECT);
3080 g_value_set_object (&val, factory);
3081 g_value_array_append (result, &val);
3082 g_value_unset (&val);
3084 gst_plugin_feature_list_free (mylist);
3089 /* autoplug-continue decides, if a pad has raw caps that can be exposed
3090 * directly or if further decoding is necessary. We use this to expose
3091 * supported subtitles directly */
3093 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
3094 * explicitely the caps it supports and if it claims to support ANY
3095 * caps it really should support everything */
3097 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
3098 GstSourceGroup * group)
3100 gboolean ret = TRUE;
3102 GstPad *sinkpad = NULL;
3104 GST_PLAY_BIN_LOCK (group->playbin);
3105 GST_SOURCE_GROUP_LOCK (group);
3107 if ((sink = group->playbin->text_sink))
3108 sinkpad = gst_element_get_static_pad (sink, "sink");
3112 /* Ignore errors here, if a custom sink fails to go
3113 * to READY things are wrong and will error out later
3115 if (GST_STATE (sink) < GST_STATE_READY)
3116 gst_element_set_state (sink, GST_STATE_READY);
3118 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3119 if (!gst_caps_is_any (sinkcaps))
3120 ret = !gst_pad_accept_caps (sinkpad, caps);
3121 gst_caps_unref (sinkcaps);
3122 gst_object_unref (sinkpad);
3124 GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3125 ret = !gst_caps_is_subset (caps, subcaps);
3126 gst_caps_unref (subcaps);
3128 /* If autoplugging can stop don't do additional checks */
3132 /* If this is from the subtitle uridecodebin we don't need to
3133 * check the audio and video sink */
3134 if (group->suburidecodebin
3135 && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3136 GST_OBJECT_CAST (group->suburidecodebin)))
3139 if ((sink = group->audio_sink)) {
3140 sinkpad = gst_element_get_static_pad (sink, "sink");
3144 /* Ignore errors here, if a custom sink fails to go
3145 * to READY things are wrong and will error out later
3147 if (GST_STATE (sink) < GST_STATE_READY)
3148 gst_element_set_state (sink, GST_STATE_READY);
3150 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3151 if (!gst_caps_is_any (sinkcaps))
3152 ret = !gst_pad_accept_caps (sinkpad, caps);
3153 gst_caps_unref (sinkcaps);
3154 gst_object_unref (sinkpad);
3160 if ((sink = group->video_sink)) {
3161 sinkpad = gst_element_get_static_pad (sink, "sink");
3165 /* Ignore errors here, if a custom sink fails to go
3166 * to READY things are wrong and will error out later
3168 if (GST_STATE (sink) < GST_STATE_READY)
3169 gst_element_set_state (sink, GST_STATE_READY);
3171 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3172 if (!gst_caps_is_any (sinkcaps))
3173 ret = !gst_pad_accept_caps (sinkpad, caps);
3174 gst_caps_unref (sinkcaps);
3175 gst_object_unref (sinkpad);
3180 GST_SOURCE_GROUP_UNLOCK (group);
3181 GST_PLAY_BIN_UNLOCK (group->playbin);
3183 GST_DEBUG_OBJECT (group->playbin,
3184 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3185 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3191 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3195 /* ... activate it ... We do this before adding it to the bin so that we
3196 * don't accidentally make it post error messages that will stop
3198 if (GST_STATE (sink) < GST_STATE_READY &&
3199 gst_element_set_state (sink,
3200 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3204 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3205 /* Got the sink pad, now let's see if the element actually does accept the
3206 * caps that we have */
3207 if (!gst_pad_accept_caps (sinkpad, caps)) {
3208 gst_object_unref (sinkpad);
3211 gst_object_unref (sinkpad);
3217 /* We are asked to select an element. See if the next element to check
3218 * is a sink. If this is the case, we see if the sink works by setting it to
3219 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3220 * expose the raw pad so that we can setup the mixers. */
3221 static GstAutoplugSelectResult
3222 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3223 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3225 GstPlayBin *playbin;
3226 GstElement *element;
3228 GstPlaySinkType type;
3231 playbin = group->playbin;
3233 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3234 group, GST_DEBUG_PAD_NAME (pad), caps);
3236 GST_DEBUG_OBJECT (playbin, "checking factory %s", GST_OBJECT_NAME (factory));
3238 /* if it's not a sink, we make sure the element is compatible with
3240 if (!gst_element_factory_list_is_type (factory,
3241 GST_ELEMENT_FACTORY_TYPE_SINK)) {
3242 gboolean isvideodec = gst_element_factory_list_is_type (factory,
3243 GST_ELEMENT_FACTORY_TYPE_DECODER |
3244 GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
3245 GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
3246 gboolean isaudiodec = gst_element_factory_list_is_type (factory,
3247 GST_ELEMENT_FACTORY_TYPE_DECODER |
3248 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
3250 /* If it is a decoder and we have a fixed sink for the media
3251 * type it outputs, check that the decoder is compatible with this sink */
3252 if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) {
3253 gboolean compatible = TRUE;
3259 sink = group->audio_sink;
3261 sink = group->video_sink;
3263 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3264 caps = gst_pad_query_caps (sinkpad, NULL);
3266 compatible = gst_element_factory_can_src_any_caps (factory, caps);
3268 gst_object_unref (sinkpad);
3269 gst_caps_unref (caps);
3273 return GST_AUTOPLUG_SELECT_TRY;
3275 GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink",
3276 GST_OBJECT_NAME (factory));
3278 return GST_AUTOPLUG_SELECT_SKIP;
3280 return GST_AUTOPLUG_SELECT_TRY;
3283 /* it's a sink, see if an instance of it actually works */
3284 GST_DEBUG_OBJECT (playbin, "we found a sink");
3286 klass = gst_element_factory_get_klass (factory);
3288 /* figure out the klass */
3289 if (strstr (klass, "Audio")) {
3290 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3291 type = GST_PLAY_SINK_TYPE_AUDIO;
3292 sinkp = &group->audio_sink;
3293 } else if (strstr (klass, "Video")) {
3294 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3295 type = GST_PLAY_SINK_TYPE_VIDEO;
3296 sinkp = &group->video_sink;
3298 /* unknown klass, skip this element */
3299 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3300 return GST_AUTOPLUG_SELECT_SKIP;
3303 /* if we are asked to do visualisations and it's an audio sink, skip the
3304 * element. We can only do visualisations with raw sinks */
3305 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3306 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3307 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3308 return GST_AUTOPLUG_SELECT_SKIP;
3312 /* now see if we already have a sink element */
3313 GST_SOURCE_GROUP_LOCK (group);
3315 GstElement *sink = gst_object_ref (*sinkp);
3317 if (sink_accepts_caps (sink, caps)) {
3318 GST_DEBUG_OBJECT (playbin,
3319 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3320 GST_ELEMENT_NAME (sink), caps);
3321 gst_object_unref (sink);
3322 GST_SOURCE_GROUP_UNLOCK (group);
3323 return GST_AUTOPLUG_SELECT_EXPOSE;
3325 GST_DEBUG_OBJECT (playbin,
3326 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3327 GST_ELEMENT_NAME (sink), caps);
3328 gst_object_unref (sink);
3329 GST_SOURCE_GROUP_UNLOCK (group);
3330 return GST_AUTOPLUG_SELECT_SKIP;
3333 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3335 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3336 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3337 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3338 GST_SOURCE_GROUP_UNLOCK (group);
3339 return GST_AUTOPLUG_SELECT_SKIP;
3342 /* Check if the selected sink actually supports the
3343 * caps and can be set to READY*/
3344 if (!sink_accepts_caps (element, caps)) {
3345 gst_element_set_state (element, GST_STATE_NULL);
3346 gst_object_unref (element);
3347 GST_SOURCE_GROUP_UNLOCK (group);
3348 return GST_AUTOPLUG_SELECT_SKIP;
3351 /* remember the sink in the group now, the element is floating, we take
3354 * store the sink in the group, we will configure it later when we
3355 * reconfigure the sink */
3356 GST_DEBUG_OBJECT (playbin, "remember sink");
3357 gst_object_ref_sink (element);
3359 GST_SOURCE_GROUP_UNLOCK (group);
3361 /* tell decodebin to expose the pad because we are going to use this
3363 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3365 return GST_AUTOPLUG_SELECT_EXPOSE;
3369 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3370 GstSourceGroup * group)
3372 GstPlayBin *playbin;
3375 playbin = group->playbin;
3377 g_object_get (group->uridecodebin, "source", &source, NULL);
3379 GST_OBJECT_LOCK (playbin);
3380 if (playbin->source)
3381 gst_object_unref (playbin->source);
3382 playbin->source = source;
3383 GST_OBJECT_UNLOCK (playbin);
3385 g_object_notify (G_OBJECT (playbin), "source");
3387 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3388 0, playbin->source);
3391 /* must be called with the group lock */
3393 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3396 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3398 if (group->uridecodebin)
3399 gst_element_set_locked_state (group->uridecodebin, locked);
3400 if (group->suburidecodebin)
3401 gst_element_set_locked_state (group->suburidecodebin, locked);
3406 /* must be called with PLAY_BIN_LOCK */
3408 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3410 GstElement *uridecodebin;
3411 GstElement *suburidecodebin = NULL;
3414 g_return_val_if_fail (group->valid, FALSE);
3415 g_return_val_if_fail (!group->active, FALSE);
3417 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3419 GST_SOURCE_GROUP_LOCK (group);
3421 /* First set up the custom sources */
3422 if (playbin->audio_sink)
3423 group->audio_sink = gst_object_ref (playbin->audio_sink);
3424 if (playbin->video_sink)
3425 group->video_sink = gst_object_ref (playbin->video_sink);
3427 g_list_free (group->stream_changed_pending);
3428 group->stream_changed_pending = NULL;
3429 if (!group->stream_changed_pending_lock)
3430 group->stream_changed_pending_lock = g_mutex_new ();
3432 if (group->uridecodebin) {
3433 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3434 uridecodebin = group->uridecodebin;
3435 gst_element_set_state (uridecodebin, GST_STATE_READY);
3436 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3438 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3439 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3442 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3443 group->uridecodebin = gst_object_ref (uridecodebin);
3446 flags = gst_play_sink_get_flags (playbin->playsink);
3448 g_object_set (uridecodebin,
3449 /* configure connection speed */
3450 "connection-speed", playbin->connection_speed / 1000,
3453 /* configure download buffering */
3454 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3455 /* configure buffering of demuxed/parsed data */
3456 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3457 /* configure buffering parameters */
3458 "buffer-duration", playbin->buffer_duration,
3459 "buffer-size", playbin->buffer_size,
3460 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3462 /* connect pads and other things */
3463 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3464 G_CALLBACK (pad_added_cb), group);
3465 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3466 G_CALLBACK (pad_removed_cb), group);
3467 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3468 G_CALLBACK (no_more_pads_cb), group);
3469 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3470 G_CALLBACK (notify_source_cb), group);
3472 /* we have 1 pending no-more-pads */
3475 /* is called when the uridecodebin is out of data and we can switch to the
3478 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3481 /* will be called when a new media type is found. We return a list of decoders
3482 * including sinks for decodebin to try */
3483 group->autoplug_factories_id =
3484 g_signal_connect (uridecodebin, "autoplug-factories",
3485 G_CALLBACK (autoplug_factories_cb), group);
3486 group->autoplug_select_id =
3487 g_signal_connect (uridecodebin, "autoplug-select",
3488 G_CALLBACK (autoplug_select_cb), group);
3489 group->autoplug_continue_id =
3490 g_signal_connect (uridecodebin, "autoplug-continue",
3491 G_CALLBACK (autoplug_continue_cb), group);
3493 if (group->suburi) {
3495 if (group->suburidecodebin) {
3496 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3497 suburidecodebin = group->suburidecodebin;
3498 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3499 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3501 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3502 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3503 if (!suburidecodebin)
3506 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3507 group->suburidecodebin = gst_object_ref (suburidecodebin);
3510 g_object_set (suburidecodebin,
3511 /* configure connection speed */
3512 "connection-speed", playbin->connection_speed,
3514 "uri", group->suburi, NULL);
3516 /* connect pads and other things */
3517 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3518 G_CALLBACK (pad_added_cb), group);
3519 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3520 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3521 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3522 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3524 group->sub_autoplug_continue_id =
3525 g_signal_connect (suburidecodebin, "autoplug-continue",
3526 G_CALLBACK (autoplug_continue_cb), group);
3528 /* we have 2 pending no-more-pads */
3530 group->sub_pending = TRUE;
3532 group->sub_pending = FALSE;
3535 /* release the group lock before setting the state of the decodebins, they
3536 * might fire signals in this thread that we need to handle with the
3537 * group_lock taken. */
3538 GST_SOURCE_GROUP_UNLOCK (group);
3540 if (suburidecodebin) {
3541 if (gst_element_set_state (suburidecodebin,
3542 target) == GST_STATE_CHANGE_FAILURE) {
3543 GST_DEBUG_OBJECT (playbin,
3544 "failed state change of subtitle uridecodebin");
3545 GST_SOURCE_GROUP_LOCK (group);
3547 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3548 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3549 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3550 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3551 /* Might already be removed because of an error message */
3552 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3553 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3554 if (group->sub_pending) {
3556 group->sub_pending = FALSE;
3558 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3559 GST_SOURCE_GROUP_UNLOCK (group);
3562 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3563 goto uridecodebin_failure;
3565 GST_SOURCE_GROUP_LOCK (group);
3566 /* alow state changes of the playbin affect the group elements now */
3567 group_set_locked_state_unlocked (playbin, group, FALSE);
3568 group->active = TRUE;
3569 GST_SOURCE_GROUP_UNLOCK (group);
3578 /* delete any custom sinks we might have */
3579 if (group->audio_sink) {
3580 /* If this is a automatically created sink set it to NULL */
3581 if (group->audio_sink != playbin->audio_sink)
3582 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3583 gst_object_unref (group->audio_sink);
3585 group->audio_sink = NULL;
3586 if (group->video_sink) {
3587 /* If this is a automatically created sink set it to NULL */
3588 if (group->video_sink != playbin->video_sink)
3589 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3590 gst_object_unref (group->video_sink);
3592 group->video_sink = NULL;
3594 GST_SOURCE_GROUP_UNLOCK (group);
3596 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3598 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3600 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3601 (_("Could not create \"uridecodebin\" element.")), (NULL));
3604 uridecodebin_failure:
3606 /* delete any custom sinks we might have */
3607 if (group->audio_sink) {
3608 /* If this is a automatically created sink set it to NULL */
3609 if (group->audio_sink != playbin->audio_sink)
3610 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3611 gst_object_unref (group->audio_sink);
3613 group->audio_sink = NULL;
3614 if (group->video_sink) {
3615 /* If this is a automatically created sink set it to NULL */
3616 if (group->video_sink != playbin->video_sink)
3617 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3618 gst_object_unref (group->video_sink);
3620 group->video_sink = NULL;
3622 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3627 /* unlink a group of uridecodebins from the sink.
3628 * must be called with PLAY_BIN_LOCK */
3630 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3634 g_return_val_if_fail (group->valid, FALSE);
3635 g_return_val_if_fail (group->active, FALSE);
3637 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3639 GST_SOURCE_GROUP_LOCK (group);
3640 group->active = FALSE;
3641 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3642 GstSourceSelect *select = &group->selector[i];
3644 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3646 if (select->srcpad) {
3647 if (select->sinkpad) {
3648 GST_LOG_OBJECT (playbin, "unlinking from sink");
3649 gst_pad_unlink (select->srcpad, select->sinkpad);
3652 GST_LOG_OBJECT (playbin, "release sink pad");
3653 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3654 select->sinkpad = NULL;
3657 gst_object_unref (select->srcpad);
3658 select->srcpad = NULL;
3661 if (select->selector) {
3664 /* release and unref requests pad from the selector */
3665 for (n = 0; n < select->channels->len; n++) {
3666 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3668 gst_element_release_request_pad (select->selector, sinkpad);
3669 gst_object_unref (sinkpad);
3671 g_ptr_array_set_size (select->channels, 0);
3673 gst_element_set_state (select->selector, GST_STATE_NULL);
3674 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3675 select->selector = NULL;
3678 /* delete any custom sinks we might have */
3679 if (group->audio_sink) {
3680 /* If this is a automatically created sink set it to NULL */
3681 if (group->audio_sink != playbin->audio_sink)
3682 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3683 gst_object_unref (group->audio_sink);
3685 group->audio_sink = NULL;
3686 if (group->video_sink) {
3687 /* If this is a automatically created sink set it to NULL */
3688 if (group->video_sink != playbin->video_sink)
3689 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3690 gst_object_unref (group->video_sink);
3692 group->video_sink = NULL;
3694 if (group->uridecodebin) {
3695 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3696 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3697 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3698 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3699 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3700 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3701 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3702 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3703 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3706 if (group->suburidecodebin) {
3707 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3708 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3709 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3710 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3712 /* Might already be removed because of errors */
3713 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3714 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3717 GST_SOURCE_GROUP_UNLOCK (group);
3722 /* setup the next group to play, this assumes the next_group is valid and
3723 * configured. It swaps out the current_group and activates the valid
3726 setup_next_source (GstPlayBin * playbin, GstState target)
3728 GstSourceGroup *new_group, *old_group;
3730 GST_DEBUG_OBJECT (playbin, "setup sources");
3732 /* see if there is a next group */
3733 GST_PLAY_BIN_LOCK (playbin);
3734 new_group = playbin->next_group;
3735 if (!new_group || !new_group->valid)
3738 /* first unlink the current source, if any */
3739 old_group = playbin->curr_group;
3740 if (old_group && old_group->valid && old_group->active) {
3741 gst_play_bin_update_cached_duration (playbin);
3742 /* unlink our pads with the sink */
3743 deactivate_group (playbin, old_group);
3744 old_group->valid = FALSE;
3747 /* swap old and new */
3748 playbin->curr_group = new_group;
3749 playbin->next_group = old_group;
3751 /* activate the new group */
3752 if (!activate_group (playbin, new_group, target))
3753 goto activate_failed;
3755 GST_PLAY_BIN_UNLOCK (playbin);
3762 GST_DEBUG_OBJECT (playbin, "no next group");
3763 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3764 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3765 GST_PLAY_BIN_UNLOCK (playbin);
3770 GST_DEBUG_OBJECT (playbin, "activate failed");
3771 GST_PLAY_BIN_UNLOCK (playbin);
3776 /* The group that is currently playing is copied again to the
3777 * next_group so that it will start playing the next time.
3780 save_current_group (GstPlayBin * playbin)
3782 GstSourceGroup *curr_group;
3784 GST_DEBUG_OBJECT (playbin, "save current group");
3786 /* see if there is a current group */
3787 GST_PLAY_BIN_LOCK (playbin);
3788 curr_group = playbin->curr_group;
3789 if (curr_group && curr_group->valid) {
3790 /* unlink our pads with the sink */
3791 deactivate_group (playbin, curr_group);
3793 /* swap old and new */
3794 playbin->curr_group = playbin->next_group;
3795 playbin->next_group = curr_group;
3796 GST_PLAY_BIN_UNLOCK (playbin);
3801 /* clear the locked state from all groups. This function is called before a
3802 * state change to NULL is performed on them. */
3804 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3806 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3809 GST_PLAY_BIN_LOCK (playbin);
3810 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3811 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3812 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3813 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3814 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3815 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3816 GST_PLAY_BIN_UNLOCK (playbin);
3821 static GstStateChangeReturn
3822 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3824 GstStateChangeReturn ret;
3825 GstPlayBin *playbin;
3826 gboolean do_save = FALSE;
3828 playbin = GST_PLAY_BIN (element);
3830 switch (transition) {
3831 case GST_STATE_CHANGE_NULL_TO_READY:
3832 memset (&playbin->duration, 0, sizeof (playbin->duration));
3834 case GST_STATE_CHANGE_READY_TO_PAUSED:
3835 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3836 memset (&playbin->duration, 0, sizeof (playbin->duration));
3837 g_atomic_int_set (&playbin->shutdown, 0);
3839 if (!setup_next_source (playbin, GST_STATE_READY)) {
3840 ret = GST_STATE_CHANGE_FAILURE;
3844 case GST_STATE_CHANGE_PAUSED_TO_READY:
3846 /* FIXME unlock our waiting groups */
3847 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3848 g_atomic_int_set (&playbin->shutdown, 1);
3849 memset (&playbin->duration, 0, sizeof (playbin->duration));
3851 /* wait for all callbacks to end by taking the lock.
3852 * No dynamic (critical) new callbacks will
3853 * be able to happen as we set the shutdown flag. */
3854 GST_PLAY_BIN_DYN_LOCK (playbin);
3855 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3856 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3859 case GST_STATE_CHANGE_READY_TO_NULL:
3860 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3861 * an no state change PAUSED to READY passes here,
3862 * though it is a nice-to-have ... */
3863 if (!g_atomic_int_get (&playbin->shutdown)) {
3867 memset (&playbin->duration, 0, sizeof (playbin->duration));
3869 /* unlock so that all groups go to NULL */
3870 groups_set_locked_state (playbin, FALSE);
3876 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3877 if (ret == GST_STATE_CHANGE_FAILURE)
3880 switch (transition) {
3881 case GST_STATE_CHANGE_READY_TO_PAUSED:
3883 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3884 /* FIXME Release audio device when we implement that */
3886 case GST_STATE_CHANGE_PAUSED_TO_READY:
3887 save_current_group (playbin);
3889 case GST_STATE_CHANGE_READY_TO_NULL:
3893 /* also do missed state change down to READY */
3895 save_current_group (playbin);
3896 /* Deactive the groups, set the uridecodebins to NULL
3899 for (i = 0; i < 2; i++) {
3900 if (playbin->groups[i].active && playbin->groups[i].valid) {
3901 deactivate_group (playbin, &playbin->groups[i]);
3902 playbin->groups[i].valid = FALSE;
3905 if (playbin->groups[i].uridecodebin) {
3906 gst_element_set_state (playbin->groups[i].uridecodebin,
3908 gst_object_unref (playbin->groups[i].uridecodebin);
3909 playbin->groups[i].uridecodebin = NULL;
3912 if (playbin->groups[i].suburidecodebin) {
3913 gst_element_set_state (playbin->groups[i].suburidecodebin,
3915 gst_object_unref (playbin->groups[i].suburidecodebin);
3916 playbin->groups[i].suburidecodebin = NULL;
3920 /* Set our sinks back to NULL, they might not be child of playbin */
3921 if (playbin->audio_sink)
3922 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
3923 if (playbin->video_sink)
3924 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
3925 if (playbin->text_sink)
3926 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
3928 /* make sure the groups don't perform a state change anymore until we
3929 * enable them again */
3930 groups_set_locked_state (playbin, TRUE);
3942 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
3943 GstSourceGroup *curr_group;
3945 curr_group = playbin->curr_group;
3946 if (curr_group && curr_group->active && curr_group->valid) {
3947 /* unlink our pads with the sink */
3948 deactivate_group (playbin, curr_group);
3949 curr_group->valid = FALSE;
3952 /* Swap current and next group back */
3953 playbin->curr_group = playbin->next_group;
3954 playbin->next_group = curr_group;
3961 gst_play_bin2_plugin_init (GstPlugin * plugin)
3963 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin", 0, "play bin");
3965 return gst_element_register (plugin, "playbin", GST_RANK_NONE,