2 * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * SECTION:element-playbin2
23 * Playbin2 provides a stand-alone everything-in-one abstraction for an
24 * audio and/or video player.
26 * playbin2 is considered stable now. It is the prefered playback API now,
27 * and replaces the old #playbin element, which is no longer supported.
29 * It can handle both audio and video files and features
32 * automatic file type recognition and based on that automatic
33 * selection and usage of the right audio/video/subtitle demuxers/decoders
36 * visualisations for audio files
39 * subtitle support for video files. Subtitles can be store in external
43 * stream selection between different video/audio/subtitles streams
46 * meta info (tag) extraction
49 * easy access to the last video frame
52 * buffering when playing streams over a network
55 * volume control with mute option
60 * <title>Usage</title>
62 * A playbin2 element can be created just like any other element using
63 * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin2:uri
64 * property. This must be an absolute URI, relative file paths are not allowed.
65 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
67 * Playbin is a #GstPipeline. It will notify the application of everything
68 * that's happening (errors, end of stream, tags found, state changes, etc.)
69 * by posting messages on its #GstBus. The application needs to watch the
72 * Playback can be initiated by setting the element to PLAYING state using
73 * gst_element_set_state(). Note that the state change will take place in
74 * the background in a separate thread, when the function returns playback
75 * is probably not happening yet and any errors might not have occured yet.
76 * Applications using playbin should ideally be written to deal with things
77 * completely asynchroneous.
79 * When playback has finished (an EOS message has been received on the bus)
80 * or an error has occured (an ERROR message has been received on the bus) or
81 * the user wants to play a different track, playbin should be set back to
82 * READY or NULL state, then the #GstPlayBin2:uri property should be set to the
83 * new location and then playbin be set to PLAYING state again.
85 * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
86 * on the playbin element. Again, the seek will not be executed
87 * instantaneously, but will be done in a background thread. When the seek
88 * call returns the seek will most likely still be in process. An application
89 * may wait for the seek to finish (or fail) using gst_element_get_state() with
90 * -1 as the timeout, but this will block the user interface and is not
93 * Applications may query the current position and duration of the stream
94 * via gst_element_query_position() and gst_element_query_duration() and
95 * setting the format passed to GST_FORMAT_TIME. If the query was successful,
96 * the duration or position will have been returned in units of nanoseconds.
100 * <title>Advanced Usage: specifying the audio and video sink</title>
102 * By default, if no audio sink or video sink has been specified via the
103 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property, playbin will use the autoaudiosink
104 * and autovideosink elements to find the first-best available output method.
105 * This should work in most cases, but is not always desirable. Often either
106 * the user or application might want to specify more explicitly what to use
107 * for audio and video output.
109 * If the application wants more control over how audio or video should be
110 * output, it may create the audio/video sink elements itself (for example
111 * using gst_element_factory_make()) and provide them to playbin using the
112 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property.
114 * GNOME-based applications, for example, will usually want to create
115 * gconfaudiosink and gconfvideosink elements and make playbin use those,
116 * so that output happens to whatever the user has configured in the GNOME
117 * Multimedia System Selector configuration dialog.
119 * The sink elements do not necessarily need to be ready-made sinks. It is
120 * possible to create container elements that look like a sink to playbin,
121 * but in reality contain a number of custom elements linked together. This
122 * can be achieved by creating a #GstBin and putting elements in there and
123 * linking them, and then creating a sink #GstGhostPad for the bin and pointing
124 * it to the sink pad of the first element within the bin. This can be used
125 * for a number of purposes, for example to force output to a particular
126 * format or to modify or observe the data before it is output.
128 * It is also possible to 'suppress' audio and/or video output by using
129 * 'fakesink' elements (or capture it from there using the fakesink element's
130 * "handoff" signal, which, nota bene, is fired from the streaming thread!).
134 * <title>Retrieving Tags and Other Meta Data</title>
136 * Most of the common meta data (artist, title, etc.) can be retrieved by
137 * watching for TAG messages on the pipeline's bus (see above).
139 * Other more specific meta information like width/height/framerate of video
140 * streams or samplerate/number of channels of audio streams can be obtained
141 * from the negotiated caps on the sink pads of the sinks.
145 * <title>Buffering</title>
146 * Playbin handles buffering automatically for the most part, but applications
147 * need to handle parts of the buffering process as well. Whenever playbin is
148 * buffering, it will post BUFFERING messages on the bus with a percentage
149 * value that shows the progress of the buffering process. Applications need
150 * to set playbin to PLAYING or PAUSED state in response to these messages.
151 * They may also want to convey the buffering progress to the user in some
152 * way. Here is how to extract the percentage information from the message
153 * (requires GStreamer >= 0.10.11):
155 * switch (GST_MESSAGE_TYPE (msg)) {
156 * case GST_MESSAGE_BUFFERING: {
158 * gst_message_parse_buffering (msg, &percent);
159 * g_print ("Buffering (%%u percent done)", percent);
165 * Note that applications should keep/set the pipeline in the PAUSED state when
166 * a BUFFERING message is received with a buffer percent value < 100 and set
167 * the pipeline back to PLAYING state when a BUFFERING message with a value
168 * of 100 percent is received (if PLAYING is the desired state, that is).
171 * <title>Embedding the video window in your application</title>
172 * By default, playbin (or rather the video sinks used) will create their own
173 * window. Applications will usually want to force output to a window of their
174 * own, however. This can be done using the #GstXOverlay interface, which most
175 * video sinks implement. See the documentation there for more details.
178 * <title>Specifying which CD/DVD device to use</title>
179 * The device to use for CDs/DVDs needs to be set on the source element
180 * playbin creates before it is opened. The only way to do this at the moment
181 * is to connect to playbin's "notify::source" signal, which will be emitted
182 * by playbin when it has created the source element for a particular URI.
183 * In the signal callback you can check if the source element has a "device"
184 * property and set it appropriately. In future ways might be added to specify
185 * the device as part of the URI, but at the time of writing this is not
189 * <title>Handling redirects</title>
191 * Some elements may post 'redirect' messages on the bus to tell the
192 * application to open another location. These are element messages containing
193 * a structure named 'redirect' along with a 'new-location' field of string
194 * type. The new location may be a relative or an absolute URI. Examples
195 * for such redirects can be found in many quicktime movie trailers.
199 * <title>Examples</title>
201 * gst-launch -v playbin uri=file:///path/to/somefile.avi
202 * ]| This will play back the given AVI video file, given that the video and
203 * audio decoders required to decode the content are installed. Since no
204 * special audio sink or video sink is supplied (not possible via gst-launch),
205 * playbin will try to find a suitable audio and video sink automatically
206 * using the autoaudiosink and autovideosink elements.
208 * gst-launch -v playbin uri=cdda://4
209 * ]| This will play back track 4 on an audio CD in your disc drive (assuming
210 * the drive is detected automatically by the plugin).
212 * gst-launch -v playbin uri=dvd://1
213 * ]| This will play back title 1 of a DVD in your disc drive (assuming
214 * the drive is detected automatically by the plugin).
225 #include <gst/gst-i18n-plugin.h>
226 #include <gst/pbutils/pbutils.h>
227 #include <gst/interfaces/streamvolume.h>
229 #include "gstplay-enum.h"
230 #include "gstplay-marshal.h"
231 #include "gstplayback.h"
232 #include "gstplaysink.h"
233 #include "gstsubtitleoverlay.h"
235 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
236 #define GST_CAT_DEFAULT gst_play_bin_debug
238 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type())
239 #define GST_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
240 #define GST_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
241 #define GST_IS_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
242 #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
244 #define VOLUME_MAX_DOUBLE 10.0
246 typedef struct _GstPlayBin GstPlayBin;
247 typedef struct _GstPlayBinClass GstPlayBinClass;
248 typedef struct _GstSourceGroup GstSourceGroup;
249 typedef struct _GstSourceSelect GstSourceSelect;
251 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
253 /* has the info for a selector and provides the link to the sink */
254 struct _GstSourceSelect
256 const gchar *media_list[8]; /* the media types for the selector */
257 SourceSelectGetMediaCapsFunc get_media_caps; /* more complex caps for the selector */
258 GstPlaySinkType type; /* the sink pad type of the selector */
260 GstElement *selector; /* the selector */
262 GstPad *srcpad; /* the source pad of the selector */
263 GstPad *sinkpad; /* the sinkpad of the sink when the selector
266 GstEvent *sinkpad_delayed_event;
267 gulong sinkpad_data_probe;
270 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
271 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
272 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
274 /* a structure to hold the objects for decoding a uri and the subtitle uri
276 struct _GstSourceGroup
282 gboolean valid; /* the group has valid info to start playback */
283 gboolean active; /* the group is active */
288 GValueArray *streaminfo;
291 GPtrArray *video_channels; /* links to selector pads */
292 GPtrArray *audio_channels; /* links to selector pads */
293 GPtrArray *text_channels; /* links to selector pads */
295 GstElement *audio_sink; /* autoplugged audio and video sinks */
296 GstElement *video_sink;
298 /* uridecodebins for uri and subtitle uri */
299 GstElement *uridecodebin;
300 GstElement *suburidecodebin;
302 gboolean sub_pending;
305 gulong pad_removed_id;
306 gulong no_more_pads_id;
307 gulong notify_source_id;
309 gulong autoplug_factories_id;
310 gulong autoplug_select_id;
311 gulong autoplug_continue_id;
313 gulong sub_pad_added_id;
314 gulong sub_pad_removed_id;
315 gulong sub_no_more_pads_id;
316 gulong sub_autoplug_continue_id;
318 GMutex *stream_changed_pending_lock;
319 GList *stream_changed_pending;
321 /* selectors for different streams */
322 GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST];
325 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
326 #define GST_PLAY_BIN_LOCK(bin) (g_static_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
327 #define GST_PLAY_BIN_UNLOCK(bin) (g_static_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
329 /* lock to protect dynamic callbacks, like no-more-pads */
330 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->dyn_lock)
331 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->dyn_lock)
333 /* lock for shutdown */
334 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
336 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
338 GST_PLAY_BIN_DYN_LOCK (bin); \
339 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
340 GST_PLAY_BIN_DYN_UNLOCK (bin); \
345 /* unlock for shutdown */
346 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
347 GST_PLAY_BIN_DYN_UNLOCK (bin); \
352 * playbin element structure
358 GStaticRecMutex lock; /* to protect group switching */
360 /* the groups, we use a double buffer to switch between current and next */
361 GstSourceGroup groups[2]; /* array with group info */
362 GstSourceGroup *curr_group; /* pointer to the currently playing group */
363 GstSourceGroup *next_group; /* pointer to the next group */
366 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
367 gint current_video; /* the currently selected stream */
368 gint current_audio; /* the currently selected stream */
369 gint current_text; /* the currently selected stream */
371 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
372 guint buffer_size; /* When buffering, the max buffer size (bytes) */
375 GstPlaySink *playsink;
377 /* the last activated source */
380 /* lock protecting dynamic adding/removing */
382 /* if we are shutting down or not */
385 GMutex *elements_lock;
386 guint32 elements_cookie;
387 GList *elements; /* factories we can use for selecting elements */
389 gboolean have_selector; /* set to FALSE when we fail to create an
390 * input-selector, so that we only post a
393 GstElement *audio_sink; /* configured audio sink, or NULL */
394 GstElement *video_sink; /* configured video sink, or NULL */
395 GstElement *text_sink; /* configured text sink, or NULL */
402 } duration[5]; /* cached durations */
404 guint64 ring_buffer_max_size; /* 0 means disabled */
407 struct _GstPlayBinClass
409 GstPipelineClass parent_class;
411 /* notify app that the current uri finished decoding and it is possible to
412 * queue a new one for gapless playback */
413 void (*about_to_finish) (GstPlayBin * playbin);
415 /* notify app that number of audio/video/text streams changed */
416 void (*video_changed) (GstPlayBin * playbin);
417 void (*audio_changed) (GstPlayBin * playbin);
418 void (*text_changed) (GstPlayBin * playbin);
420 /* notify app that the tags of audio/video/text streams changed */
421 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
422 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
423 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
425 /* get audio/video/text tags for a stream */
426 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
427 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
428 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
430 /* get the last video frame and convert it to the given caps */
431 GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
433 /* get audio/video/text pad for a stream */
434 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
435 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
436 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
440 #define DEFAULT_URI NULL
441 #define DEFAULT_SUBURI NULL
442 #define DEFAULT_SOURCE NULL
443 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
444 GST_PLAY_FLAG_SOFT_VOLUME
445 #define DEFAULT_N_VIDEO 0
446 #define DEFAULT_CURRENT_VIDEO -1
447 #define DEFAULT_N_AUDIO 0
448 #define DEFAULT_CURRENT_AUDIO -1
449 #define DEFAULT_N_TEXT 0
450 #define DEFAULT_CURRENT_TEXT -1
451 #define DEFAULT_SUBTITLE_ENCODING NULL
452 #define DEFAULT_AUDIO_SINK NULL
453 #define DEFAULT_VIDEO_SINK NULL
454 #define DEFAULT_VIS_PLUGIN NULL
455 #define DEFAULT_TEXT_SINK NULL
456 #define DEFAULT_VOLUME 1.0
457 #define DEFAULT_MUTE FALSE
458 #define DEFAULT_FRAME NULL
459 #define DEFAULT_FONT_DESC NULL
460 #define DEFAULT_CONNECTION_SPEED 0
461 #define DEFAULT_BUFFER_DURATION -1
462 #define DEFAULT_BUFFER_SIZE -1
463 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
478 PROP_SUBTITLE_ENCODING,
487 PROP_CONNECTION_SPEED,
489 PROP_BUFFER_DURATION,
491 PROP_RING_BUFFER_MAX_SIZE,
498 SIGNAL_ABOUT_TO_FINISH,
499 SIGNAL_CONVERT_FRAME,
500 SIGNAL_VIDEO_CHANGED,
501 SIGNAL_AUDIO_CHANGED,
503 SIGNAL_VIDEO_TAGS_CHANGED,
504 SIGNAL_AUDIO_TAGS_CHANGED,
505 SIGNAL_TEXT_TAGS_CHANGED,
506 SIGNAL_GET_VIDEO_TAGS,
507 SIGNAL_GET_AUDIO_TAGS,
508 SIGNAL_GET_TEXT_TAGS,
509 SIGNAL_GET_VIDEO_PAD,
510 SIGNAL_GET_AUDIO_PAD,
516 static void gst_play_bin_class_init (GstPlayBinClass * klass);
517 static void gst_play_bin_init (GstPlayBin * playbin);
518 static void gst_play_bin_finalize (GObject * object);
520 static void gst_play_bin_set_property (GObject * object, guint prop_id,
521 const GValue * value, GParamSpec * spec);
522 static void gst_play_bin_get_property (GObject * object, guint prop_id,
523 GValue * value, GParamSpec * spec);
525 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
526 GstStateChange transition);
528 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
529 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
531 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
533 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
535 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
538 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
541 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
542 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
543 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
545 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
547 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
548 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
549 GstSourceGroup * group);
551 static void gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
553 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
556 static GstElementClass *parent_class;
558 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
560 #define REMOVE_SIGNAL(obj,id) \
562 g_signal_handler_disconnect (obj, id); \
567 gst_play_bin_get_type (void)
569 static GType gst_play_bin_type = 0;
571 if (!gst_play_bin_type) {
572 static const GTypeInfo gst_play_bin_info = {
573 sizeof (GstPlayBinClass),
576 (GClassInitFunc) gst_play_bin_class_init,
581 (GInstanceInitFunc) gst_play_bin_init,
584 static const GInterfaceInfo svol_info = {
588 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
589 "GstPlayBin2", &gst_play_bin_info, 0);
591 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
595 return gst_play_bin_type;
599 gst_play_bin_class_init (GstPlayBinClass * klass)
601 GObjectClass *gobject_klass;
602 GstElementClass *gstelement_klass;
603 GstBinClass *gstbin_klass;
605 gobject_klass = (GObjectClass *) klass;
606 gstelement_klass = (GstElementClass *) klass;
607 gstbin_klass = (GstBinClass *) klass;
609 parent_class = g_type_class_peek_parent (klass);
611 gobject_klass->set_property = gst_play_bin_set_property;
612 gobject_klass->get_property = gst_play_bin_get_property;
614 gobject_klass->finalize = gst_play_bin_finalize;
619 * Set the next URI that playbin will play. This property can be set from the
620 * about-to-finish signal to queue the next media file.
622 g_object_class_install_property (gobject_klass, PROP_URI,
623 g_param_spec_string ("uri", "URI", "URI of the media to play",
624 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
629 * Set the next subtitle URI that playbin will play. This property can be
630 * set from the about-to-finish signal to queue the next subtitle media file.
632 g_object_class_install_property (gobject_klass, PROP_SUBURI,
633 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
634 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
636 g_object_class_install_property (gobject_klass, PROP_SOURCE,
637 g_param_spec_object ("source", "Source", "Source element",
638 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
643 * Control the behaviour of playbin.
645 g_object_class_install_property (gobject_klass, PROP_FLAGS,
646 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
647 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
648 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
651 * GstPlayBin2:n-video
653 * Get the total number of available video streams.
655 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
656 g_param_spec_int ("n-video", "Number Video",
657 "Total number of video streams", 0, G_MAXINT, 0,
658 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
660 * GstPlayBin2:current-video
662 * Get or set the currently playing video stream. By default the first video
663 * stream with data is played.
665 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
666 g_param_spec_int ("current-video", "Current Video",
667 "Currently playing video stream (-1 = auto)",
668 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
670 * GstPlayBin2:n-audio
672 * Get the total number of available audio streams.
674 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
675 g_param_spec_int ("n-audio", "Number Audio",
676 "Total number of audio streams", 0, G_MAXINT, 0,
677 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
679 * GstPlayBin2:current-audio
681 * Get or set the currently playing audio stream. By default the first audio
682 * stream with data is played.
684 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
685 g_param_spec_int ("current-audio", "Current audio",
686 "Currently playing audio stream (-1 = auto)",
687 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
691 * Get the total number of available subtitle streams.
693 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
694 g_param_spec_int ("n-text", "Number Text",
695 "Total number of text streams", 0, G_MAXINT, 0,
696 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
698 * GstPlayBin2:current-text:
700 * Get or set the currently playing subtitle stream. By default the first
701 * subtitle stream with data is played.
703 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
704 g_param_spec_int ("current-text", "Current Text",
705 "Currently playing text stream (-1 = auto)",
706 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
708 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
709 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
710 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
711 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
712 "be checked for an encoding to use. If that is not set either, "
713 "ISO-8859-15 will be assumed.", NULL,
714 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
716 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
717 g_param_spec_object ("video-sink", "Video Sink",
718 "the video output element to use (NULL = default sink)",
719 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
720 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
721 g_param_spec_object ("audio-sink", "Audio Sink",
722 "the audio output element to use (NULL = default sink)",
723 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
724 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
725 g_param_spec_object ("vis-plugin", "Vis plugin",
726 "the visualization element to use (NULL = default)",
727 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
728 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
729 g_param_spec_object ("text-sink", "Text plugin",
730 "the text output element to use (NULL = default textoverlay)",
731 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
734 * GstPlayBin2:volume:
736 * Get or set the current audio stream volume. 1.0 means 100%,
737 * 0.0 means mute. This uses a linear volume scale.
740 g_object_class_install_property (gobject_klass, PROP_VOLUME,
741 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
742 0.0, VOLUME_MAX_DOUBLE, 1.0,
743 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
744 g_object_class_install_property (gobject_klass, PROP_MUTE,
745 g_param_spec_boolean ("mute", "Mute",
746 "Mute the audio channel without changing the volume", FALSE,
747 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
751 * @playbin: a #GstPlayBin2
753 * Get the currently rendered or prerolled frame in the video sink.
754 * The #GstCaps on the buffer will describe the format of the buffer.
756 g_object_class_install_property (gobject_klass, PROP_FRAME,
757 g_param_spec_boxed ("frame", "Frame",
758 "The last frame (NULL = no video available)",
759 GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
760 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
761 g_param_spec_string ("subtitle-font-desc",
762 "Subtitle font description",
763 "Pango font description of font "
764 "to be used for subtitle rendering", NULL,
765 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
767 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
768 g_param_spec_uint ("connection-speed", "Connection Speed",
769 "Network connection speed in kbps (0 = unknown)",
770 0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
771 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
773 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
774 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
775 "Buffer size when buffering network streams",
776 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
777 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
778 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
779 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
780 "Buffer duration when buffering network streams",
781 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
782 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
784 * GstPlayBin2:av-offset:
786 * Control the synchronisation offset between the audio and video streams.
787 * Positive values make the audio ahead of the video and negative values make
788 * the audio go behind the video.
792 g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
793 g_param_spec_int64 ("av-offset", "AV Offset",
794 "The synchronisation offset between audio and video in nanoseconds",
795 G_MININT64, G_MAXINT64, 0,
796 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
799 * GstQueue2:ring-buffer-max-size
801 * The maximum size of the ring buffer in bytes. If set to 0, the ring
802 * buffer is disabled. Default 0.
806 g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
807 g_param_spec_uint64 ("ring-buffer-max-size",
808 "Max. ring buffer size (bytes)",
809 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
810 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
811 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
814 * GstPlayBin2::about-to-finish
815 * @playbin: a #GstPlayBin2
817 * This signal is emitted when the current uri is about to finish. You can
818 * set the uri and suburi to make sure that playback continues.
820 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
821 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
823 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
824 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
827 * GstPlayBin2::video-changed
828 * @playbin: a #GstPlayBin2
830 * This signal is emitted whenever the number or order of the video
831 * streams has changed. The application will most likely want to select
832 * a new video stream.
834 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
835 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
837 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
838 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
840 * GstPlayBin2::audio-changed
841 * @playbin: a #GstPlayBin2
843 * This signal is emitted whenever the number or order of the audio
844 * streams has changed. The application will most likely want to select
845 * a new audio stream.
847 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
848 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
850 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
851 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
853 * GstPlayBin2::text-changed
854 * @playbin: a #GstPlayBin2
856 * This signal is emitted whenever the number or order of the text
857 * streams has changed. The application will most likely want to select
860 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
861 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
863 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
864 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
867 * GstPlayBin2::video-tags-changed
868 * @playbin: a #GstPlayBin2
869 * @stream: stream index with changed tags
871 * This signal is emitted whenever the tags of a video stream have changed.
872 * The application will most likely want to get the new tags.
876 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
877 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
879 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
880 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
883 * GstPlayBin2::audio-tags-changed
884 * @playbin: a #GstPlayBin2
885 * @stream: stream index with changed tags
887 * This signal is emitted whenever the tags of an audio stream have changed.
888 * The application will most likely want to get the new tags.
892 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
893 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
895 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
896 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
899 * GstPlayBin2::text-tags-changed
900 * @playbin: a #GstPlayBin2
901 * @stream: stream index with changed tags
903 * This signal is emitted whenever the tags of a text stream have changed.
904 * The application will most likely want to get the new tags.
908 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
909 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
911 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
912 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
915 * GstPlayBin2::source-setup:
916 * @playbin: a #GstPlayBin2
917 * @source: source element
919 * This signal is emitted after the source element has been created, so
920 * it can be configured by setting additional properties (e.g. set a
921 * proxy server for an http source, or set the device and read speed for
922 * an audio cd source). This is functionally equivalent to connecting to
923 * the notify::source signal, but more convenient.
927 gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
928 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
929 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
930 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
933 * GstPlayBin2::get-video-tags
934 * @playbin: a #GstPlayBin2
935 * @stream: a video stream number
937 * Action signal to retrieve the tags of a specific video stream number.
938 * This information can be used to select a stream.
940 * Returns: a GstTagList with tags or NULL when the stream number does not
943 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
944 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
945 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
946 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
947 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
949 * GstPlayBin2::get-audio-tags
950 * @playbin: a #GstPlayBin2
951 * @stream: an audio stream number
953 * Action signal to retrieve the tags of a specific audio stream number.
954 * This information can be used to select a stream.
956 * Returns: a GstTagList with tags or NULL when the stream number does not
959 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
960 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
961 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
962 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
963 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
965 * GstPlayBin2::get-text-tags
966 * @playbin: a #GstPlayBin2
967 * @stream: a text stream number
969 * Action signal to retrieve the tags of a specific text stream number.
970 * This information can be used to select a stream.
972 * Returns: a GstTagList with tags or NULL when the stream number does not
975 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
976 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
977 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
978 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
979 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
981 * GstPlayBin2::convert-frame
982 * @playbin: a #GstPlayBin2
983 * @caps: the target format of the frame
985 * Action signal to retrieve the currently playing video frame in the format
986 * specified by @caps.
987 * If @caps is %NULL, no conversion will be performed and this function is
988 * equivalent to the #GstPlayBin::frame property.
990 * Returns: a #GstBuffer of the current video frame converted to #caps.
991 * The caps on the buffer will describe the final layout of the buffer data.
992 * %NULL is returned when no current buffer can be retrieved or when the
995 gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
996 g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
997 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
998 G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
999 gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
1002 * GstPlayBin2::get-video-pad
1003 * @playbin: a #GstPlayBin2
1004 * @stream: a video stream number
1006 * Action signal to retrieve the stream-selector sinkpad for a specific
1008 * This pad can be used for notifications of caps changes, stream-specific
1011 * Returns: a #GstPad, or NULL when the stream number does not exist.
1013 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1014 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1015 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1016 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1017 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1019 * GstPlayBin2::get-audio-pad
1020 * @playbin: a #GstPlayBin2
1021 * @stream: an audio stream number
1023 * Action signal to retrieve the stream-selector sinkpad for a specific
1025 * This pad can be used for notifications of caps changes, stream-specific
1028 * Returns: a #GstPad, or NULL when the stream number does not exist.
1030 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1031 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1032 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1033 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1034 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1036 * GstPlayBin2::get-text-pad
1037 * @playbin: a #GstPlayBin2
1038 * @stream: a text stream number
1040 * Action signal to retrieve the stream-selector sinkpad for a specific
1042 * This pad can be used for notifications of caps changes, stream-specific
1045 * Returns: a #GstPad, or NULL when the stream number does not exist.
1047 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1048 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1049 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1050 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1051 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1053 klass->get_video_tags = gst_play_bin_get_video_tags;
1054 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1055 klass->get_text_tags = gst_play_bin_get_text_tags;
1057 klass->convert_frame = gst_play_bin_convert_frame;
1059 klass->get_video_pad = gst_play_bin_get_video_pad;
1060 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1061 klass->get_text_pad = gst_play_bin_get_text_pad;
1063 gst_element_class_set_details_simple (gstelement_klass,
1064 "Player Bin 2", "Generic/Bin/Player",
1065 "Autoplug and play media from an uri",
1066 "Wim Taymans <wim.taymans@gmail.com>");
1068 gstelement_klass->change_state =
1069 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1070 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1072 gstbin_klass->handle_message =
1073 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1077 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1081 /* store the array for the different channels */
1082 group->video_channels = g_ptr_array_new ();
1083 group->audio_channels = g_ptr_array_new ();
1084 group->text_channels = g_ptr_array_new ();
1085 group->lock = g_mutex_new ();
1086 /* init selectors. The selector is found by finding the first prefix that
1087 * matches the media. */
1088 group->playbin = playbin;
1089 /* If you add any items to these lists, check that media_list[] is defined
1090 * above to be large enough to hold MAX(items)+1, so as to accomodate a
1091 * NULL terminator (set when the memory is zeroed on allocation) */
1092 group->selector[0].media_list[0] = "audio/x-raw-";
1093 group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
1094 group->selector[0].channels = group->audio_channels;
1095 group->selector[1].media_list[0] = "audio/";
1096 group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO;
1097 group->selector[1].channels = group->audio_channels;
1098 group->selector[2].media_list[0] = "text/";
1099 group->selector[2].media_list[1] = "application/x-subtitle";
1100 group->selector[2].media_list[2] = "application/x-ssa";
1101 group->selector[2].media_list[3] = "application/x-ass";
1102 group->selector[2].media_list[4] = "video/x-dvd-subpicture";
1103 group->selector[2].media_list[5] = "subpicture/";
1104 group->selector[2].media_list[6] = "subtitle/";
1105 group->selector[2].get_media_caps = gst_subtitle_overlay_create_factory_caps;
1106 group->selector[2].type = GST_PLAY_SINK_TYPE_TEXT;
1107 group->selector[2].channels = group->text_channels;
1108 group->selector[3].media_list[0] = "video/x-raw-";
1109 group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
1110 group->selector[3].channels = group->video_channels;
1111 group->selector[4].media_list[0] = "video/";
1112 group->selector[4].type = GST_PLAY_SINK_TYPE_VIDEO;
1113 group->selector[4].channels = group->video_channels;
1115 for (n = 0; n < GST_PLAY_SINK_TYPE_LAST; n++) {
1116 GstSourceSelect *select = &group->selector[n];
1117 select->sinkpad_delayed_event = NULL;
1118 select->sinkpad_data_probe = 0;
1123 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1127 for (n = 0; n < GST_PLAY_SINK_TYPE_LAST; n++) {
1128 GstSourceSelect *select = &group->selector[n];
1129 if (select->sinkpad && select->sinkpad_data_probe)
1130 gst_pad_remove_data_probe (select->sinkpad, select->sinkpad_data_probe);
1131 if (select->sinkpad_delayed_event)
1132 gst_event_unref (select->sinkpad_delayed_event);
1135 g_free (group->uri);
1136 g_free (group->suburi);
1137 g_ptr_array_free (group->video_channels, TRUE);
1138 g_ptr_array_free (group->audio_channels, TRUE);
1139 g_ptr_array_free (group->text_channels, TRUE);
1141 g_mutex_free (group->lock);
1142 if (group->audio_sink) {
1143 if (group->audio_sink != playbin->audio_sink)
1144 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1145 gst_object_unref (group->audio_sink);
1147 group->audio_sink = NULL;
1148 if (group->video_sink) {
1149 if (group->video_sink != playbin->video_sink)
1150 gst_element_set_state (group->video_sink, GST_STATE_NULL);
1151 gst_object_unref (group->video_sink);
1153 group->video_sink = NULL;
1155 g_list_free (group->stream_changed_pending);
1156 group->stream_changed_pending = NULL;
1158 if (group->stream_changed_pending_lock)
1159 g_mutex_free (group->stream_changed_pending_lock);
1160 group->stream_changed_pending_lock = NULL;
1164 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1166 g_object_notify (G_OBJECT (playbin), "volume");
1170 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1172 g_object_notify (G_OBJECT (playbin), "mute");
1175 /* Must be called with elements lock! */
1177 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1181 if (!playbin->elements ||
1182 playbin->elements_cookie !=
1183 gst_default_registry_get_feature_list_cookie ()) {
1184 if (playbin->elements)
1185 gst_plugin_feature_list_free (playbin->elements);
1187 gst_element_factory_list_get_elements
1188 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1190 gst_element_factory_list_get_elements
1191 (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1192 playbin->elements = g_list_concat (res, tmp);
1194 g_list_sort (playbin->elements, gst_plugin_feature_rank_compare_func);
1195 playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1200 gst_play_bin_init (GstPlayBin * playbin)
1202 g_static_rec_mutex_init (&playbin->lock);
1203 playbin->dyn_lock = g_mutex_new ();
1205 /* assume we can create a selector */
1206 playbin->have_selector = TRUE;
1209 playbin->curr_group = &playbin->groups[0];
1210 playbin->next_group = &playbin->groups[1];
1211 init_group (playbin, &playbin->groups[0]);
1212 init_group (playbin, &playbin->groups[1]);
1214 /* first filter out the interesting element factories */
1215 playbin->elements_lock = g_mutex_new ();
1218 playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1219 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1220 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1221 /* Connect to notify::volume and notify::mute signals for proxying */
1222 g_signal_connect (playbin->playsink, "notify::volume",
1223 G_CALLBACK (notify_volume_cb), playbin);
1224 g_signal_connect (playbin->playsink, "notify::mute",
1225 G_CALLBACK (notify_mute_cb), playbin);
1227 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1228 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1229 playbin->current_text = DEFAULT_CURRENT_TEXT;
1231 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1232 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1233 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1237 gst_play_bin_finalize (GObject * object)
1239 GstPlayBin *playbin;
1241 playbin = GST_PLAY_BIN (object);
1243 free_group (playbin, &playbin->groups[0]);
1244 free_group (playbin, &playbin->groups[1]);
1246 if (playbin->source)
1247 gst_object_unref (playbin->source);
1248 if (playbin->video_sink) {
1249 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1250 gst_object_unref (playbin->video_sink);
1252 if (playbin->audio_sink) {
1253 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1254 gst_object_unref (playbin->audio_sink);
1256 if (playbin->text_sink) {
1257 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1258 gst_object_unref (playbin->text_sink);
1261 if (playbin->elements)
1262 gst_plugin_feature_list_free (playbin->elements);
1264 g_static_rec_mutex_free (&playbin->lock);
1265 g_mutex_free (playbin->dyn_lock);
1266 g_mutex_free (playbin->elements_lock);
1268 G_OBJECT_CLASS (parent_class)->finalize (object);
1272 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1274 GstSourceGroup *group;
1277 g_warning ("cannot set NULL uri");
1281 GST_PLAY_BIN_LOCK (playbin);
1282 group = playbin->next_group;
1284 GST_SOURCE_GROUP_LOCK (group);
1285 /* store the uri in the next group we will play */
1286 g_free (group->uri);
1287 group->uri = g_strdup (uri);
1288 group->valid = TRUE;
1289 GST_SOURCE_GROUP_UNLOCK (group);
1291 GST_DEBUG ("set new uri to %s", uri);
1292 GST_PLAY_BIN_UNLOCK (playbin);
1296 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1298 GstSourceGroup *group;
1300 GST_PLAY_BIN_LOCK (playbin);
1301 group = playbin->next_group;
1303 GST_SOURCE_GROUP_LOCK (group);
1304 g_free (group->suburi);
1305 group->suburi = g_strdup (suburi);
1306 GST_SOURCE_GROUP_UNLOCK (group);
1308 GST_DEBUG ("setting new .sub uri to %s", suburi);
1310 GST_PLAY_BIN_UNLOCK (playbin);
1314 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1316 gst_play_sink_set_flags (playbin->playsink, flags);
1317 gst_play_sink_reconfigure (playbin->playsink);
1321 gst_play_bin_get_flags (GstPlayBin * playbin)
1325 flags = gst_play_sink_get_flags (playbin->playsink);
1330 /* get the currently playing group or if nothing is playing, the next
1331 * group. Must be called with the PLAY_BIN_LOCK. */
1332 static GstSourceGroup *
1333 get_group (GstPlayBin * playbin)
1335 GstSourceGroup *result;
1337 if (!(result = playbin->curr_group))
1338 result = playbin->next_group;
1344 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1346 GstPad *sinkpad = NULL;
1347 GstSourceGroup *group;
1349 GST_PLAY_BIN_LOCK (playbin);
1350 group = get_group (playbin);
1351 if (stream < group->video_channels->len) {
1352 sinkpad = g_ptr_array_index (group->video_channels, stream);
1353 gst_object_ref (sinkpad);
1355 GST_PLAY_BIN_UNLOCK (playbin);
1361 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1363 GstPad *sinkpad = NULL;
1364 GstSourceGroup *group;
1366 GST_PLAY_BIN_LOCK (playbin);
1367 group = get_group (playbin);
1368 if (stream < group->audio_channels->len) {
1369 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1370 gst_object_ref (sinkpad);
1372 GST_PLAY_BIN_UNLOCK (playbin);
1378 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1380 GstPad *sinkpad = NULL;
1381 GstSourceGroup *group;
1383 GST_PLAY_BIN_LOCK (playbin);
1384 group = get_group (playbin);
1385 if (stream < group->text_channels->len) {
1386 sinkpad = g_ptr_array_index (group->text_channels, stream);
1387 gst_object_ref (sinkpad);
1389 GST_PLAY_BIN_UNLOCK (playbin);
1396 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1401 if (!channels || stream >= channels->len)
1404 sinkpad = g_ptr_array_index (channels, stream);
1405 g_object_get (sinkpad, "tags", &result, NULL);
1411 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1414 GstSourceGroup *group;
1416 GST_PLAY_BIN_LOCK (playbin);
1417 group = get_group (playbin);
1418 result = get_tags (playbin, group->video_channels, stream);
1419 GST_PLAY_BIN_UNLOCK (playbin);
1425 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1428 GstSourceGroup *group;
1430 GST_PLAY_BIN_LOCK (playbin);
1431 group = get_group (playbin);
1432 result = get_tags (playbin, group->audio_channels, stream);
1433 GST_PLAY_BIN_UNLOCK (playbin);
1439 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1442 GstSourceGroup *group;
1444 GST_PLAY_BIN_LOCK (playbin);
1445 group = get_group (playbin);
1446 result = get_tags (playbin, group->text_channels, stream);
1447 GST_PLAY_BIN_UNLOCK (playbin);
1453 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1455 return gst_play_sink_convert_frame (playbin->playsink, caps);
1458 /* Returns current stream number, or -1 if none has been selected yet */
1460 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1462 /* Internal API cleanup would make this easier... */
1464 GstPad *pad, *current;
1465 GstObject *selector = NULL;
1468 for (i = 0; i < channels->len; i++) {
1469 pad = g_ptr_array_index (channels, i);
1470 if ((selector = gst_pad_get_parent (pad))) {
1471 g_object_get (selector, "active-pad", ¤t, NULL);
1472 gst_object_unref (selector);
1474 if (pad == current) {
1475 gst_object_unref (current);
1481 gst_object_unref (current);
1489 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1491 GstSourceGroup *group;
1492 GPtrArray *channels;
1495 GST_PLAY_BIN_LOCK (playbin);
1496 group = get_group (playbin);
1497 if (!(channels = group->video_channels))
1500 if (stream == -1 || channels->len <= stream) {
1503 /* take channel from selected stream */
1504 sinkpad = g_ptr_array_index (channels, stream);
1508 gst_object_ref (sinkpad);
1509 GST_PLAY_BIN_UNLOCK (playbin);
1512 GstObject *selector;
1514 if ((selector = gst_pad_get_parent (sinkpad))) {
1515 /* activate the selected pad */
1516 g_object_set (selector, "active-pad", sinkpad, NULL);
1517 gst_object_unref (selector);
1519 gst_object_unref (sinkpad);
1525 GST_PLAY_BIN_UNLOCK (playbin);
1526 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1532 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1534 GstSourceGroup *group;
1535 GPtrArray *channels;
1538 GST_PLAY_BIN_LOCK (playbin);
1539 group = get_group (playbin);
1540 if (!(channels = group->audio_channels))
1543 if (stream == -1 || channels->len <= stream) {
1546 /* take channel from selected stream */
1547 sinkpad = g_ptr_array_index (channels, stream);
1551 gst_object_ref (sinkpad);
1552 GST_PLAY_BIN_UNLOCK (playbin);
1555 GstObject *selector;
1557 if ((selector = gst_pad_get_parent (sinkpad))) {
1558 /* activate the selected pad */
1559 g_object_set (selector, "active-pad", sinkpad, NULL);
1560 gst_object_unref (selector);
1562 gst_object_unref (sinkpad);
1568 GST_PLAY_BIN_UNLOCK (playbin);
1569 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1575 _suburidecodebin_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
1577 GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
1581 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1583 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1586 if (it && gst_iterator_next (it, (gpointer) & sinkpad) == GST_ITERATOR_OK
1591 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1592 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1593 if (!gst_pad_send_event (sinkpad, event)) {
1595 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1596 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1597 if (!gst_pad_send_event (sinkpad, event))
1598 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1601 gst_object_unref (sinkpad);
1605 gst_iterator_free (it);
1609 gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
1612 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1613 gboolean done = FALSE;
1615 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1622 switch (gst_iterator_next (it, (gpointer) & sinkpad)) {
1623 case GST_ITERATOR_OK:
1624 gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
1626 gst_object_unref (sinkpad);
1628 case GST_ITERATOR_DONE:
1631 case GST_ITERATOR_RESYNC:
1632 gst_iterator_resync (it);
1634 case GST_ITERATOR_ERROR:
1639 gst_iterator_free (it);
1643 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1645 GstSourceGroup *group;
1646 GPtrArray *channels;
1649 GST_PLAY_BIN_LOCK (playbin);
1650 group = get_group (playbin);
1651 if (!(channels = group->text_channels))
1654 if (stream == -1 || channels->len <= stream) {
1657 /* take channel from selected stream */
1658 sinkpad = g_ptr_array_index (channels, stream);
1662 gst_object_ref (sinkpad);
1663 GST_PLAY_BIN_UNLOCK (playbin);
1666 GstObject *selector;
1668 if ((selector = gst_pad_get_parent (sinkpad))) {
1669 GstPad *old_sinkpad;
1671 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1673 if (old_sinkpad != sinkpad) {
1674 gboolean need_unblock, need_block, need_seek;
1675 GstPad *src, *peer = NULL, *oldpeer = NULL;
1676 GstElement *parent_element = NULL, *old_parent_element = NULL;
1678 /* Now check if we need to seek the suburidecodebin to the beginning
1679 * or if we need to block all suburidecodebin sinkpads or if we need
1680 * to unblock all suburidecodebin sinkpads
1683 peer = gst_pad_get_peer (sinkpad);
1685 oldpeer = gst_pad_get_peer (old_sinkpad);
1688 parent_element = gst_pad_get_parent_element (peer);
1690 old_parent_element = gst_pad_get_parent_element (oldpeer);
1692 need_block = (old_parent_element == group->suburidecodebin
1693 && parent_element != old_parent_element);
1694 need_unblock = (parent_element == group->suburidecodebin
1695 && parent_element != old_parent_element);
1696 need_seek = (parent_element == group->suburidecodebin);
1699 gst_object_unref (peer);
1701 gst_object_unref (oldpeer);
1703 gst_object_unref (parent_element);
1704 if (old_parent_element)
1705 gst_object_unref (old_parent_element);
1707 /* Block all suburidecodebin sinkpads */
1709 gst_play_bin_suburidecodebin_block (group->suburidecodebin, TRUE);
1711 /* activate the selected pad */
1712 g_object_set (selector, "active-pad", sinkpad, NULL);
1714 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1715 peer = gst_pad_get_peer (src);
1719 /* Flush the subtitle renderer to remove any
1720 * currently displayed subtitles. This event will
1721 * never travel outside subtitleoverlay!
1723 s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1724 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1725 gst_pad_send_event (peer, event);
1726 gst_object_unref (peer);
1728 gst_object_unref (src);
1730 /* Unblock pads if necessary */
1732 gst_play_bin_suburidecodebin_block (group->suburidecodebin, FALSE);
1734 /* seek to the beginning */
1736 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1738 gst_object_unref (selector);
1741 gst_object_unref (old_sinkpad);
1743 gst_object_unref (sinkpad);
1749 GST_PLAY_BIN_UNLOCK (playbin);
1755 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1756 const gchar * dbg, GstElement * sink)
1758 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1760 GST_PLAY_BIN_LOCK (playbin);
1761 if (*elem != sink) {
1766 gst_object_ref_sink (sink);
1770 gst_object_unref (old);
1772 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1773 GST_PLAY_BIN_UNLOCK (playbin);
1777 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1781 GST_PLAY_BIN_LOCK (playbin);
1783 /* set subtitles on all current and next decodebins. */
1784 if ((elem = playbin->groups[0].uridecodebin))
1785 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1786 if ((elem = playbin->groups[0].suburidecodebin))
1787 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1788 if ((elem = playbin->groups[1].uridecodebin))
1789 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1790 if ((elem = playbin->groups[1].suburidecodebin))
1791 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1793 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1794 GST_PLAY_BIN_UNLOCK (playbin);
1798 gst_play_bin_set_property (GObject * object, guint prop_id,
1799 const GValue * value, GParamSpec * pspec)
1801 GstPlayBin *playbin = GST_PLAY_BIN (object);
1805 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1808 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1811 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1813 case PROP_CURRENT_VIDEO:
1814 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1816 case PROP_CURRENT_AUDIO:
1817 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1819 case PROP_CURRENT_TEXT:
1820 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1822 case PROP_SUBTITLE_ENCODING:
1823 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1825 case PROP_VIDEO_SINK:
1826 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1827 g_value_get_object (value));
1829 case PROP_AUDIO_SINK:
1830 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1831 g_value_get_object (value));
1833 case PROP_VIS_PLUGIN:
1834 gst_play_sink_set_vis_plugin (playbin->playsink,
1835 g_value_get_object (value));
1837 case PROP_TEXT_SINK:
1838 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1839 g_value_get_object (value));
1842 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1845 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1847 case PROP_FONT_DESC:
1848 gst_play_sink_set_font_desc (playbin->playsink,
1849 g_value_get_string (value));
1851 case PROP_CONNECTION_SPEED:
1852 GST_PLAY_BIN_LOCK (playbin);
1853 playbin->connection_speed = g_value_get_uint (value) * 1000;
1854 GST_PLAY_BIN_UNLOCK (playbin);
1856 case PROP_BUFFER_SIZE:
1857 playbin->buffer_size = g_value_get_int (value);
1859 case PROP_BUFFER_DURATION:
1860 playbin->buffer_duration = g_value_get_int64 (value);
1862 case PROP_AV_OFFSET:
1863 gst_play_sink_set_av_offset (playbin->playsink,
1864 g_value_get_int64 (value));
1866 case PROP_RING_BUFFER_MAX_SIZE:
1867 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
1870 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1876 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1877 const gchar * dbg, GstPlaySinkType type)
1879 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
1881 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1882 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1883 dbg, sink, dbg, *elem);
1886 GST_PLAY_BIN_LOCK (playbin);
1888 gst_object_ref (sink);
1889 GST_PLAY_BIN_UNLOCK (playbin);
1896 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1899 GstPlayBin *playbin = GST_PLAY_BIN (object);
1904 GstSourceGroup *group;
1906 GST_PLAY_BIN_LOCK (playbin);
1907 group = get_group (playbin);
1908 g_value_set_string (value, group->uri);
1909 GST_PLAY_BIN_UNLOCK (playbin);
1914 GstSourceGroup *group;
1916 GST_PLAY_BIN_LOCK (playbin);
1917 group = get_group (playbin);
1918 g_value_set_string (value, group->suburi);
1919 GST_PLAY_BIN_UNLOCK (playbin);
1924 GST_OBJECT_LOCK (playbin);
1925 g_value_set_object (value, playbin->source);
1926 GST_OBJECT_UNLOCK (playbin);
1930 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
1934 GstSourceGroup *group;
1937 GST_PLAY_BIN_LOCK (playbin);
1938 group = get_group (playbin);
1939 n_video = (group->video_channels ? group->video_channels->len : 0);
1940 g_value_set_int (value, n_video);
1941 GST_PLAY_BIN_UNLOCK (playbin);
1944 case PROP_CURRENT_VIDEO:
1945 GST_PLAY_BIN_LOCK (playbin);
1946 g_value_set_int (value, playbin->current_video);
1947 GST_PLAY_BIN_UNLOCK (playbin);
1951 GstSourceGroup *group;
1954 GST_PLAY_BIN_LOCK (playbin);
1955 group = get_group (playbin);
1956 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
1957 g_value_set_int (value, n_audio);
1958 GST_PLAY_BIN_UNLOCK (playbin);
1961 case PROP_CURRENT_AUDIO:
1962 GST_PLAY_BIN_LOCK (playbin);
1963 g_value_set_int (value, playbin->current_audio);
1964 GST_PLAY_BIN_UNLOCK (playbin);
1968 GstSourceGroup *group;
1971 GST_PLAY_BIN_LOCK (playbin);
1972 group = get_group (playbin);
1973 n_text = (group->text_channels ? group->text_channels->len : 0);
1974 g_value_set_int (value, n_text);
1975 GST_PLAY_BIN_UNLOCK (playbin);
1978 case PROP_CURRENT_TEXT:
1979 GST_PLAY_BIN_LOCK (playbin);
1980 g_value_set_int (value, playbin->current_text);
1981 GST_PLAY_BIN_UNLOCK (playbin);
1983 case PROP_SUBTITLE_ENCODING:
1984 GST_PLAY_BIN_LOCK (playbin);
1985 g_value_take_string (value,
1986 gst_play_sink_get_subtitle_encoding (playbin->playsink));
1987 GST_PLAY_BIN_UNLOCK (playbin);
1989 case PROP_VIDEO_SINK:
1990 g_value_take_object (value,
1991 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
1992 "video", GST_PLAY_SINK_TYPE_VIDEO));
1994 case PROP_AUDIO_SINK:
1995 g_value_take_object (value,
1996 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
1997 "audio", GST_PLAY_SINK_TYPE_AUDIO));
1999 case PROP_VIS_PLUGIN:
2000 g_value_take_object (value,
2001 gst_play_sink_get_vis_plugin (playbin->playsink));
2003 case PROP_TEXT_SINK:
2004 g_value_take_object (value,
2005 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2006 "text", GST_PLAY_SINK_TYPE_TEXT));
2009 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2012 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2015 gst_value_take_buffer (value,
2016 gst_play_sink_get_last_frame (playbin->playsink));
2018 case PROP_FONT_DESC:
2019 g_value_take_string (value,
2020 gst_play_sink_get_font_desc (playbin->playsink));
2022 case PROP_CONNECTION_SPEED:
2023 GST_PLAY_BIN_LOCK (playbin);
2024 g_value_set_uint (value, playbin->connection_speed / 1000);
2025 GST_PLAY_BIN_UNLOCK (playbin);
2027 case PROP_BUFFER_SIZE:
2028 GST_OBJECT_LOCK (playbin);
2029 g_value_set_int (value, playbin->buffer_size);
2030 GST_OBJECT_UNLOCK (playbin);
2032 case PROP_BUFFER_DURATION:
2033 GST_OBJECT_LOCK (playbin);
2034 g_value_set_int64 (value, playbin->buffer_duration);
2035 GST_OBJECT_UNLOCK (playbin);
2037 case PROP_AV_OFFSET:
2038 g_value_set_int64 (value,
2039 gst_play_sink_get_av_offset (playbin->playsink));
2041 case PROP_RING_BUFFER_MAX_SIZE:
2042 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2045 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2051 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2052 gboolean valid, GstQuery * query)
2058 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2059 gst_query_parse_duration (query, &fmt, &duration);
2061 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2062 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2063 playbin->duration[i].valid = valid;
2064 playbin->duration[i].format = fmt;
2065 playbin->duration[i].duration = valid ? duration : -1;
2072 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2074 const GstFormat formats[] =
2075 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2080 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2081 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2082 query = gst_query_new_duration (formats[i]);
2084 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2086 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2087 gst_query_unref (query);
2092 gst_play_bin_query (GstElement * element, GstQuery * query)
2094 GstPlayBin *playbin = GST_PLAY_BIN (element);
2097 /* During a group switch we shouldn't allow duration queries
2098 * because it's not clear if the old or new group's duration
2099 * is returned and if the sinks are already playing new data
2100 * or old data. See bug #585969
2102 * While we're at it, also don't do any other queries during
2103 * a group switch or any other event that causes topology changes
2104 * by taking the playbin lock in any case.
2106 GST_PLAY_BIN_LOCK (playbin);
2108 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2109 GstSourceGroup *group = playbin->curr_group;
2112 GST_SOURCE_GROUP_LOCK (group);
2113 if (group->stream_changed_pending_lock) {
2114 g_mutex_lock (group->stream_changed_pending_lock);
2115 pending = group->pending || group->stream_changed_pending;
2116 g_mutex_unlock (group->stream_changed_pending_lock);
2118 pending = group->pending;
2125 gst_query_parse_duration (query, &fmt, NULL);
2126 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2127 if (fmt == playbin->duration[i].format) {
2128 ret = playbin->duration[i].valid;
2129 gst_query_set_duration (query, fmt,
2130 (ret ? playbin->duration[i].duration : -1));
2134 /* if nothing cached yet, we might as well request duration,
2135 * such as during initial startup */
2137 GST_DEBUG_OBJECT (playbin,
2138 "Taking cached duration because of pending group switch: %d", ret);
2139 GST_SOURCE_GROUP_UNLOCK (group);
2140 GST_PLAY_BIN_UNLOCK (playbin);
2144 GST_SOURCE_GROUP_UNLOCK (group);
2147 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2149 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2150 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2151 GST_PLAY_BIN_UNLOCK (playbin);
2156 /* mime types we are not handling on purpose right now, don't post a
2157 * missing-plugin message for these */
2158 static const gchar *blacklisted_mimes[] = {
2163 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2165 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2166 GstSourceGroup *group;
2168 if (gst_is_missing_plugin_message (msg)) {
2172 detail = gst_missing_plugin_message_get_installer_detail (msg);
2173 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2174 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2175 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2176 gst_message_unref (msg);
2182 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2183 const GstStructure *s = gst_message_get_structure (msg);
2185 /* Drop all stream-changed messages except the last one */
2186 if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2187 guint32 seqnum = gst_message_get_seqnum (msg);
2190 group = playbin->curr_group;
2191 g_mutex_lock (group->stream_changed_pending_lock);
2192 for (l = group->stream_changed_pending; l;) {
2193 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2195 if (l_seqnum == seqnum) {
2198 group->stream_changed_pending =
2199 g_list_delete_link (group->stream_changed_pending, l_prev);
2200 if (group->stream_changed_pending) {
2201 gst_message_unref (msg);
2209 g_mutex_unlock (group->stream_changed_pending_lock);
2211 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2212 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2213 GstObject *src = GST_OBJECT_CAST (msg->src);
2215 /* Ignore async state changes from the uridecodebin children,
2216 * see bug #602000. */
2217 group = playbin->curr_group;
2218 if (src && (group = playbin->curr_group) &&
2219 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2220 || (group->suburidecodebin
2221 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2222 GST_DEBUG_OBJECT (playbin,
2223 "Ignoring async state change of uridecodebin: %s",
2224 GST_OBJECT_NAME (src));
2225 gst_message_unref (msg);
2228 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2229 /* If we get an error of the subtitle uridecodebin transform
2230 * them into warnings and disable the subtitles */
2231 group = playbin->curr_group;
2232 if (group && group->suburidecodebin) {
2233 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2234 (group->suburidecodebin)))) {
2236 gchar *debug = NULL;
2237 GstMessage *new_msg;
2239 gboolean done = FALSE;
2241 gst_message_parse_error (msg, &err, &debug);
2242 new_msg = gst_message_new_warning (msg->src, err, debug);
2244 gst_message_unref (msg);
2249 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2250 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2251 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2252 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2254 it = gst_element_iterate_src_pads (group->suburidecodebin);
2255 while (it && !done) {
2257 GstIteratorResult res;
2259 res = gst_iterator_next (it, (gpointer) & p);
2262 case GST_ITERATOR_DONE:
2265 case GST_ITERATOR_OK:
2266 pad_removed_cb (NULL, p, group);
2267 gst_object_unref (p);
2270 case GST_ITERATOR_RESYNC:
2271 gst_iterator_resync (it);
2273 case GST_ITERATOR_ERROR:
2279 gst_iterator_free (it);
2281 gst_object_ref (group->suburidecodebin);
2282 gst_bin_remove (bin, group->suburidecodebin);
2283 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2285 if (group->sub_pending) {
2286 group->sub_pending = FALSE;
2287 no_more_pads_cb (NULL, group);
2294 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2298 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2299 GstPlayBin * playbin)
2301 const gchar *property;
2302 GstSourceGroup *group;
2303 GstSourceSelect *select = NULL;
2306 GST_PLAY_BIN_LOCK (playbin);
2307 group = get_group (playbin);
2309 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2310 if (selector == G_OBJECT (group->selector[i].selector)) {
2311 select = &group->selector[i];
2315 /* We got a pad-change after our group got switched out; no need to notify */
2317 GST_PLAY_BIN_UNLOCK (playbin);
2321 switch (select->type) {
2322 case GST_PLAY_SINK_TYPE_VIDEO:
2323 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2324 property = "current-video";
2325 playbin->current_video = get_current_stream_number (playbin,
2326 group->video_channels);
2328 case GST_PLAY_SINK_TYPE_AUDIO:
2329 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2330 property = "current-audio";
2331 playbin->current_audio = get_current_stream_number (playbin,
2332 group->audio_channels);
2334 case GST_PLAY_SINK_TYPE_TEXT:
2335 property = "current-text";
2336 playbin->current_text = get_current_stream_number (playbin,
2337 group->text_channels);
2342 GST_PLAY_BIN_UNLOCK (playbin);
2345 g_object_notify (G_OBJECT (playbin), property);
2349 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
2352 GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
2355 /* this callback sends a delayed event once the pad becomes unblocked */
2357 stream_changed_data_probe (GstPad * pad, GstMiniObject * object, gpointer data)
2359 GstSourceSelect *select = (GstSourceSelect *) data;
2362 /* we need do this just once, so cleanup first */
2363 gst_pad_remove_data_probe (pad, select->sinkpad_data_probe);
2364 select->sinkpad_data_probe = 0;
2365 e = select->sinkpad_delayed_event;
2366 select->sinkpad_delayed_event = NULL;
2368 /* really, this should not happen */
2370 GST_WARNING ("Data probed called, but no delayed event");
2374 if (GST_IS_EVENT (object)
2375 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_NEWSEGMENT) {
2376 /* push the event first, then send the delayed one */
2377 gst_event_ref (GST_EVENT_CAST (object));
2378 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2379 gst_pad_send_event (pad, e);
2382 /* send delayed event, then allow the caller to go on */
2383 gst_pad_send_event (pad, e);
2388 /* helper function to lookup stuff in lists */
2390 array_has_value (const gchar * values[], const gchar * value)
2394 for (i = 0; values[i]; i++) {
2395 if (g_str_has_prefix (value, values[i]))
2403 GstPlayBin *playbin;
2405 GstPlaySinkType type;
2409 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2411 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2414 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2415 " with stream id %d and type %d have changed",
2416 object, ntdata->stream_id, ntdata->type);
2418 switch (ntdata->type) {
2419 case GST_PLAY_SINK_TYPE_VIDEO:
2420 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2421 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2423 case GST_PLAY_SINK_TYPE_AUDIO:
2424 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2425 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2427 case GST_PLAY_SINK_TYPE_TEXT:
2428 signal = SIGNAL_TEXT_TAGS_CHANGED;
2436 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2440 /* this function is called when a new pad is added to decodebin. We check the
2441 * type of the pad and add it to the selector element of the group.
2444 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2446 GstPlayBin *playbin;
2448 const GstStructure *s;
2451 GstPadLinkReturn res;
2452 GstSourceSelect *select = NULL;
2454 gboolean changed = FALSE;
2456 playbin = group->playbin;
2458 caps = gst_pad_get_caps_reffed (pad);
2459 s = gst_caps_get_structure (caps, 0);
2460 name = gst_structure_get_name (s);
2462 GST_DEBUG_OBJECT (playbin,
2463 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2464 GST_DEBUG_PAD_NAME (pad), caps, group);
2466 /* major type of the pad, this determines the selector to use */
2467 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2468 if (array_has_value (group->selector[i].media_list, name)) {
2469 select = &group->selector[i];
2471 } else if (group->selector[i].get_media_caps) {
2472 GstCaps *media_caps = group->selector[i].get_media_caps ();
2474 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2475 select = &group->selector[i];
2476 gst_caps_unref (media_caps);
2479 gst_caps_unref (media_caps);
2482 /* no selector found for the media type, don't bother linking it to a
2483 * selector. This will leave the pad unlinked and thus ignored. */
2487 GST_SOURCE_GROUP_LOCK (group);
2488 if (select->selector == NULL && playbin->have_selector) {
2489 /* no selector, create one */
2490 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2491 select->selector = gst_element_factory_make ("input-selector", NULL);
2492 if (select->selector == NULL) {
2493 /* post the missing selector message only once */
2494 playbin->have_selector = FALSE;
2495 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2496 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2498 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2499 (_("Missing element '%s' - check your GStreamer installation."),
2500 "input-selector"), (NULL));
2502 g_signal_connect (select->selector, "notify::active-pad",
2503 G_CALLBACK (selector_active_pad_changed), playbin);
2505 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2506 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2507 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2511 if (select->srcpad == NULL) {
2512 if (select->selector) {
2513 /* save source pad of the selector */
2514 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2516 /* no selector, use the pad as the source pad then */
2517 select->srcpad = gst_object_ref (pad);
2520 /* block the selector srcpad. It's possible that multiple decodebins start
2521 * pushing data into the selectors before we have a chance to collect all
2522 * streams and connect the sinks, resulting in not-linked errors. After we
2523 * configured the sinks we will unblock them all. */
2524 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2525 gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
2528 /* get sinkpad for the new stream */
2529 if (select->selector) {
2530 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2531 gulong notify_tags_handler = 0;
2532 NotifyTagsData *ntdata;
2534 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2535 GST_DEBUG_PAD_NAME (sinkpad));
2537 /* store the selector for the pad */
2538 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2540 /* connect to the notify::tags signal for our
2541 * own *-tags-changed signals
2543 ntdata = g_new0 (NotifyTagsData, 1);
2544 ntdata->playbin = playbin;
2545 ntdata->stream_id = select->channels->len;
2546 ntdata->type = select->type;
2548 notify_tags_handler =
2549 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2550 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2552 g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2553 (gpointer) notify_tags_handler);
2555 /* store the pad in the array */
2556 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2557 g_ptr_array_add (select->channels, sinkpad);
2559 res = gst_pad_link (pad, sinkpad);
2560 if (GST_PAD_LINK_FAILED (res))
2563 /* store selector pad so we can release it */
2564 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2567 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2568 GST_DEBUG_PAD_NAME (pad), select->selector);
2571 /* no selector, don't configure anything, we'll link the new pad directly to
2576 GST_SOURCE_GROUP_UNLOCK (group);
2580 gboolean always_ok = (decodebin == group->suburidecodebin);
2582 switch (select->type) {
2583 case GST_PLAY_SINK_TYPE_VIDEO:
2584 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2585 /* we want to return NOT_LINKED for unselected pads but only for pads
2586 * from the normal uridecodebin. This makes sure that subtitle streams
2587 * are not raced past audio/video from decodebin2's multiqueue.
2588 * For pads from suburidecodebin OK should always be returned, otherwise
2589 * it will most likely stop. */
2590 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2591 signal = SIGNAL_VIDEO_CHANGED;
2593 case GST_PLAY_SINK_TYPE_AUDIO:
2594 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2595 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2596 signal = SIGNAL_AUDIO_CHANGED;
2598 case GST_PLAY_SINK_TYPE_TEXT:
2599 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2600 signal = SIGNAL_TEXT_CHANGED;
2607 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2611 gst_caps_unref (caps);
2617 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2618 name, GST_DEBUG_PAD_NAME (pad));
2623 GST_ERROR_OBJECT (playbin,
2624 "failed to link pad %s:%s to selector, reason %d",
2625 GST_DEBUG_PAD_NAME (pad), res);
2626 GST_SOURCE_GROUP_UNLOCK (group);
2631 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2632 * the selector. This will make the selector select a new pad. */
2634 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2636 GstPlayBin *playbin;
2638 GstElement *selector;
2639 GstSourceSelect *select;
2641 playbin = group->playbin;
2643 GST_DEBUG_OBJECT (playbin,
2644 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2646 GST_SOURCE_GROUP_LOCK (group);
2647 /* get the selector sinkpad */
2648 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2651 if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2652 gulong notify_tags_handler;
2654 notify_tags_handler =
2655 (gulong) g_object_get_data (G_OBJECT (peer),
2656 "playbin2.notify_tags_handler");
2657 if (notify_tags_handler != 0)
2658 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2659 g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2661 /* remove the pad from the array */
2662 g_ptr_array_remove (select->channels, peer);
2663 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2666 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2667 gst_pad_unlink (pad, peer);
2669 /* get selector, this can be NULL when the element is removing the pads
2670 * because it's being disposed. */
2671 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2673 gst_object_unref (peer);
2677 /* release the pad to the selector, this will make the selector choose a new
2679 gst_element_release_request_pad (selector, peer);
2680 gst_object_unref (peer);
2682 gst_object_unref (selector);
2683 GST_SOURCE_GROUP_UNLOCK (group);
2690 GST_DEBUG_OBJECT (playbin, "pad not linked");
2691 GST_SOURCE_GROUP_UNLOCK (group);
2696 GST_DEBUG_OBJECT (playbin, "selector not found");
2697 GST_SOURCE_GROUP_UNLOCK (group);
2702 /* we get called when all pads are available and we must connect the sinks to
2704 * The main purpose of the code is to see if we have video/audio and subtitles
2705 * and pick the right pipelines to display them.
2707 * The selectors installed on the group tell us about the presence of
2708 * audio/video and subtitle streams. This allows us to see if we need
2709 * visualisation, video or/and audio.
2712 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2714 GstPlayBin *playbin;
2715 GstPadLinkReturn res;
2719 playbin = group->playbin;
2721 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2723 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2725 GST_SOURCE_GROUP_LOCK (group);
2726 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2727 GstSourceSelect *select = &group->selector[i];
2729 /* check if the specific media type was detected and thus has a selector
2730 * created for it. If there is the media type, get a sinkpad from the sink
2731 * and link it. We only do this if we have not yet requested the sinkpad
2733 if (select->srcpad && select->sinkpad == NULL) {
2734 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2736 gst_play_sink_request_pad (playbin->playsink, select->type);
2738 res = gst_pad_link (select->srcpad, select->sinkpad);
2739 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2740 select->media_list[0], res);
2741 if (res != GST_PAD_LINK_OK) {
2742 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2743 ("Internal playbin error."),
2744 ("Failed to link selector to sink. Error %d", res));
2748 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2749 group->pending - 1);
2751 if (group->pending > 0)
2754 if (group->suburidecodebin == decodebin)
2755 group->sub_pending = FALSE;
2757 if (group->pending == 0) {
2758 /* we are the last group to complete, we will configure the output and then
2759 * signal the other waiters. */
2760 GST_LOG_OBJECT (playbin, "last group complete");
2763 GST_LOG_OBJECT (playbin, "have more pending groups");
2766 GST_SOURCE_GROUP_UNLOCK (group);
2769 /* if we have custom sinks, configure them now */
2770 GST_SOURCE_GROUP_LOCK (group);
2772 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2774 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2777 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2779 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2782 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
2783 playbin->text_sink);
2784 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2785 playbin->text_sink);
2787 GST_SOURCE_GROUP_UNLOCK (group);
2789 GST_LOG_OBJECT (playbin, "reconfigure sink");
2790 /* we configure the modes if we were the last decodebin to complete. */
2791 gst_play_sink_reconfigure (playbin->playsink);
2793 /* signal the other decodebins that they can continue now. */
2794 GST_SOURCE_GROUP_LOCK (group);
2795 /* unblock all selectors */
2796 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2797 GstSourceSelect *select = &group->selector[i];
2799 /* All streamsynchronizer streams should see stream-changed message,
2800 * to arrange for blocking unblocking. */
2801 if (select->sinkpad) {
2807 s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2810 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2811 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2812 seqnum = gst_message_get_seqnum (msg);
2813 event = gst_event_new_sink_message (msg);
2814 g_mutex_lock (group->stream_changed_pending_lock);
2815 group->stream_changed_pending =
2816 g_list_prepend (group->stream_changed_pending,
2817 GUINT_TO_POINTER (seqnum));
2819 /* remove any data probe we might have, and replace */
2820 if (select->sinkpad_delayed_event)
2821 gst_event_unref (select->sinkpad_delayed_event);
2822 select->sinkpad_delayed_event = event;
2823 if (select->sinkpad_data_probe)
2824 gst_pad_remove_data_probe (select->sinkpad,
2825 select->sinkpad_data_probe);
2827 /* we go to the trouble of setting a probe on the pad to send
2828 the playbin2-stream-changed event as sending it here might
2829 find that the pad is blocked, so we'd block here, and the
2830 pad might not be linked yet. Additionally, sending it here
2831 apparently would be on the wrong thread */
2832 select->sinkpad_data_probe =
2833 gst_pad_add_data_probe (select->sinkpad,
2834 (GCallback) stream_changed_data_probe, (gpointer) select);
2836 g_mutex_unlock (group->stream_changed_pending_lock);
2837 gst_message_unref (msg);
2840 if (select->srcpad) {
2841 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2843 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2847 GST_SOURCE_GROUP_UNLOCK (group);
2850 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2856 GST_DEBUG ("ignoring, we are shutting down");
2857 /* Request a flushing pad from playsink that we then link to the selector.
2858 * Then we unblock the selectors so that they stop with a WRONG_STATE
2859 * instead of a NOT_LINKED error.
2861 GST_SOURCE_GROUP_LOCK (group);
2862 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2863 GstSourceSelect *select = &group->selector[i];
2865 if (select->srcpad) {
2866 if (select->sinkpad == NULL) {
2867 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2869 gst_play_sink_request_pad (playbin->playsink,
2870 GST_PLAY_SINK_TYPE_FLUSHING);
2871 res = gst_pad_link (select->srcpad, select->sinkpad);
2872 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2874 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2876 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2880 GST_SOURCE_GROUP_UNLOCK (group);
2886 drained_cb (GstElement * decodebin, GstSourceGroup * group)
2888 GstPlayBin *playbin;
2890 playbin = group->playbin;
2892 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
2894 /* after this call, we should have a next group to activate or we EOS */
2895 g_signal_emit (G_OBJECT (playbin),
2896 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
2898 /* now activate the next group. If the app did not set a uri, this will
2899 * fail and we can do EOS */
2900 setup_next_source (playbin, GST_STATE_PAUSED);
2903 /* Called when we must provide a list of factories to plug to @pad with @caps.
2904 * We first check if we have a sink that can handle the format and if we do, we
2905 * return NULL, to expose the pad. If we have no sink (or the sink does not
2906 * work), we return the list of elements that can connect. */
2907 static GValueArray *
2908 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
2909 GstCaps * caps, GstSourceGroup * group)
2911 GstPlayBin *playbin;
2912 GList *mylist, *tmp;
2913 GValueArray *result;
2915 playbin = group->playbin;
2917 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
2918 group, GST_DEBUG_PAD_NAME (pad), caps);
2920 /* filter out the elements based on the caps. */
2921 g_mutex_lock (playbin->elements_lock);
2922 gst_play_bin_update_elements_list (playbin);
2924 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
2926 g_mutex_unlock (playbin->elements_lock);
2928 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
2929 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
2931 result = g_value_array_new (g_list_length (mylist));
2933 for (tmp = mylist; tmp; tmp = tmp->next) {
2934 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
2935 GValue val = { 0, };
2937 g_value_init (&val, G_TYPE_OBJECT);
2938 g_value_set_object (&val, factory);
2939 g_value_array_append (result, &val);
2940 g_value_unset (&val);
2942 gst_plugin_feature_list_free (mylist);
2947 /* autoplug-continue decides, if a pad has raw caps that can be exposed
2948 * directly or if further decoding is necessary. We use this to expose
2949 * supported subtitles directly */
2951 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
2952 * explicitely the caps it supports and if it claims to support ANY
2953 * caps it really should support everything */
2955 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
2956 GstSourceGroup * group)
2958 gboolean ret = TRUE;
2960 GstPad *sinkpad = NULL;
2962 GST_PLAY_BIN_LOCK (group->playbin);
2963 GST_SOURCE_GROUP_LOCK (group);
2965 if ((sink = group->playbin->text_sink))
2966 sinkpad = gst_element_get_static_pad (sink, "sink");
2970 /* Ignore errors here, if a custom sink fails to go
2971 * to READY things are wrong and will error out later
2973 if (GST_STATE (sink) < GST_STATE_READY)
2974 gst_element_set_state (sink, GST_STATE_READY);
2976 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
2977 if (!gst_caps_is_any (sinkcaps))
2978 ret = !gst_pad_accept_caps (sinkpad, caps);
2979 gst_caps_unref (sinkcaps);
2980 gst_object_unref (sinkpad);
2982 GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
2983 ret = !gst_caps_can_intersect (caps, subcaps);
2984 gst_caps_unref (subcaps);
2986 /* If autoplugging can stop don't do additional checks */
2990 /* If this is from the subtitle uridecodebin we don't need to
2991 * check the audio and video sink */
2992 if (group->suburidecodebin
2993 && gst_object_has_ancestor (GST_OBJECT_CAST (element),
2994 GST_OBJECT_CAST (group->suburidecodebin)))
2997 if ((sink = group->audio_sink)) {
2998 sinkpad = gst_element_get_static_pad (sink, "sink");
3002 /* Ignore errors here, if a custom sink fails to go
3003 * to READY things are wrong and will error out later
3005 if (GST_STATE (sink) < GST_STATE_READY)
3006 gst_element_set_state (sink, GST_STATE_READY);
3008 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3009 if (!gst_caps_is_any (sinkcaps))
3010 ret = !gst_pad_accept_caps (sinkpad, caps);
3011 gst_caps_unref (sinkcaps);
3012 gst_object_unref (sinkpad);
3018 if ((sink = group->video_sink)) {
3019 sinkpad = gst_element_get_static_pad (sink, "sink");
3023 /* Ignore errors here, if a custom sink fails to go
3024 * to READY things are wrong and will error out later
3026 if (GST_STATE (sink) < GST_STATE_READY)
3027 gst_element_set_state (sink, GST_STATE_READY);
3029 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3030 if (!gst_caps_is_any (sinkcaps))
3031 ret = !gst_pad_accept_caps (sinkpad, caps);
3032 gst_caps_unref (sinkcaps);
3033 gst_object_unref (sinkpad);
3038 GST_SOURCE_GROUP_UNLOCK (group);
3039 GST_PLAY_BIN_UNLOCK (group->playbin);
3041 GST_DEBUG_OBJECT (group->playbin,
3042 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3043 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3049 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3053 /* ... activate it ... We do this before adding it to the bin so that we
3054 * don't accidentally make it post error messages that will stop
3056 if (GST_STATE (sink) < GST_STATE_READY &&
3057 gst_element_set_state (sink,
3058 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3062 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3063 /* Got the sink pad, now let's see if the element actually does accept the
3064 * caps that we have */
3065 if (!gst_pad_accept_caps (sinkpad, caps)) {
3066 gst_object_unref (sinkpad);
3069 gst_object_unref (sinkpad);
3075 /* We are asked to select an element. See if the next element to check
3076 * is a sink. If this is the case, we see if the sink works by setting it to
3077 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3078 * expose the raw pad so that we can setup the mixers. */
3079 static GstAutoplugSelectResult
3080 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3081 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3083 GstPlayBin *playbin;
3084 GstElement *element;
3086 GstPlaySinkType type;
3089 playbin = group->playbin;
3091 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3092 group, GST_DEBUG_PAD_NAME (pad), caps);
3094 GST_DEBUG_OBJECT (playbin, "checking factory %s",
3095 GST_PLUGIN_FEATURE_NAME (factory));
3097 /* if it's not a sink, we just make decodebin try it */
3098 if (!gst_element_factory_list_is_type (factory,
3099 GST_ELEMENT_FACTORY_TYPE_SINK))
3100 return GST_AUTOPLUG_SELECT_TRY;
3102 /* it's a sink, see if an instance of it actually works */
3103 GST_DEBUG_OBJECT (playbin, "we found a sink");
3105 klass = gst_element_factory_get_klass (factory);
3107 /* figure out the klass */
3108 if (strstr (klass, "Audio")) {
3109 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3110 type = GST_PLAY_SINK_TYPE_AUDIO;
3111 sinkp = &group->audio_sink;
3112 } else if (strstr (klass, "Video")) {
3113 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3114 type = GST_PLAY_SINK_TYPE_VIDEO;
3115 sinkp = &group->video_sink;
3117 /* unknown klass, skip this element */
3118 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3119 return GST_AUTOPLUG_SELECT_SKIP;
3122 /* if we are asked to do visualisations and it's an audio sink, skip the
3123 * element. We can only do visualisations with raw sinks */
3124 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3125 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3126 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3127 return GST_AUTOPLUG_SELECT_SKIP;
3131 /* now see if we already have a sink element */
3132 GST_SOURCE_GROUP_LOCK (group);
3134 GstElement *sink = gst_object_ref (*sinkp);
3136 if (sink_accepts_caps (sink, caps)) {
3137 GST_DEBUG_OBJECT (playbin,
3138 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3139 GST_ELEMENT_NAME (sink), caps);
3140 gst_object_unref (sink);
3141 GST_SOURCE_GROUP_UNLOCK (group);
3142 return GST_AUTOPLUG_SELECT_EXPOSE;
3144 GST_DEBUG_OBJECT (playbin,
3145 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3146 GST_ELEMENT_NAME (sink), caps);
3147 gst_object_unref (sink);
3148 GST_SOURCE_GROUP_UNLOCK (group);
3149 return GST_AUTOPLUG_SELECT_SKIP;
3152 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3154 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3155 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3156 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3157 GST_SOURCE_GROUP_UNLOCK (group);
3158 return GST_AUTOPLUG_SELECT_SKIP;
3161 /* Check if the selected sink actually supports the
3162 * caps and can be set to READY*/
3163 if (!sink_accepts_caps (element, caps)) {
3164 gst_element_set_state (element, GST_STATE_NULL);
3165 gst_object_unref (element);
3166 GST_SOURCE_GROUP_UNLOCK (group);
3167 return GST_AUTOPLUG_SELECT_SKIP;
3170 /* remember the sink in the group now, the element is floating, we take
3173 * store the sink in the group, we will configure it later when we
3174 * reconfigure the sink */
3175 GST_DEBUG_OBJECT (playbin, "remember sink");
3176 gst_object_ref_sink (element);
3178 GST_SOURCE_GROUP_UNLOCK (group);
3180 /* tell decodebin to expose the pad because we are going to use this
3182 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3184 return GST_AUTOPLUG_SELECT_EXPOSE;
3188 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3189 GstSourceGroup * group)
3191 GstPlayBin *playbin;
3194 playbin = group->playbin;
3196 g_object_get (group->uridecodebin, "source", &source, NULL);
3198 GST_OBJECT_LOCK (playbin);
3199 if (playbin->source)
3200 gst_object_unref (playbin->source);
3201 playbin->source = source;
3202 GST_OBJECT_UNLOCK (playbin);
3204 g_object_notify (G_OBJECT (playbin), "source");
3206 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3207 0, playbin->source);
3210 /* must be called with the group lock */
3212 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3215 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3217 if (group->uridecodebin)
3218 gst_element_set_locked_state (group->uridecodebin, locked);
3219 if (group->suburidecodebin)
3220 gst_element_set_locked_state (group->suburidecodebin, locked);
3225 /* must be called with PLAY_BIN_LOCK */
3227 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3229 GstElement *uridecodebin;
3230 GstElement *suburidecodebin = NULL;
3233 g_return_val_if_fail (group->valid, FALSE);
3234 g_return_val_if_fail (!group->active, FALSE);
3236 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3238 GST_SOURCE_GROUP_LOCK (group);
3240 /* First set up the custom sources */
3241 if (playbin->audio_sink)
3242 group->audio_sink = gst_object_ref (playbin->audio_sink);
3243 if (playbin->video_sink)
3244 group->video_sink = gst_object_ref (playbin->video_sink);
3246 g_list_free (group->stream_changed_pending);
3247 group->stream_changed_pending = NULL;
3248 if (!group->stream_changed_pending_lock)
3249 group->stream_changed_pending_lock = g_mutex_new ();
3251 if (group->uridecodebin) {
3252 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3253 uridecodebin = group->uridecodebin;
3254 gst_element_set_state (uridecodebin, GST_STATE_READY);
3255 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3257 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3258 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3261 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3262 group->uridecodebin = gst_object_ref (uridecodebin);
3265 flags = gst_play_sink_get_flags (playbin->playsink);
3267 g_object_set (uridecodebin,
3268 /* configure connection speed */
3269 "connection-speed", playbin->connection_speed / 1000,
3272 /* configure download buffering */
3273 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3274 /* configure buffering of demuxed/parsed data */
3275 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3276 /* configure buffering parameters */
3277 "buffer-duration", playbin->buffer_duration,
3278 "buffer-size", playbin->buffer_size,
3279 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3281 /* connect pads and other things */
3282 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3283 G_CALLBACK (pad_added_cb), group);
3284 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3285 G_CALLBACK (pad_removed_cb), group);
3286 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3287 G_CALLBACK (no_more_pads_cb), group);
3288 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3289 G_CALLBACK (notify_source_cb), group);
3291 /* we have 1 pending no-more-pads */
3294 /* is called when the uridecodebin is out of data and we can switch to the
3297 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3300 /* will be called when a new media type is found. We return a list of decoders
3301 * including sinks for decodebin to try */
3302 group->autoplug_factories_id =
3303 g_signal_connect (uridecodebin, "autoplug-factories",
3304 G_CALLBACK (autoplug_factories_cb), group);
3305 group->autoplug_select_id =
3306 g_signal_connect (uridecodebin, "autoplug-select",
3307 G_CALLBACK (autoplug_select_cb), group);
3308 group->autoplug_continue_id =
3309 g_signal_connect (uridecodebin, "autoplug-continue",
3310 G_CALLBACK (autoplug_continue_cb), group);
3312 if (group->suburi) {
3314 if (group->suburidecodebin) {
3315 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3316 suburidecodebin = group->suburidecodebin;
3317 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3318 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3320 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3321 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3322 if (!suburidecodebin)
3325 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3326 group->suburidecodebin = gst_object_ref (suburidecodebin);
3329 g_object_set (suburidecodebin,
3330 /* configure connection speed */
3331 "connection-speed", playbin->connection_speed,
3333 "uri", group->suburi, NULL);
3335 /* connect pads and other things */
3336 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3337 G_CALLBACK (pad_added_cb), group);
3338 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3339 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3340 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3341 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3343 group->sub_autoplug_continue_id =
3344 g_signal_connect (suburidecodebin, "autoplug-continue",
3345 G_CALLBACK (autoplug_continue_cb), group);
3347 /* we have 2 pending no-more-pads */
3349 group->sub_pending = TRUE;
3351 group->sub_pending = FALSE;
3354 /* release the group lock before setting the state of the decodebins, they
3355 * might fire signals in this thread that we need to handle with the
3356 * group_lock taken. */
3357 GST_SOURCE_GROUP_UNLOCK (group);
3359 if (suburidecodebin) {
3360 if (gst_element_set_state (suburidecodebin,
3361 target) == GST_STATE_CHANGE_FAILURE) {
3362 GST_DEBUG_OBJECT (playbin,
3363 "failed state change of subtitle uridecodebin");
3364 GST_SOURCE_GROUP_LOCK (group);
3366 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3367 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3368 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3369 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3370 /* Might already be removed because of an error message */
3371 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3372 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3373 if (group->sub_pending) {
3375 group->sub_pending = FALSE;
3377 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3378 GST_SOURCE_GROUP_UNLOCK (group);
3381 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3382 goto uridecodebin_failure;
3384 GST_SOURCE_GROUP_LOCK (group);
3385 /* alow state changes of the playbin2 affect the group elements now */
3386 group_set_locked_state_unlocked (playbin, group, FALSE);
3387 group->active = TRUE;
3388 GST_SOURCE_GROUP_UNLOCK (group);
3397 /* delete any custom sinks we might have */
3398 if (group->audio_sink) {
3399 /* If this is a automatically created sink set it to NULL */
3400 if (group->audio_sink != playbin->audio_sink)
3401 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3402 gst_object_unref (group->audio_sink);
3404 group->audio_sink = NULL;
3405 if (group->video_sink) {
3406 /* If this is a automatically created sink set it to NULL */
3407 if (group->video_sink != playbin->video_sink)
3408 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3409 gst_object_unref (group->video_sink);
3411 group->video_sink = NULL;
3413 GST_SOURCE_GROUP_UNLOCK (group);
3415 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3417 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3419 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3420 (_("Could not create \"uridecodebin\" element.")), (NULL));
3423 uridecodebin_failure:
3425 /* delete any custom sinks we might have */
3426 if (group->audio_sink) {
3427 /* If this is a automatically created sink set it to NULL */
3428 if (group->audio_sink != playbin->audio_sink)
3429 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3430 gst_object_unref (group->audio_sink);
3432 group->audio_sink = NULL;
3433 if (group->video_sink) {
3434 /* If this is a automatically created sink set it to NULL */
3435 if (group->video_sink != playbin->video_sink)
3436 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3437 gst_object_unref (group->video_sink);
3439 group->video_sink = NULL;
3441 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3446 /* unlink a group of uridecodebins from the sink.
3447 * must be called with PLAY_BIN_LOCK */
3449 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3453 g_return_val_if_fail (group->valid, FALSE);
3454 g_return_val_if_fail (group->active, FALSE);
3456 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3458 GST_SOURCE_GROUP_LOCK (group);
3459 group->active = FALSE;
3460 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
3461 GstSourceSelect *select = &group->selector[i];
3463 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3465 if (select->srcpad) {
3466 if (select->sinkpad) {
3467 GST_LOG_OBJECT (playbin, "unlinking from sink");
3468 gst_pad_unlink (select->srcpad, select->sinkpad);
3471 GST_LOG_OBJECT (playbin, "release sink pad");
3472 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3473 select->sinkpad = NULL;
3476 gst_object_unref (select->srcpad);
3477 select->srcpad = NULL;
3480 if (select->selector) {
3483 /* release and unref requests pad from the selector */
3484 for (n = 0; n < select->channels->len; n++) {
3485 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3487 gst_element_release_request_pad (select->selector, sinkpad);
3488 gst_object_unref (sinkpad);
3490 g_ptr_array_set_size (select->channels, 0);
3492 gst_element_set_state (select->selector, GST_STATE_NULL);
3493 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3494 select->selector = NULL;
3497 /* delete any custom sinks we might have */
3498 if (group->audio_sink) {
3499 /* If this is a automatically created sink set it to NULL */
3500 if (group->audio_sink != playbin->audio_sink)
3501 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3502 gst_object_unref (group->audio_sink);
3504 group->audio_sink = NULL;
3505 if (group->video_sink) {
3506 /* If this is a automatically created sink set it to NULL */
3507 if (group->video_sink != playbin->video_sink)
3508 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3509 gst_object_unref (group->video_sink);
3511 group->video_sink = NULL;
3513 if (group->uridecodebin) {
3514 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3515 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3516 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3517 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3518 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3519 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3520 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3521 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3522 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3525 if (group->suburidecodebin) {
3526 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3527 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3528 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3529 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3531 /* Might already be removed because of errors */
3532 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3533 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3536 GST_SOURCE_GROUP_UNLOCK (group);
3541 /* setup the next group to play, this assumes the next_group is valid and
3542 * configured. It swaps out the current_group and activates the valid
3545 setup_next_source (GstPlayBin * playbin, GstState target)
3547 GstSourceGroup *new_group, *old_group;
3549 GST_DEBUG_OBJECT (playbin, "setup sources");
3551 /* see if there is a next group */
3552 GST_PLAY_BIN_LOCK (playbin);
3553 new_group = playbin->next_group;
3554 if (!new_group || !new_group->valid)
3557 /* first unlink the current source, if any */
3558 old_group = playbin->curr_group;
3559 if (old_group && old_group->valid && old_group->active) {
3560 gst_play_bin_update_cached_duration (playbin);
3561 /* unlink our pads with the sink */
3562 deactivate_group (playbin, old_group);
3563 old_group->valid = FALSE;
3566 /* swap old and new */
3567 playbin->curr_group = new_group;
3568 playbin->next_group = old_group;
3570 /* activate the new group */
3571 if (!activate_group (playbin, new_group, target))
3572 goto activate_failed;
3574 GST_PLAY_BIN_UNLOCK (playbin);
3581 GST_DEBUG_OBJECT (playbin, "no next group");
3582 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3583 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3584 GST_PLAY_BIN_UNLOCK (playbin);
3589 GST_DEBUG_OBJECT (playbin, "activate failed");
3590 GST_PLAY_BIN_UNLOCK (playbin);
3595 /* The group that is currently playing is copied again to the
3596 * next_group so that it will start playing the next time.
3599 save_current_group (GstPlayBin * playbin)
3601 GstSourceGroup *curr_group;
3603 GST_DEBUG_OBJECT (playbin, "save current group");
3605 /* see if there is a current group */
3606 GST_PLAY_BIN_LOCK (playbin);
3607 curr_group = playbin->curr_group;
3608 if (curr_group && curr_group->valid) {
3609 /* unlink our pads with the sink */
3610 deactivate_group (playbin, curr_group);
3612 /* swap old and new */
3613 playbin->curr_group = playbin->next_group;
3614 playbin->next_group = curr_group;
3615 GST_PLAY_BIN_UNLOCK (playbin);
3620 /* clear the locked state from all groups. This function is called before a
3621 * state change to NULL is performed on them. */
3623 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3625 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3628 GST_PLAY_BIN_LOCK (playbin);
3629 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3630 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3631 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3632 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3633 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3634 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3635 GST_PLAY_BIN_UNLOCK (playbin);
3640 static GstStateChangeReturn
3641 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3643 GstStateChangeReturn ret;
3644 GstPlayBin *playbin;
3645 gboolean do_save = FALSE;
3647 playbin = GST_PLAY_BIN (element);
3649 switch (transition) {
3650 case GST_STATE_CHANGE_NULL_TO_READY:
3651 memset (&playbin->duration, 0, sizeof (playbin->duration));
3653 case GST_STATE_CHANGE_READY_TO_PAUSED:
3654 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3655 memset (&playbin->duration, 0, sizeof (playbin->duration));
3656 g_atomic_int_set (&playbin->shutdown, 0);
3658 if (!setup_next_source (playbin, GST_STATE_READY)) {
3659 ret = GST_STATE_CHANGE_FAILURE;
3663 case GST_STATE_CHANGE_PAUSED_TO_READY:
3665 /* FIXME unlock our waiting groups */
3666 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3667 g_atomic_int_set (&playbin->shutdown, 1);
3668 memset (&playbin->duration, 0, sizeof (playbin->duration));
3670 /* wait for all callbacks to end by taking the lock.
3671 * No dynamic (critical) new callbacks will
3672 * be able to happen as we set the shutdown flag. */
3673 GST_PLAY_BIN_DYN_LOCK (playbin);
3674 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3675 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3678 case GST_STATE_CHANGE_READY_TO_NULL:
3679 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3680 * an no state change PAUSED to READY passes here,
3681 * though it is a nice-to-have ... */
3682 if (!g_atomic_int_get (&playbin->shutdown)) {
3686 memset (&playbin->duration, 0, sizeof (playbin->duration));
3688 /* unlock so that all groups go to NULL */
3689 groups_set_locked_state (playbin, FALSE);
3695 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3696 if (ret == GST_STATE_CHANGE_FAILURE)
3699 switch (transition) {
3700 case GST_STATE_CHANGE_READY_TO_PAUSED:
3702 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3703 /* FIXME Release audio device when we implement that */
3705 case GST_STATE_CHANGE_PAUSED_TO_READY:
3706 save_current_group (playbin);
3708 case GST_STATE_CHANGE_READY_TO_NULL:
3712 /* also do missed state change down to READY */
3714 save_current_group (playbin);
3715 /* Deactive the groups, set the uridecodebins to NULL
3718 for (i = 0; i < 2; i++) {
3719 if (playbin->groups[i].active && playbin->groups[i].valid) {
3720 deactivate_group (playbin, &playbin->groups[i]);
3721 playbin->groups[i].valid = FALSE;
3724 if (playbin->groups[i].uridecodebin) {
3725 gst_element_set_state (playbin->groups[i].uridecodebin,
3727 gst_object_unref (playbin->groups[i].uridecodebin);
3728 playbin->groups[i].uridecodebin = NULL;
3731 if (playbin->groups[i].suburidecodebin) {
3732 gst_element_set_state (playbin->groups[i].suburidecodebin,
3734 gst_object_unref (playbin->groups[i].suburidecodebin);
3735 playbin->groups[i].suburidecodebin = NULL;
3739 /* Set our sinks back to NULL, they might not be child of playbin */
3740 if (playbin->audio_sink)
3741 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
3742 if (playbin->video_sink)
3743 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
3744 if (playbin->text_sink)
3745 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
3747 /* make sure the groups don't perform a state change anymore until we
3748 * enable them again */
3749 groups_set_locked_state (playbin, TRUE);
3761 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
3762 GstSourceGroup *curr_group;
3764 curr_group = playbin->curr_group;
3765 if (curr_group && curr_group->active && curr_group->valid) {
3766 /* unlink our pads with the sink */
3767 deactivate_group (playbin, curr_group);
3768 curr_group->valid = FALSE;
3771 /* Swap current and next group back */
3772 playbin->curr_group = playbin->next_group;
3773 playbin->next_group = curr_group;
3780 gst_play_bin2_plugin_init (GstPlugin * plugin)
3782 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
3784 return gst_element_register (plugin, "playbin2", GST_RANK_NONE,