2 * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
3 * Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * SECTION:element-playbin2
24 * Playbin2 provides a stand-alone everything-in-one abstraction for an
25 * audio and/or video player.
27 * playbin2 is considered stable now. It is the prefered playback API now,
28 * and replaces the old #playbin element, which is no longer supported.
30 * It can handle both audio and video files and features
33 * automatic file type recognition and based on that automatic
34 * selection and usage of the right audio/video/subtitle demuxers/decoders
37 * visualisations for audio files
40 * subtitle support for video files. Subtitles can be store in external
44 * stream selection between different video/audio/subtitles streams
47 * meta info (tag) extraction
50 * easy access to the last video frame
53 * buffering when playing streams over a network
56 * volume control with mute option
61 * <title>Usage</title>
63 * A playbin2 element can be created just like any other element using
64 * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin2:uri
65 * property. This must be an absolute URI, relative file paths are not allowed.
66 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
68 * Playbin is a #GstPipeline. It will notify the application of everything
69 * that's happening (errors, end of stream, tags found, state changes, etc.)
70 * by posting messages on its #GstBus. The application needs to watch the
73 * Playback can be initiated by setting the element to PLAYING state using
74 * gst_element_set_state(). Note that the state change will take place in
75 * the background in a separate thread, when the function returns playback
76 * is probably not happening yet and any errors might not have occured yet.
77 * Applications using playbin should ideally be written to deal with things
78 * completely asynchroneous.
80 * When playback has finished (an EOS message has been received on the bus)
81 * or an error has occured (an ERROR message has been received on the bus) or
82 * the user wants to play a different track, playbin should be set back to
83 * READY or NULL state, then the #GstPlayBin2:uri property should be set to the
84 * new location and then playbin be set to PLAYING state again.
86 * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
87 * on the playbin element. Again, the seek will not be executed
88 * instantaneously, but will be done in a background thread. When the seek
89 * call returns the seek will most likely still be in process. An application
90 * may wait for the seek to finish (or fail) using gst_element_get_state() with
91 * -1 as the timeout, but this will block the user interface and is not
94 * Applications may query the current position and duration of the stream
95 * via gst_element_query_position() and gst_element_query_duration() and
96 * setting the format passed to GST_FORMAT_TIME. If the query was successful,
97 * the duration or position will have been returned in units of nanoseconds.
101 * <title>Advanced Usage: specifying the audio and video sink</title>
103 * By default, if no audio sink or video sink has been specified via the
104 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property, playbin will use the autoaudiosink
105 * and autovideosink elements to find the first-best available output method.
106 * This should work in most cases, but is not always desirable. Often either
107 * the user or application might want to specify more explicitly what to use
108 * for audio and video output.
110 * If the application wants more control over how audio or video should be
111 * output, it may create the audio/video sink elements itself (for example
112 * using gst_element_factory_make()) and provide them to playbin using the
113 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property.
115 * GNOME-based applications, for example, will usually want to create
116 * gconfaudiosink and gconfvideosink elements and make playbin use those,
117 * so that output happens to whatever the user has configured in the GNOME
118 * Multimedia System Selector configuration dialog.
120 * The sink elements do not necessarily need to be ready-made sinks. It is
121 * possible to create container elements that look like a sink to playbin,
122 * but in reality contain a number of custom elements linked together. This
123 * can be achieved by creating a #GstBin and putting elements in there and
124 * linking them, and then creating a sink #GstGhostPad for the bin and pointing
125 * it to the sink pad of the first element within the bin. This can be used
126 * for a number of purposes, for example to force output to a particular
127 * format or to modify or observe the data before it is output.
129 * It is also possible to 'suppress' audio and/or video output by using
130 * 'fakesink' elements (or capture it from there using the fakesink element's
131 * "handoff" signal, which, nota bene, is fired from the streaming thread!).
135 * <title>Retrieving Tags and Other Meta Data</title>
137 * Most of the common meta data (artist, title, etc.) can be retrieved by
138 * watching for TAG messages on the pipeline's bus (see above).
140 * Other more specific meta information like width/height/framerate of video
141 * streams or samplerate/number of channels of audio streams can be obtained
142 * from the negotiated caps on the sink pads of the sinks.
146 * <title>Buffering</title>
147 * Playbin handles buffering automatically for the most part, but applications
148 * need to handle parts of the buffering process as well. Whenever playbin is
149 * buffering, it will post BUFFERING messages on the bus with a percentage
150 * value that shows the progress of the buffering process. Applications need
151 * to set playbin to PLAYING or PAUSED state in response to these messages.
152 * They may also want to convey the buffering progress to the user in some
153 * way. Here is how to extract the percentage information from the message
154 * (requires GStreamer >= 0.10.11):
156 * switch (GST_MESSAGE_TYPE (msg)) {
157 * case GST_MESSAGE_BUFFERING: {
159 * gst_message_parse_buffering (msg, &percent);
160 * g_print ("Buffering (%%u percent done)", percent);
166 * Note that applications should keep/set the pipeline in the PAUSED state when
167 * a BUFFERING message is received with a buffer percent value < 100 and set
168 * the pipeline back to PLAYING state when a BUFFERING message with a value
169 * of 100 percent is received (if PLAYING is the desired state, that is).
172 * <title>Embedding the video window in your application</title>
173 * By default, playbin (or rather the video sinks used) will create their own
174 * window. Applications will usually want to force output to a window of their
175 * own, however. This can be done using the #GstXOverlay interface, which most
176 * video sinks implement. See the documentation there for more details.
179 * <title>Specifying which CD/DVD device to use</title>
180 * The device to use for CDs/DVDs needs to be set on the source element
181 * playbin creates before it is opened. The only way to do this at the moment
182 * is to connect to playbin's "notify::source" signal, which will be emitted
183 * by playbin when it has created the source element for a particular URI.
184 * In the signal callback you can check if the source element has a "device"
185 * property and set it appropriately. In future ways might be added to specify
186 * the device as part of the URI, but at the time of writing this is not
190 * <title>Handling redirects</title>
192 * Some elements may post 'redirect' messages on the bus to tell the
193 * application to open another location. These are element messages containing
194 * a structure named 'redirect' along with a 'new-location' field of string
195 * type. The new location may be a relative or an absolute URI. Examples
196 * for such redirects can be found in many quicktime movie trailers.
200 * <title>Examples</title>
202 * gst-launch -v playbin uri=file:///path/to/somefile.avi
203 * ]| This will play back the given AVI video file, given that the video and
204 * audio decoders required to decode the content are installed. Since no
205 * special audio sink or video sink is supplied (not possible via gst-launch),
206 * playbin will try to find a suitable audio and video sink automatically
207 * using the autoaudiosink and autovideosink elements.
209 * gst-launch -v playbin uri=cdda://4
210 * ]| This will play back track 4 on an audio CD in your disc drive (assuming
211 * the drive is detected automatically by the plugin).
213 * gst-launch -v playbin uri=dvd://1
214 * ]| This will play back title 1 of a DVD in your disc drive (assuming
215 * the drive is detected automatically by the plugin).
223 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
224 * with newer GLib versions (>= 2.31.0) */
225 #define GLIB_DISABLE_DEPRECATION_WARNINGS
230 #include <gst/gst-i18n-plugin.h>
231 #include <gst/pbutils/pbutils.h>
232 #include <gst/interfaces/streamvolume.h>
234 #include "gstplay-enum.h"
235 #include "gstplay-marshal.h"
236 #include "gstplayback.h"
237 #include "gstplaysink.h"
238 #include "gstsubtitleoverlay.h"
240 #include "gst/glib-compat-private.h"
242 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
243 #define GST_CAT_DEFAULT gst_play_bin_debug
245 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type())
246 #define GST_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
247 #define GST_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
248 #define GST_IS_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
249 #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
251 #define VOLUME_MAX_DOUBLE 10.0
253 typedef struct _GstPlayBin GstPlayBin;
254 typedef struct _GstPlayBinClass GstPlayBinClass;
255 typedef struct _GstSourceGroup GstSourceGroup;
256 typedef struct _GstSourceSelect GstSourceSelect;
258 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
260 /* has the info for a selector and provides the link to the sink */
261 struct _GstSourceSelect
263 const gchar *media_list[8]; /* the media types for the selector */
264 SourceSelectGetMediaCapsFunc get_media_caps; /* more complex caps for the selector */
265 GstPlaySinkType type; /* the sink pad type of the selector */
267 GstElement *selector; /* the selector */
269 GstPad *srcpad; /* the source pad of the selector */
270 GstPad *sinkpad; /* the sinkpad of the sink when the selector
273 GstEvent *sinkpad_delayed_event;
274 gulong sinkpad_data_probe;
277 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
278 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
279 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
283 PLAYBIN_STREAM_AUDIO = 0,
284 PLAYBIN_STREAM_VIDEO,
289 /* a structure to hold the objects for decoding a uri and the subtitle uri
291 struct _GstSourceGroup
297 gboolean valid; /* the group has valid info to start playback */
298 gboolean active; /* the group is active */
303 GValueArray *streaminfo;
306 GPtrArray *video_channels; /* links to selector pads */
307 GPtrArray *audio_channels; /* links to selector pads */
308 GPtrArray *text_channels; /* links to selector pads */
310 GstElement *audio_sink; /* autoplugged audio and video sinks */
311 GstElement *video_sink;
313 /* uridecodebins for uri and subtitle uri */
314 GstElement *uridecodebin;
315 GstElement *suburidecodebin;
317 gboolean sub_pending;
320 gulong pad_removed_id;
321 gulong no_more_pads_id;
322 gulong notify_source_id;
324 gulong autoplug_factories_id;
325 gulong autoplug_select_id;
326 gulong autoplug_continue_id;
328 gulong sub_pad_added_id;
329 gulong sub_pad_removed_id;
330 gulong sub_no_more_pads_id;
331 gulong sub_autoplug_continue_id;
333 GMutex *stream_changed_pending_lock;
334 GList *stream_changed_pending;
336 /* selectors for different streams */
337 GstSourceSelect selector[PLAYBIN_STREAM_LAST];
340 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
341 #define GST_PLAY_BIN_LOCK(bin) (g_static_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
342 #define GST_PLAY_BIN_UNLOCK(bin) (g_static_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
344 /* lock to protect dynamic callbacks, like no-more-pads */
345 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->dyn_lock)
346 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->dyn_lock)
348 /* lock for shutdown */
349 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
351 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
353 GST_PLAY_BIN_DYN_LOCK (bin); \
354 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
355 GST_PLAY_BIN_DYN_UNLOCK (bin); \
360 /* unlock for shutdown */
361 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
362 GST_PLAY_BIN_DYN_UNLOCK (bin); \
367 * playbin element structure
373 GStaticRecMutex lock; /* to protect group switching */
375 /* the groups, we use a double buffer to switch between current and next */
376 GstSourceGroup groups[2]; /* array with group info */
377 GstSourceGroup *curr_group; /* pointer to the currently playing group */
378 GstSourceGroup *next_group; /* pointer to the next group */
381 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
382 gint current_video; /* the currently selected stream */
383 gint current_audio; /* the currently selected stream */
384 gint current_text; /* the currently selected stream */
386 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
387 guint buffer_size; /* When buffering, the max buffer size (bytes) */
390 GstPlaySink *playsink;
392 /* the last activated source */
395 /* lock protecting dynamic adding/removing */
397 /* if we are shutting down or not */
400 GMutex *elements_lock;
401 guint32 elements_cookie;
402 GList *elements; /* factories we can use for selecting elements */
404 gboolean have_selector; /* set to FALSE when we fail to create an
405 * input-selector, so that we only post a
408 GstElement *audio_sink; /* configured audio sink, or NULL */
409 GstElement *video_sink; /* configured video sink, or NULL */
410 GstElement *text_sink; /* configured text sink, or NULL */
417 } duration[5]; /* cached durations */
419 guint64 ring_buffer_max_size; /* 0 means disabled */
422 struct _GstPlayBinClass
424 GstPipelineClass parent_class;
426 /* notify app that the current uri finished decoding and it is possible to
427 * queue a new one for gapless playback */
428 void (*about_to_finish) (GstPlayBin * playbin);
430 /* notify app that number of audio/video/text streams changed */
431 void (*video_changed) (GstPlayBin * playbin);
432 void (*audio_changed) (GstPlayBin * playbin);
433 void (*text_changed) (GstPlayBin * playbin);
435 /* notify app that the tags of audio/video/text streams changed */
436 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
437 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
438 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
440 /* get audio/video/text tags for a stream */
441 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
442 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
443 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
445 /* get the last video frame and convert it to the given caps */
446 GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
448 /* get audio/video/text pad for a stream */
449 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
450 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
451 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
455 #define DEFAULT_URI NULL
456 #define DEFAULT_SUBURI NULL
457 #define DEFAULT_SOURCE NULL
458 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
459 GST_PLAY_FLAG_SOFT_VOLUME
460 #define DEFAULT_N_VIDEO 0
461 #define DEFAULT_CURRENT_VIDEO -1
462 #define DEFAULT_N_AUDIO 0
463 #define DEFAULT_CURRENT_AUDIO -1
464 #define DEFAULT_N_TEXT 0
465 #define DEFAULT_CURRENT_TEXT -1
466 #define DEFAULT_SUBTITLE_ENCODING NULL
467 #define DEFAULT_AUDIO_SINK NULL
468 #define DEFAULT_VIDEO_SINK NULL
469 #define DEFAULT_VIS_PLUGIN NULL
470 #define DEFAULT_TEXT_SINK NULL
471 #define DEFAULT_VOLUME 1.0
472 #define DEFAULT_MUTE FALSE
473 #define DEFAULT_FRAME NULL
474 #define DEFAULT_FONT_DESC NULL
475 #define DEFAULT_CONNECTION_SPEED 0
476 #define DEFAULT_BUFFER_DURATION -1
477 #define DEFAULT_BUFFER_SIZE -1
478 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
493 PROP_SUBTITLE_ENCODING,
502 PROP_CONNECTION_SPEED,
504 PROP_BUFFER_DURATION,
506 PROP_RING_BUFFER_MAX_SIZE,
513 SIGNAL_ABOUT_TO_FINISH,
514 SIGNAL_CONVERT_FRAME,
515 SIGNAL_VIDEO_CHANGED,
516 SIGNAL_AUDIO_CHANGED,
518 SIGNAL_VIDEO_TAGS_CHANGED,
519 SIGNAL_AUDIO_TAGS_CHANGED,
520 SIGNAL_TEXT_TAGS_CHANGED,
521 SIGNAL_GET_VIDEO_TAGS,
522 SIGNAL_GET_AUDIO_TAGS,
523 SIGNAL_GET_TEXT_TAGS,
524 SIGNAL_GET_VIDEO_PAD,
525 SIGNAL_GET_AUDIO_PAD,
531 static void gst_play_bin_class_init (GstPlayBinClass * klass);
532 static void gst_play_bin_init (GstPlayBin * playbin);
533 static void gst_play_bin_finalize (GObject * object);
535 static void gst_play_bin_set_property (GObject * object, guint prop_id,
536 const GValue * value, GParamSpec * spec);
537 static void gst_play_bin_get_property (GObject * object, guint prop_id,
538 GValue * value, GParamSpec * spec);
540 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
541 GstStateChange transition);
543 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
544 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
546 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
548 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
550 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
553 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
556 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
557 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
558 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
560 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
562 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
563 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
564 GstSourceGroup * group);
566 static void gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
568 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
571 static GstElementClass *parent_class;
573 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
575 #define REMOVE_SIGNAL(obj,id) \
577 g_signal_handler_disconnect (obj, id); \
582 gst_play_bin_get_type (void)
584 static GType gst_play_bin_type = 0;
586 if (!gst_play_bin_type) {
587 static const GTypeInfo gst_play_bin_info = {
588 sizeof (GstPlayBinClass),
591 (GClassInitFunc) gst_play_bin_class_init,
596 (GInstanceInitFunc) gst_play_bin_init,
599 static const GInterfaceInfo svol_info = {
603 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
604 "GstPlayBin2", &gst_play_bin_info, 0);
606 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
610 return gst_play_bin_type;
614 gst_play_bin_class_init (GstPlayBinClass * klass)
616 GObjectClass *gobject_klass;
617 GstElementClass *gstelement_klass;
618 GstBinClass *gstbin_klass;
620 gobject_klass = (GObjectClass *) klass;
621 gstelement_klass = (GstElementClass *) klass;
622 gstbin_klass = (GstBinClass *) klass;
624 parent_class = g_type_class_peek_parent (klass);
626 gobject_klass->set_property = gst_play_bin_set_property;
627 gobject_klass->get_property = gst_play_bin_get_property;
629 gobject_klass->finalize = gst_play_bin_finalize;
634 * Set the next URI that playbin will play. This property can be set from the
635 * about-to-finish signal to queue the next media file.
637 g_object_class_install_property (gobject_klass, PROP_URI,
638 g_param_spec_string ("uri", "URI", "URI of the media to play",
639 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
644 * Set the next subtitle URI that playbin will play. This property can be
645 * set from the about-to-finish signal to queue the next subtitle media file.
647 g_object_class_install_property (gobject_klass, PROP_SUBURI,
648 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
649 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
651 g_object_class_install_property (gobject_klass, PROP_SOURCE,
652 g_param_spec_object ("source", "Source", "Source element",
653 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
658 * Control the behaviour of playbin.
660 g_object_class_install_property (gobject_klass, PROP_FLAGS,
661 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
662 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
663 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
666 * GstPlayBin2:n-video
668 * Get the total number of available video streams.
670 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
671 g_param_spec_int ("n-video", "Number Video",
672 "Total number of video streams", 0, G_MAXINT, 0,
673 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
675 * GstPlayBin2:current-video
677 * Get or set the currently playing video stream. By default the first video
678 * stream with data is played.
680 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
681 g_param_spec_int ("current-video", "Current Video",
682 "Currently playing video stream (-1 = auto)",
683 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
685 * GstPlayBin2:n-audio
687 * Get the total number of available audio streams.
689 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
690 g_param_spec_int ("n-audio", "Number Audio",
691 "Total number of audio streams", 0, G_MAXINT, 0,
692 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
694 * GstPlayBin2:current-audio
696 * Get or set the currently playing audio stream. By default the first audio
697 * stream with data is played.
699 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
700 g_param_spec_int ("current-audio", "Current audio",
701 "Currently playing audio stream (-1 = auto)",
702 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
706 * Get the total number of available subtitle streams.
708 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
709 g_param_spec_int ("n-text", "Number Text",
710 "Total number of text streams", 0, G_MAXINT, 0,
711 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
713 * GstPlayBin2:current-text:
715 * Get or set the currently playing subtitle stream. By default the first
716 * subtitle stream with data is played.
718 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
719 g_param_spec_int ("current-text", "Current Text",
720 "Currently playing text stream (-1 = auto)",
721 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
723 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
724 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
725 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
726 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
727 "be checked for an encoding to use. If that is not set either, "
728 "ISO-8859-15 will be assumed.", NULL,
729 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
731 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
732 g_param_spec_object ("video-sink", "Video Sink",
733 "the video output element to use (NULL = default sink)",
734 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
735 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
736 g_param_spec_object ("audio-sink", "Audio Sink",
737 "the audio output element to use (NULL = default sink)",
738 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
739 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
740 g_param_spec_object ("vis-plugin", "Vis plugin",
741 "the visualization element to use (NULL = default)",
742 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
743 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
744 g_param_spec_object ("text-sink", "Text plugin",
745 "the text output element to use (NULL = default textoverlay)",
746 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
749 * GstPlayBin2:volume:
751 * Get or set the current audio stream volume. 1.0 means 100%,
752 * 0.0 means mute. This uses a linear volume scale.
755 g_object_class_install_property (gobject_klass, PROP_VOLUME,
756 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
757 0.0, VOLUME_MAX_DOUBLE, 1.0,
758 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
759 g_object_class_install_property (gobject_klass, PROP_MUTE,
760 g_param_spec_boolean ("mute", "Mute",
761 "Mute the audio channel without changing the volume", FALSE,
762 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
766 * @playbin: a #GstPlayBin2
768 * Get the currently rendered or prerolled frame in the video sink.
769 * The #GstCaps on the buffer will describe the format of the buffer.
771 g_object_class_install_property (gobject_klass, PROP_FRAME,
772 gst_param_spec_mini_object ("frame", "Frame",
773 "The last frame (NULL = no video available)",
774 GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
775 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
776 g_param_spec_string ("subtitle-font-desc",
777 "Subtitle font description",
778 "Pango font description of font "
779 "to be used for subtitle rendering", NULL,
780 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
782 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
783 g_param_spec_uint ("connection-speed", "Connection Speed",
784 "Network connection speed in kbps (0 = unknown)",
785 0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
786 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
788 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
789 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
790 "Buffer size when buffering network streams",
791 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
792 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
793 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
794 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
795 "Buffer duration when buffering network streams",
796 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
797 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
799 * GstPlayBin2:av-offset:
801 * Control the synchronisation offset between the audio and video streams.
802 * Positive values make the audio ahead of the video and negative values make
803 * the audio go behind the video.
807 g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
808 g_param_spec_int64 ("av-offset", "AV Offset",
809 "The synchronisation offset between audio and video in nanoseconds",
810 G_MININT64, G_MAXINT64, 0,
811 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
814 * GstQueue2:ring-buffer-max-size
816 * The maximum size of the ring buffer in bytes. If set to 0, the ring
817 * buffer is disabled. Default 0.
821 g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
822 g_param_spec_uint64 ("ring-buffer-max-size",
823 "Max. ring buffer size (bytes)",
824 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
825 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
826 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
829 * GstPlayBin2::about-to-finish
830 * @playbin: a #GstPlayBin2
832 * This signal is emitted when the current uri is about to finish. You can
833 * set the uri and suburi to make sure that playback continues.
835 * This signal is emitted from the context of a GStreamer streaming thread.
837 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
838 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
840 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
841 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
844 * GstPlayBin2::video-changed
845 * @playbin: a #GstPlayBin2
847 * This signal is emitted whenever the number or order of the video
848 * streams has changed. The application will most likely want to select
849 * a new video stream.
851 * This signal is usually emitted from the context of a GStreamer streaming
852 * thread. You can use gst_message_new_application() and
853 * gst_element_post_message() to notify your application's main thread.
855 /* FIXME 0.11: turn video-changed signal into message? */
856 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
857 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
859 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
860 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
862 * GstPlayBin2::audio-changed
863 * @playbin: a #GstPlayBin2
865 * This signal is emitted whenever the number or order of the audio
866 * streams has changed. The application will most likely want to select
867 * a new audio stream.
869 * This signal may be emitted from the context of a GStreamer streaming thread.
870 * You can use gst_message_new_application() and gst_element_post_message()
871 * to notify your application's main thread.
873 /* FIXME 0.11: turn audio-changed signal into message? */
874 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
875 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
877 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
878 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
880 * GstPlayBin2::text-changed
881 * @playbin: a #GstPlayBin2
883 * This signal is emitted whenever the number or order of the text
884 * streams has changed. The application will most likely want to select
887 * This signal may be emitted from the context of a GStreamer streaming thread.
888 * You can use gst_message_new_application() and gst_element_post_message()
889 * to notify your application's main thread.
891 /* FIXME 0.11: turn text-changed signal into message? */
892 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
893 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
895 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
896 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
899 * GstPlayBin2::video-tags-changed
900 * @playbin: a #GstPlayBin2
901 * @stream: stream index with changed tags
903 * This signal is emitted whenever the tags of a video stream have changed.
904 * The application will most likely want to get the new tags.
906 * This signal may be emitted from the context of a GStreamer streaming thread.
907 * You can use gst_message_new_application() and gst_element_post_message()
908 * to notify your application's main thread.
912 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
913 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
915 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
916 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
919 * GstPlayBin2::audio-tags-changed
920 * @playbin: a #GstPlayBin2
921 * @stream: stream index with changed tags
923 * This signal is emitted whenever the tags of an audio stream have changed.
924 * The application will most likely want to get the new tags.
926 * This signal may be emitted from the context of a GStreamer streaming thread.
927 * You can use gst_message_new_application() and gst_element_post_message()
928 * to notify your application's main thread.
932 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
933 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
935 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
936 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
939 * GstPlayBin2::text-tags-changed
940 * @playbin: a #GstPlayBin2
941 * @stream: stream index with changed tags
943 * This signal is emitted whenever the tags of a text stream have changed.
944 * The application will most likely want to get the new tags.
946 * This signal may be emitted from the context of a GStreamer streaming thread.
947 * You can use gst_message_new_application() and gst_element_post_message()
948 * to notify your application's main thread.
952 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
953 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
955 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
956 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
959 * GstPlayBin2::source-setup:
960 * @playbin: a #GstPlayBin2
961 * @source: source element
963 * This signal is emitted after the source element has been created, so
964 * it can be configured by setting additional properties (e.g. set a
965 * proxy server for an http source, or set the device and read speed for
966 * an audio cd source). This is functionally equivalent to connecting to
967 * the notify::source signal, but more convenient.
969 * This signal is usually emitted from the context of a GStreamer streaming
974 gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
975 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
976 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
977 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
980 * GstPlayBin2::get-video-tags
981 * @playbin: a #GstPlayBin2
982 * @stream: a video stream number
984 * Action signal to retrieve the tags of a specific video stream number.
985 * This information can be used to select a stream.
987 * Returns: a GstTagList with tags or NULL when the stream number does not
990 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
991 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
992 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
993 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
994 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
996 * GstPlayBin2::get-audio-tags
997 * @playbin: a #GstPlayBin2
998 * @stream: an audio stream number
1000 * Action signal to retrieve the tags of a specific audio stream number.
1001 * This information can be used to select a stream.
1003 * Returns: a GstTagList with tags or NULL when the stream number does not
1006 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
1007 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
1008 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1009 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
1010 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1012 * GstPlayBin2::get-text-tags
1013 * @playbin: a #GstPlayBin2
1014 * @stream: a text stream number
1016 * Action signal to retrieve the tags of a specific text stream number.
1017 * This information can be used to select a stream.
1019 * Returns: a GstTagList with tags or NULL when the stream number does not
1022 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
1023 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
1024 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1025 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
1026 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1028 * GstPlayBin2::convert-frame
1029 * @playbin: a #GstPlayBin2
1030 * @caps: the target format of the frame
1032 * Action signal to retrieve the currently playing video frame in the format
1033 * specified by @caps.
1034 * If @caps is %NULL, no conversion will be performed and this function is
1035 * equivalent to the #GstPlayBin::frame property.
1037 * Returns: a #GstBuffer of the current video frame converted to #caps.
1038 * The caps on the buffer will describe the final layout of the buffer data.
1039 * %NULL is returned when no current buffer can be retrieved or when the
1040 * conversion failed.
1042 gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
1043 g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
1044 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1045 G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
1046 gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
1049 * GstPlayBin2::get-video-pad
1050 * @playbin: a #GstPlayBin2
1051 * @stream: a video stream number
1053 * Action signal to retrieve the stream-selector sinkpad for a specific
1055 * This pad can be used for notifications of caps changes, stream-specific
1058 * Returns: a #GstPad, or NULL when the stream number does not exist.
1060 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1061 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1062 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1063 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1064 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1066 * GstPlayBin2::get-audio-pad
1067 * @playbin: a #GstPlayBin2
1068 * @stream: an audio stream number
1070 * Action signal to retrieve the stream-selector sinkpad for a specific
1072 * This pad can be used for notifications of caps changes, stream-specific
1075 * Returns: a #GstPad, or NULL when the stream number does not exist.
1077 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1078 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1079 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1080 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1081 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1083 * GstPlayBin2::get-text-pad
1084 * @playbin: a #GstPlayBin2
1085 * @stream: a text stream number
1087 * Action signal to retrieve the stream-selector sinkpad for a specific
1089 * This pad can be used for notifications of caps changes, stream-specific
1092 * Returns: a #GstPad, or NULL when the stream number does not exist.
1094 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1095 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1096 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1097 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1098 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1100 klass->get_video_tags = gst_play_bin_get_video_tags;
1101 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1102 klass->get_text_tags = gst_play_bin_get_text_tags;
1104 klass->convert_frame = gst_play_bin_convert_frame;
1106 klass->get_video_pad = gst_play_bin_get_video_pad;
1107 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1108 klass->get_text_pad = gst_play_bin_get_text_pad;
1110 gst_element_class_set_details_simple (gstelement_klass,
1111 "Player Bin 2", "Generic/Bin/Player",
1112 "Autoplug and play media from an uri",
1113 "Wim Taymans <wim.taymans@gmail.com>");
1115 gstelement_klass->change_state =
1116 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1117 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1119 gstbin_klass->handle_message =
1120 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1124 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1128 /* store the array for the different channels */
1129 group->video_channels = g_ptr_array_new ();
1130 group->audio_channels = g_ptr_array_new ();
1131 group->text_channels = g_ptr_array_new ();
1132 group->lock = g_mutex_new ();
1133 /* init selectors. The selector is found by finding the first prefix that
1134 * matches the media. */
1135 group->playbin = playbin;
1136 /* If you add any items to these lists, check that media_list[] is defined
1137 * above to be large enough to hold MAX(items)+1, so as to accommodate a
1138 * NULL terminator (set when the memory is zeroed on allocation) */
1139 group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
1140 group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
1141 group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
1142 group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
1143 group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
1144 group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
1145 group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
1146 group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
1147 group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
1148 group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
1149 group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
1150 group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
1151 group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
1152 group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
1153 gst_subtitle_overlay_create_factory_caps;
1154 group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
1155 group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
1157 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1158 GstSourceSelect *select = &group->selector[n];
1159 select->sinkpad_delayed_event = NULL;
1160 select->sinkpad_data_probe = 0;
1165 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1169 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1170 GstSourceSelect *select = &group->selector[n];
1171 if (select->sinkpad && select->sinkpad_data_probe)
1172 gst_pad_remove_data_probe (select->sinkpad, select->sinkpad_data_probe);
1173 if (select->sinkpad_delayed_event)
1174 gst_event_unref (select->sinkpad_delayed_event);
1177 g_free (group->uri);
1178 g_free (group->suburi);
1179 g_ptr_array_free (group->video_channels, TRUE);
1180 g_ptr_array_free (group->audio_channels, TRUE);
1181 g_ptr_array_free (group->text_channels, TRUE);
1183 g_mutex_free (group->lock);
1184 if (group->audio_sink) {
1185 if (group->audio_sink != playbin->audio_sink)
1186 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1187 gst_object_unref (group->audio_sink);
1189 group->audio_sink = NULL;
1190 if (group->video_sink) {
1191 if (group->video_sink != playbin->video_sink)
1192 gst_element_set_state (group->video_sink, GST_STATE_NULL);
1193 gst_object_unref (group->video_sink);
1195 group->video_sink = NULL;
1197 g_list_free (group->stream_changed_pending);
1198 group->stream_changed_pending = NULL;
1200 if (group->stream_changed_pending_lock)
1201 g_mutex_free (group->stream_changed_pending_lock);
1202 group->stream_changed_pending_lock = NULL;
1206 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1208 g_object_notify (G_OBJECT (playbin), "volume");
1212 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1214 g_object_notify (G_OBJECT (playbin), "mute");
1217 /* Must be called with elements lock! */
1219 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1223 if (!playbin->elements ||
1224 playbin->elements_cookie !=
1225 gst_default_registry_get_feature_list_cookie ()) {
1226 if (playbin->elements)
1227 gst_plugin_feature_list_free (playbin->elements);
1229 gst_element_factory_list_get_elements
1230 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1232 gst_element_factory_list_get_elements
1233 (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1234 playbin->elements = g_list_concat (res, tmp);
1236 g_list_sort (playbin->elements, gst_plugin_feature_rank_compare_func);
1237 playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1242 gst_play_bin_init (GstPlayBin * playbin)
1244 g_static_rec_mutex_init (&playbin->lock);
1245 playbin->dyn_lock = g_mutex_new ();
1247 /* assume we can create a selector */
1248 playbin->have_selector = TRUE;
1251 playbin->curr_group = &playbin->groups[0];
1252 playbin->next_group = &playbin->groups[1];
1253 init_group (playbin, &playbin->groups[0]);
1254 init_group (playbin, &playbin->groups[1]);
1256 /* first filter out the interesting element factories */
1257 playbin->elements_lock = g_mutex_new ();
1260 playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1261 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1262 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1263 /* Connect to notify::volume and notify::mute signals for proxying */
1264 g_signal_connect (playbin->playsink, "notify::volume",
1265 G_CALLBACK (notify_volume_cb), playbin);
1266 g_signal_connect (playbin->playsink, "notify::mute",
1267 G_CALLBACK (notify_mute_cb), playbin);
1269 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1270 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1271 playbin->current_text = DEFAULT_CURRENT_TEXT;
1273 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1274 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1275 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1279 gst_play_bin_finalize (GObject * object)
1281 GstPlayBin *playbin;
1283 playbin = GST_PLAY_BIN (object);
1285 free_group (playbin, &playbin->groups[0]);
1286 free_group (playbin, &playbin->groups[1]);
1288 if (playbin->source)
1289 gst_object_unref (playbin->source);
1290 if (playbin->video_sink) {
1291 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1292 gst_object_unref (playbin->video_sink);
1294 if (playbin->audio_sink) {
1295 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1296 gst_object_unref (playbin->audio_sink);
1298 if (playbin->text_sink) {
1299 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1300 gst_object_unref (playbin->text_sink);
1303 if (playbin->elements)
1304 gst_plugin_feature_list_free (playbin->elements);
1306 g_static_rec_mutex_free (&playbin->lock);
1307 g_mutex_free (playbin->dyn_lock);
1308 g_mutex_free (playbin->elements_lock);
1310 G_OBJECT_CLASS (parent_class)->finalize (object);
1314 gst_playbin_uri_is_valid (GstPlayBin * playbin, const gchar * uri)
1318 GST_LOG_OBJECT (playbin, "checking uri '%s'", uri);
1320 /* this just checks the protocol */
1321 if (!gst_uri_is_valid (uri))
1324 for (c = uri; *c != '\0'; ++c) {
1325 if (!g_ascii_isprint (*c))
1335 GST_WARNING_OBJECT (playbin, "uri '%s' not valid, character #%u",
1336 uri, (guint) ((guintptr) c - (guintptr) uri));
1342 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1344 GstSourceGroup *group;
1347 g_warning ("cannot set NULL uri");
1351 if (!gst_playbin_uri_is_valid (playbin, uri)) {
1352 if (g_str_has_prefix (uri, "file:")) {
1353 GST_WARNING_OBJECT (playbin, "not entirely correct file URI '%s' - make "
1354 "sure to escape spaces and non-ASCII characters properly and specify "
1355 "an absolute path. Use gst_filename_to_uri() to convert filenames "
1358 /* GST_ERROR_OBJECT (playbin, "malformed URI '%s'", uri); */
1362 GST_PLAY_BIN_LOCK (playbin);
1363 group = playbin->next_group;
1365 GST_SOURCE_GROUP_LOCK (group);
1366 /* store the uri in the next group we will play */
1367 g_free (group->uri);
1368 group->uri = g_strdup (uri);
1369 group->valid = TRUE;
1370 GST_SOURCE_GROUP_UNLOCK (group);
1372 GST_DEBUG ("set new uri to %s", uri);
1373 GST_PLAY_BIN_UNLOCK (playbin);
1377 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1379 GstSourceGroup *group;
1381 GST_PLAY_BIN_LOCK (playbin);
1382 group = playbin->next_group;
1384 GST_SOURCE_GROUP_LOCK (group);
1385 g_free (group->suburi);
1386 group->suburi = g_strdup (suburi);
1387 GST_SOURCE_GROUP_UNLOCK (group);
1389 GST_DEBUG ("setting new .sub uri to %s", suburi);
1391 GST_PLAY_BIN_UNLOCK (playbin);
1395 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1397 gst_play_sink_set_flags (playbin->playsink, flags);
1398 gst_play_sink_reconfigure (playbin->playsink);
1402 gst_play_bin_get_flags (GstPlayBin * playbin)
1406 flags = gst_play_sink_get_flags (playbin->playsink);
1411 /* get the currently playing group or if nothing is playing, the next
1412 * group. Must be called with the PLAY_BIN_LOCK. */
1413 static GstSourceGroup *
1414 get_group (GstPlayBin * playbin)
1416 GstSourceGroup *result;
1418 if (!(result = playbin->curr_group))
1419 result = playbin->next_group;
1425 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1427 GstPad *sinkpad = NULL;
1428 GstSourceGroup *group;
1430 GST_PLAY_BIN_LOCK (playbin);
1431 group = get_group (playbin);
1432 if (stream < group->video_channels->len) {
1433 sinkpad = g_ptr_array_index (group->video_channels, stream);
1434 gst_object_ref (sinkpad);
1436 GST_PLAY_BIN_UNLOCK (playbin);
1442 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1444 GstPad *sinkpad = NULL;
1445 GstSourceGroup *group;
1447 GST_PLAY_BIN_LOCK (playbin);
1448 group = get_group (playbin);
1449 if (stream < group->audio_channels->len) {
1450 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1451 gst_object_ref (sinkpad);
1453 GST_PLAY_BIN_UNLOCK (playbin);
1459 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1461 GstPad *sinkpad = NULL;
1462 GstSourceGroup *group;
1464 GST_PLAY_BIN_LOCK (playbin);
1465 group = get_group (playbin);
1466 if (stream < group->text_channels->len) {
1467 sinkpad = g_ptr_array_index (group->text_channels, stream);
1468 gst_object_ref (sinkpad);
1470 GST_PLAY_BIN_UNLOCK (playbin);
1477 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1482 if (!channels || stream >= channels->len)
1485 sinkpad = g_ptr_array_index (channels, stream);
1486 g_object_get (sinkpad, "tags", &result, NULL);
1492 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1495 GstSourceGroup *group;
1497 GST_PLAY_BIN_LOCK (playbin);
1498 group = get_group (playbin);
1499 result = get_tags (playbin, group->video_channels, stream);
1500 GST_PLAY_BIN_UNLOCK (playbin);
1506 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1509 GstSourceGroup *group;
1511 GST_PLAY_BIN_LOCK (playbin);
1512 group = get_group (playbin);
1513 result = get_tags (playbin, group->audio_channels, stream);
1514 GST_PLAY_BIN_UNLOCK (playbin);
1520 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1523 GstSourceGroup *group;
1525 GST_PLAY_BIN_LOCK (playbin);
1526 group = get_group (playbin);
1527 result = get_tags (playbin, group->text_channels, stream);
1528 GST_PLAY_BIN_UNLOCK (playbin);
1534 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1536 return gst_play_sink_convert_frame (playbin->playsink, caps);
1539 /* Returns current stream number, or -1 if none has been selected yet */
1541 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1543 /* Internal API cleanup would make this easier... */
1545 GstPad *pad, *current;
1546 GstObject *selector = NULL;
1549 for (i = 0; i < channels->len; i++) {
1550 pad = g_ptr_array_index (channels, i);
1551 if ((selector = gst_pad_get_parent (pad))) {
1552 g_object_get (selector, "active-pad", ¤t, NULL);
1553 gst_object_unref (selector);
1555 if (pad == current) {
1556 gst_object_unref (current);
1562 gst_object_unref (current);
1570 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1572 GstSourceGroup *group;
1573 GPtrArray *channels;
1576 GST_PLAY_BIN_LOCK (playbin);
1578 GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1579 playbin->current_video, stream);
1581 group = get_group (playbin);
1582 if (!(channels = group->video_channels))
1585 if (stream == -1 || channels->len <= stream) {
1588 /* take channel from selected stream */
1589 sinkpad = g_ptr_array_index (channels, stream);
1593 gst_object_ref (sinkpad);
1594 GST_PLAY_BIN_UNLOCK (playbin);
1597 GstObject *selector;
1599 if ((selector = gst_pad_get_parent (sinkpad))) {
1600 /* activate the selected pad */
1601 g_object_set (selector, "active-pad", sinkpad, NULL);
1602 gst_object_unref (selector);
1604 gst_object_unref (sinkpad);
1610 GST_PLAY_BIN_UNLOCK (playbin);
1611 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1617 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1619 GstSourceGroup *group;
1620 GPtrArray *channels;
1623 GST_PLAY_BIN_LOCK (playbin);
1625 GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1626 playbin->current_audio, stream);
1628 group = get_group (playbin);
1629 if (!(channels = group->audio_channels))
1632 if (stream == -1 || channels->len <= stream) {
1635 /* take channel from selected stream */
1636 sinkpad = g_ptr_array_index (channels, stream);
1640 gst_object_ref (sinkpad);
1641 GST_PLAY_BIN_UNLOCK (playbin);
1644 GstObject *selector;
1646 if ((selector = gst_pad_get_parent (sinkpad))) {
1647 /* activate the selected pad */
1648 g_object_set (selector, "active-pad", sinkpad, NULL);
1649 gst_object_unref (selector);
1651 gst_object_unref (sinkpad);
1657 GST_PLAY_BIN_UNLOCK (playbin);
1658 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1664 _suburidecodebin_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
1666 GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
1670 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1672 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1675 if (it && gst_iterator_next (it, (gpointer) & sinkpad) == GST_ITERATOR_OK
1680 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1681 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1682 if (!gst_pad_send_event (sinkpad, event)) {
1684 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1685 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1686 if (!gst_pad_send_event (sinkpad, event))
1687 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1690 gst_object_unref (sinkpad);
1694 gst_iterator_free (it);
1698 gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
1701 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1702 gboolean done = FALSE;
1704 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1711 switch (gst_iterator_next (it, (gpointer) & sinkpad)) {
1712 case GST_ITERATOR_OK:
1713 gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
1715 gst_object_unref (sinkpad);
1717 case GST_ITERATOR_DONE:
1720 case GST_ITERATOR_RESYNC:
1721 gst_iterator_resync (it);
1723 case GST_ITERATOR_ERROR:
1728 gst_iterator_free (it);
1732 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1734 GstSourceGroup *group;
1735 GPtrArray *channels;
1738 GST_PLAY_BIN_LOCK (playbin);
1740 GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1741 playbin->current_text, stream);
1743 group = get_group (playbin);
1744 if (!(channels = group->text_channels))
1747 if (stream == -1 || channels->len <= stream) {
1750 /* take channel from selected stream */
1751 sinkpad = g_ptr_array_index (channels, stream);
1755 gst_object_ref (sinkpad);
1756 GST_PLAY_BIN_UNLOCK (playbin);
1759 GstObject *selector;
1761 if ((selector = gst_pad_get_parent (sinkpad))) {
1762 GstPad *old_sinkpad;
1764 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1766 if (old_sinkpad != sinkpad) {
1767 gboolean need_unblock, need_block, need_seek;
1768 GstPad *src, *peer = NULL, *oldpeer = NULL;
1769 GstElement *parent_element = NULL, *old_parent_element = NULL;
1771 /* Now check if we need to seek the suburidecodebin to the beginning
1772 * or if we need to block all suburidecodebin sinkpads or if we need
1773 * to unblock all suburidecodebin sinkpads
1776 peer = gst_pad_get_peer (sinkpad);
1778 oldpeer = gst_pad_get_peer (old_sinkpad);
1781 parent_element = gst_pad_get_parent_element (peer);
1783 old_parent_element = gst_pad_get_parent_element (oldpeer);
1785 need_block = (old_parent_element == group->suburidecodebin
1786 && parent_element != old_parent_element);
1787 need_unblock = (parent_element == group->suburidecodebin
1788 && parent_element != old_parent_element);
1789 need_seek = (parent_element == group->suburidecodebin);
1792 gst_object_unref (peer);
1794 gst_object_unref (oldpeer);
1796 gst_object_unref (parent_element);
1797 if (old_parent_element)
1798 gst_object_unref (old_parent_element);
1800 /* Block all suburidecodebin sinkpads */
1802 gst_play_bin_suburidecodebin_block (group->suburidecodebin, TRUE);
1804 /* activate the selected pad */
1805 g_object_set (selector, "active-pad", sinkpad, NULL);
1807 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1808 peer = gst_pad_get_peer (src);
1812 /* Flush the subtitle renderer to remove any
1813 * currently displayed subtitles. This event will
1814 * never travel outside subtitleoverlay!
1816 s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1817 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1818 gst_pad_send_event (peer, event);
1819 gst_object_unref (peer);
1821 gst_object_unref (src);
1823 /* Unblock pads if necessary */
1825 gst_play_bin_suburidecodebin_block (group->suburidecodebin, FALSE);
1827 /* seek to the beginning */
1829 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1831 gst_object_unref (selector);
1834 gst_object_unref (old_sinkpad);
1836 gst_object_unref (sinkpad);
1842 GST_PLAY_BIN_UNLOCK (playbin);
1848 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1849 const gchar * dbg, GstElement * sink)
1851 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1853 GST_PLAY_BIN_LOCK (playbin);
1854 if (*elem != sink) {
1859 gst_object_ref_sink (sink);
1863 gst_object_unref (old);
1865 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1866 GST_PLAY_BIN_UNLOCK (playbin);
1870 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1874 GST_PLAY_BIN_LOCK (playbin);
1876 /* set subtitles on all current and next decodebins. */
1877 if ((elem = playbin->groups[0].uridecodebin))
1878 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1879 if ((elem = playbin->groups[0].suburidecodebin))
1880 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1881 if ((elem = playbin->groups[1].uridecodebin))
1882 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1883 if ((elem = playbin->groups[1].suburidecodebin))
1884 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1886 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1887 GST_PLAY_BIN_UNLOCK (playbin);
1891 gst_play_bin_set_property (GObject * object, guint prop_id,
1892 const GValue * value, GParamSpec * pspec)
1894 GstPlayBin *playbin = GST_PLAY_BIN (object);
1898 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1901 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1904 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1906 case PROP_CURRENT_VIDEO:
1907 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1909 case PROP_CURRENT_AUDIO:
1910 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1912 case PROP_CURRENT_TEXT:
1913 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1915 case PROP_SUBTITLE_ENCODING:
1916 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1918 case PROP_VIDEO_SINK:
1919 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1920 g_value_get_object (value));
1922 case PROP_AUDIO_SINK:
1923 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1924 g_value_get_object (value));
1926 case PROP_VIS_PLUGIN:
1927 gst_play_sink_set_vis_plugin (playbin->playsink,
1928 g_value_get_object (value));
1930 case PROP_TEXT_SINK:
1931 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1932 g_value_get_object (value));
1935 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1938 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1940 case PROP_FONT_DESC:
1941 gst_play_sink_set_font_desc (playbin->playsink,
1942 g_value_get_string (value));
1944 case PROP_CONNECTION_SPEED:
1945 GST_PLAY_BIN_LOCK (playbin);
1946 playbin->connection_speed = g_value_get_uint (value) * 1000;
1947 GST_PLAY_BIN_UNLOCK (playbin);
1949 case PROP_BUFFER_SIZE:
1950 playbin->buffer_size = g_value_get_int (value);
1952 case PROP_BUFFER_DURATION:
1953 playbin->buffer_duration = g_value_get_int64 (value);
1955 case PROP_AV_OFFSET:
1956 gst_play_sink_set_av_offset (playbin->playsink,
1957 g_value_get_int64 (value));
1959 case PROP_RING_BUFFER_MAX_SIZE:
1960 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
1963 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1969 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1970 const gchar * dbg, GstPlaySinkType type)
1972 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
1974 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1975 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1976 dbg, sink, dbg, *elem);
1979 GST_PLAY_BIN_LOCK (playbin);
1981 gst_object_ref (sink);
1982 GST_PLAY_BIN_UNLOCK (playbin);
1989 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1992 GstPlayBin *playbin = GST_PLAY_BIN (object);
1997 GstSourceGroup *group;
1999 GST_PLAY_BIN_LOCK (playbin);
2000 group = get_group (playbin);
2001 g_value_set_string (value, group->uri);
2002 GST_PLAY_BIN_UNLOCK (playbin);
2007 GstSourceGroup *group;
2009 GST_PLAY_BIN_LOCK (playbin);
2010 group = get_group (playbin);
2011 g_value_set_string (value, group->suburi);
2012 GST_PLAY_BIN_UNLOCK (playbin);
2017 GST_OBJECT_LOCK (playbin);
2018 g_value_set_object (value, playbin->source);
2019 GST_OBJECT_UNLOCK (playbin);
2023 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
2027 GstSourceGroup *group;
2030 GST_PLAY_BIN_LOCK (playbin);
2031 group = get_group (playbin);
2032 n_video = (group->video_channels ? group->video_channels->len : 0);
2033 g_value_set_int (value, n_video);
2034 GST_PLAY_BIN_UNLOCK (playbin);
2037 case PROP_CURRENT_VIDEO:
2038 GST_PLAY_BIN_LOCK (playbin);
2039 g_value_set_int (value, playbin->current_video);
2040 GST_PLAY_BIN_UNLOCK (playbin);
2044 GstSourceGroup *group;
2047 GST_PLAY_BIN_LOCK (playbin);
2048 group = get_group (playbin);
2049 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
2050 g_value_set_int (value, n_audio);
2051 GST_PLAY_BIN_UNLOCK (playbin);
2054 case PROP_CURRENT_AUDIO:
2055 GST_PLAY_BIN_LOCK (playbin);
2056 g_value_set_int (value, playbin->current_audio);
2057 GST_PLAY_BIN_UNLOCK (playbin);
2061 GstSourceGroup *group;
2064 GST_PLAY_BIN_LOCK (playbin);
2065 group = get_group (playbin);
2066 n_text = (group->text_channels ? group->text_channels->len : 0);
2067 g_value_set_int (value, n_text);
2068 GST_PLAY_BIN_UNLOCK (playbin);
2071 case PROP_CURRENT_TEXT:
2072 GST_PLAY_BIN_LOCK (playbin);
2073 g_value_set_int (value, playbin->current_text);
2074 GST_PLAY_BIN_UNLOCK (playbin);
2076 case PROP_SUBTITLE_ENCODING:
2077 GST_PLAY_BIN_LOCK (playbin);
2078 g_value_take_string (value,
2079 gst_play_sink_get_subtitle_encoding (playbin->playsink));
2080 GST_PLAY_BIN_UNLOCK (playbin);
2082 case PROP_VIDEO_SINK:
2083 g_value_take_object (value,
2084 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2085 "video", GST_PLAY_SINK_TYPE_VIDEO));
2087 case PROP_AUDIO_SINK:
2088 g_value_take_object (value,
2089 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2090 "audio", GST_PLAY_SINK_TYPE_AUDIO));
2092 case PROP_VIS_PLUGIN:
2093 g_value_take_object (value,
2094 gst_play_sink_get_vis_plugin (playbin->playsink));
2096 case PROP_TEXT_SINK:
2097 g_value_take_object (value,
2098 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2099 "text", GST_PLAY_SINK_TYPE_TEXT));
2102 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2105 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2108 gst_value_take_buffer (value,
2109 gst_play_sink_get_last_frame (playbin->playsink));
2111 case PROP_FONT_DESC:
2112 g_value_take_string (value,
2113 gst_play_sink_get_font_desc (playbin->playsink));
2115 case PROP_CONNECTION_SPEED:
2116 GST_PLAY_BIN_LOCK (playbin);
2117 g_value_set_uint (value, playbin->connection_speed / 1000);
2118 GST_PLAY_BIN_UNLOCK (playbin);
2120 case PROP_BUFFER_SIZE:
2121 GST_OBJECT_LOCK (playbin);
2122 g_value_set_int (value, playbin->buffer_size);
2123 GST_OBJECT_UNLOCK (playbin);
2125 case PROP_BUFFER_DURATION:
2126 GST_OBJECT_LOCK (playbin);
2127 g_value_set_int64 (value, playbin->buffer_duration);
2128 GST_OBJECT_UNLOCK (playbin);
2130 case PROP_AV_OFFSET:
2131 g_value_set_int64 (value,
2132 gst_play_sink_get_av_offset (playbin->playsink));
2134 case PROP_RING_BUFFER_MAX_SIZE:
2135 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2138 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2144 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2145 gboolean valid, GstQuery * query)
2151 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2152 gst_query_parse_duration (query, &fmt, &duration);
2154 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2155 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2156 playbin->duration[i].valid = valid;
2157 playbin->duration[i].format = fmt;
2158 playbin->duration[i].duration = valid ? duration : -1;
2165 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2167 const GstFormat formats[] =
2168 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2173 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2174 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2175 query = gst_query_new_duration (formats[i]);
2177 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2179 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2180 gst_query_unref (query);
2185 gst_play_bin_query (GstElement * element, GstQuery * query)
2187 GstPlayBin *playbin = GST_PLAY_BIN (element);
2190 /* During a group switch we shouldn't allow duration queries
2191 * because it's not clear if the old or new group's duration
2192 * is returned and if the sinks are already playing new data
2193 * or old data. See bug #585969
2195 * While we're at it, also don't do any other queries during
2196 * a group switch or any other event that causes topology changes
2197 * by taking the playbin lock in any case.
2199 GST_PLAY_BIN_LOCK (playbin);
2201 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2202 GstSourceGroup *group = playbin->curr_group;
2205 GST_SOURCE_GROUP_LOCK (group);
2206 if (group->stream_changed_pending_lock) {
2207 g_mutex_lock (group->stream_changed_pending_lock);
2208 pending = group->pending || group->stream_changed_pending;
2209 g_mutex_unlock (group->stream_changed_pending_lock);
2211 pending = group->pending;
2218 gst_query_parse_duration (query, &fmt, NULL);
2219 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2220 if (fmt == playbin->duration[i].format) {
2221 ret = playbin->duration[i].valid;
2222 gst_query_set_duration (query, fmt,
2223 (ret ? playbin->duration[i].duration : -1));
2227 /* if nothing cached yet, we might as well request duration,
2228 * such as during initial startup */
2230 GST_DEBUG_OBJECT (playbin,
2231 "Taking cached duration because of pending group switch: %d", ret);
2232 GST_SOURCE_GROUP_UNLOCK (group);
2233 GST_PLAY_BIN_UNLOCK (playbin);
2237 GST_SOURCE_GROUP_UNLOCK (group);
2240 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2242 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2243 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2244 GST_PLAY_BIN_UNLOCK (playbin);
2249 /* mime types we are not handling on purpose right now, don't post a
2250 * missing-plugin message for these */
2251 static const gchar *blacklisted_mimes[] = {
2256 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2258 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2259 GstSourceGroup *group;
2261 if (gst_is_missing_plugin_message (msg)) {
2265 detail = gst_missing_plugin_message_get_installer_detail (msg);
2266 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2267 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2268 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2269 gst_message_unref (msg);
2275 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2276 const GstStructure *s = gst_message_get_structure (msg);
2278 /* Drop all stream-changed messages except the last one */
2279 if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2280 guint32 seqnum = gst_message_get_seqnum (msg);
2283 group = playbin->curr_group;
2284 g_mutex_lock (group->stream_changed_pending_lock);
2285 for (l = group->stream_changed_pending; l;) {
2286 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2288 if (l_seqnum == seqnum) {
2291 group->stream_changed_pending =
2292 g_list_delete_link (group->stream_changed_pending, l_prev);
2293 if (group->stream_changed_pending) {
2294 gst_message_unref (msg);
2302 g_mutex_unlock (group->stream_changed_pending_lock);
2304 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2305 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2306 GstObject *src = GST_OBJECT_CAST (msg->src);
2308 /* Ignore async state changes from the uridecodebin children,
2309 * see bug #602000. */
2310 group = playbin->curr_group;
2311 if (src && (group = playbin->curr_group) &&
2312 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2313 || (group->suburidecodebin
2314 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2315 GST_DEBUG_OBJECT (playbin,
2316 "Ignoring async state change of uridecodebin: %s",
2317 GST_OBJECT_NAME (src));
2318 gst_message_unref (msg);
2321 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2322 /* If we get an error of the subtitle uridecodebin transform
2323 * them into warnings and disable the subtitles */
2324 group = playbin->curr_group;
2325 if (group && group->suburidecodebin) {
2326 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2327 (group->suburidecodebin)))) {
2329 gchar *debug = NULL;
2330 GstMessage *new_msg;
2332 gboolean done = FALSE;
2334 gst_message_parse_error (msg, &err, &debug);
2335 new_msg = gst_message_new_warning (msg->src, err, debug);
2337 gst_message_unref (msg);
2342 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2343 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2344 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2345 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2347 it = gst_element_iterate_src_pads (group->suburidecodebin);
2348 while (it && !done) {
2350 GstIteratorResult res;
2352 res = gst_iterator_next (it, (gpointer) & p);
2355 case GST_ITERATOR_DONE:
2358 case GST_ITERATOR_OK:
2359 pad_removed_cb (NULL, p, group);
2360 gst_object_unref (p);
2363 case GST_ITERATOR_RESYNC:
2364 gst_iterator_resync (it);
2366 case GST_ITERATOR_ERROR:
2372 gst_iterator_free (it);
2374 gst_object_ref (group->suburidecodebin);
2375 gst_bin_remove (bin, group->suburidecodebin);
2376 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2378 if (group->sub_pending) {
2379 group->sub_pending = FALSE;
2380 no_more_pads_cb (NULL, group);
2387 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2391 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2392 GstPlayBin * playbin)
2394 const gchar *property;
2395 GstSourceGroup *group;
2396 GstSourceSelect *select = NULL;
2399 GST_PLAY_BIN_LOCK (playbin);
2400 group = get_group (playbin);
2402 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2403 if (selector == G_OBJECT (group->selector[i].selector)) {
2404 select = &group->selector[i];
2408 /* We got a pad-change after our group got switched out; no need to notify */
2410 GST_PLAY_BIN_UNLOCK (playbin);
2414 switch (select->type) {
2415 case GST_PLAY_SINK_TYPE_VIDEO:
2416 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2417 property = "current-video";
2418 playbin->current_video = get_current_stream_number (playbin,
2419 group->video_channels);
2421 case GST_PLAY_SINK_TYPE_AUDIO:
2422 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2423 property = "current-audio";
2424 playbin->current_audio = get_current_stream_number (playbin,
2425 group->audio_channels);
2427 case GST_PLAY_SINK_TYPE_TEXT:
2428 property = "current-text";
2429 playbin->current_text = get_current_stream_number (playbin,
2430 group->text_channels);
2435 GST_PLAY_BIN_UNLOCK (playbin);
2438 g_object_notify (G_OBJECT (playbin), property);
2442 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
2445 GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
2448 /* this callback sends a delayed event once the pad becomes unblocked */
2450 stream_changed_data_probe (GstPad * pad, GstMiniObject * object, gpointer data)
2452 GstSourceSelect *select = (GstSourceSelect *) data;
2455 /* we need do this just once, so cleanup first */
2456 gst_pad_remove_data_probe (pad, select->sinkpad_data_probe);
2457 select->sinkpad_data_probe = 0;
2458 e = select->sinkpad_delayed_event;
2459 select->sinkpad_delayed_event = NULL;
2461 /* really, this should not happen */
2463 GST_WARNING ("Data probed called, but no delayed event");
2467 if (GST_IS_EVENT (object)
2468 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_NEWSEGMENT) {
2469 /* push the event first, then send the delayed one */
2470 gst_event_ref (GST_EVENT_CAST (object));
2471 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2472 gst_pad_send_event (pad, e);
2475 /* send delayed event, then allow the caller to go on */
2476 gst_pad_send_event (pad, e);
2481 /* helper function to lookup stuff in lists */
2483 array_has_value (const gchar * values[], const gchar * value, gboolean exact)
2487 for (i = 0; values[i]; i++) {
2488 if (exact && !strcmp (value, values[i]))
2490 if (!exact && g_str_has_prefix (value, values[i]))
2498 GstPlayBin *playbin;
2500 GstPlaySinkType type;
2504 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2506 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2509 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2510 " with stream id %d and type %d have changed",
2511 object, ntdata->stream_id, ntdata->type);
2513 switch (ntdata->type) {
2514 case GST_PLAY_SINK_TYPE_VIDEO:
2515 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2516 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2518 case GST_PLAY_SINK_TYPE_AUDIO:
2519 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2520 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2522 case GST_PLAY_SINK_TYPE_TEXT:
2523 signal = SIGNAL_TEXT_TAGS_CHANGED;
2531 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2535 /* this function is called when a new pad is added to decodebin. We check the
2536 * type of the pad and add it to the selector element of the group.
2539 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2541 GstPlayBin *playbin;
2543 const GstStructure *s;
2546 GstPadLinkReturn res;
2547 GstSourceSelect *select = NULL;
2549 gboolean changed = FALSE;
2551 playbin = group->playbin;
2553 caps = gst_pad_get_caps_reffed (pad);
2554 s = gst_caps_get_structure (caps, 0);
2555 name = gst_structure_get_name (s);
2557 GST_DEBUG_OBJECT (playbin,
2558 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2559 GST_DEBUG_PAD_NAME (pad), caps, group);
2561 /* major type of the pad, this determines the selector to use,
2562 try exact match first so we don't prematurely match video/
2563 for video/x-dvd-subpicture */
2564 for (pass = 0; !select && pass < 2; pass++) {
2565 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2566 if (array_has_value (group->selector[i].media_list, name, pass == 0)) {
2567 select = &group->selector[i];
2569 } else if (group->selector[i].get_media_caps) {
2570 GstCaps *media_caps = group->selector[i].get_media_caps ();
2572 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2573 select = &group->selector[i];
2574 gst_caps_unref (media_caps);
2577 gst_caps_unref (media_caps);
2581 /* no selector found for the media type, don't bother linking it to a
2582 * selector. This will leave the pad unlinked and thus ignored. */
2586 GST_SOURCE_GROUP_LOCK (group);
2587 if (select->selector == NULL && playbin->have_selector) {
2588 /* no selector, create one */
2589 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2590 select->selector = gst_element_factory_make ("input-selector", NULL);
2591 if (select->selector == NULL) {
2592 /* post the missing selector message only once */
2593 playbin->have_selector = FALSE;
2594 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2595 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2597 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2598 (_("Missing element '%s' - check your GStreamer installation."),
2599 "input-selector"), (NULL));
2601 g_object_set (select->selector, "sync-streams", TRUE, NULL);
2603 g_signal_connect (select->selector, "notify::active-pad",
2604 G_CALLBACK (selector_active_pad_changed), playbin);
2606 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2607 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2608 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2612 if (select->srcpad == NULL) {
2613 if (select->selector) {
2614 /* save source pad of the selector */
2615 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2617 /* no selector, use the pad as the source pad then */
2618 select->srcpad = gst_object_ref (pad);
2621 /* block the selector srcpad. It's possible that multiple decodebins start
2622 * pushing data into the selectors before we have a chance to collect all
2623 * streams and connect the sinks, resulting in not-linked errors. After we
2624 * configured the sinks we will unblock them all. */
2625 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2626 gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
2629 /* get sinkpad for the new stream */
2630 if (select->selector) {
2631 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2632 gulong notify_tags_handler = 0;
2633 NotifyTagsData *ntdata;
2635 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2636 GST_DEBUG_PAD_NAME (sinkpad));
2638 /* store the selector for the pad */
2639 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2641 /* connect to the notify::tags signal for our
2642 * own *-tags-changed signals
2644 ntdata = g_new0 (NotifyTagsData, 1);
2645 ntdata->playbin = playbin;
2646 ntdata->stream_id = select->channels->len;
2647 ntdata->type = select->type;
2649 notify_tags_handler =
2650 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2651 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2653 g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2654 (gpointer) (guintptr) notify_tags_handler);
2656 /* store the pad in the array */
2657 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2658 g_ptr_array_add (select->channels, sinkpad);
2660 res = gst_pad_link (pad, sinkpad);
2661 if (GST_PAD_LINK_FAILED (res))
2664 /* store selector pad so we can release it */
2665 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2668 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2669 GST_DEBUG_PAD_NAME (pad), select->selector);
2672 /* no selector, don't configure anything, we'll link the new pad directly to
2677 GST_SOURCE_GROUP_UNLOCK (group);
2681 gboolean always_ok = (decodebin == group->suburidecodebin);
2683 switch (select->type) {
2684 case GST_PLAY_SINK_TYPE_VIDEO:
2685 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2686 /* we want to return NOT_LINKED for unselected pads but only for pads
2687 * from the normal uridecodebin. This makes sure that subtitle streams
2688 * are not raced past audio/video from decodebin2's multiqueue.
2689 * For pads from suburidecodebin OK should always be returned, otherwise
2690 * it will most likely stop. */
2691 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2692 signal = SIGNAL_VIDEO_CHANGED;
2694 case GST_PLAY_SINK_TYPE_AUDIO:
2695 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2696 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2697 signal = SIGNAL_AUDIO_CHANGED;
2699 case GST_PLAY_SINK_TYPE_TEXT:
2700 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2701 signal = SIGNAL_TEXT_CHANGED;
2708 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2712 gst_caps_unref (caps);
2718 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2719 name, GST_DEBUG_PAD_NAME (pad));
2724 GST_ERROR_OBJECT (playbin,
2725 "failed to link pad %s:%s to selector, reason %d",
2726 GST_DEBUG_PAD_NAME (pad), res);
2727 GST_SOURCE_GROUP_UNLOCK (group);
2732 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2733 * the selector. This will make the selector select a new pad. */
2735 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2737 GstPlayBin *playbin;
2739 GstElement *selector;
2740 GstSourceSelect *select;
2742 playbin = group->playbin;
2744 GST_DEBUG_OBJECT (playbin,
2745 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2747 GST_SOURCE_GROUP_LOCK (group);
2748 /* get the selector sinkpad */
2749 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2752 if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2753 gulong notify_tags_handler;
2755 notify_tags_handler =
2756 (guintptr) g_object_get_data (G_OBJECT (peer),
2757 "playbin2.notify_tags_handler");
2758 if (notify_tags_handler != 0)
2759 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2760 g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2762 /* remove the pad from the array */
2763 g_ptr_array_remove (select->channels, peer);
2764 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2767 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2768 gst_pad_unlink (pad, peer);
2770 /* get selector, this can be NULL when the element is removing the pads
2771 * because it's being disposed. */
2772 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2774 gst_object_unref (peer);
2778 /* release the pad to the selector, this will make the selector choose a new
2780 gst_element_release_request_pad (selector, peer);
2781 gst_object_unref (peer);
2783 gst_object_unref (selector);
2784 GST_SOURCE_GROUP_UNLOCK (group);
2791 GST_DEBUG_OBJECT (playbin, "pad not linked");
2792 GST_SOURCE_GROUP_UNLOCK (group);
2797 GST_DEBUG_OBJECT (playbin, "selector not found");
2798 GST_SOURCE_GROUP_UNLOCK (group);
2803 /* we get called when all pads are available and we must connect the sinks to
2805 * The main purpose of the code is to see if we have video/audio and subtitles
2806 * and pick the right pipelines to display them.
2808 * The selectors installed on the group tell us about the presence of
2809 * audio/video and subtitle streams. This allows us to see if we need
2810 * visualisation, video or/and audio.
2813 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2815 GstPlayBin *playbin;
2816 GstPadLinkReturn res;
2820 playbin = group->playbin;
2822 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2824 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2826 GST_SOURCE_GROUP_LOCK (group);
2827 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2828 GstSourceSelect *select = &group->selector[i];
2830 /* check if the specific media type was detected and thus has a selector
2831 * created for it. If there is the media type, get a sinkpad from the sink
2832 * and link it. We only do this if we have not yet requested the sinkpad
2834 if (select->srcpad && select->sinkpad == NULL) {
2835 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2837 gst_play_sink_request_pad (playbin->playsink, select->type);
2839 res = gst_pad_link (select->srcpad, select->sinkpad);
2840 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2841 select->media_list[0], res);
2842 if (res != GST_PAD_LINK_OK) {
2843 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2844 ("Internal playbin error."),
2845 ("Failed to link selector to sink. Error %d", res));
2849 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2850 group->pending - 1);
2852 if (group->pending > 0)
2855 if (group->suburidecodebin == decodebin)
2856 group->sub_pending = FALSE;
2858 if (group->pending == 0) {
2859 /* we are the last group to complete, we will configure the output and then
2860 * signal the other waiters. */
2861 GST_LOG_OBJECT (playbin, "last group complete");
2864 GST_LOG_OBJECT (playbin, "have more pending groups");
2867 GST_SOURCE_GROUP_UNLOCK (group);
2870 /* if we have custom sinks, configure them now */
2871 GST_SOURCE_GROUP_LOCK (group);
2873 if (group->audio_sink) {
2874 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2876 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2880 if (group->video_sink) {
2881 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2883 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2887 if (playbin->text_sink) {
2888 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
2889 playbin->text_sink);
2890 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2891 playbin->text_sink);
2894 GST_SOURCE_GROUP_UNLOCK (group);
2896 /* signal the other decodebins that they can continue now. */
2897 GST_SOURCE_GROUP_LOCK (group);
2898 /* unblock all selectors */
2899 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2900 GstSourceSelect *select = &group->selector[i];
2902 /* All streamsynchronizer streams should see stream-changed message,
2903 * to arrange for blocking unblocking. */
2904 if (select->sinkpad) {
2910 s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2913 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2914 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2915 seqnum = gst_message_get_seqnum (msg);
2916 event = gst_event_new_sink_message (msg);
2917 g_mutex_lock (group->stream_changed_pending_lock);
2918 group->stream_changed_pending =
2919 g_list_prepend (group->stream_changed_pending,
2920 GUINT_TO_POINTER (seqnum));
2922 /* remove any data probe we might have, and replace */
2923 if (select->sinkpad_delayed_event)
2924 gst_event_unref (select->sinkpad_delayed_event);
2925 select->sinkpad_delayed_event = event;
2926 if (select->sinkpad_data_probe)
2927 gst_pad_remove_data_probe (select->sinkpad,
2928 select->sinkpad_data_probe);
2930 /* we go to the trouble of setting a probe on the pad to send
2931 the playbin2-stream-changed event as sending it here might
2932 find that the pad is blocked, so we'd block here, and the
2933 pad might not be linked yet. Additionally, sending it here
2934 apparently would be on the wrong thread */
2935 select->sinkpad_data_probe =
2936 gst_pad_add_data_probe (select->sinkpad,
2937 (GCallback) stream_changed_data_probe, (gpointer) select);
2939 g_mutex_unlock (group->stream_changed_pending_lock);
2940 gst_message_unref (msg);
2943 if (select->srcpad) {
2944 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2946 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2950 GST_SOURCE_GROUP_UNLOCK (group);
2953 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2959 GST_DEBUG ("ignoring, we are shutting down");
2960 /* Request a flushing pad from playsink that we then link to the selector.
2961 * Then we unblock the selectors so that they stop with a WRONG_STATE
2962 * instead of a NOT_LINKED error.
2964 GST_SOURCE_GROUP_LOCK (group);
2965 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2966 GstSourceSelect *select = &group->selector[i];
2968 if (select->srcpad) {
2969 if (select->sinkpad == NULL) {
2970 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2972 gst_play_sink_request_pad (playbin->playsink,
2973 GST_PLAY_SINK_TYPE_FLUSHING);
2974 res = gst_pad_link (select->srcpad, select->sinkpad);
2975 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2977 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2979 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2983 GST_SOURCE_GROUP_UNLOCK (group);
2989 drained_cb (GstElement * decodebin, GstSourceGroup * group)
2991 GstPlayBin *playbin;
2993 playbin = group->playbin;
2995 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
2997 /* after this call, we should have a next group to activate or we EOS */
2998 g_signal_emit (G_OBJECT (playbin),
2999 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
3001 /* now activate the next group. If the app did not set a uri, this will
3002 * fail and we can do EOS */
3003 setup_next_source (playbin, GST_STATE_PAUSED);
3006 /* Like gst_element_factory_can_sink_any_caps() but doesn't
3007 * allow ANY caps on the sinkpad template */
3009 _factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps)
3011 const GList *templs;
3013 templs = gst_element_factory_get_static_pad_templates (factory);
3016 GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
3018 if (templ->direction == GST_PAD_SINK) {
3019 GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
3021 if (!gst_caps_is_any (templcaps)
3022 && gst_caps_can_intersect (templcaps, caps)) {
3023 gst_caps_unref (templcaps);
3026 gst_caps_unref (templcaps);
3028 templs = g_list_next (templs);
3034 /* Called when we must provide a list of factories to plug to @pad with @caps.
3035 * We first check if we have a sink that can handle the format and if we do, we
3036 * return NULL, to expose the pad. If we have no sink (or the sink does not
3037 * work), we return the list of elements that can connect. */
3038 static GValueArray *
3039 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
3040 GstCaps * caps, GstSourceGroup * group)
3042 GstPlayBin *playbin;
3043 GList *mylist, *tmp;
3044 GValueArray *result;
3046 playbin = group->playbin;
3048 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
3049 group, GST_DEBUG_PAD_NAME (pad), caps);
3051 /* filter out the elements based on the caps. */
3052 g_mutex_lock (playbin->elements_lock);
3053 gst_play_bin_update_elements_list (playbin);
3055 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
3057 g_mutex_unlock (playbin->elements_lock);
3059 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
3060 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
3062 /* 2 additional elements for the already set audio/video sinks */
3063 result = g_value_array_new (g_list_length (mylist) + 2);
3065 /* Check if we already have an audio/video sink and if this is the case
3066 * put it as the first element of the array */
3067 if (group->audio_sink) {
3068 GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
3070 if (factory && _factory_can_sink_caps (factory, caps)) {
3071 GValue val = { 0, };
3073 g_value_init (&val, G_TYPE_OBJECT);
3074 g_value_set_object (&val, factory);
3075 result = g_value_array_append (result, &val);
3076 g_value_unset (&val);
3080 if (group->video_sink) {
3081 GstElementFactory *factory = gst_element_get_factory (group->video_sink);
3083 if (factory && _factory_can_sink_caps (factory, caps)) {
3084 GValue val = { 0, };
3086 g_value_init (&val, G_TYPE_OBJECT);
3087 g_value_set_object (&val, factory);
3088 result = g_value_array_append (result, &val);
3089 g_value_unset (&val);
3093 for (tmp = mylist; tmp; tmp = tmp->next) {
3094 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
3095 GValue val = { 0, };
3097 if (group->audio_sink && gst_element_factory_list_is_type (factory,
3098 GST_ELEMENT_FACTORY_TYPE_SINK |
3099 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
3102 if (group->video_sink && gst_element_factory_list_is_type (factory,
3103 GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
3104 | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
3108 g_value_init (&val, G_TYPE_OBJECT);
3109 g_value_set_object (&val, factory);
3110 g_value_array_append (result, &val);
3111 g_value_unset (&val);
3113 gst_plugin_feature_list_free (mylist);
3118 /* autoplug-continue decides, if a pad has raw caps that can be exposed
3119 * directly or if further decoding is necessary. We use this to expose
3120 * supported subtitles directly */
3122 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
3123 * explicitly the caps it supports and if it claims to support ANY
3124 * caps it really should support everything */
3126 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
3127 GstSourceGroup * group)
3129 gboolean ret = TRUE;
3131 GstPad *sinkpad = NULL;
3133 GST_PLAY_BIN_LOCK (group->playbin);
3134 GST_SOURCE_GROUP_LOCK (group);
3136 if ((sink = group->playbin->text_sink))
3137 sinkpad = gst_element_get_static_pad (sink, "sink");
3141 /* Ignore errors here, if a custom sink fails to go
3142 * to READY things are wrong and will error out later
3144 if (GST_STATE (sink) < GST_STATE_READY)
3145 gst_element_set_state (sink, GST_STATE_READY);
3147 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3148 if (!gst_caps_is_any (sinkcaps))
3149 ret = !gst_pad_accept_caps (sinkpad, caps);
3150 gst_caps_unref (sinkcaps);
3151 gst_object_unref (sinkpad);
3153 GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3154 ret = !gst_caps_is_subset (caps, subcaps);
3155 gst_caps_unref (subcaps);
3157 /* If autoplugging can stop don't do additional checks */
3161 /* If this is from the subtitle uridecodebin we don't need to
3162 * check the audio and video sink */
3163 if (group->suburidecodebin
3164 && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3165 GST_OBJECT_CAST (group->suburidecodebin)))
3168 if ((sink = group->audio_sink)) {
3169 sinkpad = gst_element_get_static_pad (sink, "sink");
3173 /* Ignore errors here, if a custom sink fails to go
3174 * to READY things are wrong and will error out later
3176 if (GST_STATE (sink) < GST_STATE_READY)
3177 gst_element_set_state (sink, GST_STATE_READY);
3179 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3180 if (!gst_caps_is_any (sinkcaps))
3181 ret = !gst_pad_accept_caps (sinkpad, caps);
3182 gst_caps_unref (sinkcaps);
3183 gst_object_unref (sinkpad);
3189 if ((sink = group->video_sink)) {
3190 sinkpad = gst_element_get_static_pad (sink, "sink");
3194 /* Ignore errors here, if a custom sink fails to go
3195 * to READY things are wrong and will error out later
3197 if (GST_STATE (sink) < GST_STATE_READY)
3198 gst_element_set_state (sink, GST_STATE_READY);
3200 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3201 if (!gst_caps_is_any (sinkcaps))
3202 ret = !gst_pad_accept_caps (sinkpad, caps);
3203 gst_caps_unref (sinkcaps);
3204 gst_object_unref (sinkpad);
3209 GST_SOURCE_GROUP_UNLOCK (group);
3210 GST_PLAY_BIN_UNLOCK (group->playbin);
3212 GST_DEBUG_OBJECT (group->playbin,
3213 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3214 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3220 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3224 /* ... activate it ... We do this before adding it to the bin so that we
3225 * don't accidentally make it post error messages that will stop
3227 if (GST_STATE (sink) < GST_STATE_READY &&
3228 gst_element_set_state (sink,
3229 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3233 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3234 /* Got the sink pad, now let's see if the element actually does accept the
3235 * caps that we have */
3236 if (!gst_pad_accept_caps (sinkpad, caps)) {
3237 gst_object_unref (sinkpad);
3240 gst_object_unref (sinkpad);
3246 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw-int; "
3247 "audio/x-raw-float");
3248 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw-rgb; "
3249 "video/x-raw-yuv; " "video/x-raw-gray");
3251 /* We are asked to select an element. See if the next element to check
3252 * is a sink. If this is the case, we see if the sink works by setting it to
3253 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3254 * expose the raw pad so that we can setup the mixers. */
3255 static GstAutoplugSelectResult
3256 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3257 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3259 GstPlayBin *playbin;
3260 GstElement *element;
3262 GstPlaySinkType type;
3265 playbin = group->playbin;
3267 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3268 group, GST_DEBUG_PAD_NAME (pad), caps);
3270 GST_DEBUG_OBJECT (playbin, "checking factory %s",
3271 GST_PLUGIN_FEATURE_NAME (factory));
3273 /* if it's not a sink, we make sure the element is compatible with
3275 if (!gst_element_factory_list_is_type (factory,
3276 GST_ELEMENT_FACTORY_TYPE_SINK)) {
3277 gboolean isvideodec = gst_element_factory_list_is_type (factory,
3278 GST_ELEMENT_FACTORY_TYPE_DECODER |
3279 GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
3280 GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
3281 gboolean isaudiodec = gst_element_factory_list_is_type (factory,
3282 GST_ELEMENT_FACTORY_TYPE_DECODER |
3283 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
3285 /* If it is a decoder and we have a fixed sink for the media
3286 * type it outputs, check that the decoder is compatible with this sink */
3287 if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) {
3288 gboolean compatible = TRUE;
3294 sink = group->audio_sink;
3296 sink = group->video_sink;
3298 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3299 GstPlayFlags flags = gst_play_bin_get_flags (playbin);
3301 (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) :
3302 gst_static_caps_get (&raw_video_caps);
3304 caps = gst_pad_get_caps_reffed (sinkpad);
3306 /* If the sink supports raw audio/video, we first check
3307 * if the decoder could output any raw audio/video format
3308 * and assume it is compatible with the sink then. We don't
3309 * do a complete compatibility check here if converters
3310 * are plugged between the decoder and the sink because
3311 * the converters will convert between raw formats and
3312 * even if the decoder format is not supported by the decoder
3313 * a converter will convert it.
3315 * We assume here that the converters can convert between
3318 if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO)
3319 && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec
3320 && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO)
3321 && gst_caps_can_intersect (caps, raw_caps))) {
3322 compatible = gst_element_factory_can_src_any_caps (factory, raw_caps)
3323 || gst_element_factory_can_src_any_caps (factory, caps);
3325 compatible = gst_element_factory_can_src_any_caps (factory, caps);
3328 gst_object_unref (sinkpad);
3329 gst_caps_unref (caps);
3333 return GST_AUTOPLUG_SELECT_TRY;
3335 GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink",
3336 GST_PLUGIN_FEATURE_NAME (factory));
3338 return GST_AUTOPLUG_SELECT_SKIP;
3340 return GST_AUTOPLUG_SELECT_TRY;
3343 /* it's a sink, see if an instance of it actually works */
3344 GST_DEBUG_OBJECT (playbin, "we found a sink");
3346 klass = gst_element_factory_get_klass (factory);
3348 /* figure out the klass */
3349 if (strstr (klass, "Audio")) {
3350 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3351 type = GST_PLAY_SINK_TYPE_AUDIO;
3352 sinkp = &group->audio_sink;
3353 } else if (strstr (klass, "Video")) {
3354 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3355 type = GST_PLAY_SINK_TYPE_VIDEO;
3356 sinkp = &group->video_sink;
3358 /* unknown klass, skip this element */
3359 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3360 return GST_AUTOPLUG_SELECT_SKIP;
3363 /* if we are asked to do visualisations and it's an audio sink, skip the
3364 * element. We can only do visualisations with raw sinks */
3365 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3366 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3367 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3368 return GST_AUTOPLUG_SELECT_SKIP;
3372 /* now see if we already have a sink element */
3373 GST_SOURCE_GROUP_LOCK (group);
3375 GstElement *sink = gst_object_ref (*sinkp);
3377 if (sink_accepts_caps (sink, caps)) {
3378 GST_DEBUG_OBJECT (playbin,
3379 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3380 GST_ELEMENT_NAME (sink), caps);
3381 gst_object_unref (sink);
3382 GST_SOURCE_GROUP_UNLOCK (group);
3383 return GST_AUTOPLUG_SELECT_EXPOSE;
3385 GST_DEBUG_OBJECT (playbin,
3386 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3387 GST_ELEMENT_NAME (sink), caps);
3388 gst_object_unref (sink);
3389 GST_SOURCE_GROUP_UNLOCK (group);
3390 return GST_AUTOPLUG_SELECT_SKIP;
3393 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3395 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3396 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3397 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3398 GST_SOURCE_GROUP_UNLOCK (group);
3399 return GST_AUTOPLUG_SELECT_SKIP;
3402 /* Check if the selected sink actually supports the
3403 * caps and can be set to READY*/
3404 if (!sink_accepts_caps (element, caps)) {
3405 gst_element_set_state (element, GST_STATE_NULL);
3406 gst_object_unref (element);
3407 GST_SOURCE_GROUP_UNLOCK (group);
3408 return GST_AUTOPLUG_SELECT_SKIP;
3411 /* remember the sink in the group now, the element is floating, we take
3414 * store the sink in the group, we will configure it later when we
3415 * reconfigure the sink */
3416 GST_DEBUG_OBJECT (playbin, "remember sink");
3417 gst_object_ref_sink (element);
3419 GST_SOURCE_GROUP_UNLOCK (group);
3421 /* tell decodebin to expose the pad because we are going to use this
3423 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3425 return GST_AUTOPLUG_SELECT_EXPOSE;
3429 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3430 GstSourceGroup * group)
3432 GstPlayBin *playbin;
3435 playbin = group->playbin;
3437 g_object_get (group->uridecodebin, "source", &source, NULL);
3439 GST_OBJECT_LOCK (playbin);
3440 if (playbin->source)
3441 gst_object_unref (playbin->source);
3442 playbin->source = source;
3443 GST_OBJECT_UNLOCK (playbin);
3445 g_object_notify (G_OBJECT (playbin), "source");
3447 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3448 0, playbin->source);
3451 /* must be called with the group lock */
3453 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3456 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3458 if (group->uridecodebin)
3459 gst_element_set_locked_state (group->uridecodebin, locked);
3460 if (group->suburidecodebin)
3461 gst_element_set_locked_state (group->suburidecodebin, locked);
3466 /* must be called with PLAY_BIN_LOCK */
3468 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3470 GstElement *uridecodebin;
3471 GstElement *suburidecodebin = NULL;
3474 g_return_val_if_fail (group->valid, FALSE);
3475 g_return_val_if_fail (!group->active, FALSE);
3477 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3479 GST_SOURCE_GROUP_LOCK (group);
3481 /* First set up the custom sources */
3482 if (playbin->audio_sink)
3483 group->audio_sink = gst_object_ref (playbin->audio_sink);
3484 if (playbin->video_sink)
3485 group->video_sink = gst_object_ref (playbin->video_sink);
3487 g_list_free (group->stream_changed_pending);
3488 group->stream_changed_pending = NULL;
3489 if (!group->stream_changed_pending_lock)
3490 group->stream_changed_pending_lock = g_mutex_new ();
3492 if (group->uridecodebin) {
3493 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3494 uridecodebin = group->uridecodebin;
3495 gst_element_set_state (uridecodebin, GST_STATE_READY);
3496 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3498 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3499 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3502 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3503 group->uridecodebin = gst_object_ref (uridecodebin);
3506 flags = gst_play_sink_get_flags (playbin->playsink);
3508 g_object_set (uridecodebin,
3509 /* configure connection speed */
3510 "connection-speed", playbin->connection_speed / 1000,
3513 /* configure download buffering */
3514 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3515 /* configure buffering of demuxed/parsed data */
3516 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3517 /* configure buffering parameters */
3518 "buffer-duration", playbin->buffer_duration,
3519 "buffer-size", playbin->buffer_size,
3520 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3522 /* connect pads and other things */
3523 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3524 G_CALLBACK (pad_added_cb), group);
3525 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3526 G_CALLBACK (pad_removed_cb), group);
3527 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3528 G_CALLBACK (no_more_pads_cb), group);
3529 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3530 G_CALLBACK (notify_source_cb), group);
3532 /* we have 1 pending no-more-pads */
3535 /* is called when the uridecodebin is out of data and we can switch to the
3538 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3541 /* will be called when a new media type is found. We return a list of decoders
3542 * including sinks for decodebin to try */
3543 group->autoplug_factories_id =
3544 g_signal_connect (uridecodebin, "autoplug-factories",
3545 G_CALLBACK (autoplug_factories_cb), group);
3546 group->autoplug_select_id =
3547 g_signal_connect (uridecodebin, "autoplug-select",
3548 G_CALLBACK (autoplug_select_cb), group);
3549 group->autoplug_continue_id =
3550 g_signal_connect (uridecodebin, "autoplug-continue",
3551 G_CALLBACK (autoplug_continue_cb), group);
3553 if (group->suburi) {
3555 if (group->suburidecodebin) {
3556 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3557 suburidecodebin = group->suburidecodebin;
3558 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3559 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3561 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3562 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3563 if (!suburidecodebin)
3566 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3567 group->suburidecodebin = gst_object_ref (suburidecodebin);
3570 g_object_set (suburidecodebin,
3571 /* configure connection speed */
3572 "connection-speed", playbin->connection_speed,
3574 "uri", group->suburi, NULL);
3576 /* connect pads and other things */
3577 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3578 G_CALLBACK (pad_added_cb), group);
3579 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3580 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3581 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3582 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3584 group->sub_autoplug_continue_id =
3585 g_signal_connect (suburidecodebin, "autoplug-continue",
3586 G_CALLBACK (autoplug_continue_cb), group);
3588 /* we have 2 pending no-more-pads */
3590 group->sub_pending = TRUE;
3592 group->sub_pending = FALSE;
3595 /* release the group lock before setting the state of the decodebins, they
3596 * might fire signals in this thread that we need to handle with the
3597 * group_lock taken. */
3598 GST_SOURCE_GROUP_UNLOCK (group);
3600 if (suburidecodebin) {
3601 if (gst_element_set_state (suburidecodebin,
3602 target) == GST_STATE_CHANGE_FAILURE) {
3603 GST_DEBUG_OBJECT (playbin,
3604 "failed state change of subtitle uridecodebin");
3605 GST_SOURCE_GROUP_LOCK (group);
3607 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3608 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3609 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3610 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3611 /* Might already be removed because of an error message */
3612 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3613 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3614 if (group->sub_pending) {
3616 group->sub_pending = FALSE;
3618 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3619 GST_SOURCE_GROUP_UNLOCK (group);
3622 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3623 goto uridecodebin_failure;
3625 GST_SOURCE_GROUP_LOCK (group);
3626 /* alow state changes of the playbin2 affect the group elements now */
3627 group_set_locked_state_unlocked (playbin, group, FALSE);
3628 group->active = TRUE;
3629 GST_SOURCE_GROUP_UNLOCK (group);
3638 /* delete any custom sinks we might have */
3639 if (group->audio_sink) {
3640 /* If this is a automatically created sink set it to NULL */
3641 if (group->audio_sink != playbin->audio_sink)
3642 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3643 gst_object_unref (group->audio_sink);
3645 group->audio_sink = NULL;
3646 if (group->video_sink) {
3647 /* If this is a automatically created sink set it to NULL */
3648 if (group->video_sink != playbin->video_sink)
3649 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3650 gst_object_unref (group->video_sink);
3652 group->video_sink = NULL;
3654 GST_SOURCE_GROUP_UNLOCK (group);
3656 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3658 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3660 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3661 (_("Could not create \"uridecodebin\" element.")), (NULL));
3664 uridecodebin_failure:
3666 /* delete any custom sinks we might have */
3667 if (group->audio_sink) {
3668 /* If this is a automatically created sink set it to NULL */
3669 if (group->audio_sink != playbin->audio_sink)
3670 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3671 gst_object_unref (group->audio_sink);
3673 group->audio_sink = NULL;
3674 if (group->video_sink) {
3675 /* If this is a automatically created sink set it to NULL */
3676 if (group->video_sink != playbin->video_sink)
3677 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3678 gst_object_unref (group->video_sink);
3680 group->video_sink = NULL;
3682 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3687 /* unlink a group of uridecodebins from the sink.
3688 * must be called with PLAY_BIN_LOCK */
3690 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3694 g_return_val_if_fail (group->valid, FALSE);
3695 g_return_val_if_fail (group->active, FALSE);
3697 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3699 GST_SOURCE_GROUP_LOCK (group);
3700 group->active = FALSE;
3701 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3702 GstSourceSelect *select = &group->selector[i];
3704 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3706 if (select->srcpad) {
3707 if (select->sinkpad) {
3708 GST_LOG_OBJECT (playbin, "unlinking from sink");
3709 gst_pad_unlink (select->srcpad, select->sinkpad);
3712 GST_LOG_OBJECT (playbin, "release sink pad");
3713 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3714 select->sinkpad = NULL;
3717 gst_object_unref (select->srcpad);
3718 select->srcpad = NULL;
3721 if (select->selector) {
3724 /* release and unref requests pad from the selector */
3725 for (n = 0; n < select->channels->len; n++) {
3726 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3728 gst_element_release_request_pad (select->selector, sinkpad);
3729 gst_object_unref (sinkpad);
3731 g_ptr_array_set_size (select->channels, 0);
3733 gst_element_set_state (select->selector, GST_STATE_NULL);
3734 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3735 select->selector = NULL;
3738 /* delete any custom sinks we might have */
3739 if (group->audio_sink) {
3740 /* If this is a automatically created sink set it to NULL */
3741 if (group->audio_sink != playbin->audio_sink)
3742 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3743 gst_object_unref (group->audio_sink);
3745 group->audio_sink = NULL;
3746 if (group->video_sink) {
3747 /* If this is a automatically created sink set it to NULL */
3748 if (group->video_sink != playbin->video_sink)
3749 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3750 gst_object_unref (group->video_sink);
3752 group->video_sink = NULL;
3754 if (group->uridecodebin) {
3755 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3756 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3757 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3758 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3759 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3760 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3761 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3762 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3763 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3766 if (group->suburidecodebin) {
3767 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3768 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3769 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3770 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3772 /* Might already be removed because of errors */
3773 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3774 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3777 GST_SOURCE_GROUP_UNLOCK (group);
3782 /* setup the next group to play, this assumes the next_group is valid and
3783 * configured. It swaps out the current_group and activates the valid
3786 setup_next_source (GstPlayBin * playbin, GstState target)
3788 GstSourceGroup *new_group, *old_group;
3790 GST_DEBUG_OBJECT (playbin, "setup sources");
3792 /* see if there is a next group */
3793 GST_PLAY_BIN_LOCK (playbin);
3794 new_group = playbin->next_group;
3795 if (!new_group || !new_group->valid)
3798 /* first unlink the current source, if any */
3799 old_group = playbin->curr_group;
3800 if (old_group && old_group->valid && old_group->active) {
3801 gst_play_bin_update_cached_duration (playbin);
3802 /* unlink our pads with the sink */
3803 deactivate_group (playbin, old_group);
3804 old_group->valid = FALSE;
3807 /* swap old and new */
3808 playbin->curr_group = new_group;
3809 playbin->next_group = old_group;
3811 /* activate the new group */
3812 if (!activate_group (playbin, new_group, target))
3813 goto activate_failed;
3815 GST_PLAY_BIN_UNLOCK (playbin);
3822 GST_DEBUG_OBJECT (playbin, "no next group");
3823 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3824 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3825 GST_PLAY_BIN_UNLOCK (playbin);
3830 GST_DEBUG_OBJECT (playbin, "activate failed");
3831 GST_PLAY_BIN_UNLOCK (playbin);
3836 /* The group that is currently playing is copied again to the
3837 * next_group so that it will start playing the next time.
3840 save_current_group (GstPlayBin * playbin)
3842 GstSourceGroup *curr_group;
3844 GST_DEBUG_OBJECT (playbin, "save current group");
3846 /* see if there is a current group */
3847 GST_PLAY_BIN_LOCK (playbin);
3848 curr_group = playbin->curr_group;
3849 if (curr_group && curr_group->valid && curr_group->active) {
3850 /* unlink our pads with the sink */
3851 deactivate_group (playbin, curr_group);
3853 /* swap old and new */
3854 playbin->curr_group = playbin->next_group;
3855 playbin->next_group = curr_group;
3856 GST_PLAY_BIN_UNLOCK (playbin);
3861 /* clear the locked state from all groups. This function is called before a
3862 * state change to NULL is performed on them. */
3864 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3866 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3869 GST_PLAY_BIN_LOCK (playbin);
3870 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3871 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3872 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3873 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3874 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3875 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3876 GST_PLAY_BIN_UNLOCK (playbin);
3881 static GstStateChangeReturn
3882 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3884 GstStateChangeReturn ret;
3885 GstPlayBin *playbin;
3886 gboolean do_save = FALSE;
3888 playbin = GST_PLAY_BIN (element);
3890 switch (transition) {
3891 case GST_STATE_CHANGE_NULL_TO_READY:
3892 memset (&playbin->duration, 0, sizeof (playbin->duration));
3894 case GST_STATE_CHANGE_READY_TO_PAUSED:
3895 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3896 memset (&playbin->duration, 0, sizeof (playbin->duration));
3897 g_atomic_int_set (&playbin->shutdown, 0);
3899 if (!setup_next_source (playbin, GST_STATE_READY)) {
3900 ret = GST_STATE_CHANGE_FAILURE;
3904 case GST_STATE_CHANGE_PAUSED_TO_READY:
3906 /* FIXME unlock our waiting groups */
3907 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3908 g_atomic_int_set (&playbin->shutdown, 1);
3909 memset (&playbin->duration, 0, sizeof (playbin->duration));
3911 /* wait for all callbacks to end by taking the lock.
3912 * No dynamic (critical) new callbacks will
3913 * be able to happen as we set the shutdown flag. */
3914 GST_PLAY_BIN_DYN_LOCK (playbin);
3915 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3916 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3919 case GST_STATE_CHANGE_READY_TO_NULL:
3920 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3921 * an no state change PAUSED to READY passes here,
3922 * though it is a nice-to-have ... */
3923 if (!g_atomic_int_get (&playbin->shutdown)) {
3927 memset (&playbin->duration, 0, sizeof (playbin->duration));
3929 /* unlock so that all groups go to NULL */
3930 groups_set_locked_state (playbin, FALSE);
3936 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3937 if (ret == GST_STATE_CHANGE_FAILURE)
3940 switch (transition) {
3941 case GST_STATE_CHANGE_READY_TO_PAUSED:
3943 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3944 /* FIXME Release audio device when we implement that */
3946 case GST_STATE_CHANGE_PAUSED_TO_READY:
3947 save_current_group (playbin);
3949 case GST_STATE_CHANGE_READY_TO_NULL:
3953 /* also do missed state change down to READY */
3955 save_current_group (playbin);
3956 /* Deactive the groups, set the uridecodebins to NULL
3959 for (i = 0; i < 2; i++) {
3960 if (playbin->groups[i].active && playbin->groups[i].valid) {
3961 deactivate_group (playbin, &playbin->groups[i]);
3962 playbin->groups[i].valid = FALSE;
3965 if (playbin->groups[i].uridecodebin) {
3966 gst_element_set_state (playbin->groups[i].uridecodebin,
3968 gst_object_unref (playbin->groups[i].uridecodebin);
3969 playbin->groups[i].uridecodebin = NULL;
3972 if (playbin->groups[i].suburidecodebin) {
3973 gst_element_set_state (playbin->groups[i].suburidecodebin,
3975 gst_object_unref (playbin->groups[i].suburidecodebin);
3976 playbin->groups[i].suburidecodebin = NULL;
3980 /* Set our sinks back to NULL, they might not be child of playbin */
3981 if (playbin->audio_sink)
3982 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
3983 if (playbin->video_sink)
3984 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
3985 if (playbin->text_sink)
3986 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
3988 /* make sure the groups don't perform a state change anymore until we
3989 * enable them again */
3990 groups_set_locked_state (playbin, TRUE);
4002 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
4003 GstSourceGroup *curr_group;
4005 curr_group = playbin->curr_group;
4006 if (curr_group && curr_group->active && curr_group->valid) {
4007 /* unlink our pads with the sink */
4008 deactivate_group (playbin, curr_group);
4009 curr_group->valid = FALSE;
4012 /* Swap current and next group back */
4013 playbin->curr_group = playbin->next_group;
4014 playbin->next_group = curr_group;
4021 gst_play_bin2_plugin_init (GstPlugin * plugin)
4023 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
4025 return gst_element_register (plugin, "playbin2", GST_RANK_NONE,