2 * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
3 * Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * SECTION:element-playbin2
24 * Playbin2 provides a stand-alone everything-in-one abstraction for an
25 * audio and/or video player.
27 * playbin2 is considered stable now. It is the prefered playback API now,
28 * and replaces the old #playbin element, which is no longer supported.
30 * It can handle both audio and video files and features
33 * automatic file type recognition and based on that automatic
34 * selection and usage of the right audio/video/subtitle demuxers/decoders
37 * visualisations for audio files
40 * subtitle support for video files. Subtitles can be store in external
44 * stream selection between different video/audio/subtitles streams
47 * meta info (tag) extraction
50 * easy access to the last video frame
53 * buffering when playing streams over a network
56 * volume control with mute option
61 * <title>Usage</title>
63 * A playbin2 element can be created just like any other element using
64 * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin2:uri
65 * property. This must be an absolute URI, relative file paths are not allowed.
66 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
68 * Playbin is a #GstPipeline. It will notify the application of everything
69 * that's happening (errors, end of stream, tags found, state changes, etc.)
70 * by posting messages on its #GstBus. The application needs to watch the
73 * Playback can be initiated by setting the element to PLAYING state using
74 * gst_element_set_state(). Note that the state change will take place in
75 * the background in a separate thread, when the function returns playback
76 * is probably not happening yet and any errors might not have occured yet.
77 * Applications using playbin should ideally be written to deal with things
78 * completely asynchroneous.
80 * When playback has finished (an EOS message has been received on the bus)
81 * or an error has occured (an ERROR message has been received on the bus) or
82 * the user wants to play a different track, playbin should be set back to
83 * READY or NULL state, then the #GstPlayBin2:uri property should be set to the
84 * new location and then playbin be set to PLAYING state again.
86 * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
87 * on the playbin element. Again, the seek will not be executed
88 * instantaneously, but will be done in a background thread. When the seek
89 * call returns the seek will most likely still be in process. An application
90 * may wait for the seek to finish (or fail) using gst_element_get_state() with
91 * -1 as the timeout, but this will block the user interface and is not
94 * Applications may query the current position and duration of the stream
95 * via gst_element_query_position() and gst_element_query_duration() and
96 * setting the format passed to GST_FORMAT_TIME. If the query was successful,
97 * the duration or position will have been returned in units of nanoseconds.
101 * <title>Advanced Usage: specifying the audio and video sink</title>
103 * By default, if no audio sink or video sink has been specified via the
104 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property, playbin will use the autoaudiosink
105 * and autovideosink elements to find the first-best available output method.
106 * This should work in most cases, but is not always desirable. Often either
107 * the user or application might want to specify more explicitly what to use
108 * for audio and video output.
110 * If the application wants more control over how audio or video should be
111 * output, it may create the audio/video sink elements itself (for example
112 * using gst_element_factory_make()) and provide them to playbin using the
113 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property.
115 * GNOME-based applications, for example, will usually want to create
116 * gconfaudiosink and gconfvideosink elements and make playbin use those,
117 * so that output happens to whatever the user has configured in the GNOME
118 * Multimedia System Selector configuration dialog.
120 * The sink elements do not necessarily need to be ready-made sinks. It is
121 * possible to create container elements that look like a sink to playbin,
122 * but in reality contain a number of custom elements linked together. This
123 * can be achieved by creating a #GstBin and putting elements in there and
124 * linking them, and then creating a sink #GstGhostPad for the bin and pointing
125 * it to the sink pad of the first element within the bin. This can be used
126 * for a number of purposes, for example to force output to a particular
127 * format or to modify or observe the data before it is output.
129 * It is also possible to 'suppress' audio and/or video output by using
130 * 'fakesink' elements (or capture it from there using the fakesink element's
131 * "handoff" signal, which, nota bene, is fired from the streaming thread!).
135 * <title>Retrieving Tags and Other Meta Data</title>
137 * Most of the common meta data (artist, title, etc.) can be retrieved by
138 * watching for TAG messages on the pipeline's bus (see above).
140 * Other more specific meta information like width/height/framerate of video
141 * streams or samplerate/number of channels of audio streams can be obtained
142 * from the negotiated caps on the sink pads of the sinks.
146 * <title>Buffering</title>
147 * Playbin handles buffering automatically for the most part, but applications
148 * need to handle parts of the buffering process as well. Whenever playbin is
149 * buffering, it will post BUFFERING messages on the bus with a percentage
150 * value that shows the progress of the buffering process. Applications need
151 * to set playbin to PLAYING or PAUSED state in response to these messages.
152 * They may also want to convey the buffering progress to the user in some
153 * way. Here is how to extract the percentage information from the message
154 * (requires GStreamer >= 0.10.11):
156 * switch (GST_MESSAGE_TYPE (msg)) {
157 * case GST_MESSAGE_BUFFERING: {
159 * gst_message_parse_buffering (msg, &percent);
160 * g_print ("Buffering (%%u percent done)", percent);
166 * Note that applications should keep/set the pipeline in the PAUSED state when
167 * a BUFFERING message is received with a buffer percent value < 100 and set
168 * the pipeline back to PLAYING state when a BUFFERING message with a value
169 * of 100 percent is received (if PLAYING is the desired state, that is).
172 * <title>Embedding the video window in your application</title>
173 * By default, playbin (or rather the video sinks used) will create their own
174 * window. Applications will usually want to force output to a window of their
175 * own, however. This can be done using the #GstXOverlay interface, which most
176 * video sinks implement. See the documentation there for more details.
179 * <title>Specifying which CD/DVD device to use</title>
180 * The device to use for CDs/DVDs needs to be set on the source element
181 * playbin creates before it is opened. The most generic way of doing this
182 * is to connect to playbin's "source-setup" (or "notify::source") signal,
183 * which will be emitted by playbin2 when it has created the source element
184 * for a particular URI. In the signal callback you can check if the source
185 * element has a "device" property and set it appropriately. In some cases
186 * the device can also be set as part of the URI, but it depends on the
187 * elements involved if this will work or not. For example, for DVD menu
188 * playback, the following syntax might work (if the resindvd plugin is used):
189 * dvd://[/path/to/device]
192 * <title>Handling redirects</title>
194 * Some elements may post 'redirect' messages on the bus to tell the
195 * application to open another location. These are element messages containing
196 * a structure named 'redirect' along with a 'new-location' field of string
197 * type. The new location may be a relative or an absolute URI. Examples
198 * for such redirects can be found in many quicktime movie trailers.
202 * <title>Examples</title>
204 * gst-launch -v playbin2 uri=file:///path/to/somefile.avi
205 * ]| This will play back the given AVI video file, given that the video and
206 * audio decoders required to decode the content are installed. Since no
207 * special audio sink or video sink is supplied (not possible via gst-launch),
208 * playbin will try to find a suitable audio and video sink automatically
209 * using the autoaudiosink and autovideosink elements.
211 * gst-launch -v playbin2 uri=cdda://4
212 * ]| This will play back track 4 on an audio CD in your disc drive (assuming
213 * the drive is detected automatically by the plugin).
215 * gst-launch -v playbin2 uri=dvd://
216 * ]| This will play back the DVD in your disc drive (assuming
217 * the drive is detected automatically by the plugin).
225 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
226 * with newer GLib versions (>= 2.31.0) */
227 #define GLIB_DISABLE_DEPRECATION_WARNINGS
232 #include <gst/gst-i18n-plugin.h>
233 #include <gst/pbutils/pbutils.h>
234 #include <gst/interfaces/streamvolume.h>
236 #include "gstplay-enum.h"
237 #include "gstplay-marshal.h"
238 #include "gstplayback.h"
239 #include "gstplaysink.h"
240 #include "gstsubtitleoverlay.h"
242 #include "gst/glib-compat-private.h"
244 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
245 #define GST_CAT_DEFAULT gst_play_bin_debug
247 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type())
248 #define GST_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
249 #define GST_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
250 #define GST_IS_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
251 #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
253 #define VOLUME_MAX_DOUBLE 10.0
255 typedef struct _GstPlayBin GstPlayBin;
256 typedef struct _GstPlayBinClass GstPlayBinClass;
257 typedef struct _GstSourceGroup GstSourceGroup;
258 typedef struct _GstSourceSelect GstSourceSelect;
260 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
262 /* has the info for a selector and provides the link to the sink */
263 struct _GstSourceSelect
265 const gchar *media_list[8]; /* the media types for the selector */
266 SourceSelectGetMediaCapsFunc get_media_caps; /* more complex caps for the selector */
267 GstPlaySinkType type; /* the sink pad type of the selector */
269 GstElement *selector; /* the selector */
271 GstPad *srcpad; /* the source pad of the selector */
272 GstPad *sinkpad; /* the sinkpad of the sink when the selector
275 GstEvent *sinkpad_delayed_event;
276 gulong sinkpad_data_probe;
279 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
280 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
281 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
285 PLAYBIN_STREAM_AUDIO = 0,
286 PLAYBIN_STREAM_VIDEO,
291 /* a structure to hold the objects for decoding a uri and the subtitle uri
293 struct _GstSourceGroup
299 gboolean valid; /* the group has valid info to start playback */
300 gboolean active; /* the group is active */
305 GValueArray *streaminfo;
308 GPtrArray *video_channels; /* links to selector pads */
309 GPtrArray *audio_channels; /* links to selector pads */
310 GPtrArray *text_channels; /* links to selector pads */
312 GstElement *audio_sink; /* autoplugged audio and video sinks */
313 GstElement *video_sink;
315 /* uridecodebins for uri and subtitle uri */
316 GstElement *uridecodebin;
317 GstElement *suburidecodebin;
319 gboolean sub_pending;
322 gulong pad_removed_id;
323 gulong no_more_pads_id;
324 gulong notify_source_id;
326 gulong autoplug_factories_id;
327 gulong autoplug_select_id;
328 gulong autoplug_continue_id;
330 gulong sub_pad_added_id;
331 gulong sub_pad_removed_id;
332 gulong sub_no_more_pads_id;
333 gulong sub_autoplug_continue_id;
335 GMutex *stream_changed_pending_lock;
336 GList *stream_changed_pending;
338 /* selectors for different streams */
339 GstSourceSelect selector[PLAYBIN_STREAM_LAST];
342 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
343 #define GST_PLAY_BIN_LOCK(bin) (g_static_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
344 #define GST_PLAY_BIN_UNLOCK(bin) (g_static_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
346 /* lock to protect dynamic callbacks, like no-more-pads */
347 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->dyn_lock)
348 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->dyn_lock)
350 /* lock for shutdown */
351 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
353 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
355 GST_PLAY_BIN_DYN_LOCK (bin); \
356 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
357 GST_PLAY_BIN_DYN_UNLOCK (bin); \
362 /* unlock for shutdown */
363 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
364 GST_PLAY_BIN_DYN_UNLOCK (bin); \
369 * playbin element structure
375 GStaticRecMutex lock; /* to protect group switching */
377 /* the groups, we use a double buffer to switch between current and next */
378 GstSourceGroup groups[2]; /* array with group info */
379 GstSourceGroup *curr_group; /* pointer to the currently playing group */
380 GstSourceGroup *next_group; /* pointer to the next group */
383 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
384 gint current_video; /* the currently selected stream */
385 gint current_audio; /* the currently selected stream */
386 gint current_text; /* the currently selected stream */
388 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
389 guint buffer_size; /* When buffering, the max buffer size (bytes) */
392 GstPlaySink *playsink;
394 /* the last activated source */
397 /* lock protecting dynamic adding/removing */
399 /* if we are shutting down or not */
402 GMutex *elements_lock;
403 guint32 elements_cookie;
404 GList *elements; /* factories we can use for selecting elements */
406 gboolean have_selector; /* set to FALSE when we fail to create an
407 * input-selector, so that we only post a
410 GstElement *audio_sink; /* configured audio sink, or NULL */
411 GstElement *video_sink; /* configured video sink, or NULL */
412 GstElement *text_sink; /* configured text sink, or NULL */
419 } duration[5]; /* cached durations */
421 guint64 ring_buffer_max_size; /* 0 means disabled */
424 struct _GstPlayBinClass
426 GstPipelineClass parent_class;
428 /* notify app that the current uri finished decoding and it is possible to
429 * queue a new one for gapless playback */
430 void (*about_to_finish) (GstPlayBin * playbin);
432 /* notify app that number of audio/video/text streams changed */
433 void (*video_changed) (GstPlayBin * playbin);
434 void (*audio_changed) (GstPlayBin * playbin);
435 void (*text_changed) (GstPlayBin * playbin);
437 /* notify app that the tags of audio/video/text streams changed */
438 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
439 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
440 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
442 /* get audio/video/text tags for a stream */
443 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
444 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
445 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
447 /* get the last video frame and convert it to the given caps */
448 GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
450 /* get audio/video/text pad for a stream */
451 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
452 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
453 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
457 #define DEFAULT_URI NULL
458 #define DEFAULT_SUBURI NULL
459 #define DEFAULT_SOURCE NULL
460 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
461 GST_PLAY_FLAG_SOFT_VOLUME
462 #define DEFAULT_N_VIDEO 0
463 #define DEFAULT_CURRENT_VIDEO -1
464 #define DEFAULT_N_AUDIO 0
465 #define DEFAULT_CURRENT_AUDIO -1
466 #define DEFAULT_N_TEXT 0
467 #define DEFAULT_CURRENT_TEXT -1
468 #define DEFAULT_SUBTITLE_ENCODING NULL
469 #define DEFAULT_AUDIO_SINK NULL
470 #define DEFAULT_VIDEO_SINK NULL
471 #define DEFAULT_VIS_PLUGIN NULL
472 #define DEFAULT_TEXT_SINK NULL
473 #define DEFAULT_VOLUME 1.0
474 #define DEFAULT_MUTE FALSE
475 #define DEFAULT_FRAME NULL
476 #define DEFAULT_FONT_DESC NULL
477 #define DEFAULT_CONNECTION_SPEED 0
478 #define DEFAULT_BUFFER_DURATION -1
479 #define DEFAULT_BUFFER_SIZE -1
480 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
495 PROP_SUBTITLE_ENCODING,
504 PROP_CONNECTION_SPEED,
506 PROP_BUFFER_DURATION,
508 PROP_RING_BUFFER_MAX_SIZE,
515 SIGNAL_ABOUT_TO_FINISH,
516 SIGNAL_CONVERT_FRAME,
517 SIGNAL_VIDEO_CHANGED,
518 SIGNAL_AUDIO_CHANGED,
520 SIGNAL_VIDEO_TAGS_CHANGED,
521 SIGNAL_AUDIO_TAGS_CHANGED,
522 SIGNAL_TEXT_TAGS_CHANGED,
523 SIGNAL_GET_VIDEO_TAGS,
524 SIGNAL_GET_AUDIO_TAGS,
525 SIGNAL_GET_TEXT_TAGS,
526 SIGNAL_GET_VIDEO_PAD,
527 SIGNAL_GET_AUDIO_PAD,
533 static void gst_play_bin_class_init (GstPlayBinClass * klass);
534 static void gst_play_bin_init (GstPlayBin * playbin);
535 static void gst_play_bin_finalize (GObject * object);
537 static void gst_play_bin_set_property (GObject * object, guint prop_id,
538 const GValue * value, GParamSpec * spec);
539 static void gst_play_bin_get_property (GObject * object, guint prop_id,
540 GValue * value, GParamSpec * spec);
542 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
543 GstStateChange transition);
545 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
546 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
548 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
550 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
552 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
555 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
558 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
559 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
560 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
562 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
564 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
565 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
566 GstSourceGroup * group);
568 static void gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
570 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
573 static GstElementClass *parent_class;
575 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
577 #define REMOVE_SIGNAL(obj,id) \
579 g_signal_handler_disconnect (obj, id); \
584 gst_play_bin_get_type (void)
586 static GType gst_play_bin_type = 0;
588 if (!gst_play_bin_type) {
589 static const GTypeInfo gst_play_bin_info = {
590 sizeof (GstPlayBinClass),
593 (GClassInitFunc) gst_play_bin_class_init,
598 (GInstanceInitFunc) gst_play_bin_init,
601 static const GInterfaceInfo svol_info = {
605 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
606 "GstPlayBin2", &gst_play_bin_info, 0);
608 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
612 return gst_play_bin_type;
616 gst_play_bin_class_init (GstPlayBinClass * klass)
618 GObjectClass *gobject_klass;
619 GstElementClass *gstelement_klass;
620 GstBinClass *gstbin_klass;
622 gobject_klass = (GObjectClass *) klass;
623 gstelement_klass = (GstElementClass *) klass;
624 gstbin_klass = (GstBinClass *) klass;
626 parent_class = g_type_class_peek_parent (klass);
628 gobject_klass->set_property = gst_play_bin_set_property;
629 gobject_klass->get_property = gst_play_bin_get_property;
631 gobject_klass->finalize = gst_play_bin_finalize;
636 * Set the next URI that playbin will play. This property can be set from the
637 * about-to-finish signal to queue the next media file.
639 g_object_class_install_property (gobject_klass, PROP_URI,
640 g_param_spec_string ("uri", "URI", "URI of the media to play",
641 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
646 * Set the next subtitle URI that playbin will play. This property can be
647 * set from the about-to-finish signal to queue the next subtitle media file.
649 g_object_class_install_property (gobject_klass, PROP_SUBURI,
650 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
651 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
653 g_object_class_install_property (gobject_klass, PROP_SOURCE,
654 g_param_spec_object ("source", "Source", "Source element",
655 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
660 * Control the behaviour of playbin.
662 g_object_class_install_property (gobject_klass, PROP_FLAGS,
663 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
664 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
665 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
668 * GstPlayBin2:n-video
670 * Get the total number of available video streams.
672 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
673 g_param_spec_int ("n-video", "Number Video",
674 "Total number of video streams", 0, G_MAXINT, 0,
675 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
677 * GstPlayBin2:current-video
679 * Get or set the currently playing video stream. By default the first video
680 * stream with data is played.
682 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
683 g_param_spec_int ("current-video", "Current Video",
684 "Currently playing video stream (-1 = auto)",
685 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
687 * GstPlayBin2:n-audio
689 * Get the total number of available audio streams.
691 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
692 g_param_spec_int ("n-audio", "Number Audio",
693 "Total number of audio streams", 0, G_MAXINT, 0,
694 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
696 * GstPlayBin2:current-audio
698 * Get or set the currently playing audio stream. By default the first audio
699 * stream with data is played.
701 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
702 g_param_spec_int ("current-audio", "Current audio",
703 "Currently playing audio stream (-1 = auto)",
704 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
708 * Get the total number of available subtitle streams.
710 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
711 g_param_spec_int ("n-text", "Number Text",
712 "Total number of text streams", 0, G_MAXINT, 0,
713 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
715 * GstPlayBin2:current-text:
717 * Get or set the currently playing subtitle stream. By default the first
718 * subtitle stream with data is played.
720 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
721 g_param_spec_int ("current-text", "Current Text",
722 "Currently playing text stream (-1 = auto)",
723 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
725 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
726 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
727 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
728 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
729 "be checked for an encoding to use. If that is not set either, "
730 "ISO-8859-15 will be assumed.", NULL,
731 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
733 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
734 g_param_spec_object ("video-sink", "Video Sink",
735 "the video output element to use (NULL = default sink)",
736 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
737 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
738 g_param_spec_object ("audio-sink", "Audio Sink",
739 "the audio output element to use (NULL = default sink)",
740 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
741 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
742 g_param_spec_object ("vis-plugin", "Vis plugin",
743 "the visualization element to use (NULL = default)",
744 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
745 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
746 g_param_spec_object ("text-sink", "Text plugin",
747 "the text output element to use (NULL = default textoverlay)",
748 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
751 * GstPlayBin2:volume:
753 * Get or set the current audio stream volume. 1.0 means 100%,
754 * 0.0 means mute. This uses a linear volume scale.
757 g_object_class_install_property (gobject_klass, PROP_VOLUME,
758 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
759 0.0, VOLUME_MAX_DOUBLE, 1.0,
760 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
761 g_object_class_install_property (gobject_klass, PROP_MUTE,
762 g_param_spec_boolean ("mute", "Mute",
763 "Mute the audio channel without changing the volume", FALSE,
764 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
768 * @playbin: a #GstPlayBin2
770 * Get the currently rendered or prerolled frame in the video sink.
771 * The #GstCaps on the buffer will describe the format of the buffer.
773 g_object_class_install_property (gobject_klass, PROP_FRAME,
774 gst_param_spec_mini_object ("frame", "Frame",
775 "The last frame (NULL = no video available)",
776 GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
777 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
778 g_param_spec_string ("subtitle-font-desc",
779 "Subtitle font description",
780 "Pango font description of font "
781 "to be used for subtitle rendering", NULL,
782 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
784 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
785 g_param_spec_uint ("connection-speed", "Connection Speed",
786 "Network connection speed in kbps (0 = unknown)",
787 0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
788 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
790 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
791 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
792 "Buffer size when buffering network streams",
793 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
794 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
795 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
796 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
797 "Buffer duration when buffering network streams",
798 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
799 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
801 * GstPlayBin2:av-offset:
803 * Control the synchronisation offset between the audio and video streams.
804 * Positive values make the audio ahead of the video and negative values make
805 * the audio go behind the video.
809 g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
810 g_param_spec_int64 ("av-offset", "AV Offset",
811 "The synchronisation offset between audio and video in nanoseconds",
812 G_MININT64, G_MAXINT64, 0,
813 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
816 * GstQueue2:ring-buffer-max-size
818 * The maximum size of the ring buffer in bytes. If set to 0, the ring
819 * buffer is disabled. Default 0.
823 g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
824 g_param_spec_uint64 ("ring-buffer-max-size",
825 "Max. ring buffer size (bytes)",
826 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
827 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
828 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
831 * GstPlayBin2::about-to-finish
832 * @playbin: a #GstPlayBin2
834 * This signal is emitted when the current uri is about to finish. You can
835 * set the uri and suburi to make sure that playback continues.
837 * This signal is emitted from the context of a GStreamer streaming thread.
839 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
840 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
842 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
843 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
846 * GstPlayBin2::video-changed
847 * @playbin: a #GstPlayBin2
849 * This signal is emitted whenever the number or order of the video
850 * streams has changed. The application will most likely want to select
851 * a new video stream.
853 * This signal is usually emitted from the context of a GStreamer streaming
854 * thread. You can use gst_message_new_application() and
855 * gst_element_post_message() to notify your application's main thread.
857 /* FIXME 0.11: turn video-changed signal into message? */
858 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
859 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
861 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
862 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
864 * GstPlayBin2::audio-changed
865 * @playbin: a #GstPlayBin2
867 * This signal is emitted whenever the number or order of the audio
868 * streams has changed. The application will most likely want to select
869 * a new audio stream.
871 * This signal may be emitted from the context of a GStreamer streaming thread.
872 * You can use gst_message_new_application() and gst_element_post_message()
873 * to notify your application's main thread.
875 /* FIXME 0.11: turn audio-changed signal into message? */
876 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
877 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
879 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
880 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
882 * GstPlayBin2::text-changed
883 * @playbin: a #GstPlayBin2
885 * This signal is emitted whenever the number or order of the text
886 * streams has changed. The application will most likely want to select
889 * This signal may be emitted from the context of a GStreamer streaming thread.
890 * You can use gst_message_new_application() and gst_element_post_message()
891 * to notify your application's main thread.
893 /* FIXME 0.11: turn text-changed signal into message? */
894 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
895 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
897 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
898 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
901 * GstPlayBin2::video-tags-changed
902 * @playbin: a #GstPlayBin2
903 * @stream: stream index with changed tags
905 * This signal is emitted whenever the tags of a video stream have changed.
906 * The application will most likely want to get the new tags.
908 * This signal may be emitted from the context of a GStreamer streaming thread.
909 * You can use gst_message_new_application() and gst_element_post_message()
910 * to notify your application's main thread.
914 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
915 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
917 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
918 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
921 * GstPlayBin2::audio-tags-changed
922 * @playbin: a #GstPlayBin2
923 * @stream: stream index with changed tags
925 * This signal is emitted whenever the tags of an audio stream have changed.
926 * The application will most likely want to get the new tags.
928 * This signal may be emitted from the context of a GStreamer streaming thread.
929 * You can use gst_message_new_application() and gst_element_post_message()
930 * to notify your application's main thread.
934 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
935 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
937 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
938 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
941 * GstPlayBin2::text-tags-changed
942 * @playbin: a #GstPlayBin2
943 * @stream: stream index with changed tags
945 * This signal is emitted whenever the tags of a text stream have changed.
946 * The application will most likely want to get the new tags.
948 * This signal may be emitted from the context of a GStreamer streaming thread.
949 * You can use gst_message_new_application() and gst_element_post_message()
950 * to notify your application's main thread.
954 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
955 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
957 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
958 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
961 * GstPlayBin2::source-setup:
962 * @playbin: a #GstPlayBin2
963 * @source: source element
965 * This signal is emitted after the source element has been created, so
966 * it can be configured by setting additional properties (e.g. set a
967 * proxy server for an http source, or set the device and read speed for
968 * an audio cd source). This is functionally equivalent to connecting to
969 * the notify::source signal, but more convenient.
971 * This signal is usually emitted from the context of a GStreamer streaming
976 gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
977 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
978 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
979 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
982 * GstPlayBin2::get-video-tags
983 * @playbin: a #GstPlayBin2
984 * @stream: a video stream number
986 * Action signal to retrieve the tags of a specific video stream number.
987 * This information can be used to select a stream.
989 * Returns: a GstTagList with tags or NULL when the stream number does not
992 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
993 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
994 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
995 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
996 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
998 * GstPlayBin2::get-audio-tags
999 * @playbin: a #GstPlayBin2
1000 * @stream: an audio stream number
1002 * Action signal to retrieve the tags of a specific audio stream number.
1003 * This information can be used to select a stream.
1005 * Returns: a GstTagList with tags or NULL when the stream number does not
1008 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
1009 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
1010 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1011 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
1012 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1014 * GstPlayBin2::get-text-tags
1015 * @playbin: a #GstPlayBin2
1016 * @stream: a text stream number
1018 * Action signal to retrieve the tags of a specific text stream number.
1019 * This information can be used to select a stream.
1021 * Returns: a GstTagList with tags or NULL when the stream number does not
1024 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
1025 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
1026 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1027 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
1028 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1030 * GstPlayBin2::convert-frame
1031 * @playbin: a #GstPlayBin2
1032 * @caps: the target format of the frame
1034 * Action signal to retrieve the currently playing video frame in the format
1035 * specified by @caps.
1036 * If @caps is %NULL, no conversion will be performed and this function is
1037 * equivalent to the #GstPlayBin::frame property.
1039 * Returns: a #GstBuffer of the current video frame converted to #caps.
1040 * The caps on the buffer will describe the final layout of the buffer data.
1041 * %NULL is returned when no current buffer can be retrieved or when the
1042 * conversion failed.
1044 gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
1045 g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
1046 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1047 G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
1048 gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
1051 * GstPlayBin2::get-video-pad
1052 * @playbin: a #GstPlayBin2
1053 * @stream: a video stream number
1055 * Action signal to retrieve the stream-selector sinkpad for a specific
1057 * This pad can be used for notifications of caps changes, stream-specific
1060 * Returns: a #GstPad, or NULL when the stream number does not exist.
1062 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1063 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1064 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1065 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1066 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1068 * GstPlayBin2::get-audio-pad
1069 * @playbin: a #GstPlayBin2
1070 * @stream: an audio stream number
1072 * Action signal to retrieve the stream-selector sinkpad for a specific
1074 * This pad can be used for notifications of caps changes, stream-specific
1077 * Returns: a #GstPad, or NULL when the stream number does not exist.
1079 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1080 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1081 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1082 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1083 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1085 * GstPlayBin2::get-text-pad
1086 * @playbin: a #GstPlayBin2
1087 * @stream: a text stream number
1089 * Action signal to retrieve the stream-selector sinkpad for a specific
1091 * This pad can be used for notifications of caps changes, stream-specific
1094 * Returns: a #GstPad, or NULL when the stream number does not exist.
1096 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1097 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1098 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1099 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1100 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1102 klass->get_video_tags = gst_play_bin_get_video_tags;
1103 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1104 klass->get_text_tags = gst_play_bin_get_text_tags;
1106 klass->convert_frame = gst_play_bin_convert_frame;
1108 klass->get_video_pad = gst_play_bin_get_video_pad;
1109 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1110 klass->get_text_pad = gst_play_bin_get_text_pad;
1112 gst_element_class_set_details_simple (gstelement_klass,
1113 "Player Bin 2", "Generic/Bin/Player",
1114 "Autoplug and play media from an uri",
1115 "Wim Taymans <wim.taymans@gmail.com>");
1117 gstelement_klass->change_state =
1118 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1119 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1121 gstbin_klass->handle_message =
1122 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1126 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1130 /* store the array for the different channels */
1131 group->video_channels = g_ptr_array_new ();
1132 group->audio_channels = g_ptr_array_new ();
1133 group->text_channels = g_ptr_array_new ();
1134 group->lock = g_mutex_new ();
1135 /* init selectors. The selector is found by finding the first prefix that
1136 * matches the media. */
1137 group->playbin = playbin;
1138 /* If you add any items to these lists, check that media_list[] is defined
1139 * above to be large enough to hold MAX(items)+1, so as to accommodate a
1140 * NULL terminator (set when the memory is zeroed on allocation) */
1141 group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
1142 group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
1143 group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
1144 group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
1145 group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
1146 group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
1147 group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
1148 group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
1149 group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
1150 group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
1151 group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
1152 group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
1153 group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
1154 group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
1155 gst_subtitle_overlay_create_factory_caps;
1156 group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
1157 group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
1159 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1160 GstSourceSelect *select = &group->selector[n];
1161 select->sinkpad_delayed_event = NULL;
1162 select->sinkpad_data_probe = 0;
1167 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1171 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1172 GstSourceSelect *select = &group->selector[n];
1173 if (select->sinkpad && select->sinkpad_data_probe)
1174 gst_pad_remove_data_probe (select->sinkpad, select->sinkpad_data_probe);
1175 if (select->sinkpad_delayed_event)
1176 gst_event_unref (select->sinkpad_delayed_event);
1179 g_free (group->uri);
1180 g_free (group->suburi);
1181 g_ptr_array_free (group->video_channels, TRUE);
1182 g_ptr_array_free (group->audio_channels, TRUE);
1183 g_ptr_array_free (group->text_channels, TRUE);
1185 g_mutex_free (group->lock);
1186 if (group->audio_sink) {
1187 if (group->audio_sink != playbin->audio_sink)
1188 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1189 gst_object_unref (group->audio_sink);
1191 group->audio_sink = NULL;
1192 if (group->video_sink) {
1193 if (group->video_sink != playbin->video_sink)
1194 gst_element_set_state (group->video_sink, GST_STATE_NULL);
1195 gst_object_unref (group->video_sink);
1197 group->video_sink = NULL;
1199 g_list_free (group->stream_changed_pending);
1200 group->stream_changed_pending = NULL;
1202 if (group->stream_changed_pending_lock)
1203 g_mutex_free (group->stream_changed_pending_lock);
1204 group->stream_changed_pending_lock = NULL;
1208 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1210 g_object_notify (G_OBJECT (playbin), "volume");
1214 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1216 g_object_notify (G_OBJECT (playbin), "mute");
1219 /* Must be called with elements lock! */
1221 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1225 if (!playbin->elements ||
1226 playbin->elements_cookie !=
1227 gst_default_registry_get_feature_list_cookie ()) {
1228 if (playbin->elements)
1229 gst_plugin_feature_list_free (playbin->elements);
1231 gst_element_factory_list_get_elements
1232 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1234 gst_element_factory_list_get_elements
1235 (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1236 playbin->elements = g_list_concat (res, tmp);
1238 g_list_sort (playbin->elements, gst_plugin_feature_rank_compare_func);
1239 playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1244 gst_play_bin_init (GstPlayBin * playbin)
1246 g_static_rec_mutex_init (&playbin->lock);
1247 playbin->dyn_lock = g_mutex_new ();
1249 /* assume we can create a selector */
1250 playbin->have_selector = TRUE;
1253 playbin->curr_group = &playbin->groups[0];
1254 playbin->next_group = &playbin->groups[1];
1255 init_group (playbin, &playbin->groups[0]);
1256 init_group (playbin, &playbin->groups[1]);
1258 /* first filter out the interesting element factories */
1259 playbin->elements_lock = g_mutex_new ();
1262 playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1263 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1264 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1265 /* Connect to notify::volume and notify::mute signals for proxying */
1266 g_signal_connect (playbin->playsink, "notify::volume",
1267 G_CALLBACK (notify_volume_cb), playbin);
1268 g_signal_connect (playbin->playsink, "notify::mute",
1269 G_CALLBACK (notify_mute_cb), playbin);
1271 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1272 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1273 playbin->current_text = DEFAULT_CURRENT_TEXT;
1275 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1276 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1277 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1281 gst_play_bin_finalize (GObject * object)
1283 GstPlayBin *playbin;
1285 playbin = GST_PLAY_BIN (object);
1287 free_group (playbin, &playbin->groups[0]);
1288 free_group (playbin, &playbin->groups[1]);
1290 if (playbin->source)
1291 gst_object_unref (playbin->source);
1292 if (playbin->video_sink) {
1293 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1294 gst_object_unref (playbin->video_sink);
1296 if (playbin->audio_sink) {
1297 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1298 gst_object_unref (playbin->audio_sink);
1300 if (playbin->text_sink) {
1301 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1302 gst_object_unref (playbin->text_sink);
1305 if (playbin->elements)
1306 gst_plugin_feature_list_free (playbin->elements);
1308 g_static_rec_mutex_free (&playbin->lock);
1309 g_mutex_free (playbin->dyn_lock);
1310 g_mutex_free (playbin->elements_lock);
1312 G_OBJECT_CLASS (parent_class)->finalize (object);
1316 gst_playbin_uri_is_valid (GstPlayBin * playbin, const gchar * uri)
1320 GST_LOG_OBJECT (playbin, "checking uri '%s'", uri);
1322 /* this just checks the protocol */
1323 if (!gst_uri_is_valid (uri))
1326 for (c = uri; *c != '\0'; ++c) {
1327 if (!g_ascii_isprint (*c))
1337 GST_WARNING_OBJECT (playbin, "uri '%s' not valid, character #%u",
1338 uri, (guint) ((guintptr) c - (guintptr) uri));
1344 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1346 GstSourceGroup *group;
1349 g_warning ("cannot set NULL uri");
1353 if (!gst_playbin_uri_is_valid (playbin, uri)) {
1354 if (g_str_has_prefix (uri, "file:")) {
1355 GST_WARNING_OBJECT (playbin, "not entirely correct file URI '%s' - make "
1356 "sure to escape spaces and non-ASCII characters properly and specify "
1357 "an absolute path. Use gst_filename_to_uri() to convert filenames "
1360 /* GST_ERROR_OBJECT (playbin, "malformed URI '%s'", uri); */
1364 GST_PLAY_BIN_LOCK (playbin);
1365 group = playbin->next_group;
1367 GST_SOURCE_GROUP_LOCK (group);
1368 /* store the uri in the next group we will play */
1369 g_free (group->uri);
1370 group->uri = g_strdup (uri);
1371 group->valid = TRUE;
1372 GST_SOURCE_GROUP_UNLOCK (group);
1374 GST_DEBUG ("set new uri to %s", uri);
1375 GST_PLAY_BIN_UNLOCK (playbin);
1379 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1381 GstSourceGroup *group;
1383 GST_PLAY_BIN_LOCK (playbin);
1384 group = playbin->next_group;
1386 GST_SOURCE_GROUP_LOCK (group);
1387 g_free (group->suburi);
1388 group->suburi = g_strdup (suburi);
1389 GST_SOURCE_GROUP_UNLOCK (group);
1391 GST_DEBUG ("setting new .sub uri to %s", suburi);
1393 GST_PLAY_BIN_UNLOCK (playbin);
1397 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1399 gst_play_sink_set_flags (playbin->playsink, flags);
1400 gst_play_sink_reconfigure (playbin->playsink);
1404 gst_play_bin_get_flags (GstPlayBin * playbin)
1408 flags = gst_play_sink_get_flags (playbin->playsink);
1413 /* get the currently playing group or if nothing is playing, the next
1414 * group. Must be called with the PLAY_BIN_LOCK. */
1415 static GstSourceGroup *
1416 get_group (GstPlayBin * playbin)
1418 GstSourceGroup *result;
1420 if (!(result = playbin->curr_group))
1421 result = playbin->next_group;
1427 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1429 GstPad *sinkpad = NULL;
1430 GstSourceGroup *group;
1432 GST_PLAY_BIN_LOCK (playbin);
1433 group = get_group (playbin);
1434 if (stream < group->video_channels->len) {
1435 sinkpad = g_ptr_array_index (group->video_channels, stream);
1436 gst_object_ref (sinkpad);
1438 GST_PLAY_BIN_UNLOCK (playbin);
1444 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1446 GstPad *sinkpad = NULL;
1447 GstSourceGroup *group;
1449 GST_PLAY_BIN_LOCK (playbin);
1450 group = get_group (playbin);
1451 if (stream < group->audio_channels->len) {
1452 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1453 gst_object_ref (sinkpad);
1455 GST_PLAY_BIN_UNLOCK (playbin);
1461 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1463 GstPad *sinkpad = NULL;
1464 GstSourceGroup *group;
1466 GST_PLAY_BIN_LOCK (playbin);
1467 group = get_group (playbin);
1468 if (stream < group->text_channels->len) {
1469 sinkpad = g_ptr_array_index (group->text_channels, stream);
1470 gst_object_ref (sinkpad);
1472 GST_PLAY_BIN_UNLOCK (playbin);
1479 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1484 if (!channels || stream >= channels->len)
1487 sinkpad = g_ptr_array_index (channels, stream);
1488 g_object_get (sinkpad, "tags", &result, NULL);
1494 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1497 GstSourceGroup *group;
1499 GST_PLAY_BIN_LOCK (playbin);
1500 group = get_group (playbin);
1501 result = get_tags (playbin, group->video_channels, stream);
1502 GST_PLAY_BIN_UNLOCK (playbin);
1508 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1511 GstSourceGroup *group;
1513 GST_PLAY_BIN_LOCK (playbin);
1514 group = get_group (playbin);
1515 result = get_tags (playbin, group->audio_channels, stream);
1516 GST_PLAY_BIN_UNLOCK (playbin);
1522 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1525 GstSourceGroup *group;
1527 GST_PLAY_BIN_LOCK (playbin);
1528 group = get_group (playbin);
1529 result = get_tags (playbin, group->text_channels, stream);
1530 GST_PLAY_BIN_UNLOCK (playbin);
1536 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1538 return gst_play_sink_convert_frame (playbin->playsink, caps);
1541 /* Returns current stream number, or -1 if none has been selected yet */
1543 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1545 /* Internal API cleanup would make this easier... */
1547 GstPad *pad, *current;
1548 GstObject *selector = NULL;
1551 for (i = 0; i < channels->len; i++) {
1552 pad = g_ptr_array_index (channels, i);
1553 if ((selector = gst_pad_get_parent (pad))) {
1554 g_object_get (selector, "active-pad", ¤t, NULL);
1555 gst_object_unref (selector);
1557 if (pad == current) {
1558 gst_object_unref (current);
1564 gst_object_unref (current);
1572 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1574 GstSourceGroup *group;
1575 GPtrArray *channels;
1578 GST_PLAY_BIN_LOCK (playbin);
1580 GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1581 playbin->current_video, stream);
1583 group = get_group (playbin);
1584 if (!(channels = group->video_channels))
1587 if (stream == -1 || channels->len <= stream) {
1590 /* take channel from selected stream */
1591 sinkpad = g_ptr_array_index (channels, stream);
1595 gst_object_ref (sinkpad);
1596 GST_PLAY_BIN_UNLOCK (playbin);
1599 GstObject *selector;
1601 if ((selector = gst_pad_get_parent (sinkpad))) {
1602 /* activate the selected pad */
1603 g_object_set (selector, "active-pad", sinkpad, NULL);
1604 gst_object_unref (selector);
1606 gst_object_unref (sinkpad);
1612 GST_PLAY_BIN_UNLOCK (playbin);
1613 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1619 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1621 GstSourceGroup *group;
1622 GPtrArray *channels;
1625 GST_PLAY_BIN_LOCK (playbin);
1627 GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1628 playbin->current_audio, stream);
1630 group = get_group (playbin);
1631 if (!(channels = group->audio_channels))
1634 if (stream == -1 || channels->len <= stream) {
1637 /* take channel from selected stream */
1638 sinkpad = g_ptr_array_index (channels, stream);
1642 gst_object_ref (sinkpad);
1643 GST_PLAY_BIN_UNLOCK (playbin);
1646 GstObject *selector;
1648 if ((selector = gst_pad_get_parent (sinkpad))) {
1649 /* activate the selected pad */
1650 g_object_set (selector, "active-pad", sinkpad, NULL);
1651 gst_object_unref (selector);
1653 gst_object_unref (sinkpad);
1659 GST_PLAY_BIN_UNLOCK (playbin);
1660 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1666 _suburidecodebin_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
1668 GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
1672 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1674 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1677 if (it && gst_iterator_next (it, (gpointer) & sinkpad) == GST_ITERATOR_OK
1682 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1683 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1684 if (!gst_pad_send_event (sinkpad, event)) {
1686 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1687 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1688 if (!gst_pad_send_event (sinkpad, event))
1689 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1692 gst_object_unref (sinkpad);
1696 gst_iterator_free (it);
1700 gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
1703 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1704 gboolean done = FALSE;
1706 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1713 switch (gst_iterator_next (it, (gpointer) & sinkpad)) {
1714 case GST_ITERATOR_OK:
1715 gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
1717 gst_object_unref (sinkpad);
1719 case GST_ITERATOR_DONE:
1722 case GST_ITERATOR_RESYNC:
1723 gst_iterator_resync (it);
1725 case GST_ITERATOR_ERROR:
1730 gst_iterator_free (it);
1734 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1736 GstSourceGroup *group;
1737 GPtrArray *channels;
1740 GST_PLAY_BIN_LOCK (playbin);
1742 GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1743 playbin->current_text, stream);
1745 group = get_group (playbin);
1746 if (!(channels = group->text_channels))
1749 if (stream == -1 || channels->len <= stream) {
1752 /* take channel from selected stream */
1753 sinkpad = g_ptr_array_index (channels, stream);
1757 gst_object_ref (sinkpad);
1758 GST_PLAY_BIN_UNLOCK (playbin);
1761 GstObject *selector;
1763 if ((selector = gst_pad_get_parent (sinkpad))) {
1764 GstPad *old_sinkpad;
1766 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1768 if (old_sinkpad != sinkpad) {
1769 gboolean need_unblock, need_block, need_seek;
1770 GstPad *src, *peer = NULL, *oldpeer = NULL;
1771 GstElement *parent_element = NULL, *old_parent_element = NULL;
1773 /* Now check if we need to seek the suburidecodebin to the beginning
1774 * or if we need to block all suburidecodebin sinkpads or if we need
1775 * to unblock all suburidecodebin sinkpads
1778 peer = gst_pad_get_peer (sinkpad);
1780 oldpeer = gst_pad_get_peer (old_sinkpad);
1783 parent_element = gst_pad_get_parent_element (peer);
1785 old_parent_element = gst_pad_get_parent_element (oldpeer);
1787 need_block = (old_parent_element == group->suburidecodebin
1788 && parent_element != old_parent_element);
1789 need_unblock = (parent_element == group->suburidecodebin
1790 && parent_element != old_parent_element);
1791 need_seek = (parent_element == group->suburidecodebin);
1794 gst_object_unref (peer);
1796 gst_object_unref (oldpeer);
1798 gst_object_unref (parent_element);
1799 if (old_parent_element)
1800 gst_object_unref (old_parent_element);
1802 /* Block all suburidecodebin sinkpads */
1804 gst_play_bin_suburidecodebin_block (group->suburidecodebin, TRUE);
1806 /* activate the selected pad */
1807 g_object_set (selector, "active-pad", sinkpad, NULL);
1809 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1810 peer = gst_pad_get_peer (src);
1814 /* Flush the subtitle renderer to remove any
1815 * currently displayed subtitles. This event will
1816 * never travel outside subtitleoverlay!
1818 s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1819 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1820 gst_pad_send_event (peer, event);
1821 gst_object_unref (peer);
1823 gst_object_unref (src);
1825 /* Unblock pads if necessary */
1827 gst_play_bin_suburidecodebin_block (group->suburidecodebin, FALSE);
1829 /* seek to the beginning */
1831 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1833 gst_object_unref (selector);
1836 gst_object_unref (old_sinkpad);
1838 gst_object_unref (sinkpad);
1844 GST_PLAY_BIN_UNLOCK (playbin);
1850 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1851 const gchar * dbg, GstElement * sink)
1853 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1855 GST_PLAY_BIN_LOCK (playbin);
1856 if (*elem != sink) {
1861 gst_object_ref_sink (sink);
1865 gst_object_unref (old);
1867 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1868 GST_PLAY_BIN_UNLOCK (playbin);
1872 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1876 GST_PLAY_BIN_LOCK (playbin);
1878 /* set subtitles on all current and next decodebins. */
1879 if ((elem = playbin->groups[0].uridecodebin))
1880 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1881 if ((elem = playbin->groups[0].suburidecodebin))
1882 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1883 if ((elem = playbin->groups[1].uridecodebin))
1884 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1885 if ((elem = playbin->groups[1].suburidecodebin))
1886 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1888 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1889 GST_PLAY_BIN_UNLOCK (playbin);
1893 gst_play_bin_set_property (GObject * object, guint prop_id,
1894 const GValue * value, GParamSpec * pspec)
1896 GstPlayBin *playbin = GST_PLAY_BIN (object);
1900 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1903 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1906 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1908 case PROP_CURRENT_VIDEO:
1909 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1911 case PROP_CURRENT_AUDIO:
1912 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1914 case PROP_CURRENT_TEXT:
1915 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1917 case PROP_SUBTITLE_ENCODING:
1918 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1920 case PROP_VIDEO_SINK:
1921 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1922 g_value_get_object (value));
1924 case PROP_AUDIO_SINK:
1925 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1926 g_value_get_object (value));
1928 case PROP_VIS_PLUGIN:
1929 gst_play_sink_set_vis_plugin (playbin->playsink,
1930 g_value_get_object (value));
1932 case PROP_TEXT_SINK:
1933 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1934 g_value_get_object (value));
1937 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1940 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1942 case PROP_FONT_DESC:
1943 gst_play_sink_set_font_desc (playbin->playsink,
1944 g_value_get_string (value));
1946 case PROP_CONNECTION_SPEED:
1947 GST_PLAY_BIN_LOCK (playbin);
1948 playbin->connection_speed = g_value_get_uint (value) * 1000;
1949 GST_PLAY_BIN_UNLOCK (playbin);
1951 case PROP_BUFFER_SIZE:
1952 playbin->buffer_size = g_value_get_int (value);
1954 case PROP_BUFFER_DURATION:
1955 playbin->buffer_duration = g_value_get_int64 (value);
1957 case PROP_AV_OFFSET:
1958 gst_play_sink_set_av_offset (playbin->playsink,
1959 g_value_get_int64 (value));
1961 case PROP_RING_BUFFER_MAX_SIZE:
1962 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
1965 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1971 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1972 const gchar * dbg, GstPlaySinkType type)
1974 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
1976 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1977 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1978 dbg, sink, dbg, *elem);
1981 GST_PLAY_BIN_LOCK (playbin);
1983 gst_object_ref (sink);
1984 GST_PLAY_BIN_UNLOCK (playbin);
1991 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1994 GstPlayBin *playbin = GST_PLAY_BIN (object);
1999 GstSourceGroup *group;
2001 GST_PLAY_BIN_LOCK (playbin);
2002 group = get_group (playbin);
2003 g_value_set_string (value, group->uri);
2004 GST_PLAY_BIN_UNLOCK (playbin);
2009 GstSourceGroup *group;
2011 GST_PLAY_BIN_LOCK (playbin);
2012 group = get_group (playbin);
2013 g_value_set_string (value, group->suburi);
2014 GST_PLAY_BIN_UNLOCK (playbin);
2019 GST_OBJECT_LOCK (playbin);
2020 g_value_set_object (value, playbin->source);
2021 GST_OBJECT_UNLOCK (playbin);
2025 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
2029 GstSourceGroup *group;
2032 GST_PLAY_BIN_LOCK (playbin);
2033 group = get_group (playbin);
2034 n_video = (group->video_channels ? group->video_channels->len : 0);
2035 g_value_set_int (value, n_video);
2036 GST_PLAY_BIN_UNLOCK (playbin);
2039 case PROP_CURRENT_VIDEO:
2040 GST_PLAY_BIN_LOCK (playbin);
2041 g_value_set_int (value, playbin->current_video);
2042 GST_PLAY_BIN_UNLOCK (playbin);
2046 GstSourceGroup *group;
2049 GST_PLAY_BIN_LOCK (playbin);
2050 group = get_group (playbin);
2051 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
2052 g_value_set_int (value, n_audio);
2053 GST_PLAY_BIN_UNLOCK (playbin);
2056 case PROP_CURRENT_AUDIO:
2057 GST_PLAY_BIN_LOCK (playbin);
2058 g_value_set_int (value, playbin->current_audio);
2059 GST_PLAY_BIN_UNLOCK (playbin);
2063 GstSourceGroup *group;
2066 GST_PLAY_BIN_LOCK (playbin);
2067 group = get_group (playbin);
2068 n_text = (group->text_channels ? group->text_channels->len : 0);
2069 g_value_set_int (value, n_text);
2070 GST_PLAY_BIN_UNLOCK (playbin);
2073 case PROP_CURRENT_TEXT:
2074 GST_PLAY_BIN_LOCK (playbin);
2075 g_value_set_int (value, playbin->current_text);
2076 GST_PLAY_BIN_UNLOCK (playbin);
2078 case PROP_SUBTITLE_ENCODING:
2079 GST_PLAY_BIN_LOCK (playbin);
2080 g_value_take_string (value,
2081 gst_play_sink_get_subtitle_encoding (playbin->playsink));
2082 GST_PLAY_BIN_UNLOCK (playbin);
2084 case PROP_VIDEO_SINK:
2085 g_value_take_object (value,
2086 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2087 "video", GST_PLAY_SINK_TYPE_VIDEO));
2089 case PROP_AUDIO_SINK:
2090 g_value_take_object (value,
2091 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2092 "audio", GST_PLAY_SINK_TYPE_AUDIO));
2094 case PROP_VIS_PLUGIN:
2095 g_value_take_object (value,
2096 gst_play_sink_get_vis_plugin (playbin->playsink));
2098 case PROP_TEXT_SINK:
2099 g_value_take_object (value,
2100 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2101 "text", GST_PLAY_SINK_TYPE_TEXT));
2104 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2107 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2110 gst_value_take_buffer (value,
2111 gst_play_sink_get_last_frame (playbin->playsink));
2113 case PROP_FONT_DESC:
2114 g_value_take_string (value,
2115 gst_play_sink_get_font_desc (playbin->playsink));
2117 case PROP_CONNECTION_SPEED:
2118 GST_PLAY_BIN_LOCK (playbin);
2119 g_value_set_uint (value, playbin->connection_speed / 1000);
2120 GST_PLAY_BIN_UNLOCK (playbin);
2122 case PROP_BUFFER_SIZE:
2123 GST_OBJECT_LOCK (playbin);
2124 g_value_set_int (value, playbin->buffer_size);
2125 GST_OBJECT_UNLOCK (playbin);
2127 case PROP_BUFFER_DURATION:
2128 GST_OBJECT_LOCK (playbin);
2129 g_value_set_int64 (value, playbin->buffer_duration);
2130 GST_OBJECT_UNLOCK (playbin);
2132 case PROP_AV_OFFSET:
2133 g_value_set_int64 (value,
2134 gst_play_sink_get_av_offset (playbin->playsink));
2136 case PROP_RING_BUFFER_MAX_SIZE:
2137 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2140 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2146 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2147 gboolean valid, GstQuery * query)
2153 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2154 gst_query_parse_duration (query, &fmt, &duration);
2156 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2157 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2158 playbin->duration[i].valid = valid;
2159 playbin->duration[i].format = fmt;
2160 playbin->duration[i].duration = valid ? duration : -1;
2167 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2169 const GstFormat formats[] =
2170 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2175 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2176 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2177 query = gst_query_new_duration (formats[i]);
2179 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2181 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2182 gst_query_unref (query);
2187 gst_play_bin_query (GstElement * element, GstQuery * query)
2189 GstPlayBin *playbin = GST_PLAY_BIN (element);
2192 /* During a group switch we shouldn't allow duration queries
2193 * because it's not clear if the old or new group's duration
2194 * is returned and if the sinks are already playing new data
2195 * or old data. See bug #585969
2197 * While we're at it, also don't do any other queries during
2198 * a group switch or any other event that causes topology changes
2199 * by taking the playbin lock in any case.
2201 GST_PLAY_BIN_LOCK (playbin);
2203 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2204 GstSourceGroup *group = playbin->curr_group;
2207 GST_SOURCE_GROUP_LOCK (group);
2208 if (group->stream_changed_pending_lock) {
2209 g_mutex_lock (group->stream_changed_pending_lock);
2210 pending = group->pending || group->stream_changed_pending;
2211 g_mutex_unlock (group->stream_changed_pending_lock);
2213 pending = group->pending;
2220 gst_query_parse_duration (query, &fmt, NULL);
2221 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2222 if (fmt == playbin->duration[i].format) {
2223 ret = playbin->duration[i].valid;
2224 gst_query_set_duration (query, fmt,
2225 (ret ? playbin->duration[i].duration : -1));
2229 /* if nothing cached yet, we might as well request duration,
2230 * such as during initial startup */
2232 GST_DEBUG_OBJECT (playbin,
2233 "Taking cached duration because of pending group switch: %d", ret);
2234 GST_SOURCE_GROUP_UNLOCK (group);
2235 GST_PLAY_BIN_UNLOCK (playbin);
2239 GST_SOURCE_GROUP_UNLOCK (group);
2242 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2244 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2245 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2246 GST_PLAY_BIN_UNLOCK (playbin);
2251 /* mime types we are not handling on purpose right now, don't post a
2252 * missing-plugin message for these */
2253 static const gchar *blacklisted_mimes[] = {
2258 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2260 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2261 GstSourceGroup *group;
2263 if (gst_is_missing_plugin_message (msg)) {
2267 detail = gst_missing_plugin_message_get_installer_detail (msg);
2268 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2269 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2270 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2271 gst_message_unref (msg);
2277 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2278 const GstStructure *s = gst_message_get_structure (msg);
2280 /* Drop all stream-changed messages except the last one */
2281 if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2282 guint32 seqnum = gst_message_get_seqnum (msg);
2285 group = playbin->curr_group;
2286 g_mutex_lock (group->stream_changed_pending_lock);
2287 for (l = group->stream_changed_pending; l;) {
2288 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2290 if (l_seqnum == seqnum) {
2293 group->stream_changed_pending =
2294 g_list_delete_link (group->stream_changed_pending, l_prev);
2295 if (group->stream_changed_pending) {
2296 gst_message_unref (msg);
2304 g_mutex_unlock (group->stream_changed_pending_lock);
2306 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2307 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2308 GstObject *src = GST_OBJECT_CAST (msg->src);
2310 /* Ignore async state changes from the uridecodebin children,
2311 * see bug #602000. */
2312 group = playbin->curr_group;
2313 if (src && (group = playbin->curr_group) &&
2314 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2315 || (group->suburidecodebin
2316 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2317 GST_DEBUG_OBJECT (playbin,
2318 "Ignoring async state change of uridecodebin: %s",
2319 GST_OBJECT_NAME (src));
2320 gst_message_unref (msg);
2323 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2324 /* If we get an error of the subtitle uridecodebin transform
2325 * them into warnings and disable the subtitles */
2326 group = playbin->curr_group;
2327 if (group && group->suburidecodebin) {
2328 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2329 (group->suburidecodebin)))) {
2331 gchar *debug = NULL;
2332 GstMessage *new_msg;
2334 gboolean done = FALSE;
2336 gst_message_parse_error (msg, &err, &debug);
2337 new_msg = gst_message_new_warning (msg->src, err, debug);
2339 gst_message_unref (msg);
2344 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2345 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2346 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2347 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2349 it = gst_element_iterate_src_pads (group->suburidecodebin);
2350 while (it && !done) {
2352 GstIteratorResult res;
2354 res = gst_iterator_next (it, (gpointer) & p);
2357 case GST_ITERATOR_DONE:
2360 case GST_ITERATOR_OK:
2361 pad_removed_cb (NULL, p, group);
2362 gst_object_unref (p);
2365 case GST_ITERATOR_RESYNC:
2366 gst_iterator_resync (it);
2368 case GST_ITERATOR_ERROR:
2374 gst_iterator_free (it);
2376 gst_object_ref (group->suburidecodebin);
2377 gst_bin_remove (bin, group->suburidecodebin);
2378 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2380 if (group->sub_pending) {
2381 group->sub_pending = FALSE;
2382 no_more_pads_cb (NULL, group);
2389 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2393 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2394 GstPlayBin * playbin)
2396 const gchar *property;
2397 GstSourceGroup *group;
2398 GstSourceSelect *select = NULL;
2401 GST_PLAY_BIN_LOCK (playbin);
2402 group = get_group (playbin);
2404 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2405 if (selector == G_OBJECT (group->selector[i].selector)) {
2406 select = &group->selector[i];
2410 /* We got a pad-change after our group got switched out; no need to notify */
2412 GST_PLAY_BIN_UNLOCK (playbin);
2416 switch (select->type) {
2417 case GST_PLAY_SINK_TYPE_VIDEO:
2418 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2419 property = "current-video";
2420 playbin->current_video = get_current_stream_number (playbin,
2421 group->video_channels);
2423 case GST_PLAY_SINK_TYPE_AUDIO:
2424 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2425 property = "current-audio";
2426 playbin->current_audio = get_current_stream_number (playbin,
2427 group->audio_channels);
2429 case GST_PLAY_SINK_TYPE_TEXT:
2430 property = "current-text";
2431 playbin->current_text = get_current_stream_number (playbin,
2432 group->text_channels);
2437 GST_PLAY_BIN_UNLOCK (playbin);
2440 g_object_notify (G_OBJECT (playbin), property);
2444 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
2447 GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
2450 /* this callback sends a delayed event once the pad becomes unblocked */
2452 stream_changed_data_probe (GstPad * pad, GstMiniObject * object, gpointer data)
2454 GstSourceSelect *select = (GstSourceSelect *) data;
2457 /* we need do this just once, so cleanup first */
2458 gst_pad_remove_data_probe (pad, select->sinkpad_data_probe);
2459 select->sinkpad_data_probe = 0;
2460 e = select->sinkpad_delayed_event;
2461 select->sinkpad_delayed_event = NULL;
2463 /* really, this should not happen */
2465 GST_WARNING ("Data probed called, but no delayed event");
2469 if (GST_IS_EVENT (object)
2470 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_NEWSEGMENT) {
2471 /* push the event first, then send the delayed one */
2472 gst_event_ref (GST_EVENT_CAST (object));
2473 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2474 gst_pad_send_event (pad, e);
2477 /* send delayed event, then allow the caller to go on */
2478 gst_pad_send_event (pad, e);
2483 /* helper function to lookup stuff in lists */
2485 array_has_value (const gchar * values[], const gchar * value, gboolean exact)
2489 for (i = 0; values[i]; i++) {
2490 if (exact && !strcmp (value, values[i]))
2492 if (!exact && g_str_has_prefix (value, values[i]))
2500 GstPlayBin *playbin;
2502 GstPlaySinkType type;
2506 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2508 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2511 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2512 " with stream id %d and type %d have changed",
2513 object, ntdata->stream_id, ntdata->type);
2515 switch (ntdata->type) {
2516 case GST_PLAY_SINK_TYPE_VIDEO:
2517 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2518 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2520 case GST_PLAY_SINK_TYPE_AUDIO:
2521 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2522 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2524 case GST_PLAY_SINK_TYPE_TEXT:
2525 signal = SIGNAL_TEXT_TAGS_CHANGED;
2533 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2537 /* this function is called when a new pad is added to decodebin. We check the
2538 * type of the pad and add it to the selector element of the group.
2541 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2543 GstPlayBin *playbin;
2545 const GstStructure *s;
2548 GstPadLinkReturn res;
2549 GstSourceSelect *select = NULL;
2551 gboolean changed = FALSE;
2553 playbin = group->playbin;
2555 caps = gst_pad_get_caps_reffed (pad);
2556 s = gst_caps_get_structure (caps, 0);
2557 name = gst_structure_get_name (s);
2559 GST_DEBUG_OBJECT (playbin,
2560 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2561 GST_DEBUG_PAD_NAME (pad), caps, group);
2563 /* major type of the pad, this determines the selector to use,
2564 try exact match first so we don't prematurely match video/
2565 for video/x-dvd-subpicture */
2566 for (pass = 0; !select && pass < 2; pass++) {
2567 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2568 if (array_has_value (group->selector[i].media_list, name, pass == 0)) {
2569 select = &group->selector[i];
2571 } else if (group->selector[i].get_media_caps) {
2572 GstCaps *media_caps = group->selector[i].get_media_caps ();
2574 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2575 select = &group->selector[i];
2576 gst_caps_unref (media_caps);
2579 gst_caps_unref (media_caps);
2583 /* no selector found for the media type, don't bother linking it to a
2584 * selector. This will leave the pad unlinked and thus ignored. */
2588 GST_SOURCE_GROUP_LOCK (group);
2589 if (select->selector == NULL && playbin->have_selector) {
2590 /* no selector, create one */
2591 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2592 select->selector = gst_element_factory_make ("input-selector", NULL);
2593 if (select->selector == NULL) {
2594 /* post the missing selector message only once */
2595 playbin->have_selector = FALSE;
2596 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2597 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2599 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2600 (_("Missing element '%s' - check your GStreamer installation."),
2601 "input-selector"), (NULL));
2603 g_object_set (select->selector, "sync-streams", TRUE, NULL);
2605 g_signal_connect (select->selector, "notify::active-pad",
2606 G_CALLBACK (selector_active_pad_changed), playbin);
2608 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2609 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2610 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2614 if (select->srcpad == NULL) {
2615 if (select->selector) {
2616 /* save source pad of the selector */
2617 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2619 /* no selector, use the pad as the source pad then */
2620 select->srcpad = gst_object_ref (pad);
2623 /* block the selector srcpad. It's possible that multiple decodebins start
2624 * pushing data into the selectors before we have a chance to collect all
2625 * streams and connect the sinks, resulting in not-linked errors. After we
2626 * configured the sinks we will unblock them all. */
2627 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2628 gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
2631 /* get sinkpad for the new stream */
2632 if (select->selector) {
2633 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2634 gulong notify_tags_handler = 0;
2635 NotifyTagsData *ntdata;
2637 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2638 GST_DEBUG_PAD_NAME (sinkpad));
2640 /* store the selector for the pad */
2641 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2643 /* connect to the notify::tags signal for our
2644 * own *-tags-changed signals
2646 ntdata = g_new0 (NotifyTagsData, 1);
2647 ntdata->playbin = playbin;
2648 ntdata->stream_id = select->channels->len;
2649 ntdata->type = select->type;
2651 notify_tags_handler =
2652 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2653 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2655 g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2656 (gpointer) (guintptr) notify_tags_handler);
2658 /* store the pad in the array */
2659 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2660 g_ptr_array_add (select->channels, sinkpad);
2662 res = gst_pad_link (pad, sinkpad);
2663 if (GST_PAD_LINK_FAILED (res))
2666 /* store selector pad so we can release it */
2667 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2670 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2671 GST_DEBUG_PAD_NAME (pad), select->selector);
2674 /* no selector, don't configure anything, we'll link the new pad directly to
2679 GST_SOURCE_GROUP_UNLOCK (group);
2683 gboolean always_ok = (decodebin == group->suburidecodebin);
2685 switch (select->type) {
2686 case GST_PLAY_SINK_TYPE_VIDEO:
2687 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2688 /* we want to return NOT_LINKED for unselected pads but only for pads
2689 * from the normal uridecodebin. This makes sure that subtitle streams
2690 * are not raced past audio/video from decodebin2's multiqueue.
2691 * For pads from suburidecodebin OK should always be returned, otherwise
2692 * it will most likely stop. */
2693 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2694 signal = SIGNAL_VIDEO_CHANGED;
2696 case GST_PLAY_SINK_TYPE_AUDIO:
2697 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2698 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2699 signal = SIGNAL_AUDIO_CHANGED;
2701 case GST_PLAY_SINK_TYPE_TEXT:
2702 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2703 signal = SIGNAL_TEXT_CHANGED;
2710 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2714 gst_caps_unref (caps);
2720 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2721 name, GST_DEBUG_PAD_NAME (pad));
2726 GST_ERROR_OBJECT (playbin,
2727 "failed to link pad %s:%s to selector, reason %d",
2728 GST_DEBUG_PAD_NAME (pad), res);
2729 GST_SOURCE_GROUP_UNLOCK (group);
2734 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2735 * the selector. This will make the selector select a new pad. */
2737 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2739 GstPlayBin *playbin;
2741 GstElement *selector;
2742 GstSourceSelect *select;
2744 playbin = group->playbin;
2746 GST_DEBUG_OBJECT (playbin,
2747 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2749 GST_SOURCE_GROUP_LOCK (group);
2750 /* get the selector sinkpad */
2751 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2754 if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2755 gulong notify_tags_handler;
2757 notify_tags_handler =
2758 (guintptr) g_object_get_data (G_OBJECT (peer),
2759 "playbin2.notify_tags_handler");
2760 if (notify_tags_handler != 0)
2761 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2762 g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2764 /* remove the pad from the array */
2765 g_ptr_array_remove (select->channels, peer);
2766 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2769 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2770 gst_pad_unlink (pad, peer);
2772 /* get selector, this can be NULL when the element is removing the pads
2773 * because it's being disposed. */
2774 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2776 gst_object_unref (peer);
2780 /* release the pad to the selector, this will make the selector choose a new
2782 gst_element_release_request_pad (selector, peer);
2783 gst_object_unref (peer);
2785 gst_object_unref (selector);
2786 GST_SOURCE_GROUP_UNLOCK (group);
2793 GST_DEBUG_OBJECT (playbin, "pad not linked");
2794 GST_SOURCE_GROUP_UNLOCK (group);
2799 GST_DEBUG_OBJECT (playbin, "selector not found");
2800 GST_SOURCE_GROUP_UNLOCK (group);
2805 /* we get called when all pads are available and we must connect the sinks to
2807 * The main purpose of the code is to see if we have video/audio and subtitles
2808 * and pick the right pipelines to display them.
2810 * The selectors installed on the group tell us about the presence of
2811 * audio/video and subtitle streams. This allows us to see if we need
2812 * visualisation, video or/and audio.
2815 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2817 GstPlayBin *playbin;
2818 GstPadLinkReturn res;
2822 playbin = group->playbin;
2824 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2826 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2828 GST_SOURCE_GROUP_LOCK (group);
2829 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2830 GstSourceSelect *select = &group->selector[i];
2832 /* check if the specific media type was detected and thus has a selector
2833 * created for it. If there is the media type, get a sinkpad from the sink
2834 * and link it. We only do this if we have not yet requested the sinkpad
2836 if (select->srcpad && select->sinkpad == NULL) {
2837 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2839 gst_play_sink_request_pad (playbin->playsink, select->type);
2841 res = gst_pad_link (select->srcpad, select->sinkpad);
2842 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2843 select->media_list[0], res);
2844 if (res != GST_PAD_LINK_OK) {
2845 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2846 ("Internal playbin error."),
2847 ("Failed to link selector to sink. Error %d", res));
2851 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2852 group->pending - 1);
2854 if (group->pending > 0)
2857 if (group->suburidecodebin == decodebin)
2858 group->sub_pending = FALSE;
2860 if (group->pending == 0) {
2861 /* we are the last group to complete, we will configure the output and then
2862 * signal the other waiters. */
2863 GST_LOG_OBJECT (playbin, "last group complete");
2866 GST_LOG_OBJECT (playbin, "have more pending groups");
2869 GST_SOURCE_GROUP_UNLOCK (group);
2872 /* if we have custom sinks, configure them now */
2873 GST_SOURCE_GROUP_LOCK (group);
2875 if (group->audio_sink) {
2876 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2878 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2882 if (group->video_sink) {
2883 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2885 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2889 if (playbin->text_sink) {
2890 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
2891 playbin->text_sink);
2892 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2893 playbin->text_sink);
2896 GST_SOURCE_GROUP_UNLOCK (group);
2898 /* signal the other decodebins that they can continue now. */
2899 GST_SOURCE_GROUP_LOCK (group);
2900 /* unblock all selectors */
2901 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2902 GstSourceSelect *select = &group->selector[i];
2904 /* All streamsynchronizer streams should see stream-changed message,
2905 * to arrange for blocking unblocking. */
2906 if (select->sinkpad) {
2912 s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2915 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2916 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2917 seqnum = gst_message_get_seqnum (msg);
2918 event = gst_event_new_sink_message (msg);
2919 g_mutex_lock (group->stream_changed_pending_lock);
2920 group->stream_changed_pending =
2921 g_list_prepend (group->stream_changed_pending,
2922 GUINT_TO_POINTER (seqnum));
2924 /* remove any data probe we might have, and replace */
2925 if (select->sinkpad_delayed_event)
2926 gst_event_unref (select->sinkpad_delayed_event);
2927 select->sinkpad_delayed_event = event;
2928 if (select->sinkpad_data_probe)
2929 gst_pad_remove_data_probe (select->sinkpad,
2930 select->sinkpad_data_probe);
2932 /* we go to the trouble of setting a probe on the pad to send
2933 the playbin2-stream-changed event as sending it here might
2934 find that the pad is blocked, so we'd block here, and the
2935 pad might not be linked yet. Additionally, sending it here
2936 apparently would be on the wrong thread */
2937 select->sinkpad_data_probe =
2938 gst_pad_add_data_probe (select->sinkpad,
2939 (GCallback) stream_changed_data_probe, (gpointer) select);
2941 g_mutex_unlock (group->stream_changed_pending_lock);
2942 gst_message_unref (msg);
2945 if (select->srcpad) {
2946 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2948 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2952 GST_SOURCE_GROUP_UNLOCK (group);
2955 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2961 GST_DEBUG ("ignoring, we are shutting down");
2962 /* Request a flushing pad from playsink that we then link to the selector.
2963 * Then we unblock the selectors so that they stop with a WRONG_STATE
2964 * instead of a NOT_LINKED error.
2966 GST_SOURCE_GROUP_LOCK (group);
2967 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2968 GstSourceSelect *select = &group->selector[i];
2970 if (select->srcpad) {
2971 if (select->sinkpad == NULL) {
2972 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2974 gst_play_sink_request_pad (playbin->playsink,
2975 GST_PLAY_SINK_TYPE_FLUSHING);
2976 res = gst_pad_link (select->srcpad, select->sinkpad);
2977 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2979 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2981 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2985 GST_SOURCE_GROUP_UNLOCK (group);
2991 drained_cb (GstElement * decodebin, GstSourceGroup * group)
2993 GstPlayBin *playbin;
2995 playbin = group->playbin;
2997 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
2999 /* after this call, we should have a next group to activate or we EOS */
3000 g_signal_emit (G_OBJECT (playbin),
3001 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
3003 /* now activate the next group. If the app did not set a uri, this will
3004 * fail and we can do EOS */
3005 setup_next_source (playbin, GST_STATE_PAUSED);
3008 /* Like gst_element_factory_can_sink_any_caps() but doesn't
3009 * allow ANY caps on the sinkpad template */
3011 _factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps)
3013 const GList *templs;
3015 templs = gst_element_factory_get_static_pad_templates (factory);
3018 GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
3020 if (templ->direction == GST_PAD_SINK) {
3021 GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
3023 if (!gst_caps_is_any (templcaps)
3024 && gst_caps_can_intersect (templcaps, caps)) {
3025 gst_caps_unref (templcaps);
3028 gst_caps_unref (templcaps);
3030 templs = g_list_next (templs);
3036 /* Called when we must provide a list of factories to plug to @pad with @caps.
3037 * We first check if we have a sink that can handle the format and if we do, we
3038 * return NULL, to expose the pad. If we have no sink (or the sink does not
3039 * work), we return the list of elements that can connect. */
3040 static GValueArray *
3041 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
3042 GstCaps * caps, GstSourceGroup * group)
3044 GstPlayBin *playbin;
3045 GList *mylist, *tmp;
3046 GValueArray *result;
3048 playbin = group->playbin;
3050 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
3051 group, GST_DEBUG_PAD_NAME (pad), caps);
3053 /* filter out the elements based on the caps. */
3054 g_mutex_lock (playbin->elements_lock);
3055 gst_play_bin_update_elements_list (playbin);
3057 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
3059 g_mutex_unlock (playbin->elements_lock);
3061 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
3062 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
3064 /* 2 additional elements for the already set audio/video sinks */
3065 result = g_value_array_new (g_list_length (mylist) + 2);
3067 /* Check if we already have an audio/video sink and if this is the case
3068 * put it as the first element of the array */
3069 if (group->audio_sink) {
3070 GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
3072 if (factory && _factory_can_sink_caps (factory, caps)) {
3073 GValue val = { 0, };
3075 g_value_init (&val, G_TYPE_OBJECT);
3076 g_value_set_object (&val, factory);
3077 result = g_value_array_append (result, &val);
3078 g_value_unset (&val);
3082 if (group->video_sink) {
3083 GstElementFactory *factory = gst_element_get_factory (group->video_sink);
3085 if (factory && _factory_can_sink_caps (factory, caps)) {
3086 GValue val = { 0, };
3088 g_value_init (&val, G_TYPE_OBJECT);
3089 g_value_set_object (&val, factory);
3090 result = g_value_array_append (result, &val);
3091 g_value_unset (&val);
3095 for (tmp = mylist; tmp; tmp = tmp->next) {
3096 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
3097 GValue val = { 0, };
3099 if (group->audio_sink && gst_element_factory_list_is_type (factory,
3100 GST_ELEMENT_FACTORY_TYPE_SINK |
3101 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
3104 if (group->video_sink && gst_element_factory_list_is_type (factory,
3105 GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
3106 | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
3110 g_value_init (&val, G_TYPE_OBJECT);
3111 g_value_set_object (&val, factory);
3112 g_value_array_append (result, &val);
3113 g_value_unset (&val);
3115 gst_plugin_feature_list_free (mylist);
3120 /* autoplug-continue decides, if a pad has raw caps that can be exposed
3121 * directly or if further decoding is necessary. We use this to expose
3122 * supported subtitles directly */
3124 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
3125 * explicitly the caps it supports and if it claims to support ANY
3126 * caps it really should support everything */
3128 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
3129 GstSourceGroup * group)
3131 gboolean ret = TRUE;
3133 GstPad *sinkpad = NULL;
3135 GST_PLAY_BIN_LOCK (group->playbin);
3136 GST_SOURCE_GROUP_LOCK (group);
3138 if ((sink = group->playbin->text_sink))
3139 sinkpad = gst_element_get_static_pad (sink, "sink");
3143 /* Ignore errors here, if a custom sink fails to go
3144 * to READY things are wrong and will error out later
3146 if (GST_STATE (sink) < GST_STATE_READY)
3147 gst_element_set_state (sink, GST_STATE_READY);
3149 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3150 if (!gst_caps_is_any (sinkcaps))
3151 ret = !gst_pad_accept_caps (sinkpad, caps);
3152 gst_caps_unref (sinkcaps);
3153 gst_object_unref (sinkpad);
3155 GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3156 ret = !gst_caps_is_subset (caps, subcaps);
3157 gst_caps_unref (subcaps);
3159 /* If autoplugging can stop don't do additional checks */
3163 /* If this is from the subtitle uridecodebin we don't need to
3164 * check the audio and video sink */
3165 if (group->suburidecodebin
3166 && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3167 GST_OBJECT_CAST (group->suburidecodebin)))
3170 if ((sink = group->audio_sink)) {
3171 sinkpad = gst_element_get_static_pad (sink, "sink");
3175 /* Ignore errors here, if a custom sink fails to go
3176 * to READY things are wrong and will error out later
3178 if (GST_STATE (sink) < GST_STATE_READY)
3179 gst_element_set_state (sink, GST_STATE_READY);
3181 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3182 if (!gst_caps_is_any (sinkcaps))
3183 ret = !gst_pad_accept_caps (sinkpad, caps);
3184 gst_caps_unref (sinkcaps);
3185 gst_object_unref (sinkpad);
3191 if ((sink = group->video_sink)) {
3192 sinkpad = gst_element_get_static_pad (sink, "sink");
3196 /* Ignore errors here, if a custom sink fails to go
3197 * to READY things are wrong and will error out later
3199 if (GST_STATE (sink) < GST_STATE_READY)
3200 gst_element_set_state (sink, GST_STATE_READY);
3202 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3203 if (!gst_caps_is_any (sinkcaps))
3204 ret = !gst_pad_accept_caps (sinkpad, caps);
3205 gst_caps_unref (sinkcaps);
3206 gst_object_unref (sinkpad);
3211 GST_SOURCE_GROUP_UNLOCK (group);
3212 GST_PLAY_BIN_UNLOCK (group->playbin);
3214 GST_DEBUG_OBJECT (group->playbin,
3215 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3216 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3222 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3226 /* ... activate it ... We do this before adding it to the bin so that we
3227 * don't accidentally make it post error messages that will stop
3229 if (GST_STATE (sink) < GST_STATE_READY &&
3230 gst_element_set_state (sink,
3231 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3235 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3236 /* Got the sink pad, now let's see if the element actually does accept the
3237 * caps that we have */
3238 if (!gst_pad_accept_caps (sinkpad, caps)) {
3239 gst_object_unref (sinkpad);
3242 gst_object_unref (sinkpad);
3248 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw-int; "
3249 "audio/x-raw-float");
3250 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw-rgb; "
3251 "video/x-raw-yuv; " "video/x-raw-gray");
3253 /* We are asked to select an element. See if the next element to check
3254 * is a sink. If this is the case, we see if the sink works by setting it to
3255 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3256 * expose the raw pad so that we can setup the mixers. */
3257 static GstAutoplugSelectResult
3258 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3259 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3261 GstPlayBin *playbin;
3262 GstElement *element;
3264 GstPlaySinkType type;
3267 playbin = group->playbin;
3269 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3270 group, GST_DEBUG_PAD_NAME (pad), caps);
3272 GST_DEBUG_OBJECT (playbin, "checking factory %s",
3273 GST_PLUGIN_FEATURE_NAME (factory));
3275 /* if it's not a sink, we make sure the element is compatible with
3277 if (!gst_element_factory_list_is_type (factory,
3278 GST_ELEMENT_FACTORY_TYPE_SINK)) {
3279 gboolean isvideodec = gst_element_factory_list_is_type (factory,
3280 GST_ELEMENT_FACTORY_TYPE_DECODER |
3281 GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
3282 GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
3283 gboolean isaudiodec = gst_element_factory_list_is_type (factory,
3284 GST_ELEMENT_FACTORY_TYPE_DECODER |
3285 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
3287 /* If it is a decoder and we have a fixed sink for the media
3288 * type it outputs, check that the decoder is compatible with this sink */
3289 if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) {
3290 gboolean compatible = TRUE;
3296 sink = group->audio_sink;
3298 sink = group->video_sink;
3300 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3301 GstPlayFlags flags = gst_play_bin_get_flags (playbin);
3303 (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) :
3304 gst_static_caps_get (&raw_video_caps);
3306 caps = gst_pad_get_caps_reffed (sinkpad);
3308 /* If the sink supports raw audio/video, we first check
3309 * if the decoder could output any raw audio/video format
3310 * and assume it is compatible with the sink then. We don't
3311 * do a complete compatibility check here if converters
3312 * are plugged between the decoder and the sink because
3313 * the converters will convert between raw formats and
3314 * even if the decoder format is not supported by the decoder
3315 * a converter will convert it.
3317 * We assume here that the converters can convert between
3320 if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO)
3321 && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec
3322 && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO)
3323 && gst_caps_can_intersect (caps, raw_caps))) {
3324 compatible = gst_element_factory_can_src_any_caps (factory, raw_caps)
3325 || gst_element_factory_can_src_any_caps (factory, caps);
3327 compatible = gst_element_factory_can_src_any_caps (factory, caps);
3330 gst_object_unref (sinkpad);
3331 gst_caps_unref (caps);
3335 return GST_AUTOPLUG_SELECT_TRY;
3337 GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink",
3338 GST_PLUGIN_FEATURE_NAME (factory));
3340 return GST_AUTOPLUG_SELECT_SKIP;
3342 return GST_AUTOPLUG_SELECT_TRY;
3345 /* it's a sink, see if an instance of it actually works */
3346 GST_DEBUG_OBJECT (playbin, "we found a sink");
3348 klass = gst_element_factory_get_klass (factory);
3350 /* figure out the klass */
3351 if (strstr (klass, "Audio")) {
3352 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3353 type = GST_PLAY_SINK_TYPE_AUDIO;
3354 sinkp = &group->audio_sink;
3355 } else if (strstr (klass, "Video")) {
3356 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3357 type = GST_PLAY_SINK_TYPE_VIDEO;
3358 sinkp = &group->video_sink;
3360 /* unknown klass, skip this element */
3361 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3362 return GST_AUTOPLUG_SELECT_SKIP;
3365 /* if we are asked to do visualisations and it's an audio sink, skip the
3366 * element. We can only do visualisations with raw sinks */
3367 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3368 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3369 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3370 return GST_AUTOPLUG_SELECT_SKIP;
3374 /* now see if we already have a sink element */
3375 GST_SOURCE_GROUP_LOCK (group);
3377 GstElement *sink = gst_object_ref (*sinkp);
3379 if (sink_accepts_caps (sink, caps)) {
3380 GST_DEBUG_OBJECT (playbin,
3381 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3382 GST_ELEMENT_NAME (sink), caps);
3383 gst_object_unref (sink);
3384 GST_SOURCE_GROUP_UNLOCK (group);
3385 return GST_AUTOPLUG_SELECT_EXPOSE;
3387 GST_DEBUG_OBJECT (playbin,
3388 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3389 GST_ELEMENT_NAME (sink), caps);
3390 gst_object_unref (sink);
3391 GST_SOURCE_GROUP_UNLOCK (group);
3392 return GST_AUTOPLUG_SELECT_SKIP;
3395 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3397 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3398 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3399 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3400 GST_SOURCE_GROUP_UNLOCK (group);
3401 return GST_AUTOPLUG_SELECT_SKIP;
3404 /* Check if the selected sink actually supports the
3405 * caps and can be set to READY*/
3406 if (!sink_accepts_caps (element, caps)) {
3407 gst_element_set_state (element, GST_STATE_NULL);
3408 gst_object_unref (element);
3409 GST_SOURCE_GROUP_UNLOCK (group);
3410 return GST_AUTOPLUG_SELECT_SKIP;
3413 /* remember the sink in the group now, the element is floating, we take
3416 * store the sink in the group, we will configure it later when we
3417 * reconfigure the sink */
3418 GST_DEBUG_OBJECT (playbin, "remember sink");
3419 gst_object_ref_sink (element);
3421 GST_SOURCE_GROUP_UNLOCK (group);
3423 /* tell decodebin to expose the pad because we are going to use this
3425 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3427 return GST_AUTOPLUG_SELECT_EXPOSE;
3431 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3432 GstSourceGroup * group)
3434 GstPlayBin *playbin;
3437 playbin = group->playbin;
3439 g_object_get (group->uridecodebin, "source", &source, NULL);
3441 GST_OBJECT_LOCK (playbin);
3442 if (playbin->source)
3443 gst_object_unref (playbin->source);
3444 playbin->source = source;
3445 GST_OBJECT_UNLOCK (playbin);
3447 g_object_notify (G_OBJECT (playbin), "source");
3449 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3450 0, playbin->source);
3453 /* must be called with the group lock */
3455 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3458 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3460 if (group->uridecodebin)
3461 gst_element_set_locked_state (group->uridecodebin, locked);
3462 if (group->suburidecodebin)
3463 gst_element_set_locked_state (group->suburidecodebin, locked);
3468 /* must be called with PLAY_BIN_LOCK */
3470 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3472 GstElement *uridecodebin;
3473 GstElement *suburidecodebin = NULL;
3476 g_return_val_if_fail (group->valid, FALSE);
3477 g_return_val_if_fail (!group->active, FALSE);
3479 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3481 GST_SOURCE_GROUP_LOCK (group);
3483 /* First set up the custom sources */
3484 if (playbin->audio_sink)
3485 group->audio_sink = gst_object_ref (playbin->audio_sink);
3486 if (playbin->video_sink)
3487 group->video_sink = gst_object_ref (playbin->video_sink);
3489 g_list_free (group->stream_changed_pending);
3490 group->stream_changed_pending = NULL;
3491 if (!group->stream_changed_pending_lock)
3492 group->stream_changed_pending_lock = g_mutex_new ();
3494 if (group->uridecodebin) {
3495 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3496 uridecodebin = group->uridecodebin;
3497 gst_element_set_state (uridecodebin, GST_STATE_READY);
3498 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3500 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3501 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3504 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3505 group->uridecodebin = gst_object_ref (uridecodebin);
3508 flags = gst_play_sink_get_flags (playbin->playsink);
3510 g_object_set (uridecodebin,
3511 /* configure connection speed */
3512 "connection-speed", playbin->connection_speed / 1000,
3515 /* configure download buffering */
3516 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3517 /* configure buffering of demuxed/parsed data */
3518 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3519 /* configure buffering parameters */
3520 "buffer-duration", playbin->buffer_duration,
3521 "buffer-size", playbin->buffer_size,
3522 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3524 /* connect pads and other things */
3525 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3526 G_CALLBACK (pad_added_cb), group);
3527 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3528 G_CALLBACK (pad_removed_cb), group);
3529 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3530 G_CALLBACK (no_more_pads_cb), group);
3531 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3532 G_CALLBACK (notify_source_cb), group);
3534 /* we have 1 pending no-more-pads */
3537 /* is called when the uridecodebin is out of data and we can switch to the
3540 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3543 /* will be called when a new media type is found. We return a list of decoders
3544 * including sinks for decodebin to try */
3545 group->autoplug_factories_id =
3546 g_signal_connect (uridecodebin, "autoplug-factories",
3547 G_CALLBACK (autoplug_factories_cb), group);
3548 group->autoplug_select_id =
3549 g_signal_connect (uridecodebin, "autoplug-select",
3550 G_CALLBACK (autoplug_select_cb), group);
3551 group->autoplug_continue_id =
3552 g_signal_connect (uridecodebin, "autoplug-continue",
3553 G_CALLBACK (autoplug_continue_cb), group);
3555 if (group->suburi) {
3557 if (group->suburidecodebin) {
3558 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3559 suburidecodebin = group->suburidecodebin;
3560 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3561 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3563 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3564 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3565 if (!suburidecodebin)
3568 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3569 group->suburidecodebin = gst_object_ref (suburidecodebin);
3572 g_object_set (suburidecodebin,
3573 /* configure connection speed */
3574 "connection-speed", playbin->connection_speed,
3576 "uri", group->suburi, NULL);
3578 /* connect pads and other things */
3579 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3580 G_CALLBACK (pad_added_cb), group);
3581 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3582 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3583 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3584 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3586 group->sub_autoplug_continue_id =
3587 g_signal_connect (suburidecodebin, "autoplug-continue",
3588 G_CALLBACK (autoplug_continue_cb), group);
3590 /* we have 2 pending no-more-pads */
3592 group->sub_pending = TRUE;
3594 group->sub_pending = FALSE;
3597 /* release the group lock before setting the state of the decodebins, they
3598 * might fire signals in this thread that we need to handle with the
3599 * group_lock taken. */
3600 GST_SOURCE_GROUP_UNLOCK (group);
3602 if (suburidecodebin) {
3603 if (gst_element_set_state (suburidecodebin,
3604 target) == GST_STATE_CHANGE_FAILURE) {
3605 GST_DEBUG_OBJECT (playbin,
3606 "failed state change of subtitle uridecodebin");
3607 GST_SOURCE_GROUP_LOCK (group);
3609 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3610 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3611 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3612 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3613 /* Might already be removed because of an error message */
3614 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3615 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3616 if (group->sub_pending) {
3618 group->sub_pending = FALSE;
3620 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3621 GST_SOURCE_GROUP_UNLOCK (group);
3624 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3625 goto uridecodebin_failure;
3627 GST_SOURCE_GROUP_LOCK (group);
3628 /* alow state changes of the playbin2 affect the group elements now */
3629 group_set_locked_state_unlocked (playbin, group, FALSE);
3630 group->active = TRUE;
3631 GST_SOURCE_GROUP_UNLOCK (group);
3640 /* delete any custom sinks we might have */
3641 if (group->audio_sink) {
3642 /* If this is a automatically created sink set it to NULL */
3643 if (group->audio_sink != playbin->audio_sink)
3644 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3645 gst_object_unref (group->audio_sink);
3647 group->audio_sink = NULL;
3648 if (group->video_sink) {
3649 /* If this is a automatically created sink set it to NULL */
3650 if (group->video_sink != playbin->video_sink)
3651 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3652 gst_object_unref (group->video_sink);
3654 group->video_sink = NULL;
3656 GST_SOURCE_GROUP_UNLOCK (group);
3658 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3660 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3662 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3663 (_("Could not create \"uridecodebin\" element.")), (NULL));
3666 uridecodebin_failure:
3668 /* delete any custom sinks we might have */
3669 if (group->audio_sink) {
3670 /* If this is a automatically created sink set it to NULL */
3671 if (group->audio_sink != playbin->audio_sink)
3672 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3673 gst_object_unref (group->audio_sink);
3675 group->audio_sink = NULL;
3676 if (group->video_sink) {
3677 /* If this is a automatically created sink set it to NULL */
3678 if (group->video_sink != playbin->video_sink)
3679 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3680 gst_object_unref (group->video_sink);
3682 group->video_sink = NULL;
3684 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3689 /* unlink a group of uridecodebins from the sink.
3690 * must be called with PLAY_BIN_LOCK */
3692 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3696 g_return_val_if_fail (group->valid, FALSE);
3697 g_return_val_if_fail (group->active, FALSE);
3699 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3701 GST_SOURCE_GROUP_LOCK (group);
3702 group->active = FALSE;
3703 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3704 GstSourceSelect *select = &group->selector[i];
3706 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3708 if (select->srcpad) {
3709 if (select->sinkpad) {
3710 GST_LOG_OBJECT (playbin, "unlinking from sink");
3711 gst_pad_unlink (select->srcpad, select->sinkpad);
3714 GST_LOG_OBJECT (playbin, "release sink pad");
3715 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3716 select->sinkpad = NULL;
3719 gst_object_unref (select->srcpad);
3720 select->srcpad = NULL;
3723 if (select->selector) {
3726 /* release and unref requests pad from the selector */
3727 for (n = 0; n < select->channels->len; n++) {
3728 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3730 gst_element_release_request_pad (select->selector, sinkpad);
3731 gst_object_unref (sinkpad);
3733 g_ptr_array_set_size (select->channels, 0);
3735 gst_element_set_state (select->selector, GST_STATE_NULL);
3736 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3737 select->selector = NULL;
3740 /* delete any custom sinks we might have */
3741 if (group->audio_sink) {
3742 /* If this is a automatically created sink set it to NULL */
3743 if (group->audio_sink != playbin->audio_sink)
3744 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3745 gst_object_unref (group->audio_sink);
3747 group->audio_sink = NULL;
3748 if (group->video_sink) {
3749 /* If this is a automatically created sink set it to NULL */
3750 if (group->video_sink != playbin->video_sink)
3751 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3752 gst_object_unref (group->video_sink);
3754 group->video_sink = NULL;
3756 if (group->uridecodebin) {
3757 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3758 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3759 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3760 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3761 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3762 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3763 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3764 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3765 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3768 if (group->suburidecodebin) {
3769 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3770 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3771 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3772 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3774 /* Might already be removed because of errors */
3775 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3776 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3779 GST_SOURCE_GROUP_UNLOCK (group);
3784 /* setup the next group to play, this assumes the next_group is valid and
3785 * configured. It swaps out the current_group and activates the valid
3788 setup_next_source (GstPlayBin * playbin, GstState target)
3790 GstSourceGroup *new_group, *old_group;
3792 GST_DEBUG_OBJECT (playbin, "setup sources");
3794 /* see if there is a next group */
3795 GST_PLAY_BIN_LOCK (playbin);
3796 new_group = playbin->next_group;
3797 if (!new_group || !new_group->valid)
3800 /* first unlink the current source, if any */
3801 old_group = playbin->curr_group;
3802 if (old_group && old_group->valid && old_group->active) {
3803 gst_play_bin_update_cached_duration (playbin);
3804 /* unlink our pads with the sink */
3805 deactivate_group (playbin, old_group);
3806 old_group->valid = FALSE;
3809 /* swap old and new */
3810 playbin->curr_group = new_group;
3811 playbin->next_group = old_group;
3813 /* activate the new group */
3814 if (!activate_group (playbin, new_group, target))
3815 goto activate_failed;
3817 GST_PLAY_BIN_UNLOCK (playbin);
3824 GST_DEBUG_OBJECT (playbin, "no next group");
3825 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3826 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3827 GST_PLAY_BIN_UNLOCK (playbin);
3832 GST_DEBUG_OBJECT (playbin, "activate failed");
3833 GST_PLAY_BIN_UNLOCK (playbin);
3838 /* The group that is currently playing is copied again to the
3839 * next_group so that it will start playing the next time.
3842 save_current_group (GstPlayBin * playbin)
3844 GstSourceGroup *curr_group;
3846 GST_DEBUG_OBJECT (playbin, "save current group");
3848 /* see if there is a current group */
3849 GST_PLAY_BIN_LOCK (playbin);
3850 curr_group = playbin->curr_group;
3851 if (curr_group && curr_group->valid && curr_group->active) {
3852 /* unlink our pads with the sink */
3853 deactivate_group (playbin, curr_group);
3855 /* swap old and new */
3856 playbin->curr_group = playbin->next_group;
3857 playbin->next_group = curr_group;
3858 GST_PLAY_BIN_UNLOCK (playbin);
3863 /* clear the locked state from all groups. This function is called before a
3864 * state change to NULL is performed on them. */
3866 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3868 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3871 GST_PLAY_BIN_LOCK (playbin);
3872 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3873 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3874 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3875 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3876 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3877 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3878 GST_PLAY_BIN_UNLOCK (playbin);
3883 static GstStateChangeReturn
3884 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3886 GstStateChangeReturn ret;
3887 GstPlayBin *playbin;
3888 gboolean do_save = FALSE;
3890 playbin = GST_PLAY_BIN (element);
3892 switch (transition) {
3893 case GST_STATE_CHANGE_NULL_TO_READY:
3894 memset (&playbin->duration, 0, sizeof (playbin->duration));
3896 case GST_STATE_CHANGE_READY_TO_PAUSED:
3897 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3898 memset (&playbin->duration, 0, sizeof (playbin->duration));
3899 g_atomic_int_set (&playbin->shutdown, 0);
3901 if (!setup_next_source (playbin, GST_STATE_READY)) {
3902 ret = GST_STATE_CHANGE_FAILURE;
3906 case GST_STATE_CHANGE_PAUSED_TO_READY:
3908 /* FIXME unlock our waiting groups */
3909 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3910 g_atomic_int_set (&playbin->shutdown, 1);
3911 memset (&playbin->duration, 0, sizeof (playbin->duration));
3913 /* wait for all callbacks to end by taking the lock.
3914 * No dynamic (critical) new callbacks will
3915 * be able to happen as we set the shutdown flag. */
3916 GST_PLAY_BIN_DYN_LOCK (playbin);
3917 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3918 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3921 case GST_STATE_CHANGE_READY_TO_NULL:
3922 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3923 * an no state change PAUSED to READY passes here,
3924 * though it is a nice-to-have ... */
3925 if (!g_atomic_int_get (&playbin->shutdown)) {
3929 memset (&playbin->duration, 0, sizeof (playbin->duration));
3931 /* unlock so that all groups go to NULL */
3932 groups_set_locked_state (playbin, FALSE);
3938 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3939 if (ret == GST_STATE_CHANGE_FAILURE)
3942 switch (transition) {
3943 case GST_STATE_CHANGE_READY_TO_PAUSED:
3945 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3946 /* FIXME Release audio device when we implement that */
3948 case GST_STATE_CHANGE_PAUSED_TO_READY:
3949 save_current_group (playbin);
3951 case GST_STATE_CHANGE_READY_TO_NULL:
3955 /* also do missed state change down to READY */
3957 save_current_group (playbin);
3958 /* Deactive the groups, set the uridecodebins to NULL
3961 for (i = 0; i < 2; i++) {
3962 if (playbin->groups[i].active && playbin->groups[i].valid) {
3963 deactivate_group (playbin, &playbin->groups[i]);
3964 playbin->groups[i].valid = FALSE;
3967 if (playbin->groups[i].uridecodebin) {
3968 gst_element_set_state (playbin->groups[i].uridecodebin,
3970 gst_object_unref (playbin->groups[i].uridecodebin);
3971 playbin->groups[i].uridecodebin = NULL;
3974 if (playbin->groups[i].suburidecodebin) {
3975 gst_element_set_state (playbin->groups[i].suburidecodebin,
3977 gst_object_unref (playbin->groups[i].suburidecodebin);
3978 playbin->groups[i].suburidecodebin = NULL;
3982 /* Set our sinks back to NULL, they might not be child of playbin */
3983 if (playbin->audio_sink)
3984 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
3985 if (playbin->video_sink)
3986 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
3987 if (playbin->text_sink)
3988 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
3990 /* make sure the groups don't perform a state change anymore until we
3991 * enable them again */
3992 groups_set_locked_state (playbin, TRUE);
4004 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
4005 GstSourceGroup *curr_group;
4007 curr_group = playbin->curr_group;
4008 if (curr_group && curr_group->active && curr_group->valid) {
4009 /* unlink our pads with the sink */
4010 deactivate_group (playbin, curr_group);
4011 curr_group->valid = FALSE;
4014 /* Swap current and next group back */
4015 playbin->curr_group = playbin->next_group;
4016 playbin->next_group = curr_group;
4023 gst_play_bin2_plugin_init (GstPlugin * plugin)
4025 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
4027 return gst_element_register (plugin, "playbin2", GST_RANK_NONE,