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 * At this stage, playbin2 is considered UNSTABLE. The API provided in the
27 * signals and properties may yet change in the near future. When playbin2
28 * is stable, it will probably replace #playbin
30 * It can handle both audio and video files and features
33 * automatic file type recognition and based on that automatic
34 * selection and usage of the right audio/video/subtitle demuxers/decoders
37 * visualisations for audio files
40 * subtitle support for video files. Subtitles can be store in external
44 * stream selection between different video/audio/subtitles streams
47 * meta info (tag) extraction
50 * easy access to the last video frame
53 * buffering when playing streams over a network
56 * volume control with mute option
61 * <title>Usage</title>
63 * A playbin element can be created just like any other element using
64 * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin2:uri
65 * property. This must be an absolute URI, relative file paths are not allowed.
66 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
68 * Playbin is a #GstPipeline. It will notify the application of everything
69 * that's happening (errors, end of stream, tags found, state changes, etc.)
70 * by posting messages on its #GstBus. The application needs to watch the
73 * Playback can be initiated by setting the element to PLAYING state using
74 * gst_element_set_state(). Note that the state change will take place in
75 * the background in a separate thread, when the function returns playback
76 * is probably not happening yet and any errors might not have occured yet.
77 * Applications using playbin should ideally be written to deal with things
78 * completely asynchroneous.
80 * When playback has finished (an EOS message has been received on the bus)
81 * or an error has occured (an ERROR message has been received on the bus) or
82 * the user wants to play a different track, playbin should be set back to
83 * READY or NULL state, then the #GstPlayBin2:uri property should be set to the
84 * new location and then playbin be set to PLAYING state again.
86 * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
87 * on the playbin element. Again, the seek will not be executed
88 * instantaneously, but will be done in a background thread. When the seek
89 * call returns the seek will most likely still be in process. An application
90 * may wait for the seek to finish (or fail) using gst_element_get_state() with
91 * -1 as the timeout, but this will block the user interface and is not
94 * Applications may query the current position and duration of the stream
95 * via gst_element_query_position() and gst_element_query_duration() and
96 * setting the format passed to GST_FORMAT_TIME. If the query was successful,
97 * the duration or position will have been returned in units of nanoseconds.
101 * <title>Advanced Usage: specifying the audio and video sink</title>
103 * By default, if no audio sink or video sink has been specified via the
104 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property, playbin will use the autoaudiosink
105 * and autovideosink elements to find the first-best available output method.
106 * This should work in most cases, but is not always desirable. Often either
107 * the user or application might want to specify more explicitly what to use
108 * for audio and video output.
110 * If the application wants more control over how audio or video should be
111 * output, it may create the audio/video sink elements itself (for example
112 * using gst_element_factory_make()) and provide them to playbin using the
113 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property.
115 * GNOME-based applications, for example, will usually want to create
116 * gconfaudiosink and gconfvideosink elements and make playbin use those,
117 * so that output happens to whatever the user has configured in the GNOME
118 * Multimedia System Selector configuration dialog.
120 * The sink elements do not necessarily need to be ready-made sinks. It is
121 * possible to create container elements that look like a sink to playbin,
122 * but in reality contain a number of custom elements linked together. This
123 * can be achieved by creating a #GstBin and putting elements in there and
124 * linking them, and then creating a sink #GstGhostPad for the bin and pointing
125 * it to the sink pad of the first element within the bin. This can be used
126 * for a number of purposes, for example to force output to a particular
127 * format or to modify or observe the data before it is output.
129 * It is also possible to 'suppress' audio and/or video output by using
130 * 'fakesink' elements (or capture it from there using the fakesink element's
131 * "handoff" signal, which, nota bene, is fired from the streaming thread!).
135 * <title>Retrieving Tags and Other Meta Data</title>
137 * Most of the common meta data (artist, title, etc.) can be retrieved by
138 * watching for TAG messages on the pipeline's bus (see above).
140 * Other more specific meta information like width/height/framerate of video
141 * streams or samplerate/number of channels of audio streams can be obtained
142 * from the negotiated caps on the sink pads of the sinks.
146 * <title>Buffering</title>
147 * Playbin handles buffering automatically for the most part, but applications
148 * need to handle parts of the buffering process as well. Whenever playbin is
149 * buffering, it will post BUFFERING messages on the bus with a percentage
150 * value that shows the progress of the buffering process. Applications need
151 * to set playbin to PLAYING or PAUSED state in response to these messages.
152 * They may also want to convey the buffering progress to the user in some
153 * way. Here is how to extract the percentage information from the message
154 * (requires GStreamer >= 0.10.11):
156 * switch (GST_MESSAGE_TYPE (msg)) {
157 * case GST_MESSAGE_BUFFERING: {
159 * gst_message_parse_buffering (msg, &percent);
160 * g_print ("Buffering (%%u percent done)", percent);
166 * Note that applications should keep/set the pipeline in the PAUSED state when
167 * a BUFFERING message is received with a buffer percent value < 100 and set
168 * the pipeline back to PLAYING state when a BUFFERING message with a value
169 * of 100 percent is received (if PLAYING is the desired state, that is).
172 * <title>Embedding the video window in your application</title>
173 * By default, playbin (or rather the video sinks used) will create their own
174 * window. Applications will usually want to force output to a window of their
175 * own, however. This can be done using the #GstXOverlay interface, which most
176 * video sinks implement. See the documentation there for more details.
179 * <title>Specifying which CD/DVD device to use</title>
180 * The device to use for CDs/DVDs needs to be set on the source element
181 * playbin creates before it is opened. The only way to do this at the moment
182 * is to connect to playbin's "notify::source" signal, which will be emitted
183 * by playbin when it has created the source element for a particular URI.
184 * In the signal callback you can check if the source element has a "device"
185 * property and set it appropriately. In future ways might be added to specify
186 * the device as part of the URI, but at the time of writing this is not
190 * <title>Handling redirects</title>
192 * Some elements may post 'redirect' messages on the bus to tell the
193 * application to open another location. These are element messages containing
194 * a structure named 'redirect' along with a 'new-location' field of string
195 * type. The new location may be a relative or an absolute URI. Examples
196 * for such redirects can be found in many quicktime movie trailers.
200 * <title>Examples</title>
202 * gst-launch -v playbin uri=file:///path/to/somefile.avi
203 * ]| This will play back the given AVI video file, given that the video and
204 * audio decoders required to decode the content are installed. Since no
205 * special audio sink or video sink is supplied (not possible via gst-launch),
206 * playbin will try to find a suitable audio and video sink automatically
207 * using the autoaudiosink and autovideosink elements.
209 * gst-launch -v playbin uri=cdda://4
210 * ]| This will play back track 4 on an audio CD in your disc drive (assuming
211 * the drive is detected automatically by the plugin).
213 * gst-launch -v playbin uri=dvd://1
214 * ]| This will play back title 1 of a DVD in your disc drive (assuming
215 * the drive is detected automatically by the plugin).
226 #include <gst/gst-i18n-plugin.h>
227 #include <gst/pbutils/pbutils.h>
228 #include <gst/interfaces/streamvolume.h>
230 #include "gstplay-enum.h"
231 #include "gstplay-marshal.h"
232 #include "gstplaysink.h"
233 #include "gstfactorylists.h"
234 #include "gstinputselector.h"
235 #include "gstscreenshot.h"
236 #include "gstsubtitleoverlay.h"
238 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
239 #define GST_CAT_DEFAULT gst_play_bin_debug
241 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type())
242 #define GST_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
243 #define GST_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
244 #define GST_IS_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
245 #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
247 #define VOLUME_MAX_DOUBLE 10.0
249 typedef struct _GstPlayBin GstPlayBin;
250 typedef struct _GstPlayBinClass GstPlayBinClass;
251 typedef struct _GstSourceGroup GstSourceGroup;
252 typedef struct _GstSourceSelect GstSourceSelect;
254 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
256 /* has the info for a selector and provides the link to the sink */
257 struct _GstSourceSelect
259 const gchar *media_list[8]; /* the media types for the selector */
260 SourceSelectGetMediaCapsFunc get_media_caps; /* more complex caps for the selector */
261 GstPlaySinkType type; /* the sink pad type of the selector */
263 GstElement *selector; /* the selector */
265 GstPad *srcpad; /* the source pad of the selector */
266 GstPad *sinkpad; /* the sinkpad of the sink when the selector
270 gulong src_event_probe_id;
271 gulong sink_event_probe_id;
272 GstClockTime group_start_accum;
275 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
276 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
277 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
279 /* a structure to hold the objects for decoding a uri and the subtitle uri
281 struct _GstSourceGroup
287 gboolean valid; /* the group has valid info to start playback */
288 gboolean active; /* the group is active */
293 GValueArray *streaminfo;
296 GPtrArray *video_channels; /* links to selector pads */
297 GPtrArray *audio_channels; /* links to selector pads */
298 GPtrArray *text_channels; /* links to selector pads */
300 GstElement *audio_sink; /* autoplugged audio and video sinks */
301 GstElement *video_sink;
303 /* uridecodebins for uri and subtitle uri */
304 GstElement *uridecodebin;
305 GstElement *suburidecodebin;
307 gboolean sub_pending;
310 gulong pad_removed_id;
311 gulong no_more_pads_id;
312 gulong notify_source_id;
314 gulong autoplug_factories_id;
315 gulong autoplug_select_id;
316 gulong autoplug_continue_id;
318 gulong sub_pad_added_id;
319 gulong sub_pad_removed_id;
320 gulong sub_no_more_pads_id;
321 gulong sub_autoplug_continue_id;
323 GMutex *stream_changed_pending_lock;
324 GList *stream_changed_pending;
326 /* selectors for different streams */
327 GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST];
330 #define GST_PLAY_BIN_GET_LOCK(bin) (((GstPlayBin*)(bin))->lock)
331 #define GST_PLAY_BIN_LOCK(bin) (g_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
332 #define GST_PLAY_BIN_UNLOCK(bin) (g_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
334 /* lock to protect dynamic callbacks, like no-more-pads */
335 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->dyn_lock)
336 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->dyn_lock)
338 /* lock for shutdown */
339 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
341 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
343 GST_PLAY_BIN_DYN_LOCK (bin); \
344 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
345 GST_PLAY_BIN_DYN_UNLOCK (bin); \
350 /* unlock for shutdown */
351 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
352 GST_PLAY_BIN_DYN_UNLOCK (bin); \
357 * playbin element structure
363 GMutex *lock; /* to protect group switching */
365 /* the groups, we use a double buffer to switch between current and next */
366 GstSourceGroup groups[2]; /* array with group info */
367 GstSourceGroup *curr_group; /* pointer to the currently playing group */
368 GstSourceGroup *next_group; /* pointer to the next group */
371 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
372 gint current_video; /* the currently selected stream */
373 gint current_audio; /* the currently selected stream */
374 gint current_text; /* the currently selected stream */
376 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
377 guint buffer_size; /* When buffering, the max buffer size (bytes) */
380 GstPlaySink *playsink;
382 /* the last activated source */
385 /* lock protecting dynamic adding/removing */
387 /* if we are shutting down or not */
390 GMutex *elements_lock;
391 guint32 elements_cookie;
392 GValueArray *elements; /* factories we can use for selecting elements */
394 gboolean have_selector; /* set to FALSE when we fail to create an
395 * input-selector, so that we only post a
398 GstElement *audio_sink; /* configured audio sink, or NULL */
399 GstElement *video_sink; /* configured video sink, or NULL */
400 GstElement *text_sink; /* configured text sink, or NULL */
407 } duration[5]; /* cached durations */
409 GstSegment segments[3]; /* Video/Audio/Text segments */
412 struct _GstPlayBinClass
414 GstPipelineClass parent_class;
416 /* notify app that the current uri finished decoding and it is possible to
417 * queue a new one for gapless playback */
418 void (*about_to_finish) (GstPlayBin * playbin);
420 /* notify app that number of audio/video/text streams changed */
421 void (*video_changed) (GstPlayBin * playbin);
422 void (*audio_changed) (GstPlayBin * playbin);
423 void (*text_changed) (GstPlayBin * playbin);
425 /* notify app that the tags of audio/video/text streams changed */
426 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
427 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
428 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
430 /* get audio/video/text tags for a stream */
431 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
432 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
433 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
435 /* get the last video frame and convert it to the given caps */
436 GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
438 /* get audio/video/text pad for a stream */
439 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
440 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
441 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
445 #define DEFAULT_URI NULL
446 #define DEFAULT_SUBURI NULL
447 #define DEFAULT_SOURCE NULL
448 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
449 GST_PLAY_FLAG_SOFT_VOLUME
450 #define DEFAULT_N_VIDEO 0
451 #define DEFAULT_CURRENT_VIDEO -1
452 #define DEFAULT_N_AUDIO 0
453 #define DEFAULT_CURRENT_AUDIO -1
454 #define DEFAULT_N_TEXT 0
455 #define DEFAULT_CURRENT_TEXT -1
456 #define DEFAULT_SUBTITLE_ENCODING NULL
457 #define DEFAULT_AUDIO_SINK NULL
458 #define DEFAULT_VIDEO_SINK NULL
459 #define DEFAULT_VIS_PLUGIN NULL
460 #define DEFAULT_TEXT_SINK NULL
461 #define DEFAULT_VOLUME 1.0
462 #define DEFAULT_MUTE FALSE
463 #define DEFAULT_FRAME NULL
464 #define DEFAULT_FONT_DESC NULL
465 #define DEFAULT_CONNECTION_SPEED 0
466 #define DEFAULT_BUFFER_DURATION -1
467 #define DEFAULT_BUFFER_SIZE -1
482 PROP_SUBTITLE_ENCODING,
491 PROP_CONNECTION_SPEED,
493 PROP_BUFFER_DURATION,
500 SIGNAL_ABOUT_TO_FINISH,
501 SIGNAL_CONVERT_FRAME,
502 SIGNAL_VIDEO_CHANGED,
503 SIGNAL_AUDIO_CHANGED,
505 SIGNAL_VIDEO_TAGS_CHANGED,
506 SIGNAL_AUDIO_TAGS_CHANGED,
507 SIGNAL_TEXT_TAGS_CHANGED,
508 SIGNAL_GET_VIDEO_TAGS,
509 SIGNAL_GET_AUDIO_TAGS,
510 SIGNAL_GET_TEXT_TAGS,
511 SIGNAL_GET_VIDEO_PAD,
512 SIGNAL_GET_AUDIO_PAD,
517 static void gst_play_bin_class_init (GstPlayBinClass * klass);
518 static void gst_play_bin_init (GstPlayBin * playbin);
519 static void gst_play_bin_finalize (GObject * object);
521 static void gst_play_bin_set_property (GObject * object, guint prop_id,
522 const GValue * value, GParamSpec * spec);
523 static void gst_play_bin_get_property (GObject * object, guint prop_id,
524 GValue * value, GParamSpec * spec);
526 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
527 GstStateChange transition);
529 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
530 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
532 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
534 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
536 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
539 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
542 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
543 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
544 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
546 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
548 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
549 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
550 GstSourceGroup * group);
552 static void gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
554 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
557 static GstElementClass *parent_class;
559 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
561 static const GstElementDetails gst_play_bin_details =
562 GST_ELEMENT_DETAILS ("Player Bin 2",
563 "Generic/Bin/Player",
564 "Autoplug and play media from an uri",
565 "Wim Taymans <wim.taymans@gmail.com>");
567 #define REMOVE_SIGNAL(obj,id) \
569 g_signal_handler_disconnect (obj, id); \
574 gst_play_marshal_BUFFER__BOXED (GClosure * closure,
575 GValue * return_value G_GNUC_UNUSED,
576 guint n_param_values,
577 const GValue * param_values,
578 gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
580 typedef GstBuffer *(*GMarshalFunc_OBJECT__BOXED) (gpointer data1,
581 gpointer arg_1, gpointer data2);
582 register GMarshalFunc_OBJECT__BOXED callback;
583 register GCClosure *cc = (GCClosure *) closure;
584 register gpointer data1, data2;
587 g_return_if_fail (return_value != NULL);
588 g_return_if_fail (n_param_values == 2);
590 if (G_CCLOSURE_SWAP_DATA (closure)) {
591 data1 = closure->data;
592 data2 = g_value_peek_pointer (param_values + 0);
594 data1 = g_value_peek_pointer (param_values + 0);
595 data2 = closure->data;
598 (GMarshalFunc_OBJECT__BOXED) (marshal_data ? marshal_data : cc->callback);
600 v_return = callback (data1, g_value_get_boxed (param_values + 1), data2);
602 gst_value_take_buffer (return_value, v_return);
606 gst_play_bin_get_type (void)
608 static GType gst_play_bin_type = 0;
610 if (!gst_play_bin_type) {
611 static const GTypeInfo gst_play_bin_info = {
612 sizeof (GstPlayBinClass),
615 (GClassInitFunc) gst_play_bin_class_init,
620 (GInstanceInitFunc) gst_play_bin_init,
623 static const GInterfaceInfo svol_info = {
627 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
628 "GstPlayBin2", &gst_play_bin_info, 0);
630 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
634 return gst_play_bin_type;
638 gst_play_bin_class_init (GstPlayBinClass * klass)
640 GObjectClass *gobject_klass;
641 GstElementClass *gstelement_klass;
642 GstBinClass *gstbin_klass;
644 gobject_klass = (GObjectClass *) klass;
645 gstelement_klass = (GstElementClass *) klass;
646 gstbin_klass = (GstBinClass *) klass;
648 parent_class = g_type_class_peek_parent (klass);
650 gobject_klass->set_property = gst_play_bin_set_property;
651 gobject_klass->get_property = gst_play_bin_get_property;
653 gobject_klass->finalize = gst_play_bin_finalize;
658 * Set the next URI that playbin will play. This property can be set from the
659 * about-to-finish signal to queue the next media file.
661 g_object_class_install_property (gobject_klass, PROP_URI,
662 g_param_spec_string ("uri", "URI", "URI of the media to play",
663 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
668 * Set the next subtitle URI that playbin will play. This property can be
669 * set from the about-to-finish signal to queue the next subtitle media file.
671 g_object_class_install_property (gobject_klass, PROP_SUBURI,
672 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
673 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
675 g_object_class_install_property (gobject_klass, PROP_SOURCE,
676 g_param_spec_object ("source", "Source", "Source element",
677 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
682 * Control the behaviour of playbin.
684 g_object_class_install_property (gobject_klass, PROP_FLAGS,
685 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
686 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
687 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
690 * GstPlayBin2:n-video
692 * Get the total number of available video streams.
694 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
695 g_param_spec_int ("n-video", "Number Video",
696 "Total number of video streams", 0, G_MAXINT, 0,
697 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
699 * GstPlayBin2:current-video
701 * Get or set the currently playing video stream. By default the first video
702 * stream with data is played.
704 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
705 g_param_spec_int ("current-video", "Current Video",
706 "Currently playing video stream (-1 = auto)",
707 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
709 * GstPlayBin2:n-audio
711 * Get the total number of available audio streams.
713 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
714 g_param_spec_int ("n-audio", "Number Audio",
715 "Total number of audio streams", 0, G_MAXINT, 0,
716 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
718 * GstPlayBin2:current-audio
720 * Get or set the currently playing audio stream. By default the first audio
721 * stream with data is played.
723 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
724 g_param_spec_int ("current-audio", "Current audio",
725 "Currently playing audio stream (-1 = auto)",
726 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
730 * Get the total number of available subtitle streams.
732 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
733 g_param_spec_int ("n-text", "Number Text",
734 "Total number of text streams", 0, G_MAXINT, 0,
735 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
737 * GstPlayBin2:current-text:
739 * Get or set the currently playing subtitle stream. By default the first
740 * subtitle stream with data is played.
742 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
743 g_param_spec_int ("current-text", "Current Text",
744 "Currently playing text stream (-1 = auto)",
745 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
747 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
748 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
749 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
750 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
751 "be checked for an encoding to use. If that is not set either, "
752 "ISO-8859-15 will be assumed.", NULL,
753 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
755 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
756 g_param_spec_object ("video-sink", "Video Sink",
757 "the video output element to use (NULL = default sink)",
758 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
759 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
760 g_param_spec_object ("audio-sink", "Audio Sink",
761 "the audio output element to use (NULL = default sink)",
762 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
763 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
764 g_param_spec_object ("vis-plugin", "Vis plugin",
765 "the visualization element to use (NULL = default)",
766 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
767 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
768 g_param_spec_object ("text-sink", "Text plugin",
769 "the text output element to use (NULL = default textoverlay)",
770 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
773 * GstPlayBin2:volume:
775 * Get or set the current audio stream volume. 1.0 means 100%,
776 * 0.0 means mute. This uses a linear volume scale.
779 g_object_class_install_property (gobject_klass, PROP_VOLUME,
780 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
781 0.0, VOLUME_MAX_DOUBLE, 1.0,
782 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
783 g_object_class_install_property (gobject_klass, PROP_MUTE,
784 g_param_spec_boolean ("mute", "Mute",
785 "Mute the audio channel without changing the volume", FALSE,
786 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
790 * @playbin: a #GstPlayBin2
792 * Get the currently rendered or prerolled frame in the sink.
793 * The #GstCaps on the buffer will describe the format of the buffer.
795 g_object_class_install_property (gobject_klass, PROP_FRAME,
796 gst_param_spec_mini_object ("frame", "Frame",
797 "The last frame (NULL = no video available)",
798 GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
799 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
800 g_param_spec_string ("subtitle-font-desc",
801 "Subtitle font description",
802 "Pango font description of font "
803 "to be used for subtitle rendering", NULL,
804 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
806 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
807 g_param_spec_uint ("connection-speed", "Connection Speed",
808 "Network connection speed in kbps (0 = unknown)",
809 0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
810 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
812 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
813 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
814 "Buffer size when buffering network streams",
815 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
816 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
817 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
818 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
819 "Buffer duration when buffering network streams",
820 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
821 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
824 * GstPlayBin2::about-to-finish
825 * @playbin: a #GstPlayBin2
827 * This signal is emitted when the current uri is about to finish. You can
828 * set the uri and suburi to make sure that playback continues.
830 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
831 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
833 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
834 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
837 * GstPlayBin2::video-changed
838 * @playbin: a #GstPlayBin2
840 * This signal is emitted whenever the number or order of the video
841 * streams has changed. The application will most likely want to select
842 * a new video stream.
844 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
845 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
847 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
848 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
850 * GstPlayBin2::audio-changed
851 * @playbin: a #GstPlayBin2
853 * This signal is emitted whenever the number or order of the audio
854 * streams has changed. The application will most likely want to select
855 * a new audio stream.
857 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
858 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
860 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
861 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
863 * GstPlayBin2::text-changed
864 * @playbin: a #GstPlayBin2
866 * This signal is emitted whenever the number or order of the text
867 * streams has changed. The application will most likely want to select
870 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
871 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
873 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
874 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
877 * GstPlayBin2::video-tags-changed
878 * @playbin: a #GstPlayBin2
879 * @stream: stream index with changed tags
881 * This signal is emitted whenever the tags of a video stream have changed.
882 * The application will most likely want to get the new tags.
886 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
887 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
889 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
890 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
893 * GstPlayBin2::audio-tags-changed
894 * @playbin: a #GstPlayBin2
895 * @stream: stream index with changed tags
897 * This signal is emitted whenever the tags of an audio stream have changed.
898 * The application will most likely want to get the new tags.
902 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
903 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
905 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
906 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
909 * GstPlayBin2::text-tags-changed
910 * @playbin: a #GstPlayBin2
911 * @stream: stream index with changed tags
913 * This signal is emitted whenever the tags of a text stream have changed.
914 * The application will most likely want to get the new tags.
918 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
919 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
921 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
922 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
925 * GstPlayBin2::get-video-tags
926 * @playbin: a #GstPlayBin2
927 * @stream: a video stream number
929 * Action signal to retrieve the tags of a specific video stream number.
930 * This information can be used to select a stream.
932 * Returns: a GstTagList with tags or NULL when the stream number does not
935 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
936 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
937 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
938 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
939 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
941 * GstPlayBin2::get-audio-tags
942 * @playbin: a #GstPlayBin2
943 * @stream: an audio stream number
945 * Action signal to retrieve the tags of a specific audio stream number.
946 * This information can be used to select a stream.
948 * Returns: a GstTagList with tags or NULL when the stream number does not
951 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
952 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
953 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
954 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
955 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
957 * GstPlayBin2::get-text-tags
958 * @playbin: a #GstPlayBin2
959 * @stream: a text stream number
961 * Action signal to retrieve the tags of a specific text stream number.
962 * This information can be used to select a stream.
964 * Returns: a GstTagList with tags or NULL when the stream number does not
967 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
968 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
969 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
970 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
971 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
973 * GstPlayBin2::convert-frame
974 * @playbin: a #GstPlayBin2
975 * @caps: the target format of the frame
977 * Action signal to retrieve the currently playing video frame in the format
978 * specified by @caps.
979 * If @caps is %NULL, no conversion will be performed and this function is
980 * equivalent to the #GstPlayBin::frame property.
982 * Returns: a #GstBuffer of the current video frame converted to #caps.
983 * The caps on the buffer will describe the final layout of the buffer data.
984 * %NULL is returned when no current buffer can be retrieved or when the
987 gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
988 g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
989 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
990 G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
991 gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
994 * GstPlayBin2::get-video-pad
995 * @playbin: a #GstPlayBin2
996 * @stream: a video stream number
998 * Action signal to retrieve the stream-selector sinkpad for a specific
1000 * This pad can be used for notifications of caps changes, stream-specific
1003 * Returns: a #GstPad, or NULL when the stream number does not exist.
1005 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1006 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1007 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1008 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1009 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1011 * GstPlayBin2::get-audio-pad
1012 * @playbin: a #GstPlayBin2
1013 * @stream: an audio stream number
1015 * Action signal to retrieve the stream-selector sinkpad for a specific
1017 * This pad can be used for notifications of caps changes, stream-specific
1020 * Returns: a #GstPad, or NULL when the stream number does not exist.
1022 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1023 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1024 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1025 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1026 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1028 * GstPlayBin2::get-text-pad
1029 * @playbin: a #GstPlayBin2
1030 * @stream: a text stream number
1032 * Action signal to retrieve the stream-selector sinkpad for a specific
1034 * This pad can be used for notifications of caps changes, stream-specific
1037 * Returns: a #GstPad, or NULL when the stream number does not exist.
1039 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1040 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1041 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1042 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1043 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1045 klass->get_video_tags = gst_play_bin_get_video_tags;
1046 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1047 klass->get_text_tags = gst_play_bin_get_text_tags;
1049 klass->convert_frame = gst_play_bin_convert_frame;
1051 klass->get_video_pad = gst_play_bin_get_video_pad;
1052 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1053 klass->get_text_pad = gst_play_bin_get_text_pad;
1055 gst_element_class_set_details (gstelement_klass, &gst_play_bin_details);
1057 gstelement_klass->change_state =
1058 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1059 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1061 gstbin_klass->handle_message =
1062 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1066 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1068 /* store the array for the different channels */
1069 group->video_channels = g_ptr_array_new ();
1070 group->audio_channels = g_ptr_array_new ();
1071 group->text_channels = g_ptr_array_new ();
1072 group->lock = g_mutex_new ();
1073 /* init selectors. The selector is found by finding the first prefix that
1074 * matches the media. */
1075 group->playbin = playbin;
1076 /* If you add any items to these lists, check that media_list[] is defined
1077 * above to be large enough to hold MAX(items)+1, so as to accomodate a
1078 * NULL terminator (set when the memory is zeroed on allocation) */
1079 group->selector[0].media_list[0] = "audio/x-raw-";
1080 group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
1081 group->selector[0].channels = group->audio_channels;
1082 group->selector[1].media_list[0] = "audio/";
1083 group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO;
1084 group->selector[1].channels = group->audio_channels;
1085 group->selector[2].media_list[0] = "text/";
1086 group->selector[2].media_list[1] = "application/x-subtitle";
1087 group->selector[2].media_list[2] = "application/x-ssa";
1088 group->selector[2].media_list[3] = "application/x-ass";
1089 group->selector[2].media_list[4] = "video/x-dvd-subpicture";
1090 group->selector[2].media_list[5] = "subpicture/";
1091 group->selector[2].media_list[6] = "subtitle/";
1092 group->selector[2].get_media_caps = gst_subtitle_overlay_create_factory_caps;
1093 group->selector[2].type = GST_PLAY_SINK_TYPE_TEXT;
1094 group->selector[2].channels = group->text_channels;
1095 group->selector[3].media_list[0] = "video/x-raw-";
1096 group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
1097 group->selector[3].channels = group->video_channels;
1098 group->selector[4].media_list[0] = "video/";
1099 group->selector[4].type = GST_PLAY_SINK_TYPE_VIDEO;
1100 group->selector[4].channels = group->video_channels;
1104 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1106 g_free (group->uri);
1107 g_free (group->suburi);
1108 g_ptr_array_free (group->video_channels, TRUE);
1109 g_ptr_array_free (group->audio_channels, TRUE);
1110 g_ptr_array_free (group->text_channels, TRUE);
1112 g_mutex_free (group->lock);
1113 if (group->audio_sink)
1114 gst_object_unref (group->audio_sink);
1115 group->audio_sink = NULL;
1116 if (group->video_sink)
1117 gst_object_unref (group->video_sink);
1118 group->video_sink = NULL;
1120 g_list_free (group->stream_changed_pending);
1121 group->stream_changed_pending = NULL;
1123 if (group->stream_changed_pending_lock)
1124 g_mutex_free (group->stream_changed_pending_lock);
1125 group->stream_changed_pending_lock = NULL;
1129 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1131 g_object_notify (G_OBJECT (playbin), "volume");
1135 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1137 g_object_notify (G_OBJECT (playbin), "mute");
1140 /* Must be called with elements lock! */
1142 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1144 if (!playbin->elements ||
1145 playbin->elements_cookie !=
1146 gst_default_registry_get_feature_list_cookie ()) {
1147 if (playbin->elements)
1148 g_value_array_free (playbin->elements);
1150 gst_factory_list_get_elements (GST_FACTORY_LIST_DECODER |
1151 GST_FACTORY_LIST_SINK);
1152 playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1157 gst_play_bin_init (GstPlayBin * playbin)
1159 playbin->lock = g_mutex_new ();
1160 playbin->dyn_lock = g_mutex_new ();
1162 /* assume we can create a selector */
1163 playbin->have_selector = TRUE;
1166 playbin->curr_group = &playbin->groups[0];
1167 playbin->next_group = &playbin->groups[1];
1168 init_group (playbin, &playbin->groups[0]);
1169 init_group (playbin, &playbin->groups[1]);
1171 /* first filter out the interesting element factories */
1172 playbin->elements_lock = g_mutex_new ();
1173 gst_play_bin_update_elements_list (playbin);
1174 GST_FACTORY_LIST_DEBUG (playbin->elements);
1177 playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1178 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1179 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1180 /* Connect to notify::volume and notify::mute signals for proxying */
1181 g_signal_connect (playbin->playsink, "notify::volume",
1182 G_CALLBACK (notify_volume_cb), playbin);
1183 g_signal_connect (playbin->playsink, "notify::mute",
1184 G_CALLBACK (notify_mute_cb), playbin);
1186 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1187 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1188 playbin->current_text = DEFAULT_CURRENT_TEXT;
1190 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1191 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1195 gst_play_bin_finalize (GObject * object)
1197 GstPlayBin *playbin;
1199 playbin = GST_PLAY_BIN (object);
1201 free_group (playbin, &playbin->groups[0]);
1202 free_group (playbin, &playbin->groups[1]);
1204 if (playbin->source)
1205 gst_object_unref (playbin->source);
1206 if (playbin->video_sink)
1207 gst_object_unref (playbin->video_sink);
1208 if (playbin->audio_sink)
1209 gst_object_unref (playbin->audio_sink);
1210 if (playbin->text_sink)
1211 gst_object_unref (playbin->text_sink);
1213 g_value_array_free (playbin->elements);
1214 g_mutex_free (playbin->lock);
1215 g_mutex_free (playbin->dyn_lock);
1216 g_mutex_free (playbin->elements_lock);
1218 G_OBJECT_CLASS (parent_class)->finalize (object);
1222 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1224 GstSourceGroup *group;
1227 g_warning ("cannot set NULL uri");
1231 GST_PLAY_BIN_LOCK (playbin);
1232 group = playbin->next_group;
1234 GST_SOURCE_GROUP_LOCK (group);
1235 /* store the uri in the next group we will play */
1236 g_free (group->uri);
1237 group->uri = g_strdup (uri);
1238 group->valid = TRUE;
1239 GST_SOURCE_GROUP_UNLOCK (group);
1241 GST_DEBUG ("set new uri to %s", uri);
1242 GST_PLAY_BIN_UNLOCK (playbin);
1246 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1248 GstSourceGroup *group;
1250 GST_PLAY_BIN_LOCK (playbin);
1251 group = playbin->next_group;
1253 GST_SOURCE_GROUP_LOCK (group);
1254 g_free (group->suburi);
1255 group->suburi = g_strdup (suburi);
1256 GST_SOURCE_GROUP_UNLOCK (group);
1258 GST_DEBUG ("setting new .sub uri to %s", suburi);
1260 GST_PLAY_BIN_UNLOCK (playbin);
1264 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1266 gst_play_sink_set_flags (playbin->playsink, flags);
1267 gst_play_sink_reconfigure (playbin->playsink);
1271 gst_play_bin_get_flags (GstPlayBin * playbin)
1275 flags = gst_play_sink_get_flags (playbin->playsink);
1280 /* get the currently playing group or if nothing is playing, the next
1281 * group. Must be called with the PLAY_BIN_LOCK. */
1282 static GstSourceGroup *
1283 get_group (GstPlayBin * playbin)
1285 GstSourceGroup *result;
1287 if (!(result = playbin->curr_group))
1288 result = playbin->next_group;
1294 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1296 GstPad *sinkpad = NULL;
1297 GstSourceGroup *group;
1299 GST_PLAY_BIN_LOCK (playbin);
1300 group = get_group (playbin);
1301 if (stream < group->video_channels->len) {
1302 sinkpad = g_ptr_array_index (group->video_channels, stream);
1303 gst_object_ref (sinkpad);
1305 GST_PLAY_BIN_UNLOCK (playbin);
1311 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1313 GstPad *sinkpad = NULL;
1314 GstSourceGroup *group;
1316 GST_PLAY_BIN_LOCK (playbin);
1317 group = get_group (playbin);
1318 if (stream < group->audio_channels->len) {
1319 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1320 gst_object_ref (sinkpad);
1322 GST_PLAY_BIN_UNLOCK (playbin);
1328 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1330 GstPad *sinkpad = NULL;
1331 GstSourceGroup *group;
1333 GST_PLAY_BIN_LOCK (playbin);
1334 group = get_group (playbin);
1335 if (stream < group->text_channels->len) {
1336 sinkpad = g_ptr_array_index (group->text_channels, stream);
1337 gst_object_ref (sinkpad);
1339 GST_PLAY_BIN_UNLOCK (playbin);
1346 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1351 if (!channels || stream >= channels->len)
1354 sinkpad = g_ptr_array_index (channels, stream);
1355 g_object_get (sinkpad, "tags", &result, NULL);
1361 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1364 GstSourceGroup *group;
1366 GST_PLAY_BIN_LOCK (playbin);
1367 group = get_group (playbin);
1368 result = get_tags (playbin, group->video_channels, stream);
1369 GST_PLAY_BIN_UNLOCK (playbin);
1375 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1378 GstSourceGroup *group;
1380 GST_PLAY_BIN_LOCK (playbin);
1381 group = get_group (playbin);
1382 result = get_tags (playbin, group->audio_channels, stream);
1383 GST_PLAY_BIN_UNLOCK (playbin);
1389 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1392 GstSourceGroup *group;
1394 GST_PLAY_BIN_LOCK (playbin);
1395 group = get_group (playbin);
1396 result = get_tags (playbin, group->text_channels, stream);
1397 GST_PLAY_BIN_UNLOCK (playbin);
1403 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1407 result = gst_play_sink_get_last_frame (playbin->playsink);
1408 if (result != NULL && caps != NULL) {
1411 temp = gst_play_frame_conv_convert (result, caps);
1412 gst_buffer_unref (result);
1418 /* Returns current stream number, or -1 if none has been selected yet */
1420 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1422 /* Internal API cleanup would make this easier... */
1424 GstPad *pad, *current;
1425 GstObject *selector = NULL;
1428 for (i = 0; i < channels->len; i++) {
1429 pad = g_ptr_array_index (channels, i);
1430 if ((selector = gst_pad_get_parent (pad))) {
1431 g_object_get (selector, "active-pad", ¤t, NULL);
1432 gst_object_unref (selector);
1434 if (pad == current) {
1435 gst_object_unref (current);
1441 gst_object_unref (current);
1449 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1451 GstSourceGroup *group;
1452 GPtrArray *channels;
1455 GST_PLAY_BIN_LOCK (playbin);
1456 group = get_group (playbin);
1457 if (!(channels = group->video_channels))
1460 if (stream == -1 || channels->len <= stream) {
1463 /* take channel from selected stream */
1464 sinkpad = g_ptr_array_index (channels, stream);
1468 gst_object_ref (sinkpad);
1469 GST_PLAY_BIN_UNLOCK (playbin);
1472 GstObject *selector;
1474 if ((selector = gst_pad_get_parent (sinkpad))) {
1475 /* activate the selected pad */
1476 g_object_set (selector, "active-pad", sinkpad, NULL);
1477 gst_object_unref (selector);
1479 gst_object_unref (sinkpad);
1485 GST_PLAY_BIN_UNLOCK (playbin);
1491 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1493 GstSourceGroup *group;
1494 GPtrArray *channels;
1497 GST_PLAY_BIN_LOCK (playbin);
1498 group = get_group (playbin);
1499 if (!(channels = group->audio_channels))
1502 if (stream == -1 || channels->len <= stream) {
1505 /* take channel from selected stream */
1506 sinkpad = g_ptr_array_index (channels, stream);
1510 gst_object_ref (sinkpad);
1511 GST_PLAY_BIN_UNLOCK (playbin);
1514 GstObject *selector;
1516 if ((selector = gst_pad_get_parent (sinkpad))) {
1517 /* activate the selected pad */
1518 g_object_set (selector, "active-pad", sinkpad, NULL);
1519 gst_object_unref (selector);
1521 gst_object_unref (sinkpad);
1527 GST_PLAY_BIN_UNLOCK (playbin);
1533 _suburidecodebin_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
1535 GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
1539 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1541 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1544 if (it && gst_iterator_next (it, (gpointer) & sinkpad) == GST_ITERATOR_OK
1549 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1550 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1551 if (!gst_pad_send_event (sinkpad, event)) {
1553 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1554 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1555 if (!gst_pad_send_event (sinkpad, event))
1556 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1559 gst_object_unref (sinkpad);
1563 gst_iterator_free (it);
1567 gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
1570 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1571 gboolean done = FALSE;
1573 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1580 switch (gst_iterator_next (it, (gpointer) & sinkpad)) {
1581 case GST_ITERATOR_OK:
1582 gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
1584 gst_object_unref (sinkpad);
1586 case GST_ITERATOR_DONE:
1589 case GST_ITERATOR_RESYNC:
1590 gst_iterator_resync (it);
1592 case GST_ITERATOR_ERROR:
1597 gst_iterator_free (it);
1601 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1603 GstSourceGroup *group;
1604 GPtrArray *channels;
1607 GST_PLAY_BIN_LOCK (playbin);
1608 group = get_group (playbin);
1609 if (!(channels = group->text_channels))
1612 if (stream == -1 || channels->len <= stream) {
1615 /* take channel from selected stream */
1616 sinkpad = g_ptr_array_index (channels, stream);
1620 gst_object_ref (sinkpad);
1621 GST_PLAY_BIN_UNLOCK (playbin);
1624 GstObject *selector;
1626 if ((selector = gst_pad_get_parent (sinkpad))) {
1627 GstPad *old_sinkpad;
1629 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1631 if (old_sinkpad != sinkpad) {
1632 gboolean need_unblock, need_block, need_seek;
1633 GstPad *src, *peer = NULL, *oldpeer = NULL;
1634 GstElement *parent_element = NULL, *old_parent_element = NULL;
1636 /* Now check if we need to seek the suburidecodebin to the beginning
1637 * or if we need to block all suburidecodebin sinkpads or if we need
1638 * to unblock all suburidecodebin sinkpads
1641 peer = gst_pad_get_peer (sinkpad);
1643 oldpeer = gst_pad_get_peer (old_sinkpad);
1646 parent_element = gst_pad_get_parent_element (peer);
1648 old_parent_element = gst_pad_get_parent_element (oldpeer);
1650 need_block = (old_parent_element == group->suburidecodebin
1651 && parent_element != old_parent_element);
1652 need_unblock = (parent_element == group->suburidecodebin
1653 && parent_element != old_parent_element);
1654 need_seek = (parent_element == group->suburidecodebin);
1657 gst_object_unref (peer);
1659 gst_object_unref (oldpeer);
1661 gst_object_unref (parent_element);
1662 if (old_parent_element)
1663 gst_object_unref (old_parent_element);
1665 /* Block all suburidecodebin sinkpads */
1667 gst_play_bin_suburidecodebin_block (group->suburidecodebin, TRUE);
1669 /* activate the selected pad */
1670 g_object_set (selector, "active-pad", sinkpad, NULL);
1672 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1673 peer = gst_pad_get_peer (src);
1677 /* Flush the subtitle renderer to remove any
1678 * currently displayed subtitles. This event will
1679 * never travel outside subtitleoverlay!
1681 s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1682 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1683 gst_pad_send_event (peer, event);
1684 gst_object_unref (peer);
1686 gst_object_unref (src);
1688 /* Unblock pads if necessary */
1690 gst_play_bin_suburidecodebin_block (group->suburidecodebin, FALSE);
1692 /* seek to the beginning */
1694 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1696 gst_object_unref (selector);
1699 gst_object_unref (old_sinkpad);
1701 gst_object_unref (sinkpad);
1707 GST_PLAY_BIN_UNLOCK (playbin);
1713 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1714 const gchar * dbg, GstElement * sink)
1716 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1718 GST_PLAY_BIN_LOCK (playbin);
1719 if (*elem != sink) {
1724 gst_object_ref_sink (sink);
1728 gst_object_unref (old);
1730 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1731 GST_PLAY_BIN_UNLOCK (playbin);
1735 gst_play_bin_set_property (GObject * object, guint prop_id,
1736 const GValue * value, GParamSpec * pspec)
1738 GstPlayBin *playbin;
1740 playbin = GST_PLAY_BIN (object);
1744 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1747 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1750 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1752 case PROP_CURRENT_VIDEO:
1753 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1755 case PROP_CURRENT_AUDIO:
1756 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1758 case PROP_CURRENT_TEXT:
1759 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1761 case PROP_SUBTITLE_ENCODING:
1762 gst_play_sink_set_subtitle_encoding (playbin->playsink,
1763 g_value_get_string (value));
1765 case PROP_VIDEO_SINK:
1766 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1767 g_value_get_object (value));
1769 case PROP_AUDIO_SINK:
1770 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1771 g_value_get_object (value));
1773 case PROP_VIS_PLUGIN:
1774 gst_play_sink_set_vis_plugin (playbin->playsink,
1775 g_value_get_object (value));
1777 case PROP_TEXT_SINK:
1778 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1779 g_value_get_object (value));
1782 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1785 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1787 case PROP_FONT_DESC:
1788 gst_play_sink_set_font_desc (playbin->playsink,
1789 g_value_get_string (value));
1791 case PROP_CONNECTION_SPEED:
1792 GST_PLAY_BIN_LOCK (playbin);
1793 playbin->connection_speed = g_value_get_uint (value) * 1000;
1794 GST_PLAY_BIN_UNLOCK (playbin);
1796 case PROP_BUFFER_SIZE:
1797 playbin->buffer_size = g_value_get_int (value);
1799 case PROP_BUFFER_DURATION:
1800 playbin->buffer_duration = g_value_get_int64 (value);
1803 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1809 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1810 const gchar * dbg, GstPlaySinkType type)
1814 sink = gst_play_sink_get_sink (playbin->playsink, type);
1816 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1817 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1818 dbg, sink, dbg, *elem);
1821 GST_PLAY_BIN_LOCK (playbin);
1823 gst_object_ref (sink);
1824 GST_PLAY_BIN_UNLOCK (playbin);
1831 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1834 GstPlayBin *playbin;
1836 playbin = GST_PLAY_BIN (object);
1841 GstSourceGroup *group;
1843 GST_PLAY_BIN_LOCK (playbin);
1844 group = get_group (playbin);
1845 g_value_set_string (value, group->uri);
1846 GST_PLAY_BIN_UNLOCK (playbin);
1851 GstSourceGroup *group;
1853 GST_PLAY_BIN_LOCK (playbin);
1854 group = get_group (playbin);
1855 g_value_set_string (value, group->suburi);
1856 GST_PLAY_BIN_UNLOCK (playbin);
1861 GST_OBJECT_LOCK (playbin);
1862 g_value_set_object (value, playbin->source);
1863 GST_OBJECT_UNLOCK (playbin);
1867 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
1871 GstSourceGroup *group;
1874 GST_PLAY_BIN_LOCK (playbin);
1875 group = get_group (playbin);
1876 n_video = (group->video_channels ? group->video_channels->len : 0);
1877 g_value_set_int (value, n_video);
1878 GST_PLAY_BIN_UNLOCK (playbin);
1881 case PROP_CURRENT_VIDEO:
1882 GST_PLAY_BIN_LOCK (playbin);
1883 g_value_set_int (value, playbin->current_video);
1884 GST_PLAY_BIN_UNLOCK (playbin);
1888 GstSourceGroup *group;
1891 GST_PLAY_BIN_LOCK (playbin);
1892 group = get_group (playbin);
1893 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
1894 g_value_set_int (value, n_audio);
1895 GST_PLAY_BIN_UNLOCK (playbin);
1898 case PROP_CURRENT_AUDIO:
1899 GST_PLAY_BIN_LOCK (playbin);
1900 g_value_set_int (value, playbin->current_audio);
1901 GST_PLAY_BIN_UNLOCK (playbin);
1905 GstSourceGroup *group;
1908 GST_PLAY_BIN_LOCK (playbin);
1909 group = get_group (playbin);
1910 n_text = (group->text_channels ? group->text_channels->len : 0);
1911 g_value_set_int (value, n_text);
1912 GST_PLAY_BIN_UNLOCK (playbin);
1915 case PROP_CURRENT_TEXT:
1916 GST_PLAY_BIN_LOCK (playbin);
1917 g_value_set_int (value, playbin->current_text);
1918 GST_PLAY_BIN_UNLOCK (playbin);
1920 case PROP_SUBTITLE_ENCODING:
1921 GST_PLAY_BIN_LOCK (playbin);
1922 g_value_take_string (value,
1923 gst_play_sink_get_subtitle_encoding (playbin->playsink));
1924 GST_PLAY_BIN_UNLOCK (playbin);
1926 case PROP_VIDEO_SINK:
1927 g_value_take_object (value,
1928 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
1929 "video", GST_PLAY_SINK_TYPE_VIDEO));
1931 case PROP_AUDIO_SINK:
1932 g_value_take_object (value,
1933 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
1934 "audio", GST_PLAY_SINK_TYPE_AUDIO));
1936 case PROP_VIS_PLUGIN:
1937 g_value_take_object (value,
1938 gst_play_sink_get_vis_plugin (playbin->playsink));
1940 case PROP_TEXT_SINK:
1941 g_value_take_object (value,
1942 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
1943 "text", GST_PLAY_SINK_TYPE_TEXT));
1946 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
1949 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
1952 gst_value_take_buffer (value, gst_play_bin_convert_frame (playbin, NULL));
1954 case PROP_FONT_DESC:
1955 g_value_take_string (value,
1956 gst_play_sink_get_font_desc (playbin->playsink));
1958 case PROP_CONNECTION_SPEED:
1959 GST_PLAY_BIN_LOCK (playbin);
1960 g_value_set_uint (value, playbin->connection_speed / 1000);
1961 GST_PLAY_BIN_UNLOCK (playbin);
1963 case PROP_BUFFER_SIZE:
1964 GST_OBJECT_LOCK (playbin);
1965 g_value_set_int (value, playbin->buffer_size);
1966 GST_OBJECT_UNLOCK (playbin);
1968 case PROP_BUFFER_DURATION:
1969 GST_OBJECT_LOCK (playbin);
1970 g_value_set_int64 (value, playbin->buffer_duration);
1971 GST_OBJECT_UNLOCK (playbin);
1974 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1980 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
1981 gboolean valid, GstQuery * query)
1987 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
1988 gst_query_parse_duration (query, &fmt, &duration);
1990 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
1991 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
1992 playbin->duration[i].valid = valid;
1993 playbin->duration[i].format = fmt;
1994 playbin->duration[i].duration = valid ? duration : -1;
2001 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2003 const GstFormat formats[] =
2004 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2009 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2010 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2011 query = gst_query_new_duration (formats[i]);
2013 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2015 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2016 gst_query_unref (query);
2021 gst_play_bin_query (GstElement * element, GstQuery * query)
2023 GstPlayBin *playbin = GST_PLAY_BIN (element);
2026 /* During a group switch we shouldn't allow duration queries
2027 * because it's not clear if the old or new group's duration
2028 * is returned and if the sinks are already playing new data
2029 * or old data. See bug #585969
2031 * While we're at it, also don't do any other queries during
2032 * a group switch or any other event that causes topology changes
2033 * by taking the playbin lock in any case.
2035 GST_PLAY_BIN_LOCK (playbin);
2037 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2038 GstSourceGroup *group = playbin->curr_group;
2041 GST_SOURCE_GROUP_LOCK (group);
2042 if (group->stream_changed_pending_lock) {
2043 g_mutex_lock (group->stream_changed_pending_lock);
2044 pending = group->pending || group->stream_changed_pending;
2045 g_mutex_unlock (group->stream_changed_pending_lock);
2047 pending = group->pending;
2054 gst_query_parse_duration (query, &fmt, NULL);
2055 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2056 if (fmt == playbin->duration[i].format) {
2057 ret = playbin->duration[i].valid;
2058 gst_query_set_duration (query, fmt,
2059 (ret ? playbin->duration[i].duration : -1));
2063 GST_DEBUG_OBJECT (playbin,
2064 "Taking cached duration because of pending group switch: %d", ret);
2065 GST_SOURCE_GROUP_UNLOCK (group);
2066 GST_PLAY_BIN_UNLOCK (playbin);
2069 GST_SOURCE_GROUP_UNLOCK (group);
2072 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2074 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2075 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2076 GST_PLAY_BIN_UNLOCK (playbin);
2081 /* mime types we are not handling on purpose right now, don't post a
2082 * missing-plugin message for these */
2083 static const gchar *blacklisted_mimes[] = {
2088 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2090 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2091 GstSourceGroup *group;
2093 if (gst_is_missing_plugin_message (msg)) {
2097 detail = gst_missing_plugin_message_get_installer_detail (msg);
2098 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2099 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2100 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2101 gst_message_unref (msg);
2107 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2108 const GstStructure *s = gst_message_get_structure (msg);
2110 /* Drop all stream-changed messages except the last one */
2111 if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2112 guint32 seqnum = gst_message_get_seqnum (msg);
2115 group = playbin->curr_group;
2116 g_mutex_lock (group->stream_changed_pending_lock);
2117 for (l = group->stream_changed_pending; l;) {
2118 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2120 if (l_seqnum == seqnum) {
2123 group->stream_changed_pending =
2124 g_list_delete_link (group->stream_changed_pending, l_prev);
2125 if (group->stream_changed_pending) {
2126 gst_message_unref (msg);
2134 g_mutex_unlock (group->stream_changed_pending_lock);
2136 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2137 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2138 GstObject *src = GST_OBJECT_CAST (msg->src);
2140 /* Ignore async state changes from the uridecodebin children,
2141 * see bug #602000. */
2142 group = playbin->curr_group;
2143 if (src && (group = playbin->curr_group) &&
2144 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2145 || (group->suburidecodebin
2146 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2147 GST_DEBUG_OBJECT (playbin,
2148 "Ignoring async state change of uridecodebin: %s",
2149 GST_OBJECT_NAME (src));
2150 gst_message_unref (msg);
2153 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2154 /* If we get an error of the subtitle uridecodebin transform
2155 * them into warnings and disable the subtitles */
2156 group = playbin->curr_group;
2157 if (group && group->suburidecodebin) {
2158 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2159 (group->suburidecodebin)))) {
2161 gchar *debug = NULL;
2162 GstMessage *new_msg;
2164 gboolean done = FALSE;
2166 gst_message_parse_error (msg, &err, &debug);
2167 new_msg = gst_message_new_warning (msg->src, err, debug);
2169 gst_message_unref (msg);
2174 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2175 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2176 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2177 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2179 it = gst_element_iterate_src_pads (group->suburidecodebin);
2180 while (it && !done) {
2182 GstIteratorResult res;
2184 res = gst_iterator_next (it, (gpointer) & p);
2187 case GST_ITERATOR_DONE:
2190 case GST_ITERATOR_OK:
2191 pad_removed_cb (NULL, p, group);
2192 gst_object_unref (p);
2195 case GST_ITERATOR_RESYNC:
2196 gst_iterator_resync (it);
2198 case GST_ITERATOR_ERROR:
2204 gst_iterator_free (it);
2206 gst_object_ref (group->suburidecodebin);
2207 gst_bin_remove (bin, group->suburidecodebin);
2208 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2210 if (group->sub_pending) {
2211 group->sub_pending = FALSE;
2212 no_more_pads_cb (NULL, group);
2219 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2223 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2224 GstPlayBin * playbin)
2227 GstSourceGroup *group;
2228 GstSourceSelect *select = NULL;
2231 GST_PLAY_BIN_LOCK (playbin);
2232 group = get_group (playbin);
2234 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2235 if (selector == G_OBJECT (group->selector[i].selector)) {
2236 select = &group->selector[i];
2240 /* We got a pad-change after our group got switched out; no need to notify */
2242 GST_PLAY_BIN_UNLOCK (playbin);
2246 switch (select->type) {
2247 case GST_PLAY_SINK_TYPE_VIDEO:
2248 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2249 property = "current-video";
2250 playbin->current_video = get_current_stream_number (playbin,
2251 group->video_channels);
2253 case GST_PLAY_SINK_TYPE_AUDIO:
2254 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2255 property = "current-audio";
2256 playbin->current_audio = get_current_stream_number (playbin,
2257 group->audio_channels);
2259 case GST_PLAY_SINK_TYPE_TEXT:
2260 property = "current-text";
2261 playbin->current_text = get_current_stream_number (playbin,
2262 group->text_channels);
2267 GST_PLAY_BIN_UNLOCK (playbin);
2270 g_object_notify (G_OBJECT (playbin), property);
2274 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
2277 GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
2280 /* helper function to lookup stuff in lists */
2282 array_has_value (const gchar * values[], const gchar * value)
2286 for (i = 0; values[i]; i++) {
2287 if (g_str_has_prefix (value, values[i]))
2295 GstPlayBin *playbin;
2297 GstPlaySinkType type;
2301 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2303 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2306 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2307 " with stream id %d and type %d have changed",
2308 object, ntdata->stream_id, ntdata->type);
2310 switch (ntdata->type) {
2311 case GST_PLAY_SINK_TYPE_VIDEO:
2312 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2313 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2315 case GST_PLAY_SINK_TYPE_AUDIO:
2316 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2317 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2319 case GST_PLAY_SINK_TYPE_TEXT:
2320 signal = SIGNAL_TEXT_TAGS_CHANGED;
2328 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2334 GstPlayBin *playbin;
2335 GstSourceGroup *group;
2336 GstPlaySinkType type;
2337 } PlaySinkEventProbeData;
2340 _playsink_src_event_probe_cb (GstPad * pad, GstEvent * event,
2341 PlaySinkEventProbeData * data)
2343 if (GST_EVENT_TYPE (event) == GST_EVENT_QOS) {
2344 GstEvent *new_event;
2347 GstClockTimeDiff diff;
2348 GstClockTime group_start_accum =
2349 data->group->selector[data->type].group_start_accum;
2350 GstClockTime timestamp;
2352 s = (GstStructure *) gst_event_get_structure (event);
2353 if (gst_structure_has_field (s, "playbin2-adjusted-event"))
2356 /* If we have no group start accumulator yet, this is
2357 * a QOS event for the previous group or this stream
2358 * has a non-time segment.
2360 if (!GST_CLOCK_TIME_IS_VALID (group_start_accum))
2363 /* If the group start accumulator is 0, this is the first
2364 * group and we don't need to do everything below
2366 if (group_start_accum == 0)
2369 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
2371 /* If the running time timestamp is smaller than the accumulator,
2372 * the event is for a buffer from the previous group
2374 if (timestamp >= group_start_accum)
2375 timestamp -= group_start_accum;
2379 /* That case is invalid for QoS events, also it means that
2380 * we have switched the group but receive QoS events of
2381 * the previous group.
2383 if (diff < 0 && -diff > timestamp)
2386 new_event = gst_event_new_qos (proportion, diff, timestamp);
2387 s = (GstStructure *) gst_event_get_structure (new_event);
2388 gst_structure_set (s, "playbin2-adjusted-event", G_TYPE_BOOLEAN, TRUE,
2390 gst_pad_send_event (pad, new_event);
2399 _playsink_sink_event_probe_cb (GstPad * pad, GstEvent * event,
2400 PlaySinkEventProbeData * data)
2404 if (data->type == GST_PLAY_SINK_TYPE_VIDEO
2405 || data->type == GST_PLAY_SINK_TYPE_VIDEO_RAW)
2407 else if (data->type == GST_PLAY_SINK_TYPE_AUDIO
2408 || data->type == GST_PLAY_SINK_TYPE_AUDIO_RAW)
2410 else if (data->type == GST_PLAY_SINK_TYPE_TEXT)
2413 g_assert_not_reached ();
2415 if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
2416 GstPlayBin *playbin = data->playbin;
2417 GstSegment *segment;
2420 gdouble rate, applied_rate;
2421 gint64 start, stop, pos;
2423 segment = &playbin->segments[index];
2425 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
2426 &format, &start, &stop, &pos);
2427 if (segment->format != format)
2428 gst_segment_init (segment, format);
2429 gst_segment_set_newsegment_full (segment, update, rate, applied_rate,
2430 format, start, stop, pos);
2432 if (format != GST_FORMAT_TIME)
2433 data->group->selector[data->type].group_start_accum = GST_CLOCK_TIME_NONE;
2434 else if (!GST_CLOCK_TIME_IS_VALID (data->group->selector[data->type].
2436 data->group->selector[data->type].group_start_accum = segment->accum;
2437 } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2438 gst_segment_init (&data->playbin->segments[index], GST_FORMAT_UNDEFINED);
2444 /* this function is called when a new pad is added to decodebin. We check the
2445 * type of the pad and add it to the selector element of the group.
2448 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2450 GstPlayBin *playbin;
2452 const GstStructure *s;
2455 GstPadLinkReturn res;
2456 GstSourceSelect *select = NULL;
2458 gboolean changed = FALSE;
2460 playbin = group->playbin;
2462 caps = gst_pad_get_caps_reffed (pad);
2463 s = gst_caps_get_structure (caps, 0);
2464 name = gst_structure_get_name (s);
2466 GST_DEBUG_OBJECT (playbin,
2467 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2468 GST_DEBUG_PAD_NAME (pad), caps, group);
2470 /* major type of the pad, this determines the selector to use */
2471 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2472 if (array_has_value (group->selector[i].media_list, name)) {
2473 select = &group->selector[i];
2475 } else if (group->selector[i].get_media_caps) {
2476 GstCaps *media_caps = group->selector[i].get_media_caps ();
2478 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2479 select = &group->selector[i];
2480 gst_caps_unref (media_caps);
2483 gst_caps_unref (media_caps);
2486 /* no selector found for the media type, don't bother linking it to a
2487 * selector. This will leave the pad unlinked and thus ignored. */
2491 GST_SOURCE_GROUP_LOCK (group);
2492 if (select->selector == NULL && playbin->have_selector) {
2493 /* no selector, create one */
2494 GST_DEBUG_OBJECT (playbin, "creating new selector");
2495 select->selector = g_object_new (GST_TYPE_INPUT_SELECTOR, NULL);
2496 /* the above can't fail, but we keep the error handling around for when
2497 * the selector plugin has moved to -base or -good and we stop using an
2498 * internal copy of input-selector */
2499 if (select->selector == NULL) {
2500 /* post the missing selector message only once */
2501 playbin->have_selector = FALSE;
2502 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2503 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2505 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2506 (_("Missing element '%s' - check your GStreamer installation."),
2507 "input-selector"), (NULL));
2509 g_signal_connect (select->selector, "notify::active-pad",
2510 G_CALLBACK (selector_active_pad_changed), playbin);
2512 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2513 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2514 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2518 if (select->srcpad == NULL) {
2519 PlaySinkEventProbeData *data = g_new (PlaySinkEventProbeData, 1);
2521 if (select->selector) {
2522 /* save source pad of the selector */
2523 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2525 /* no selector, use the pad as the source pad then */
2526 select->srcpad = gst_object_ref (pad);
2529 /* Install an event probe */
2530 data->playbin = playbin;
2531 data->group = group;
2532 data->type = select->type;
2533 select->src_event_probe_id =
2534 gst_pad_add_event_probe_full (select->srcpad,
2535 G_CALLBACK (_playsink_src_event_probe_cb), data,
2536 (GDestroyNotify) g_free);
2538 select->group_start_accum = -1;
2540 /* block the selector srcpad. It's possible that multiple decodebins start
2541 * pushing data into the selectors before we have a chance to collect all
2542 * streams and connect the sinks, resulting in not-linked errors. After we
2543 * configured the sinks we will unblock them all. */
2544 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2545 gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
2548 /* get sinkpad for the new stream */
2549 if (select->selector) {
2550 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2551 gulong notify_tags_handler = 0;
2552 NotifyTagsData *ntdata;
2554 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2555 GST_DEBUG_PAD_NAME (sinkpad));
2557 /* store the selector for the pad */
2558 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2560 /* connect to the notify::tags signal for our
2561 * own *-tags-changed signals
2563 ntdata = g_new0 (NotifyTagsData, 1);
2564 ntdata->playbin = playbin;
2565 ntdata->stream_id = select->channels->len;
2566 ntdata->type = select->type;
2568 notify_tags_handler =
2569 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2570 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2572 g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2573 (gpointer) notify_tags_handler);
2575 /* store the pad in the array */
2576 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2577 g_ptr_array_add (select->channels, sinkpad);
2579 res = gst_pad_link (pad, sinkpad);
2580 if (GST_PAD_LINK_FAILED (res))
2583 /* store selector pad so we can release it */
2584 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2587 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2588 GST_DEBUG_PAD_NAME (pad), select->selector);
2591 /* no selector, don't configure anything, we'll link the new pad directly to
2596 GST_SOURCE_GROUP_UNLOCK (group);
2600 gboolean always_ok = (decodebin == group->suburidecodebin);
2602 switch (select->type) {
2603 case GST_PLAY_SINK_TYPE_VIDEO:
2604 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2605 /* we want to return NOT_LINKED for unselected pads but only for pads
2606 * from the normal uridecodebin. This makes sure that subtitle streams
2607 * are not raced past audio/video from decodebin2's multiqueue.
2608 * For pads from suburidecodebin OK should always be returned, otherwise
2609 * it will most likely stop. */
2610 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2611 signal = SIGNAL_VIDEO_CHANGED;
2613 case GST_PLAY_SINK_TYPE_AUDIO:
2614 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2615 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2616 signal = SIGNAL_AUDIO_CHANGED;
2618 case GST_PLAY_SINK_TYPE_TEXT:
2619 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2620 signal = SIGNAL_TEXT_CHANGED;
2627 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2631 gst_caps_unref (caps);
2637 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2638 name, GST_DEBUG_PAD_NAME (pad));
2643 GST_ERROR_OBJECT (playbin,
2644 "failed to link pad %s:%s to selector, reason %d",
2645 GST_DEBUG_PAD_NAME (pad), res);
2646 GST_SOURCE_GROUP_UNLOCK (group);
2651 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2652 * the selector. This will make the selector select a new pad. */
2654 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2656 GstPlayBin *playbin;
2658 GstElement *selector;
2659 GstSourceSelect *select;
2661 playbin = group->playbin;
2663 GST_DEBUG_OBJECT (playbin,
2664 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2666 GST_SOURCE_GROUP_LOCK (group);
2667 /* get the selector sinkpad */
2668 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2671 if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2672 gulong notify_tags_handler;
2674 notify_tags_handler =
2675 (gulong) g_object_get_data (G_OBJECT (peer),
2676 "playbin2.notify_tags_handler");
2677 if (notify_tags_handler != 0)
2678 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2679 g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2681 /* remove the pad from the array */
2682 g_ptr_array_remove (select->channels, peer);
2683 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2686 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2687 gst_pad_unlink (pad, peer);
2689 /* get selector, this can be NULL when the element is removing the pads
2690 * because it's being disposed. */
2691 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2693 gst_object_unref (peer);
2697 /* release the pad to the selector, this will make the selector choose a new
2699 gst_element_release_request_pad (selector, peer);
2700 gst_object_unref (peer);
2702 gst_object_unref (selector);
2703 GST_SOURCE_GROUP_UNLOCK (group);
2710 GST_DEBUG_OBJECT (playbin, "pad not linked");
2711 GST_SOURCE_GROUP_UNLOCK (group);
2716 GST_DEBUG_OBJECT (playbin, "selector not found");
2717 GST_SOURCE_GROUP_UNLOCK (group);
2722 /* we get called when all pads are available and we must connect the sinks to
2724 * The main purpose of the code is to see if we have video/audio and subtitles
2725 * and pick the right pipelines to display them.
2727 * The selectors installed on the group tell us about the presence of
2728 * audio/video and subtitle streams. This allows us to see if we need
2729 * visualisation, video or/and audio.
2732 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2734 GstPlayBin *playbin;
2735 GstPadLinkReturn res;
2739 playbin = group->playbin;
2741 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2743 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2745 GST_SOURCE_GROUP_LOCK (group);
2746 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2747 GstSourceSelect *select = &group->selector[i];
2749 /* check if the specific media type was detected and thus has a selector
2750 * created for it. If there is the media type, get a sinkpad from the sink
2751 * and link it. We only do this if we have not yet requested the sinkpad
2753 if (select->srcpad && select->sinkpad == NULL) {
2754 PlaySinkEventProbeData *data = g_new (PlaySinkEventProbeData, 1);
2756 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2758 gst_play_sink_request_pad (playbin->playsink, select->type);
2760 /* Install an event probe */
2761 data->playbin = playbin;
2762 data->group = group;
2763 data->type = select->type;
2764 select->sink_event_probe_id =
2765 gst_pad_add_event_probe_full (select->sinkpad,
2766 G_CALLBACK (_playsink_sink_event_probe_cb), data,
2767 (GDestroyNotify) g_free);
2769 res = gst_pad_link (select->srcpad, select->sinkpad);
2770 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2771 select->media_list[0], res);
2772 if (res != GST_PAD_LINK_OK) {
2773 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2774 ("Internal playbin error."),
2775 ("Failed to link selector to sink. Error %d", res));
2779 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2780 group->pending - 1);
2782 if (group->pending > 0)
2785 if (group->suburidecodebin == decodebin)
2786 group->sub_pending = FALSE;
2788 if (group->pending == 0) {
2789 /* we are the last group to complete, we will configure the output and then
2790 * signal the other waiters. */
2791 GST_LOG_OBJECT (playbin, "last group complete");
2794 GST_LOG_OBJECT (playbin, "have more pending groups");
2797 GST_SOURCE_GROUP_UNLOCK (group);
2800 /* if we have custom sinks, configure them now */
2801 GST_SOURCE_GROUP_LOCK (group);
2802 if (group->audio_sink) {
2803 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2805 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2808 GST_INFO_OBJECT (playbin, "setting default audio sink %" GST_PTR_FORMAT,
2809 playbin->audio_sink);
2810 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2811 playbin->audio_sink);
2813 if (group->video_sink) {
2814 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2816 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2819 GST_INFO_OBJECT (playbin, "setting default video sink %" GST_PTR_FORMAT,
2820 playbin->video_sink);
2821 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2822 playbin->video_sink);
2824 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2825 playbin->text_sink);
2826 GST_SOURCE_GROUP_UNLOCK (group);
2828 GST_LOG_OBJECT (playbin, "reconfigure sink");
2829 /* we configure the modes if we were the last decodebin to complete. */
2830 gst_play_sink_reconfigure (playbin->playsink);
2832 /* signal the other decodebins that they can continue now. */
2833 GST_SOURCE_GROUP_LOCK (group);
2834 /* unblock all selectors */
2835 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2836 GstSourceSelect *select = &group->selector[i];
2838 /* Wait for stream-changed messages on all selectors except
2839 * the text selector because of the sparse nature of text streams.
2841 if (select->sinkpad && select->type != GST_PLAY_SINK_TYPE_TEXT) {
2847 s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2850 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2851 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2852 seqnum = gst_message_get_seqnum (msg);
2853 event = gst_event_new_sink_message (msg);
2854 g_mutex_lock (group->stream_changed_pending_lock);
2855 group->stream_changed_pending =
2856 g_list_prepend (group->stream_changed_pending,
2857 GUINT_TO_POINTER (seqnum));
2858 g_mutex_unlock (group->stream_changed_pending_lock);
2859 gst_pad_send_event (select->sinkpad, event);
2860 gst_message_unref (msg);
2863 if (select->srcpad) {
2864 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2866 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2870 GST_SOURCE_GROUP_UNLOCK (group);
2873 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2879 GST_DEBUG ("ignoring, we are shutting down");
2880 /* Request a flushing pad from playsink that we then link to the selector.
2881 * Then we unblock the selectors so that they stop with a WRONG_STATE
2882 * instead of a NOT_LINKED error.
2884 GST_SOURCE_GROUP_LOCK (group);
2885 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2886 GstSourceSelect *select = &group->selector[i];
2888 if (select->srcpad) {
2889 if (select->sinkpad == NULL) {
2890 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2892 gst_play_sink_request_pad (playbin->playsink,
2893 GST_PLAY_SINK_TYPE_FLUSHING);
2894 res = gst_pad_link (select->srcpad, select->sinkpad);
2895 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2897 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2899 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2903 GST_SOURCE_GROUP_UNLOCK (group);
2909 drained_cb (GstElement * decodebin, GstSourceGroup * group)
2911 GstPlayBin *playbin;
2913 playbin = group->playbin;
2915 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
2917 /* after this call, we should have a next group to activate or we EOS */
2918 g_signal_emit (G_OBJECT (playbin),
2919 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
2921 /* now activate the next group. If the app did not set a uri, this will
2922 * fail and we can do EOS */
2923 setup_next_source (playbin, GST_STATE_PAUSED);
2926 /* Called when we must provide a list of factories to plug to @pad with @caps.
2927 * We first check if we have a sink that can handle the format and if we do, we
2928 * return NULL, to expose the pad. If we have no sink (or the sink does not
2929 * work), we return the list of elements that can connect. */
2930 static GValueArray *
2931 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
2932 GstCaps * caps, GstSourceGroup * group)
2934 GstPlayBin *playbin;
2935 GValueArray *result;
2937 playbin = group->playbin;
2939 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
2940 group, GST_DEBUG_PAD_NAME (pad), caps);
2942 /* filter out the elements based on the caps. */
2943 g_mutex_lock (playbin->elements_lock);
2944 gst_play_bin_update_elements_list (playbin);
2945 result = gst_factory_list_filter (playbin->elements, caps);
2946 g_mutex_unlock (playbin->elements_lock);
2948 GST_DEBUG_OBJECT (playbin, "found factories %p", result);
2949 GST_FACTORY_LIST_DEBUG (result);
2954 /* autoplug-continue decides, if a pad has raw caps that can be exposed
2955 * directly or if further decoding is necessary. We use this to expose
2956 * supported subtitles directly */
2958 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
2959 GstSourceGroup * group)
2962 gboolean ret = FALSE;
2964 subcaps = gst_subtitle_overlay_create_factory_caps ();
2965 ret = !gst_caps_can_intersect (subcaps, caps);
2966 gst_caps_unref (subcaps);
2968 GST_DEBUG_OBJECT (group->playbin,
2969 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
2970 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
2975 /* We are asked to select an element. See if the next element to check
2976 * is a sink. If this is the case, we see if the sink works by setting it to
2977 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
2978 * expose the raw pad so that we can setup the mixers. */
2979 static GstAutoplugSelectResult
2980 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
2981 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
2983 GstPlayBin *playbin;
2984 GstElement *element;
2986 GstPlaySinkType type;
2989 playbin = group->playbin;
2991 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
2992 group, GST_DEBUG_PAD_NAME (pad), caps);
2994 GST_DEBUG_OBJECT (playbin, "checking factory %s",
2995 GST_PLUGIN_FEATURE_NAME (factory));
2997 /* if it's not a sink, we just make decodebin try it */
2998 if (!gst_factory_list_is_type (factory, GST_FACTORY_LIST_SINK))
2999 return GST_AUTOPLUG_SELECT_TRY;
3001 /* it's a sink, see if an instance of it actually works */
3002 GST_DEBUG_OBJECT (playbin, "we found a sink");
3004 klass = gst_element_factory_get_klass (factory);
3006 /* figure out the klass */
3007 if (strstr (klass, "Audio")) {
3008 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3009 type = GST_PLAY_SINK_TYPE_AUDIO;
3010 sinkp = &group->audio_sink;
3011 } else if (strstr (klass, "Video")) {
3012 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3013 type = GST_PLAY_SINK_TYPE_VIDEO;
3014 sinkp = &group->video_sink;
3016 /* unknown klass, skip this element */
3017 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3018 return GST_AUTOPLUG_SELECT_SKIP;
3021 /* if we are asked to do visualisations and it's an audio sink, skip the
3022 * element. We can only do visualisations with raw sinks */
3023 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3024 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3025 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3026 return GST_AUTOPLUG_SELECT_SKIP;
3030 /* now see if we already have a sink element */
3031 GST_SOURCE_GROUP_LOCK (group);
3033 GST_DEBUG_OBJECT (playbin, "we already have a pending sink, expose pad");
3034 /* for now, just assume that we can link the pad to this same sink. FIXME,
3035 * check that we can link this new pad to this sink as well. */
3036 GST_SOURCE_GROUP_UNLOCK (group);
3037 return GST_AUTOPLUG_SELECT_EXPOSE;
3039 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3040 GST_SOURCE_GROUP_UNLOCK (group);
3042 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3043 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3044 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3045 return GST_AUTOPLUG_SELECT_SKIP;
3048 /* ... activate it ... We do this before adding it to the bin so that we
3049 * don't accidentally make it post error messages that will stop
3051 if ((gst_element_set_state (element,
3052 GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
3053 GST_WARNING_OBJECT (playbin, "Couldn't set %s to READY",
3054 GST_ELEMENT_NAME (element));
3055 gst_object_unref (element);
3056 return GST_AUTOPLUG_SELECT_SKIP;
3059 /* remember the sink in the group now, the element is floating, we take
3061 GST_SOURCE_GROUP_LOCK (group);
3062 if (*sinkp == NULL) {
3063 /* store the sink in the group, we will configure it later when we
3064 * reconfigure the sink */
3065 GST_DEBUG_OBJECT (playbin, "remember sink");
3066 gst_object_ref_sink (element);
3069 /* some other thread configured a sink while we were testing the sink, set
3070 * the sink back to NULL and assume we can use the other sink */
3071 GST_DEBUG_OBJECT (playbin, "another sink was found, expose pad");
3072 gst_element_set_state (element, GST_STATE_NULL);
3073 gst_object_unref (element);
3075 GST_SOURCE_GROUP_UNLOCK (group);
3077 /* tell decodebin to expose the pad because we are going to use this
3079 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3081 return GST_AUTOPLUG_SELECT_EXPOSE;
3085 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3086 GstSourceGroup * group)
3088 GstPlayBin *playbin;
3091 playbin = group->playbin;
3093 g_object_get (group->uridecodebin, "source", &source, NULL);
3095 GST_OBJECT_LOCK (playbin);
3096 if (playbin->source)
3097 gst_object_unref (playbin->source);
3098 playbin->source = source;
3099 GST_OBJECT_UNLOCK (playbin);
3101 g_object_notify (G_OBJECT (playbin), "source");
3104 /* must be called with the group lock */
3106 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3109 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3111 if (group->uridecodebin)
3112 gst_element_set_locked_state (group->uridecodebin, locked);
3113 if (group->suburidecodebin)
3114 gst_element_set_locked_state (group->suburidecodebin, locked);
3119 /* must be called with PLAY_BIN_LOCK */
3121 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3123 GstElement *uridecodebin;
3124 GstElement *suburidecodebin = NULL;
3127 g_return_val_if_fail (group->valid, FALSE);
3128 g_return_val_if_fail (!group->active, FALSE);
3130 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3132 GST_SOURCE_GROUP_LOCK (group);
3134 g_list_free (group->stream_changed_pending);
3135 group->stream_changed_pending = NULL;
3136 if (!group->stream_changed_pending_lock)
3137 group->stream_changed_pending_lock = g_mutex_new ();
3139 if (group->uridecodebin) {
3140 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3141 uridecodebin = group->uridecodebin;
3142 gst_element_set_state (uridecodebin, GST_STATE_READY);
3143 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3145 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3146 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3149 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3150 group->uridecodebin = gst_object_ref (uridecodebin);
3153 /* configure connection speed */
3154 g_object_set (uridecodebin, "connection-speed",
3155 playbin->connection_speed / 1000, NULL);
3157 flags = gst_play_sink_get_flags (playbin->playsink);
3159 /* configure download buffering */
3160 if (flags & GST_PLAY_FLAG_DOWNLOAD)
3161 g_object_set (uridecodebin, "download", TRUE, NULL);
3163 g_object_set (uridecodebin, "download", FALSE, NULL);
3166 g_object_set (uridecodebin, "uri", group->uri, NULL);
3167 /* configure buffering of demuxed/parsed data */
3168 if (flags & GST_PLAY_FLAG_BUFFERING)
3169 g_object_set (uridecodebin, "use-buffering", TRUE, NULL);
3171 g_object_set (uridecodebin, "use-buffering", FALSE, NULL);
3172 /* configure buffering parameters */
3173 g_object_set (uridecodebin, "buffer-duration", playbin->buffer_duration,
3175 g_object_set (uridecodebin, "buffer-size", playbin->buffer_size, NULL);
3177 /* connect pads and other things */
3178 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3179 G_CALLBACK (pad_added_cb), group);
3180 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3181 G_CALLBACK (pad_removed_cb), group);
3182 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3183 G_CALLBACK (no_more_pads_cb), group);
3184 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3185 G_CALLBACK (notify_source_cb), group);
3187 /* we have 1 pending no-more-pads */
3190 /* is called when the uridecodebin is out of data and we can switch to the
3193 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3196 /* will be called when a new media type is found. We return a list of decoders
3197 * including sinks for decodebin to try */
3198 group->autoplug_factories_id =
3199 g_signal_connect (uridecodebin, "autoplug-factories",
3200 G_CALLBACK (autoplug_factories_cb), group);
3201 group->autoplug_select_id =
3202 g_signal_connect (uridecodebin, "autoplug-select",
3203 G_CALLBACK (autoplug_select_cb), group);
3204 group->autoplug_continue_id =
3205 g_signal_connect (uridecodebin, "autoplug-continue",
3206 G_CALLBACK (autoplug_continue_cb), group);
3208 if (group->suburi) {
3210 if (group->suburidecodebin) {
3211 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3212 suburidecodebin = group->suburidecodebin;
3213 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3214 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3216 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3217 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3218 if (!suburidecodebin)
3221 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3222 group->suburidecodebin = gst_object_ref (suburidecodebin);
3225 /* configure connection speed */
3226 g_object_set (suburidecodebin, "connection-speed",
3227 playbin->connection_speed, NULL);
3229 g_object_set (suburidecodebin, "uri", group->suburi, NULL);
3231 /* connect pads and other things */
3232 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3233 G_CALLBACK (pad_added_cb), group);
3234 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3235 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3236 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3237 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3239 group->sub_autoplug_continue_id =
3240 g_signal_connect (suburidecodebin, "autoplug-continue",
3241 G_CALLBACK (autoplug_continue_cb), group);
3243 /* we have 2 pending no-more-pads */
3245 group->sub_pending = TRUE;
3247 group->sub_pending = FALSE;
3250 /* release the group lock before setting the state of the decodebins, they
3251 * might fire signals in this thread that we need to handle with the
3252 * group_lock taken. */
3253 GST_SOURCE_GROUP_UNLOCK (group);
3255 if (suburidecodebin) {
3256 if (gst_element_set_state (suburidecodebin,
3257 target) == GST_STATE_CHANGE_FAILURE) {
3258 GST_DEBUG_OBJECT (playbin,
3259 "failed state change of subtitle uridecodebin");
3260 GST_SOURCE_GROUP_LOCK (group);
3262 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3263 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3264 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3265 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3266 /* Might already be removed because of an error message */
3267 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3268 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3269 if (group->sub_pending) {
3271 group->sub_pending = FALSE;
3273 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3274 GST_SOURCE_GROUP_UNLOCK (group);
3277 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3278 goto uridecodebin_failure;
3280 GST_SOURCE_GROUP_LOCK (group);
3281 /* alow state changes of the playbin2 affect the group elements now */
3282 group_set_locked_state_unlocked (playbin, group, FALSE);
3283 group->active = TRUE;
3284 GST_SOURCE_GROUP_UNLOCK (group);
3293 GST_SOURCE_GROUP_UNLOCK (group);
3295 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3297 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3299 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3300 (_("Could not create \"uridecodebin\" element.")), (NULL));
3303 uridecodebin_failure:
3305 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3310 /* unlink a group of uridecodebins from the sink.
3311 * must be called with PLAY_BIN_LOCK */
3313 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3317 g_return_val_if_fail (group->valid, FALSE);
3318 g_return_val_if_fail (group->active, FALSE);
3320 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3322 GST_SOURCE_GROUP_LOCK (group);
3323 group->active = FALSE;
3324 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
3325 GstSourceSelect *select = &group->selector[i];
3327 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3329 if (select->srcpad) {
3330 if (select->sinkpad) {
3331 GST_LOG_OBJECT (playbin, "unlinking from sink");
3332 gst_pad_unlink (select->srcpad, select->sinkpad);
3334 if (select->sink_event_probe_id)
3335 gst_pad_remove_event_probe (select->sinkpad,
3336 select->sink_event_probe_id);
3337 select->sink_event_probe_id = 0;
3340 GST_LOG_OBJECT (playbin, "release sink pad");
3341 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3342 select->sinkpad = NULL;
3345 if (select->src_event_probe_id)
3346 gst_pad_remove_event_probe (select->srcpad, select->src_event_probe_id);
3347 select->src_event_probe_id = 0;
3349 gst_object_unref (select->srcpad);
3350 select->srcpad = NULL;
3353 if (select->selector) {
3356 /* release and unref requests pad from the selector */
3357 for (n = 0; n < select->channels->len; n++) {
3358 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3360 gst_element_release_request_pad (select->selector, sinkpad);
3361 gst_object_unref (sinkpad);
3363 g_ptr_array_set_size (select->channels, 0);
3365 gst_element_set_state (select->selector, GST_STATE_NULL);
3366 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3367 select->selector = NULL;
3370 /* delete any custom sinks we might have */
3371 if (group->audio_sink)
3372 gst_object_unref (group->audio_sink);
3373 group->audio_sink = NULL;
3374 if (group->video_sink)
3375 gst_object_unref (group->video_sink);
3376 group->video_sink = NULL;
3378 if (group->uridecodebin) {
3379 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3380 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3381 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3382 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3383 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3384 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3385 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3386 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3387 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3390 if (group->suburidecodebin) {
3391 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3392 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3393 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3394 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3396 /* Might already be removed because of errors */
3397 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3398 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3401 GST_SOURCE_GROUP_UNLOCK (group);
3406 /* setup the next group to play, this assumes the next_group is valid and
3407 * configured. It swaps out the current_group and activates the valid
3410 setup_next_source (GstPlayBin * playbin, GstState target)
3412 GstSourceGroup *new_group, *old_group;
3414 GST_DEBUG_OBJECT (playbin, "setup sources");
3416 /* see if there is a next group */
3417 GST_PLAY_BIN_LOCK (playbin);
3418 new_group = playbin->next_group;
3419 if (!new_group || !new_group->valid)
3422 /* first unlink the current source, if any */
3423 old_group = playbin->curr_group;
3424 if (old_group && old_group->valid) {
3425 gst_play_bin_update_cached_duration (playbin);
3426 /* unlink our pads with the sink */
3427 deactivate_group (playbin, old_group);
3428 old_group->valid = FALSE;
3431 /* swap old and new */
3432 playbin->curr_group = new_group;
3433 playbin->next_group = old_group;
3435 /* activate the new group */
3436 if (!activate_group (playbin, new_group, target))
3437 goto activate_failed;
3439 GST_PLAY_BIN_UNLOCK (playbin);
3446 GST_DEBUG_OBJECT (playbin, "no next group");
3447 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3448 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3449 GST_PLAY_BIN_UNLOCK (playbin);
3454 GST_DEBUG_OBJECT (playbin, "activate failed");
3455 GST_PLAY_BIN_UNLOCK (playbin);
3460 /* The group that is currently playing is copied again to the
3461 * next_group so that it will start playing the next time.
3464 save_current_group (GstPlayBin * playbin)
3466 GstSourceGroup *curr_group;
3468 GST_DEBUG_OBJECT (playbin, "save current group");
3470 /* see if there is a current group */
3471 GST_PLAY_BIN_LOCK (playbin);
3472 curr_group = playbin->curr_group;
3473 if (curr_group && curr_group->valid) {
3474 /* unlink our pads with the sink */
3475 deactivate_group (playbin, curr_group);
3477 /* swap old and new */
3478 playbin->curr_group = playbin->next_group;
3479 playbin->next_group = curr_group;
3480 GST_PLAY_BIN_UNLOCK (playbin);
3485 /* clear the locked state from all groups. This function is called before a
3486 * state change to NULL is performed on them. */
3488 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3490 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3493 GST_PLAY_BIN_LOCK (playbin);
3494 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3495 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3496 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3497 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3498 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3499 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3500 GST_PLAY_BIN_UNLOCK (playbin);
3505 static GstStateChangeReturn
3506 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3508 GstStateChangeReturn ret;
3509 GstPlayBin *playbin;
3511 playbin = GST_PLAY_BIN (element);
3513 switch (transition) {
3514 case GST_STATE_CHANGE_NULL_TO_READY:
3515 g_mutex_lock (playbin->elements_lock);
3516 gst_play_bin_update_elements_list (playbin);
3517 g_mutex_unlock (playbin->elements_lock);
3518 memset (&playbin->duration, 0, sizeof (playbin->duration));
3520 case GST_STATE_CHANGE_READY_TO_PAUSED:{
3523 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3524 memset (&playbin->duration, 0, sizeof (playbin->duration));
3525 g_atomic_int_set (&playbin->shutdown, 0);
3527 for (i = 0; i < 3; i++)
3528 gst_segment_init (&playbin->segments[i], GST_FORMAT_UNDEFINED);
3530 if (!setup_next_source (playbin, GST_STATE_READY))
3534 case GST_STATE_CHANGE_PAUSED_TO_READY:
3535 /* FIXME unlock our waiting groups */
3536 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3537 g_atomic_int_set (&playbin->shutdown, 1);
3538 memset (&playbin->duration, 0, sizeof (playbin->duration));
3540 /* wait for all callbacks to end by taking the lock.
3541 * No dynamic (critical) new callbacks will
3542 * be able to happen as we set the shutdown flag. */
3543 GST_PLAY_BIN_DYN_LOCK (playbin);
3544 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3545 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3547 case GST_STATE_CHANGE_READY_TO_NULL:{
3550 memset (&playbin->duration, 0, sizeof (playbin->duration));
3552 /* unlock so that all groups go to NULL */
3553 groups_set_locked_state (playbin, FALSE);
3555 for (i = 0; i < 2; i++) {
3556 if (playbin->groups[i].uridecodebin) {
3557 gst_element_set_state (playbin->groups[i].uridecodebin,
3559 gst_object_unref (playbin->groups[i].uridecodebin);
3560 playbin->groups[i].uridecodebin = NULL;
3562 if (playbin->groups[i].suburidecodebin) {
3563 gst_element_set_state (playbin->groups[i].suburidecodebin,
3565 gst_object_unref (playbin->groups[i].suburidecodebin);
3566 playbin->groups[i].suburidecodebin = NULL;
3575 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3576 if (ret == GST_STATE_CHANGE_FAILURE) {
3577 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
3578 GstSourceGroup *curr_group;
3580 curr_group = playbin->curr_group;
3581 if (curr_group && curr_group->valid) {
3582 /* unlink our pads with the sink */
3583 deactivate_group (playbin, curr_group);
3586 /* Swap current and next group back */
3587 playbin->curr_group = playbin->next_group;
3588 playbin->next_group = curr_group;
3593 switch (transition) {
3594 case GST_STATE_CHANGE_READY_TO_PAUSED:
3596 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3597 /* FIXME Release audio device when we implement that */
3599 case GST_STATE_CHANGE_PAUSED_TO_READY:
3600 save_current_group (playbin);
3602 case GST_STATE_CHANGE_READY_TO_NULL:
3603 /* make sure the groups don't perform a state change anymore until we
3604 * enable them again */
3605 groups_set_locked_state (playbin, TRUE);
3616 return GST_STATE_CHANGE_FAILURE;
3621 gst_play_bin2_plugin_init (GstPlugin * plugin)
3623 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
3625 g_type_class_ref (gst_input_selector_get_type ());
3626 g_type_class_ref (gst_selector_pad_get_type ());
3628 return gst_element_register (plugin, "playbin2", GST_RANK_NONE,