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 "gstplayback.h"
233 #include "gstplaysink.h"
234 #include "gstfactorylists.h"
235 #include "gstinputselector.h"
236 #include "gstscreenshot.h"
237 #include "gstsubtitleoverlay.h"
239 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
240 #define GST_CAT_DEFAULT gst_play_bin_debug
242 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type())
243 #define GST_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
244 #define GST_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
245 #define GST_IS_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
246 #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
248 #define VOLUME_MAX_DOUBLE 10.0
250 typedef struct _GstPlayBin GstPlayBin;
251 typedef struct _GstPlayBinClass GstPlayBinClass;
252 typedef struct _GstSourceGroup GstSourceGroup;
253 typedef struct _GstSourceSelect GstSourceSelect;
255 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
257 /* has the info for a selector and provides the link to the sink */
258 struct _GstSourceSelect
260 const gchar *media_list[8]; /* the media types for the selector */
261 SourceSelectGetMediaCapsFunc get_media_caps; /* more complex caps for the selector */
262 GstPlaySinkType type; /* the sink pad type of the selector */
264 GstElement *selector; /* the selector */
266 GstPad *srcpad; /* the source pad of the selector */
267 GstPad *sinkpad; /* the sinkpad of the sink when the selector
271 gulong src_event_probe_id;
272 gulong sink_event_probe_id;
273 GstClockTime group_start_accum;
276 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
277 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
278 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
280 /* a structure to hold the objects for decoding a uri and the subtitle uri
282 struct _GstSourceGroup
288 gboolean valid; /* the group has valid info to start playback */
289 gboolean active; /* the group is active */
294 GValueArray *streaminfo;
297 GPtrArray *video_channels; /* links to selector pads */
298 GPtrArray *audio_channels; /* links to selector pads */
299 GPtrArray *text_channels; /* links to selector pads */
301 GstElement *audio_sink; /* autoplugged audio and video sinks */
302 GstElement *video_sink;
304 /* uridecodebins for uri and subtitle uri */
305 GstElement *uridecodebin;
306 GstElement *suburidecodebin;
308 gboolean sub_pending;
311 gulong pad_removed_id;
312 gulong no_more_pads_id;
313 gulong notify_source_id;
315 gulong autoplug_factories_id;
316 gulong autoplug_select_id;
317 gulong autoplug_continue_id;
319 gulong sub_pad_added_id;
320 gulong sub_pad_removed_id;
321 gulong sub_no_more_pads_id;
322 gulong sub_autoplug_continue_id;
324 GMutex *stream_changed_pending_lock;
325 GList *stream_changed_pending;
327 /* selectors for different streams */
328 GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST];
331 #define GST_PLAY_BIN_GET_LOCK(bin) (((GstPlayBin*)(bin))->lock)
332 #define GST_PLAY_BIN_LOCK(bin) (g_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
333 #define GST_PLAY_BIN_UNLOCK(bin) (g_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
335 /* lock to protect dynamic callbacks, like no-more-pads */
336 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->dyn_lock)
337 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->dyn_lock)
339 /* lock for shutdown */
340 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
342 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
344 GST_PLAY_BIN_DYN_LOCK (bin); \
345 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
346 GST_PLAY_BIN_DYN_UNLOCK (bin); \
351 /* unlock for shutdown */
352 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
353 GST_PLAY_BIN_DYN_UNLOCK (bin); \
358 * playbin element structure
364 GMutex *lock; /* to protect group switching */
366 /* the groups, we use a double buffer to switch between current and next */
367 GstSourceGroup groups[2]; /* array with group info */
368 GstSourceGroup *curr_group; /* pointer to the currently playing group */
369 GstSourceGroup *next_group; /* pointer to the next group */
372 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
373 gint current_video; /* the currently selected stream */
374 gint current_audio; /* the currently selected stream */
375 gint current_text; /* the currently selected stream */
377 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
378 guint buffer_size; /* When buffering, the max buffer size (bytes) */
381 GstPlaySink *playsink;
383 /* the last activated source */
386 /* lock protecting dynamic adding/removing */
388 /* if we are shutting down or not */
391 GMutex *elements_lock;
392 guint32 elements_cookie;
393 GValueArray *elements; /* factories we can use for selecting elements */
395 gboolean have_selector; /* set to FALSE when we fail to create an
396 * input-selector, so that we only post a
399 GstElement *audio_sink; /* configured audio sink, or NULL */
400 GstElement *video_sink; /* configured video sink, or NULL */
401 GstElement *text_sink; /* configured text sink, or NULL */
408 } duration[5]; /* cached durations */
410 GstSegment segments[3]; /* Video/Audio/Text segments */
413 struct _GstPlayBinClass
415 GstPipelineClass parent_class;
417 /* notify app that the current uri finished decoding and it is possible to
418 * queue a new one for gapless playback */
419 void (*about_to_finish) (GstPlayBin * playbin);
421 /* notify app that number of audio/video/text streams changed */
422 void (*video_changed) (GstPlayBin * playbin);
423 void (*audio_changed) (GstPlayBin * playbin);
424 void (*text_changed) (GstPlayBin * playbin);
426 /* notify app that the tags of audio/video/text streams changed */
427 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
428 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
429 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
431 /* get audio/video/text tags for a stream */
432 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
433 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
434 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
436 /* get the last video frame and convert it to the given caps */
437 GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
439 /* get audio/video/text pad for a stream */
440 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
441 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
442 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
446 #define DEFAULT_URI NULL
447 #define DEFAULT_SUBURI NULL
448 #define DEFAULT_SOURCE NULL
449 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
450 GST_PLAY_FLAG_SOFT_VOLUME
451 #define DEFAULT_N_VIDEO 0
452 #define DEFAULT_CURRENT_VIDEO -1
453 #define DEFAULT_N_AUDIO 0
454 #define DEFAULT_CURRENT_AUDIO -1
455 #define DEFAULT_N_TEXT 0
456 #define DEFAULT_CURRENT_TEXT -1
457 #define DEFAULT_SUBTITLE_ENCODING NULL
458 #define DEFAULT_AUDIO_SINK NULL
459 #define DEFAULT_VIDEO_SINK NULL
460 #define DEFAULT_VIS_PLUGIN NULL
461 #define DEFAULT_TEXT_SINK NULL
462 #define DEFAULT_VOLUME 1.0
463 #define DEFAULT_MUTE FALSE
464 #define DEFAULT_FRAME NULL
465 #define DEFAULT_FONT_DESC NULL
466 #define DEFAULT_CONNECTION_SPEED 0
467 #define DEFAULT_BUFFER_DURATION -1
468 #define DEFAULT_BUFFER_SIZE -1
483 PROP_SUBTITLE_ENCODING,
492 PROP_CONNECTION_SPEED,
494 PROP_BUFFER_DURATION,
501 SIGNAL_ABOUT_TO_FINISH,
502 SIGNAL_CONVERT_FRAME,
503 SIGNAL_VIDEO_CHANGED,
504 SIGNAL_AUDIO_CHANGED,
506 SIGNAL_VIDEO_TAGS_CHANGED,
507 SIGNAL_AUDIO_TAGS_CHANGED,
508 SIGNAL_TEXT_TAGS_CHANGED,
509 SIGNAL_GET_VIDEO_TAGS,
510 SIGNAL_GET_AUDIO_TAGS,
511 SIGNAL_GET_TEXT_TAGS,
512 SIGNAL_GET_VIDEO_PAD,
513 SIGNAL_GET_AUDIO_PAD,
518 static void gst_play_bin_class_init (GstPlayBinClass * klass);
519 static void gst_play_bin_init (GstPlayBin * playbin);
520 static void gst_play_bin_finalize (GObject * object);
522 static void gst_play_bin_set_property (GObject * object, guint prop_id,
523 const GValue * value, GParamSpec * spec);
524 static void gst_play_bin_get_property (GObject * object, guint prop_id,
525 GValue * value, GParamSpec * spec);
527 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
528 GstStateChange transition);
530 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
531 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
533 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
535 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
537 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
540 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
543 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
544 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
545 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
547 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
549 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
550 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
551 GstSourceGroup * group);
553 static void gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
555 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
558 static GstElementClass *parent_class;
560 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
562 static const GstElementDetails gst_play_bin_details =
563 GST_ELEMENT_DETAILS ("Player Bin 2",
564 "Generic/Bin/Player",
565 "Autoplug and play media from an uri",
566 "Wim Taymans <wim.taymans@gmail.com>");
568 #define REMOVE_SIGNAL(obj,id) \
570 g_signal_handler_disconnect (obj, id); \
575 gst_play_marshal_BUFFER__BOXED (GClosure * closure,
576 GValue * return_value G_GNUC_UNUSED,
577 guint n_param_values,
578 const GValue * param_values,
579 gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
581 typedef GstBuffer *(*GMarshalFunc_OBJECT__BOXED) (gpointer data1,
582 gpointer arg_1, gpointer data2);
583 register GMarshalFunc_OBJECT__BOXED callback;
584 register GCClosure *cc = (GCClosure *) closure;
585 register gpointer data1, data2;
588 g_return_if_fail (return_value != NULL);
589 g_return_if_fail (n_param_values == 2);
591 if (G_CCLOSURE_SWAP_DATA (closure)) {
592 data1 = closure->data;
593 data2 = g_value_peek_pointer (param_values + 0);
595 data1 = g_value_peek_pointer (param_values + 0);
596 data2 = closure->data;
599 (GMarshalFunc_OBJECT__BOXED) (marshal_data ? marshal_data : cc->callback);
601 v_return = callback (data1, g_value_get_boxed (param_values + 1), data2);
603 gst_value_take_buffer (return_value, v_return);
607 gst_play_bin_get_type (void)
609 static GType gst_play_bin_type = 0;
611 if (!gst_play_bin_type) {
612 static const GTypeInfo gst_play_bin_info = {
613 sizeof (GstPlayBinClass),
616 (GClassInitFunc) gst_play_bin_class_init,
621 (GInstanceInitFunc) gst_play_bin_init,
624 static const GInterfaceInfo svol_info = {
628 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
629 "GstPlayBin2", &gst_play_bin_info, 0);
631 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
635 return gst_play_bin_type;
639 gst_play_bin_class_init (GstPlayBinClass * klass)
641 GObjectClass *gobject_klass;
642 GstElementClass *gstelement_klass;
643 GstBinClass *gstbin_klass;
645 gobject_klass = (GObjectClass *) klass;
646 gstelement_klass = (GstElementClass *) klass;
647 gstbin_klass = (GstBinClass *) klass;
649 parent_class = g_type_class_peek_parent (klass);
651 gobject_klass->set_property = gst_play_bin_set_property;
652 gobject_klass->get_property = gst_play_bin_get_property;
654 gobject_klass->finalize = gst_play_bin_finalize;
659 * Set the next URI that playbin will play. This property can be set from the
660 * about-to-finish signal to queue the next media file.
662 g_object_class_install_property (gobject_klass, PROP_URI,
663 g_param_spec_string ("uri", "URI", "URI of the media to play",
664 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
669 * Set the next subtitle URI that playbin will play. This property can be
670 * set from the about-to-finish signal to queue the next subtitle media file.
672 g_object_class_install_property (gobject_klass, PROP_SUBURI,
673 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
674 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
676 g_object_class_install_property (gobject_klass, PROP_SOURCE,
677 g_param_spec_object ("source", "Source", "Source element",
678 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
683 * Control the behaviour of playbin.
685 g_object_class_install_property (gobject_klass, PROP_FLAGS,
686 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
687 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
688 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
691 * GstPlayBin2:n-video
693 * Get the total number of available video streams.
695 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
696 g_param_spec_int ("n-video", "Number Video",
697 "Total number of video streams", 0, G_MAXINT, 0,
698 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
700 * GstPlayBin2:current-video
702 * Get or set the currently playing video stream. By default the first video
703 * stream with data is played.
705 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
706 g_param_spec_int ("current-video", "Current Video",
707 "Currently playing video stream (-1 = auto)",
708 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
710 * GstPlayBin2:n-audio
712 * Get the total number of available audio streams.
714 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
715 g_param_spec_int ("n-audio", "Number Audio",
716 "Total number of audio streams", 0, G_MAXINT, 0,
717 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
719 * GstPlayBin2:current-audio
721 * Get or set the currently playing audio stream. By default the first audio
722 * stream with data is played.
724 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
725 g_param_spec_int ("current-audio", "Current audio",
726 "Currently playing audio stream (-1 = auto)",
727 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
731 * Get the total number of available subtitle streams.
733 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
734 g_param_spec_int ("n-text", "Number Text",
735 "Total number of text streams", 0, G_MAXINT, 0,
736 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
738 * GstPlayBin2:current-text:
740 * Get or set the currently playing subtitle stream. By default the first
741 * subtitle stream with data is played.
743 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
744 g_param_spec_int ("current-text", "Current Text",
745 "Currently playing text stream (-1 = auto)",
746 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
748 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
749 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
750 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
751 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
752 "be checked for an encoding to use. If that is not set either, "
753 "ISO-8859-15 will be assumed.", NULL,
754 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
756 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
757 g_param_spec_object ("video-sink", "Video Sink",
758 "the video output element to use (NULL = default sink)",
759 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
760 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
761 g_param_spec_object ("audio-sink", "Audio Sink",
762 "the audio output element to use (NULL = default sink)",
763 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
764 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
765 g_param_spec_object ("vis-plugin", "Vis plugin",
766 "the visualization element to use (NULL = default)",
767 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
768 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
769 g_param_spec_object ("text-sink", "Text plugin",
770 "the text output element to use (NULL = default textoverlay)",
771 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
774 * GstPlayBin2:volume:
776 * Get or set the current audio stream volume. 1.0 means 100%,
777 * 0.0 means mute. This uses a linear volume scale.
780 g_object_class_install_property (gobject_klass, PROP_VOLUME,
781 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
782 0.0, VOLUME_MAX_DOUBLE, 1.0,
783 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
784 g_object_class_install_property (gobject_klass, PROP_MUTE,
785 g_param_spec_boolean ("mute", "Mute",
786 "Mute the audio channel without changing the volume", FALSE,
787 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
791 * @playbin: a #GstPlayBin2
793 * Get the currently rendered or prerolled frame in the sink.
794 * The #GstCaps on the buffer will describe the format of the buffer.
796 g_object_class_install_property (gobject_klass, PROP_FRAME,
797 gst_param_spec_mini_object ("frame", "Frame",
798 "The last frame (NULL = no video available)",
799 GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
800 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
801 g_param_spec_string ("subtitle-font-desc",
802 "Subtitle font description",
803 "Pango font description of font "
804 "to be used for subtitle rendering", NULL,
805 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
807 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
808 g_param_spec_uint ("connection-speed", "Connection Speed",
809 "Network connection speed in kbps (0 = unknown)",
810 0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
811 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
813 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
814 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
815 "Buffer size when buffering network streams",
816 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
817 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
818 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
819 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
820 "Buffer duration when buffering network streams",
821 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
822 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
825 * GstPlayBin2::about-to-finish
826 * @playbin: a #GstPlayBin2
828 * This signal is emitted when the current uri is about to finish. You can
829 * set the uri and suburi to make sure that playback continues.
831 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
832 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
834 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
835 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
838 * GstPlayBin2::video-changed
839 * @playbin: a #GstPlayBin2
841 * This signal is emitted whenever the number or order of the video
842 * streams has changed. The application will most likely want to select
843 * a new video stream.
845 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
846 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
848 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
849 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
851 * GstPlayBin2::audio-changed
852 * @playbin: a #GstPlayBin2
854 * This signal is emitted whenever the number or order of the audio
855 * streams has changed. The application will most likely want to select
856 * a new audio stream.
858 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
859 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
861 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
862 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
864 * GstPlayBin2::text-changed
865 * @playbin: a #GstPlayBin2
867 * This signal is emitted whenever the number or order of the text
868 * streams has changed. The application will most likely want to select
871 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
872 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
874 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
875 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
878 * GstPlayBin2::video-tags-changed
879 * @playbin: a #GstPlayBin2
880 * @stream: stream index with changed tags
882 * This signal is emitted whenever the tags of a video stream have changed.
883 * The application will most likely want to get the new tags.
887 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
888 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
890 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
891 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
894 * GstPlayBin2::audio-tags-changed
895 * @playbin: a #GstPlayBin2
896 * @stream: stream index with changed tags
898 * This signal is emitted whenever the tags of an audio stream have changed.
899 * The application will most likely want to get the new tags.
903 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
904 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
906 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
907 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
910 * GstPlayBin2::text-tags-changed
911 * @playbin: a #GstPlayBin2
912 * @stream: stream index with changed tags
914 * This signal is emitted whenever the tags of a text stream have changed.
915 * The application will most likely want to get the new tags.
919 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
920 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
922 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
923 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
926 * GstPlayBin2::get-video-tags
927 * @playbin: a #GstPlayBin2
928 * @stream: a video stream number
930 * Action signal to retrieve the tags of a specific video stream number.
931 * This information can be used to select a stream.
933 * Returns: a GstTagList with tags or NULL when the stream number does not
936 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
937 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
938 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
939 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
940 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
942 * GstPlayBin2::get-audio-tags
943 * @playbin: a #GstPlayBin2
944 * @stream: an audio stream number
946 * Action signal to retrieve the tags of a specific audio stream number.
947 * This information can be used to select a stream.
949 * Returns: a GstTagList with tags or NULL when the stream number does not
952 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
953 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
954 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
955 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
956 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
958 * GstPlayBin2::get-text-tags
959 * @playbin: a #GstPlayBin2
960 * @stream: a text stream number
962 * Action signal to retrieve the tags of a specific text stream number.
963 * This information can be used to select a stream.
965 * Returns: a GstTagList with tags or NULL when the stream number does not
968 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
969 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
970 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
971 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
972 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
974 * GstPlayBin2::convert-frame
975 * @playbin: a #GstPlayBin2
976 * @caps: the target format of the frame
978 * Action signal to retrieve the currently playing video frame in the format
979 * specified by @caps.
980 * If @caps is %NULL, no conversion will be performed and this function is
981 * equivalent to the #GstPlayBin::frame property.
983 * Returns: a #GstBuffer of the current video frame converted to #caps.
984 * The caps on the buffer will describe the final layout of the buffer data.
985 * %NULL is returned when no current buffer can be retrieved or when the
988 gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
989 g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
990 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
991 G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
992 gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
995 * GstPlayBin2::get-video-pad
996 * @playbin: a #GstPlayBin2
997 * @stream: a video stream number
999 * Action signal to retrieve the stream-selector sinkpad for a specific
1001 * This pad can be used for notifications of caps changes, stream-specific
1004 * Returns: a #GstPad, or NULL when the stream number does not exist.
1006 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1007 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1008 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1009 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1010 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1012 * GstPlayBin2::get-audio-pad
1013 * @playbin: a #GstPlayBin2
1014 * @stream: an audio stream number
1016 * Action signal to retrieve the stream-selector sinkpad for a specific
1018 * This pad can be used for notifications of caps changes, stream-specific
1021 * Returns: a #GstPad, or NULL when the stream number does not exist.
1023 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1024 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1025 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1026 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1027 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1029 * GstPlayBin2::get-text-pad
1030 * @playbin: a #GstPlayBin2
1031 * @stream: a text stream number
1033 * Action signal to retrieve the stream-selector sinkpad for a specific
1035 * This pad can be used for notifications of caps changes, stream-specific
1038 * Returns: a #GstPad, or NULL when the stream number does not exist.
1040 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1041 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1042 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1043 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1044 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1046 klass->get_video_tags = gst_play_bin_get_video_tags;
1047 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1048 klass->get_text_tags = gst_play_bin_get_text_tags;
1050 klass->convert_frame = gst_play_bin_convert_frame;
1052 klass->get_video_pad = gst_play_bin_get_video_pad;
1053 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1054 klass->get_text_pad = gst_play_bin_get_text_pad;
1056 gst_element_class_set_details (gstelement_klass, &gst_play_bin_details);
1058 gstelement_klass->change_state =
1059 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1060 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1062 gstbin_klass->handle_message =
1063 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1067 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1069 /* store the array for the different channels */
1070 group->video_channels = g_ptr_array_new ();
1071 group->audio_channels = g_ptr_array_new ();
1072 group->text_channels = g_ptr_array_new ();
1073 group->lock = g_mutex_new ();
1074 /* init selectors. The selector is found by finding the first prefix that
1075 * matches the media. */
1076 group->playbin = playbin;
1077 /* If you add any items to these lists, check that media_list[] is defined
1078 * above to be large enough to hold MAX(items)+1, so as to accomodate a
1079 * NULL terminator (set when the memory is zeroed on allocation) */
1080 group->selector[0].media_list[0] = "audio/x-raw-";
1081 group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
1082 group->selector[0].channels = group->audio_channels;
1083 group->selector[1].media_list[0] = "audio/";
1084 group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO;
1085 group->selector[1].channels = group->audio_channels;
1086 group->selector[2].media_list[0] = "text/";
1087 group->selector[2].media_list[1] = "application/x-subtitle";
1088 group->selector[2].media_list[2] = "application/x-ssa";
1089 group->selector[2].media_list[3] = "application/x-ass";
1090 group->selector[2].media_list[4] = "video/x-dvd-subpicture";
1091 group->selector[2].media_list[5] = "subpicture/";
1092 group->selector[2].media_list[6] = "subtitle/";
1093 group->selector[2].get_media_caps = gst_subtitle_overlay_create_factory_caps;
1094 group->selector[2].type = GST_PLAY_SINK_TYPE_TEXT;
1095 group->selector[2].channels = group->text_channels;
1096 group->selector[3].media_list[0] = "video/x-raw-";
1097 group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
1098 group->selector[3].channels = group->video_channels;
1099 group->selector[4].media_list[0] = "video/";
1100 group->selector[4].type = GST_PLAY_SINK_TYPE_VIDEO;
1101 group->selector[4].channels = group->video_channels;
1105 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1107 g_free (group->uri);
1108 g_free (group->suburi);
1109 g_ptr_array_free (group->video_channels, TRUE);
1110 g_ptr_array_free (group->audio_channels, TRUE);
1111 g_ptr_array_free (group->text_channels, TRUE);
1113 g_mutex_free (group->lock);
1114 if (group->audio_sink)
1115 gst_object_unref (group->audio_sink);
1116 group->audio_sink = NULL;
1117 if (group->video_sink)
1118 gst_object_unref (group->video_sink);
1119 group->video_sink = NULL;
1121 g_list_free (group->stream_changed_pending);
1122 group->stream_changed_pending = NULL;
1124 if (group->stream_changed_pending_lock)
1125 g_mutex_free (group->stream_changed_pending_lock);
1126 group->stream_changed_pending_lock = NULL;
1130 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1132 g_object_notify (G_OBJECT (playbin), "volume");
1136 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1138 g_object_notify (G_OBJECT (playbin), "mute");
1141 /* Must be called with elements lock! */
1143 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1145 if (!playbin->elements ||
1146 playbin->elements_cookie !=
1147 gst_default_registry_get_feature_list_cookie ()) {
1148 if (playbin->elements)
1149 g_value_array_free (playbin->elements);
1151 gst_factory_list_get_elements (GST_FACTORY_LIST_DECODER |
1152 GST_FACTORY_LIST_SINK);
1153 playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1158 gst_play_bin_init (GstPlayBin * playbin)
1160 playbin->lock = g_mutex_new ();
1161 playbin->dyn_lock = g_mutex_new ();
1163 /* assume we can create a selector */
1164 playbin->have_selector = TRUE;
1167 playbin->curr_group = &playbin->groups[0];
1168 playbin->next_group = &playbin->groups[1];
1169 init_group (playbin, &playbin->groups[0]);
1170 init_group (playbin, &playbin->groups[1]);
1172 /* first filter out the interesting element factories */
1173 playbin->elements_lock = g_mutex_new ();
1174 gst_play_bin_update_elements_list (playbin);
1175 GST_FACTORY_LIST_DEBUG (playbin->elements);
1178 playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1179 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1180 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1181 /* Connect to notify::volume and notify::mute signals for proxying */
1182 g_signal_connect (playbin->playsink, "notify::volume",
1183 G_CALLBACK (notify_volume_cb), playbin);
1184 g_signal_connect (playbin->playsink, "notify::mute",
1185 G_CALLBACK (notify_mute_cb), playbin);
1187 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1188 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1189 playbin->current_text = DEFAULT_CURRENT_TEXT;
1191 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1192 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1196 gst_play_bin_finalize (GObject * object)
1198 GstPlayBin *playbin;
1200 playbin = GST_PLAY_BIN (object);
1202 free_group (playbin, &playbin->groups[0]);
1203 free_group (playbin, &playbin->groups[1]);
1205 if (playbin->source)
1206 gst_object_unref (playbin->source);
1207 if (playbin->video_sink)
1208 gst_object_unref (playbin->video_sink);
1209 if (playbin->audio_sink)
1210 gst_object_unref (playbin->audio_sink);
1211 if (playbin->text_sink)
1212 gst_object_unref (playbin->text_sink);
1214 g_value_array_free (playbin->elements);
1215 g_mutex_free (playbin->lock);
1216 g_mutex_free (playbin->dyn_lock);
1217 g_mutex_free (playbin->elements_lock);
1219 G_OBJECT_CLASS (parent_class)->finalize (object);
1223 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1225 GstSourceGroup *group;
1228 g_warning ("cannot set NULL uri");
1232 GST_PLAY_BIN_LOCK (playbin);
1233 group = playbin->next_group;
1235 GST_SOURCE_GROUP_LOCK (group);
1236 /* store the uri in the next group we will play */
1237 g_free (group->uri);
1238 group->uri = g_strdup (uri);
1239 group->valid = TRUE;
1240 GST_SOURCE_GROUP_UNLOCK (group);
1242 GST_DEBUG ("set new uri to %s", uri);
1243 GST_PLAY_BIN_UNLOCK (playbin);
1247 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1249 GstSourceGroup *group;
1251 GST_PLAY_BIN_LOCK (playbin);
1252 group = playbin->next_group;
1254 GST_SOURCE_GROUP_LOCK (group);
1255 g_free (group->suburi);
1256 group->suburi = g_strdup (suburi);
1257 GST_SOURCE_GROUP_UNLOCK (group);
1259 GST_DEBUG ("setting new .sub uri to %s", suburi);
1261 GST_PLAY_BIN_UNLOCK (playbin);
1265 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1267 gst_play_sink_set_flags (playbin->playsink, flags);
1268 gst_play_sink_reconfigure (playbin->playsink);
1272 gst_play_bin_get_flags (GstPlayBin * playbin)
1276 flags = gst_play_sink_get_flags (playbin->playsink);
1281 /* get the currently playing group or if nothing is playing, the next
1282 * group. Must be called with the PLAY_BIN_LOCK. */
1283 static GstSourceGroup *
1284 get_group (GstPlayBin * playbin)
1286 GstSourceGroup *result;
1288 if (!(result = playbin->curr_group))
1289 result = playbin->next_group;
1295 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1297 GstPad *sinkpad = NULL;
1298 GstSourceGroup *group;
1300 GST_PLAY_BIN_LOCK (playbin);
1301 group = get_group (playbin);
1302 if (stream < group->video_channels->len) {
1303 sinkpad = g_ptr_array_index (group->video_channels, stream);
1304 gst_object_ref (sinkpad);
1306 GST_PLAY_BIN_UNLOCK (playbin);
1312 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1314 GstPad *sinkpad = NULL;
1315 GstSourceGroup *group;
1317 GST_PLAY_BIN_LOCK (playbin);
1318 group = get_group (playbin);
1319 if (stream < group->audio_channels->len) {
1320 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1321 gst_object_ref (sinkpad);
1323 GST_PLAY_BIN_UNLOCK (playbin);
1329 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1331 GstPad *sinkpad = NULL;
1332 GstSourceGroup *group;
1334 GST_PLAY_BIN_LOCK (playbin);
1335 group = get_group (playbin);
1336 if (stream < group->text_channels->len) {
1337 sinkpad = g_ptr_array_index (group->text_channels, stream);
1338 gst_object_ref (sinkpad);
1340 GST_PLAY_BIN_UNLOCK (playbin);
1347 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1352 if (!channels || stream >= channels->len)
1355 sinkpad = g_ptr_array_index (channels, stream);
1356 g_object_get (sinkpad, "tags", &result, NULL);
1362 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1365 GstSourceGroup *group;
1367 GST_PLAY_BIN_LOCK (playbin);
1368 group = get_group (playbin);
1369 result = get_tags (playbin, group->video_channels, stream);
1370 GST_PLAY_BIN_UNLOCK (playbin);
1376 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1379 GstSourceGroup *group;
1381 GST_PLAY_BIN_LOCK (playbin);
1382 group = get_group (playbin);
1383 result = get_tags (playbin, group->audio_channels, stream);
1384 GST_PLAY_BIN_UNLOCK (playbin);
1390 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1393 GstSourceGroup *group;
1395 GST_PLAY_BIN_LOCK (playbin);
1396 group = get_group (playbin);
1397 result = get_tags (playbin, group->text_channels, stream);
1398 GST_PLAY_BIN_UNLOCK (playbin);
1404 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1408 result = gst_play_sink_get_last_frame (playbin->playsink);
1409 if (result != NULL && caps != NULL) {
1412 temp = gst_play_frame_conv_convert (result, caps);
1413 gst_buffer_unref (result);
1419 /* Returns current stream number, or -1 if none has been selected yet */
1421 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1423 /* Internal API cleanup would make this easier... */
1425 GstPad *pad, *current;
1426 GstObject *selector = NULL;
1429 for (i = 0; i < channels->len; i++) {
1430 pad = g_ptr_array_index (channels, i);
1431 if ((selector = gst_pad_get_parent (pad))) {
1432 g_object_get (selector, "active-pad", ¤t, NULL);
1433 gst_object_unref (selector);
1435 if (pad == current) {
1436 gst_object_unref (current);
1442 gst_object_unref (current);
1450 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1452 GstSourceGroup *group;
1453 GPtrArray *channels;
1456 GST_PLAY_BIN_LOCK (playbin);
1457 group = get_group (playbin);
1458 if (!(channels = group->video_channels))
1461 if (stream == -1 || channels->len <= stream) {
1464 /* take channel from selected stream */
1465 sinkpad = g_ptr_array_index (channels, stream);
1469 gst_object_ref (sinkpad);
1470 GST_PLAY_BIN_UNLOCK (playbin);
1473 GstObject *selector;
1475 if ((selector = gst_pad_get_parent (sinkpad))) {
1476 /* activate the selected pad */
1477 g_object_set (selector, "active-pad", sinkpad, NULL);
1478 gst_object_unref (selector);
1480 gst_object_unref (sinkpad);
1486 GST_PLAY_BIN_UNLOCK (playbin);
1492 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1494 GstSourceGroup *group;
1495 GPtrArray *channels;
1498 GST_PLAY_BIN_LOCK (playbin);
1499 group = get_group (playbin);
1500 if (!(channels = group->audio_channels))
1503 if (stream == -1 || channels->len <= stream) {
1506 /* take channel from selected stream */
1507 sinkpad = g_ptr_array_index (channels, stream);
1511 gst_object_ref (sinkpad);
1512 GST_PLAY_BIN_UNLOCK (playbin);
1515 GstObject *selector;
1517 if ((selector = gst_pad_get_parent (sinkpad))) {
1518 /* activate the selected pad */
1519 g_object_set (selector, "active-pad", sinkpad, NULL);
1520 gst_object_unref (selector);
1522 gst_object_unref (sinkpad);
1528 GST_PLAY_BIN_UNLOCK (playbin);
1534 _suburidecodebin_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
1536 GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
1540 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1542 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1545 if (it && gst_iterator_next (it, (gpointer) & sinkpad) == GST_ITERATOR_OK
1550 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1551 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1552 if (!gst_pad_send_event (sinkpad, event)) {
1554 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1555 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1556 if (!gst_pad_send_event (sinkpad, event))
1557 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1560 gst_object_unref (sinkpad);
1564 gst_iterator_free (it);
1568 gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
1571 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1572 gboolean done = FALSE;
1574 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1581 switch (gst_iterator_next (it, (gpointer) & sinkpad)) {
1582 case GST_ITERATOR_OK:
1583 gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
1585 gst_object_unref (sinkpad);
1587 case GST_ITERATOR_DONE:
1590 case GST_ITERATOR_RESYNC:
1591 gst_iterator_resync (it);
1593 case GST_ITERATOR_ERROR:
1598 gst_iterator_free (it);
1602 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1604 GstSourceGroup *group;
1605 GPtrArray *channels;
1608 GST_PLAY_BIN_LOCK (playbin);
1609 group = get_group (playbin);
1610 if (!(channels = group->text_channels))
1613 if (stream == -1 || channels->len <= stream) {
1616 /* take channel from selected stream */
1617 sinkpad = g_ptr_array_index (channels, stream);
1621 gst_object_ref (sinkpad);
1622 GST_PLAY_BIN_UNLOCK (playbin);
1625 GstObject *selector;
1627 if ((selector = gst_pad_get_parent (sinkpad))) {
1628 GstPad *old_sinkpad;
1630 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1632 if (old_sinkpad != sinkpad) {
1633 gboolean need_unblock, need_block, need_seek;
1634 GstPad *src, *peer = NULL, *oldpeer = NULL;
1635 GstElement *parent_element = NULL, *old_parent_element = NULL;
1637 /* Now check if we need to seek the suburidecodebin to the beginning
1638 * or if we need to block all suburidecodebin sinkpads or if we need
1639 * to unblock all suburidecodebin sinkpads
1642 peer = gst_pad_get_peer (sinkpad);
1644 oldpeer = gst_pad_get_peer (old_sinkpad);
1647 parent_element = gst_pad_get_parent_element (peer);
1649 old_parent_element = gst_pad_get_parent_element (oldpeer);
1651 need_block = (old_parent_element == group->suburidecodebin
1652 && parent_element != old_parent_element);
1653 need_unblock = (parent_element == group->suburidecodebin
1654 && parent_element != old_parent_element);
1655 need_seek = (parent_element == group->suburidecodebin);
1658 gst_object_unref (peer);
1660 gst_object_unref (oldpeer);
1662 gst_object_unref (parent_element);
1663 if (old_parent_element)
1664 gst_object_unref (old_parent_element);
1666 /* Block all suburidecodebin sinkpads */
1668 gst_play_bin_suburidecodebin_block (group->suburidecodebin, TRUE);
1670 /* activate the selected pad */
1671 g_object_set (selector, "active-pad", sinkpad, NULL);
1673 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1674 peer = gst_pad_get_peer (src);
1678 /* Flush the subtitle renderer to remove any
1679 * currently displayed subtitles. This event will
1680 * never travel outside subtitleoverlay!
1682 s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1683 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1684 gst_pad_send_event (peer, event);
1685 gst_object_unref (peer);
1687 gst_object_unref (src);
1689 /* Unblock pads if necessary */
1691 gst_play_bin_suburidecodebin_block (group->suburidecodebin, FALSE);
1693 /* seek to the beginning */
1695 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1697 gst_object_unref (selector);
1700 gst_object_unref (old_sinkpad);
1702 gst_object_unref (sinkpad);
1708 GST_PLAY_BIN_UNLOCK (playbin);
1714 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1715 const gchar * dbg, GstElement * sink)
1717 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1719 GST_PLAY_BIN_LOCK (playbin);
1720 if (*elem != sink) {
1725 gst_object_ref_sink (sink);
1729 gst_object_unref (old);
1731 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1732 GST_PLAY_BIN_UNLOCK (playbin);
1736 gst_play_bin_set_property (GObject * object, guint prop_id,
1737 const GValue * value, GParamSpec * pspec)
1739 GstPlayBin *playbin;
1741 playbin = GST_PLAY_BIN (object);
1745 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1748 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1751 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1753 case PROP_CURRENT_VIDEO:
1754 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1756 case PROP_CURRENT_AUDIO:
1757 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1759 case PROP_CURRENT_TEXT:
1760 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1762 case PROP_SUBTITLE_ENCODING:
1763 gst_play_sink_set_subtitle_encoding (playbin->playsink,
1764 g_value_get_string (value));
1766 case PROP_VIDEO_SINK:
1767 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1768 g_value_get_object (value));
1770 case PROP_AUDIO_SINK:
1771 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1772 g_value_get_object (value));
1774 case PROP_VIS_PLUGIN:
1775 gst_play_sink_set_vis_plugin (playbin->playsink,
1776 g_value_get_object (value));
1778 case PROP_TEXT_SINK:
1779 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1780 g_value_get_object (value));
1783 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1786 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1788 case PROP_FONT_DESC:
1789 gst_play_sink_set_font_desc (playbin->playsink,
1790 g_value_get_string (value));
1792 case PROP_CONNECTION_SPEED:
1793 GST_PLAY_BIN_LOCK (playbin);
1794 playbin->connection_speed = g_value_get_uint (value) * 1000;
1795 GST_PLAY_BIN_UNLOCK (playbin);
1797 case PROP_BUFFER_SIZE:
1798 playbin->buffer_size = g_value_get_int (value);
1800 case PROP_BUFFER_DURATION:
1801 playbin->buffer_duration = g_value_get_int64 (value);
1804 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1810 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1811 const gchar * dbg, GstPlaySinkType type)
1815 sink = gst_play_sink_get_sink (playbin->playsink, type);
1817 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1818 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1819 dbg, sink, dbg, *elem);
1822 GST_PLAY_BIN_LOCK (playbin);
1824 gst_object_ref (sink);
1825 GST_PLAY_BIN_UNLOCK (playbin);
1832 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1835 GstPlayBin *playbin;
1837 playbin = GST_PLAY_BIN (object);
1842 GstSourceGroup *group;
1844 GST_PLAY_BIN_LOCK (playbin);
1845 group = get_group (playbin);
1846 g_value_set_string (value, group->uri);
1847 GST_PLAY_BIN_UNLOCK (playbin);
1852 GstSourceGroup *group;
1854 GST_PLAY_BIN_LOCK (playbin);
1855 group = get_group (playbin);
1856 g_value_set_string (value, group->suburi);
1857 GST_PLAY_BIN_UNLOCK (playbin);
1862 GST_OBJECT_LOCK (playbin);
1863 g_value_set_object (value, playbin->source);
1864 GST_OBJECT_UNLOCK (playbin);
1868 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
1872 GstSourceGroup *group;
1875 GST_PLAY_BIN_LOCK (playbin);
1876 group = get_group (playbin);
1877 n_video = (group->video_channels ? group->video_channels->len : 0);
1878 g_value_set_int (value, n_video);
1879 GST_PLAY_BIN_UNLOCK (playbin);
1882 case PROP_CURRENT_VIDEO:
1883 GST_PLAY_BIN_LOCK (playbin);
1884 g_value_set_int (value, playbin->current_video);
1885 GST_PLAY_BIN_UNLOCK (playbin);
1889 GstSourceGroup *group;
1892 GST_PLAY_BIN_LOCK (playbin);
1893 group = get_group (playbin);
1894 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
1895 g_value_set_int (value, n_audio);
1896 GST_PLAY_BIN_UNLOCK (playbin);
1899 case PROP_CURRENT_AUDIO:
1900 GST_PLAY_BIN_LOCK (playbin);
1901 g_value_set_int (value, playbin->current_audio);
1902 GST_PLAY_BIN_UNLOCK (playbin);
1906 GstSourceGroup *group;
1909 GST_PLAY_BIN_LOCK (playbin);
1910 group = get_group (playbin);
1911 n_text = (group->text_channels ? group->text_channels->len : 0);
1912 g_value_set_int (value, n_text);
1913 GST_PLAY_BIN_UNLOCK (playbin);
1916 case PROP_CURRENT_TEXT:
1917 GST_PLAY_BIN_LOCK (playbin);
1918 g_value_set_int (value, playbin->current_text);
1919 GST_PLAY_BIN_UNLOCK (playbin);
1921 case PROP_SUBTITLE_ENCODING:
1922 GST_PLAY_BIN_LOCK (playbin);
1923 g_value_take_string (value,
1924 gst_play_sink_get_subtitle_encoding (playbin->playsink));
1925 GST_PLAY_BIN_UNLOCK (playbin);
1927 case PROP_VIDEO_SINK:
1928 g_value_take_object (value,
1929 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
1930 "video", GST_PLAY_SINK_TYPE_VIDEO));
1932 case PROP_AUDIO_SINK:
1933 g_value_take_object (value,
1934 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
1935 "audio", GST_PLAY_SINK_TYPE_AUDIO));
1937 case PROP_VIS_PLUGIN:
1938 g_value_take_object (value,
1939 gst_play_sink_get_vis_plugin (playbin->playsink));
1941 case PROP_TEXT_SINK:
1942 g_value_take_object (value,
1943 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
1944 "text", GST_PLAY_SINK_TYPE_TEXT));
1947 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
1950 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
1953 gst_value_take_buffer (value, gst_play_bin_convert_frame (playbin, NULL));
1955 case PROP_FONT_DESC:
1956 g_value_take_string (value,
1957 gst_play_sink_get_font_desc (playbin->playsink));
1959 case PROP_CONNECTION_SPEED:
1960 GST_PLAY_BIN_LOCK (playbin);
1961 g_value_set_uint (value, playbin->connection_speed / 1000);
1962 GST_PLAY_BIN_UNLOCK (playbin);
1964 case PROP_BUFFER_SIZE:
1965 GST_OBJECT_LOCK (playbin);
1966 g_value_set_int (value, playbin->buffer_size);
1967 GST_OBJECT_UNLOCK (playbin);
1969 case PROP_BUFFER_DURATION:
1970 GST_OBJECT_LOCK (playbin);
1971 g_value_set_int64 (value, playbin->buffer_duration);
1972 GST_OBJECT_UNLOCK (playbin);
1975 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1981 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
1982 gboolean valid, GstQuery * query)
1988 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
1989 gst_query_parse_duration (query, &fmt, &duration);
1991 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
1992 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
1993 playbin->duration[i].valid = valid;
1994 playbin->duration[i].format = fmt;
1995 playbin->duration[i].duration = valid ? duration : -1;
2002 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2004 const GstFormat formats[] =
2005 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2010 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2011 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2012 query = gst_query_new_duration (formats[i]);
2014 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2016 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2017 gst_query_unref (query);
2022 gst_play_bin_query (GstElement * element, GstQuery * query)
2024 GstPlayBin *playbin = GST_PLAY_BIN (element);
2027 /* During a group switch we shouldn't allow duration queries
2028 * because it's not clear if the old or new group's duration
2029 * is returned and if the sinks are already playing new data
2030 * or old data. See bug #585969
2032 * While we're at it, also don't do any other queries during
2033 * a group switch or any other event that causes topology changes
2034 * by taking the playbin lock in any case.
2036 GST_PLAY_BIN_LOCK (playbin);
2038 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2039 GstSourceGroup *group = playbin->curr_group;
2042 GST_SOURCE_GROUP_LOCK (group);
2043 if (group->stream_changed_pending_lock) {
2044 g_mutex_lock (group->stream_changed_pending_lock);
2045 pending = group->pending || group->stream_changed_pending;
2046 g_mutex_unlock (group->stream_changed_pending_lock);
2048 pending = group->pending;
2055 gst_query_parse_duration (query, &fmt, NULL);
2056 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2057 if (fmt == playbin->duration[i].format) {
2058 ret = playbin->duration[i].valid;
2059 gst_query_set_duration (query, fmt,
2060 (ret ? playbin->duration[i].duration : -1));
2064 GST_DEBUG_OBJECT (playbin,
2065 "Taking cached duration because of pending group switch: %d", ret);
2066 GST_SOURCE_GROUP_UNLOCK (group);
2067 GST_PLAY_BIN_UNLOCK (playbin);
2070 GST_SOURCE_GROUP_UNLOCK (group);
2073 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2075 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2076 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2077 GST_PLAY_BIN_UNLOCK (playbin);
2082 /* mime types we are not handling on purpose right now, don't post a
2083 * missing-plugin message for these */
2084 static const gchar *blacklisted_mimes[] = {
2089 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2091 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2092 GstSourceGroup *group;
2094 if (gst_is_missing_plugin_message (msg)) {
2098 detail = gst_missing_plugin_message_get_installer_detail (msg);
2099 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2100 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2101 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2102 gst_message_unref (msg);
2108 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2109 const GstStructure *s = gst_message_get_structure (msg);
2111 /* Drop all stream-changed messages except the last one */
2112 if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2113 guint32 seqnum = gst_message_get_seqnum (msg);
2116 group = playbin->curr_group;
2117 g_mutex_lock (group->stream_changed_pending_lock);
2118 for (l = group->stream_changed_pending; l;) {
2119 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2121 if (l_seqnum == seqnum) {
2124 group->stream_changed_pending =
2125 g_list_delete_link (group->stream_changed_pending, l_prev);
2126 if (group->stream_changed_pending) {
2127 gst_message_unref (msg);
2135 g_mutex_unlock (group->stream_changed_pending_lock);
2137 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2138 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2139 GstObject *src = GST_OBJECT_CAST (msg->src);
2141 /* Ignore async state changes from the uridecodebin children,
2142 * see bug #602000. */
2143 group = playbin->curr_group;
2144 if (src && (group = playbin->curr_group) &&
2145 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2146 || (group->suburidecodebin
2147 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2148 GST_DEBUG_OBJECT (playbin,
2149 "Ignoring async state change of uridecodebin: %s",
2150 GST_OBJECT_NAME (src));
2151 gst_message_unref (msg);
2154 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2155 /* If we get an error of the subtitle uridecodebin transform
2156 * them into warnings and disable the subtitles */
2157 group = playbin->curr_group;
2158 if (group && group->suburidecodebin) {
2159 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2160 (group->suburidecodebin)))) {
2162 gchar *debug = NULL;
2163 GstMessage *new_msg;
2165 gboolean done = FALSE;
2167 gst_message_parse_error (msg, &err, &debug);
2168 new_msg = gst_message_new_warning (msg->src, err, debug);
2170 gst_message_unref (msg);
2175 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2176 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2177 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2178 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2180 it = gst_element_iterate_src_pads (group->suburidecodebin);
2181 while (it && !done) {
2183 GstIteratorResult res;
2185 res = gst_iterator_next (it, (gpointer) & p);
2188 case GST_ITERATOR_DONE:
2191 case GST_ITERATOR_OK:
2192 pad_removed_cb (NULL, p, group);
2193 gst_object_unref (p);
2196 case GST_ITERATOR_RESYNC:
2197 gst_iterator_resync (it);
2199 case GST_ITERATOR_ERROR:
2205 gst_iterator_free (it);
2207 gst_object_ref (group->suburidecodebin);
2208 gst_bin_remove (bin, group->suburidecodebin);
2209 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2211 if (group->sub_pending) {
2212 group->sub_pending = FALSE;
2213 no_more_pads_cb (NULL, group);
2220 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2224 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2225 GstPlayBin * playbin)
2228 GstSourceGroup *group;
2229 GstSourceSelect *select = NULL;
2232 GST_PLAY_BIN_LOCK (playbin);
2233 group = get_group (playbin);
2235 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2236 if (selector == G_OBJECT (group->selector[i].selector)) {
2237 select = &group->selector[i];
2241 /* We got a pad-change after our group got switched out; no need to notify */
2243 GST_PLAY_BIN_UNLOCK (playbin);
2247 switch (select->type) {
2248 case GST_PLAY_SINK_TYPE_VIDEO:
2249 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2250 property = "current-video";
2251 playbin->current_video = get_current_stream_number (playbin,
2252 group->video_channels);
2254 case GST_PLAY_SINK_TYPE_AUDIO:
2255 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2256 property = "current-audio";
2257 playbin->current_audio = get_current_stream_number (playbin,
2258 group->audio_channels);
2260 case GST_PLAY_SINK_TYPE_TEXT:
2261 property = "current-text";
2262 playbin->current_text = get_current_stream_number (playbin,
2263 group->text_channels);
2268 GST_PLAY_BIN_UNLOCK (playbin);
2271 g_object_notify (G_OBJECT (playbin), property);
2275 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
2278 GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
2281 /* helper function to lookup stuff in lists */
2283 array_has_value (const gchar * values[], const gchar * value)
2287 for (i = 0; values[i]; i++) {
2288 if (g_str_has_prefix (value, values[i]))
2296 GstPlayBin *playbin;
2298 GstPlaySinkType type;
2302 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2304 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2307 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2308 " with stream id %d and type %d have changed",
2309 object, ntdata->stream_id, ntdata->type);
2311 switch (ntdata->type) {
2312 case GST_PLAY_SINK_TYPE_VIDEO:
2313 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2314 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2316 case GST_PLAY_SINK_TYPE_AUDIO:
2317 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2318 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2320 case GST_PLAY_SINK_TYPE_TEXT:
2321 signal = SIGNAL_TEXT_TAGS_CHANGED;
2329 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2335 GstPlayBin *playbin;
2336 GstSourceGroup *group;
2337 GstPlaySinkType type;
2338 } PlaySinkEventProbeData;
2341 _playsink_src_event_probe_cb (GstPad * pad, GstEvent * event,
2342 PlaySinkEventProbeData * data)
2344 if (GST_EVENT_TYPE (event) == GST_EVENT_QOS) {
2345 GstEvent *new_event;
2348 GstClockTimeDiff diff;
2349 GstClockTime group_start_accum =
2350 data->group->selector[data->type].group_start_accum;
2351 GstClockTime timestamp;
2353 s = (GstStructure *) gst_event_get_structure (event);
2354 if (gst_structure_has_field (s, "playbin2-adjusted-event"))
2357 /* If we have no group start accumulator yet, this is
2358 * a QOS event for the previous group or this stream
2359 * has a non-time segment.
2361 if (!GST_CLOCK_TIME_IS_VALID (group_start_accum))
2364 /* If the group start accumulator is 0, this is the first
2365 * group and we don't need to do everything below
2367 if (group_start_accum == 0)
2370 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
2372 /* If the running time timestamp is smaller than the accumulator,
2373 * the event is for a buffer from the previous group
2375 if (timestamp >= group_start_accum)
2376 timestamp -= group_start_accum;
2380 /* That case is invalid for QoS events, also it means that
2381 * we have switched the group but receive QoS events of
2382 * the previous group.
2384 if (diff < 0 && -diff > timestamp)
2387 new_event = gst_event_new_qos (proportion, diff, timestamp);
2388 s = (GstStructure *) gst_event_get_structure (new_event);
2389 gst_structure_set (s, "playbin2-adjusted-event", G_TYPE_BOOLEAN, TRUE,
2391 gst_pad_send_event (pad, new_event);
2400 _playsink_sink_event_probe_cb (GstPad * pad, GstEvent * event,
2401 PlaySinkEventProbeData * data)
2405 if (data->type == GST_PLAY_SINK_TYPE_VIDEO
2406 || data->type == GST_PLAY_SINK_TYPE_VIDEO_RAW)
2408 else if (data->type == GST_PLAY_SINK_TYPE_AUDIO
2409 || data->type == GST_PLAY_SINK_TYPE_AUDIO_RAW)
2411 else if (data->type == GST_PLAY_SINK_TYPE_TEXT)
2414 g_assert_not_reached ();
2416 if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
2417 GstPlayBin *playbin = data->playbin;
2418 GstSegment *segment;
2421 gdouble rate, applied_rate;
2422 gint64 start, stop, pos;
2424 segment = &playbin->segments[index];
2426 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
2427 &format, &start, &stop, &pos);
2428 if (segment->format != format)
2429 gst_segment_init (segment, format);
2430 gst_segment_set_newsegment_full (segment, update, rate, applied_rate,
2431 format, start, stop, pos);
2433 if (format != GST_FORMAT_TIME)
2434 data->group->selector[data->type].group_start_accum = GST_CLOCK_TIME_NONE;
2435 else if (!GST_CLOCK_TIME_IS_VALID (data->group->selector[data->type].
2437 data->group->selector[data->type].group_start_accum = segment->accum;
2438 } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2439 gst_segment_init (&data->playbin->segments[index], GST_FORMAT_UNDEFINED);
2445 /* this function is called when a new pad is added to decodebin. We check the
2446 * type of the pad and add it to the selector element of the group.
2449 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2451 GstPlayBin *playbin;
2453 const GstStructure *s;
2456 GstPadLinkReturn res;
2457 GstSourceSelect *select = NULL;
2459 gboolean changed = FALSE;
2461 playbin = group->playbin;
2463 caps = gst_pad_get_caps_reffed (pad);
2464 s = gst_caps_get_structure (caps, 0);
2465 name = gst_structure_get_name (s);
2467 GST_DEBUG_OBJECT (playbin,
2468 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2469 GST_DEBUG_PAD_NAME (pad), caps, group);
2471 /* major type of the pad, this determines the selector to use */
2472 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2473 if (array_has_value (group->selector[i].media_list, name)) {
2474 select = &group->selector[i];
2476 } else if (group->selector[i].get_media_caps) {
2477 GstCaps *media_caps = group->selector[i].get_media_caps ();
2479 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2480 select = &group->selector[i];
2481 gst_caps_unref (media_caps);
2484 gst_caps_unref (media_caps);
2487 /* no selector found for the media type, don't bother linking it to a
2488 * selector. This will leave the pad unlinked and thus ignored. */
2492 GST_SOURCE_GROUP_LOCK (group);
2493 if (select->selector == NULL && playbin->have_selector) {
2494 /* no selector, create one */
2495 GST_DEBUG_OBJECT (playbin, "creating new selector");
2496 select->selector = g_object_new (GST_TYPE_INPUT_SELECTOR, NULL);
2497 /* the above can't fail, but we keep the error handling around for when
2498 * the selector plugin has moved to -base or -good and we stop using an
2499 * internal copy of input-selector */
2500 if (select->selector == NULL) {
2501 /* post the missing selector message only once */
2502 playbin->have_selector = FALSE;
2503 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2504 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2506 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2507 (_("Missing element '%s' - check your GStreamer installation."),
2508 "input-selector"), (NULL));
2510 g_signal_connect (select->selector, "notify::active-pad",
2511 G_CALLBACK (selector_active_pad_changed), playbin);
2513 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2514 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2515 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2519 if (select->srcpad == NULL) {
2520 PlaySinkEventProbeData *data = g_new (PlaySinkEventProbeData, 1);
2522 if (select->selector) {
2523 /* save source pad of the selector */
2524 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2526 /* no selector, use the pad as the source pad then */
2527 select->srcpad = gst_object_ref (pad);
2530 /* Install an event probe */
2531 data->playbin = playbin;
2532 data->group = group;
2533 data->type = select->type;
2534 select->src_event_probe_id =
2535 gst_pad_add_event_probe_full (select->srcpad,
2536 G_CALLBACK (_playsink_src_event_probe_cb), data,
2537 (GDestroyNotify) g_free);
2539 select->group_start_accum = -1;
2541 /* block the selector srcpad. It's possible that multiple decodebins start
2542 * pushing data into the selectors before we have a chance to collect all
2543 * streams and connect the sinks, resulting in not-linked errors. After we
2544 * configured the sinks we will unblock them all. */
2545 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2546 gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
2549 /* get sinkpad for the new stream */
2550 if (select->selector) {
2551 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2552 gulong notify_tags_handler = 0;
2553 NotifyTagsData *ntdata;
2555 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2556 GST_DEBUG_PAD_NAME (sinkpad));
2558 /* store the selector for the pad */
2559 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2561 /* connect to the notify::tags signal for our
2562 * own *-tags-changed signals
2564 ntdata = g_new0 (NotifyTagsData, 1);
2565 ntdata->playbin = playbin;
2566 ntdata->stream_id = select->channels->len;
2567 ntdata->type = select->type;
2569 notify_tags_handler =
2570 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2571 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2573 g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2574 (gpointer) notify_tags_handler);
2576 /* store the pad in the array */
2577 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2578 g_ptr_array_add (select->channels, sinkpad);
2580 res = gst_pad_link (pad, sinkpad);
2581 if (GST_PAD_LINK_FAILED (res))
2584 /* store selector pad so we can release it */
2585 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2588 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2589 GST_DEBUG_PAD_NAME (pad), select->selector);
2592 /* no selector, don't configure anything, we'll link the new pad directly to
2597 GST_SOURCE_GROUP_UNLOCK (group);
2601 gboolean always_ok = (decodebin == group->suburidecodebin);
2603 switch (select->type) {
2604 case GST_PLAY_SINK_TYPE_VIDEO:
2605 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2606 /* we want to return NOT_LINKED for unselected pads but only for pads
2607 * from the normal uridecodebin. This makes sure that subtitle streams
2608 * are not raced past audio/video from decodebin2's multiqueue.
2609 * For pads from suburidecodebin OK should always be returned, otherwise
2610 * it will most likely stop. */
2611 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2612 signal = SIGNAL_VIDEO_CHANGED;
2614 case GST_PLAY_SINK_TYPE_AUDIO:
2615 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2616 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2617 signal = SIGNAL_AUDIO_CHANGED;
2619 case GST_PLAY_SINK_TYPE_TEXT:
2620 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2621 signal = SIGNAL_TEXT_CHANGED;
2628 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2632 gst_caps_unref (caps);
2638 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2639 name, GST_DEBUG_PAD_NAME (pad));
2644 GST_ERROR_OBJECT (playbin,
2645 "failed to link pad %s:%s to selector, reason %d",
2646 GST_DEBUG_PAD_NAME (pad), res);
2647 GST_SOURCE_GROUP_UNLOCK (group);
2652 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2653 * the selector. This will make the selector select a new pad. */
2655 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2657 GstPlayBin *playbin;
2659 GstElement *selector;
2660 GstSourceSelect *select;
2662 playbin = group->playbin;
2664 GST_DEBUG_OBJECT (playbin,
2665 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2667 GST_SOURCE_GROUP_LOCK (group);
2668 /* get the selector sinkpad */
2669 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2672 if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2673 gulong notify_tags_handler;
2675 notify_tags_handler =
2676 (gulong) g_object_get_data (G_OBJECT (peer),
2677 "playbin2.notify_tags_handler");
2678 if (notify_tags_handler != 0)
2679 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2680 g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2682 /* remove the pad from the array */
2683 g_ptr_array_remove (select->channels, peer);
2684 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2687 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2688 gst_pad_unlink (pad, peer);
2690 /* get selector, this can be NULL when the element is removing the pads
2691 * because it's being disposed. */
2692 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2694 gst_object_unref (peer);
2698 /* release the pad to the selector, this will make the selector choose a new
2700 gst_element_release_request_pad (selector, peer);
2701 gst_object_unref (peer);
2703 gst_object_unref (selector);
2704 GST_SOURCE_GROUP_UNLOCK (group);
2711 GST_DEBUG_OBJECT (playbin, "pad not linked");
2712 GST_SOURCE_GROUP_UNLOCK (group);
2717 GST_DEBUG_OBJECT (playbin, "selector not found");
2718 GST_SOURCE_GROUP_UNLOCK (group);
2723 /* we get called when all pads are available and we must connect the sinks to
2725 * The main purpose of the code is to see if we have video/audio and subtitles
2726 * and pick the right pipelines to display them.
2728 * The selectors installed on the group tell us about the presence of
2729 * audio/video and subtitle streams. This allows us to see if we need
2730 * visualisation, video or/and audio.
2733 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2735 GstPlayBin *playbin;
2736 GstPadLinkReturn res;
2740 playbin = group->playbin;
2742 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2744 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2746 GST_SOURCE_GROUP_LOCK (group);
2747 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2748 GstSourceSelect *select = &group->selector[i];
2750 /* check if the specific media type was detected and thus has a selector
2751 * created for it. If there is the media type, get a sinkpad from the sink
2752 * and link it. We only do this if we have not yet requested the sinkpad
2754 if (select->srcpad && select->sinkpad == NULL) {
2755 PlaySinkEventProbeData *data = g_new (PlaySinkEventProbeData, 1);
2757 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2759 gst_play_sink_request_pad (playbin->playsink, select->type);
2761 /* Install an event probe */
2762 data->playbin = playbin;
2763 data->group = group;
2764 data->type = select->type;
2765 select->sink_event_probe_id =
2766 gst_pad_add_event_probe_full (select->sinkpad,
2767 G_CALLBACK (_playsink_sink_event_probe_cb), data,
2768 (GDestroyNotify) g_free);
2770 res = gst_pad_link (select->srcpad, select->sinkpad);
2771 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2772 select->media_list[0], res);
2773 if (res != GST_PAD_LINK_OK) {
2774 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2775 ("Internal playbin error."),
2776 ("Failed to link selector to sink. Error %d", res));
2780 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2781 group->pending - 1);
2783 if (group->pending > 0)
2786 if (group->suburidecodebin == decodebin)
2787 group->sub_pending = FALSE;
2789 if (group->pending == 0) {
2790 /* we are the last group to complete, we will configure the output and then
2791 * signal the other waiters. */
2792 GST_LOG_OBJECT (playbin, "last group complete");
2795 GST_LOG_OBJECT (playbin, "have more pending groups");
2798 GST_SOURCE_GROUP_UNLOCK (group);
2801 /* if we have custom sinks, configure them now */
2802 GST_SOURCE_GROUP_LOCK (group);
2803 if (group->audio_sink) {
2804 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2806 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2809 GST_INFO_OBJECT (playbin, "setting default audio sink %" GST_PTR_FORMAT,
2810 playbin->audio_sink);
2811 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2812 playbin->audio_sink);
2814 if (group->video_sink) {
2815 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2817 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2820 GST_INFO_OBJECT (playbin, "setting default video sink %" GST_PTR_FORMAT,
2821 playbin->video_sink);
2822 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2823 playbin->video_sink);
2825 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2826 playbin->text_sink);
2827 GST_SOURCE_GROUP_UNLOCK (group);
2829 GST_LOG_OBJECT (playbin, "reconfigure sink");
2830 /* we configure the modes if we were the last decodebin to complete. */
2831 gst_play_sink_reconfigure (playbin->playsink);
2833 /* signal the other decodebins that they can continue now. */
2834 GST_SOURCE_GROUP_LOCK (group);
2835 /* unblock all selectors */
2836 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2837 GstSourceSelect *select = &group->selector[i];
2839 /* Wait for stream-changed messages on all selectors except
2840 * the text selector because of the sparse nature of text streams.
2842 if (select->sinkpad && select->type != GST_PLAY_SINK_TYPE_TEXT) {
2848 s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2851 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2852 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2853 seqnum = gst_message_get_seqnum (msg);
2854 event = gst_event_new_sink_message (msg);
2855 g_mutex_lock (group->stream_changed_pending_lock);
2856 group->stream_changed_pending =
2857 g_list_prepend (group->stream_changed_pending,
2858 GUINT_TO_POINTER (seqnum));
2859 g_mutex_unlock (group->stream_changed_pending_lock);
2860 gst_pad_send_event (select->sinkpad, event);
2861 gst_message_unref (msg);
2864 if (select->srcpad) {
2865 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2867 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2871 GST_SOURCE_GROUP_UNLOCK (group);
2874 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2880 GST_DEBUG ("ignoring, we are shutting down");
2881 /* Request a flushing pad from playsink that we then link to the selector.
2882 * Then we unblock the selectors so that they stop with a WRONG_STATE
2883 * instead of a NOT_LINKED error.
2885 GST_SOURCE_GROUP_LOCK (group);
2886 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2887 GstSourceSelect *select = &group->selector[i];
2889 if (select->srcpad) {
2890 if (select->sinkpad == NULL) {
2891 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2893 gst_play_sink_request_pad (playbin->playsink,
2894 GST_PLAY_SINK_TYPE_FLUSHING);
2895 res = gst_pad_link (select->srcpad, select->sinkpad);
2896 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2898 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2900 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2904 GST_SOURCE_GROUP_UNLOCK (group);
2910 drained_cb (GstElement * decodebin, GstSourceGroup * group)
2912 GstPlayBin *playbin;
2914 playbin = group->playbin;
2916 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
2918 /* after this call, we should have a next group to activate or we EOS */
2919 g_signal_emit (G_OBJECT (playbin),
2920 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
2922 /* now activate the next group. If the app did not set a uri, this will
2923 * fail and we can do EOS */
2924 setup_next_source (playbin, GST_STATE_PAUSED);
2927 /* Called when we must provide a list of factories to plug to @pad with @caps.
2928 * We first check if we have a sink that can handle the format and if we do, we
2929 * return NULL, to expose the pad. If we have no sink (or the sink does not
2930 * work), we return the list of elements that can connect. */
2931 static GValueArray *
2932 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
2933 GstCaps * caps, GstSourceGroup * group)
2935 GstPlayBin *playbin;
2936 GValueArray *result;
2938 playbin = group->playbin;
2940 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
2941 group, GST_DEBUG_PAD_NAME (pad), caps);
2943 /* filter out the elements based on the caps. */
2944 g_mutex_lock (playbin->elements_lock);
2945 gst_play_bin_update_elements_list (playbin);
2946 result = gst_factory_list_filter (playbin->elements, caps);
2947 g_mutex_unlock (playbin->elements_lock);
2949 GST_DEBUG_OBJECT (playbin, "found factories %p", result);
2950 GST_FACTORY_LIST_DEBUG (result);
2955 /* autoplug-continue decides, if a pad has raw caps that can be exposed
2956 * directly or if further decoding is necessary. We use this to expose
2957 * supported subtitles directly */
2959 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
2960 GstSourceGroup * group)
2963 gboolean ret = FALSE;
2965 subcaps = gst_subtitle_overlay_create_factory_caps ();
2966 ret = !gst_caps_can_intersect (subcaps, caps);
2967 gst_caps_unref (subcaps);
2969 GST_DEBUG_OBJECT (group->playbin,
2970 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
2971 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
2976 /* We are asked to select an element. See if the next element to check
2977 * is a sink. If this is the case, we see if the sink works by setting it to
2978 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
2979 * expose the raw pad so that we can setup the mixers. */
2980 static GstAutoplugSelectResult
2981 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
2982 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
2984 GstPlayBin *playbin;
2985 GstElement *element;
2987 GstPlaySinkType type;
2990 playbin = group->playbin;
2992 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
2993 group, GST_DEBUG_PAD_NAME (pad), caps);
2995 GST_DEBUG_OBJECT (playbin, "checking factory %s",
2996 GST_PLUGIN_FEATURE_NAME (factory));
2998 /* if it's not a sink, we just make decodebin try it */
2999 if (!gst_factory_list_is_type (factory, GST_FACTORY_LIST_SINK))
3000 return GST_AUTOPLUG_SELECT_TRY;
3002 /* it's a sink, see if an instance of it actually works */
3003 GST_DEBUG_OBJECT (playbin, "we found a sink");
3005 klass = gst_element_factory_get_klass (factory);
3007 /* figure out the klass */
3008 if (strstr (klass, "Audio")) {
3009 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3010 type = GST_PLAY_SINK_TYPE_AUDIO;
3011 sinkp = &group->audio_sink;
3012 } else if (strstr (klass, "Video")) {
3013 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3014 type = GST_PLAY_SINK_TYPE_VIDEO;
3015 sinkp = &group->video_sink;
3017 /* unknown klass, skip this element */
3018 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3019 return GST_AUTOPLUG_SELECT_SKIP;
3022 /* if we are asked to do visualisations and it's an audio sink, skip the
3023 * element. We can only do visualisations with raw sinks */
3024 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3025 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3026 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3027 return GST_AUTOPLUG_SELECT_SKIP;
3031 /* now see if we already have a sink element */
3032 GST_SOURCE_GROUP_LOCK (group);
3034 GST_DEBUG_OBJECT (playbin, "we already have a pending sink, expose pad");
3035 /* for now, just assume that we can link the pad to this same sink. FIXME,
3036 * check that we can link this new pad to this sink as well. */
3037 GST_SOURCE_GROUP_UNLOCK (group);
3038 return GST_AUTOPLUG_SELECT_EXPOSE;
3040 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3041 GST_SOURCE_GROUP_UNLOCK (group);
3043 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3044 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3045 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3046 return GST_AUTOPLUG_SELECT_SKIP;
3049 /* ... activate it ... We do this before adding it to the bin so that we
3050 * don't accidentally make it post error messages that will stop
3052 if ((gst_element_set_state (element,
3053 GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
3054 GST_WARNING_OBJECT (playbin, "Couldn't set %s to READY",
3055 GST_ELEMENT_NAME (element));
3056 gst_object_unref (element);
3057 return GST_AUTOPLUG_SELECT_SKIP;
3060 /* remember the sink in the group now, the element is floating, we take
3062 GST_SOURCE_GROUP_LOCK (group);
3063 if (*sinkp == NULL) {
3064 /* store the sink in the group, we will configure it later when we
3065 * reconfigure the sink */
3066 GST_DEBUG_OBJECT (playbin, "remember sink");
3067 gst_object_ref_sink (element);
3070 /* some other thread configured a sink while we were testing the sink, set
3071 * the sink back to NULL and assume we can use the other sink */
3072 GST_DEBUG_OBJECT (playbin, "another sink was found, expose pad");
3073 gst_element_set_state (element, GST_STATE_NULL);
3074 gst_object_unref (element);
3076 GST_SOURCE_GROUP_UNLOCK (group);
3078 /* tell decodebin to expose the pad because we are going to use this
3080 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3082 return GST_AUTOPLUG_SELECT_EXPOSE;
3086 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3087 GstSourceGroup * group)
3089 GstPlayBin *playbin;
3092 playbin = group->playbin;
3094 g_object_get (group->uridecodebin, "source", &source, NULL);
3096 GST_OBJECT_LOCK (playbin);
3097 if (playbin->source)
3098 gst_object_unref (playbin->source);
3099 playbin->source = source;
3100 GST_OBJECT_UNLOCK (playbin);
3102 g_object_notify (G_OBJECT (playbin), "source");
3105 /* must be called with the group lock */
3107 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3110 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3112 if (group->uridecodebin)
3113 gst_element_set_locked_state (group->uridecodebin, locked);
3114 if (group->suburidecodebin)
3115 gst_element_set_locked_state (group->suburidecodebin, locked);
3120 /* must be called with PLAY_BIN_LOCK */
3122 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3124 GstElement *uridecodebin;
3125 GstElement *suburidecodebin = NULL;
3128 g_return_val_if_fail (group->valid, FALSE);
3129 g_return_val_if_fail (!group->active, FALSE);
3131 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3133 GST_SOURCE_GROUP_LOCK (group);
3135 g_list_free (group->stream_changed_pending);
3136 group->stream_changed_pending = NULL;
3137 if (!group->stream_changed_pending_lock)
3138 group->stream_changed_pending_lock = g_mutex_new ();
3140 if (group->uridecodebin) {
3141 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3142 uridecodebin = group->uridecodebin;
3143 gst_element_set_state (uridecodebin, GST_STATE_READY);
3144 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3146 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3147 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3150 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3151 group->uridecodebin = gst_object_ref (uridecodebin);
3154 /* configure connection speed */
3155 g_object_set (uridecodebin, "connection-speed",
3156 playbin->connection_speed / 1000, NULL);
3158 flags = gst_play_sink_get_flags (playbin->playsink);
3160 /* configure download buffering */
3161 if (flags & GST_PLAY_FLAG_DOWNLOAD)
3162 g_object_set (uridecodebin, "download", TRUE, NULL);
3164 g_object_set (uridecodebin, "download", FALSE, NULL);
3167 g_object_set (uridecodebin, "uri", group->uri, NULL);
3168 /* configure buffering of demuxed/parsed data */
3169 if (flags & GST_PLAY_FLAG_BUFFERING)
3170 g_object_set (uridecodebin, "use-buffering", TRUE, NULL);
3172 g_object_set (uridecodebin, "use-buffering", FALSE, NULL);
3173 /* configure buffering parameters */
3174 g_object_set (uridecodebin, "buffer-duration", playbin->buffer_duration,
3176 g_object_set (uridecodebin, "buffer-size", playbin->buffer_size, NULL);
3178 /* connect pads and other things */
3179 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3180 G_CALLBACK (pad_added_cb), group);
3181 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3182 G_CALLBACK (pad_removed_cb), group);
3183 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3184 G_CALLBACK (no_more_pads_cb), group);
3185 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3186 G_CALLBACK (notify_source_cb), group);
3188 /* we have 1 pending no-more-pads */
3191 /* is called when the uridecodebin is out of data and we can switch to the
3194 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3197 /* will be called when a new media type is found. We return a list of decoders
3198 * including sinks for decodebin to try */
3199 group->autoplug_factories_id =
3200 g_signal_connect (uridecodebin, "autoplug-factories",
3201 G_CALLBACK (autoplug_factories_cb), group);
3202 group->autoplug_select_id =
3203 g_signal_connect (uridecodebin, "autoplug-select",
3204 G_CALLBACK (autoplug_select_cb), group);
3205 group->autoplug_continue_id =
3206 g_signal_connect (uridecodebin, "autoplug-continue",
3207 G_CALLBACK (autoplug_continue_cb), group);
3209 if (group->suburi) {
3211 if (group->suburidecodebin) {
3212 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3213 suburidecodebin = group->suburidecodebin;
3214 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3215 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3217 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3218 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3219 if (!suburidecodebin)
3222 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3223 group->suburidecodebin = gst_object_ref (suburidecodebin);
3226 /* configure connection speed */
3227 g_object_set (suburidecodebin, "connection-speed",
3228 playbin->connection_speed, NULL);
3230 g_object_set (suburidecodebin, "uri", group->suburi, NULL);
3232 /* connect pads and other things */
3233 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3234 G_CALLBACK (pad_added_cb), group);
3235 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3236 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3237 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3238 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3240 group->sub_autoplug_continue_id =
3241 g_signal_connect (suburidecodebin, "autoplug-continue",
3242 G_CALLBACK (autoplug_continue_cb), group);
3244 /* we have 2 pending no-more-pads */
3246 group->sub_pending = TRUE;
3248 group->sub_pending = FALSE;
3251 /* release the group lock before setting the state of the decodebins, they
3252 * might fire signals in this thread that we need to handle with the
3253 * group_lock taken. */
3254 GST_SOURCE_GROUP_UNLOCK (group);
3256 if (suburidecodebin) {
3257 if (gst_element_set_state (suburidecodebin,
3258 target) == GST_STATE_CHANGE_FAILURE) {
3259 GST_DEBUG_OBJECT (playbin,
3260 "failed state change of subtitle uridecodebin");
3261 GST_SOURCE_GROUP_LOCK (group);
3263 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3264 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3265 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3266 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3267 /* Might already be removed because of an error message */
3268 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3269 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3270 if (group->sub_pending) {
3272 group->sub_pending = FALSE;
3274 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3275 GST_SOURCE_GROUP_UNLOCK (group);
3278 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3279 goto uridecodebin_failure;
3281 GST_SOURCE_GROUP_LOCK (group);
3282 /* alow state changes of the playbin2 affect the group elements now */
3283 group_set_locked_state_unlocked (playbin, group, FALSE);
3284 group->active = TRUE;
3285 GST_SOURCE_GROUP_UNLOCK (group);
3294 GST_SOURCE_GROUP_UNLOCK (group);
3296 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3298 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3300 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3301 (_("Could not create \"uridecodebin\" element.")), (NULL));
3304 uridecodebin_failure:
3306 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3311 /* unlink a group of uridecodebins from the sink.
3312 * must be called with PLAY_BIN_LOCK */
3314 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3318 g_return_val_if_fail (group->valid, FALSE);
3319 g_return_val_if_fail (group->active, FALSE);
3321 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3323 GST_SOURCE_GROUP_LOCK (group);
3324 group->active = FALSE;
3325 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
3326 GstSourceSelect *select = &group->selector[i];
3328 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3330 if (select->srcpad) {
3331 if (select->sinkpad) {
3332 GST_LOG_OBJECT (playbin, "unlinking from sink");
3333 gst_pad_unlink (select->srcpad, select->sinkpad);
3335 if (select->sink_event_probe_id)
3336 gst_pad_remove_event_probe (select->sinkpad,
3337 select->sink_event_probe_id);
3338 select->sink_event_probe_id = 0;
3341 GST_LOG_OBJECT (playbin, "release sink pad");
3342 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3343 select->sinkpad = NULL;
3346 if (select->src_event_probe_id)
3347 gst_pad_remove_event_probe (select->srcpad, select->src_event_probe_id);
3348 select->src_event_probe_id = 0;
3350 gst_object_unref (select->srcpad);
3351 select->srcpad = NULL;
3354 if (select->selector) {
3357 /* release and unref requests pad from the selector */
3358 for (n = 0; n < select->channels->len; n++) {
3359 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3361 gst_element_release_request_pad (select->selector, sinkpad);
3362 gst_object_unref (sinkpad);
3364 g_ptr_array_set_size (select->channels, 0);
3366 gst_element_set_state (select->selector, GST_STATE_NULL);
3367 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3368 select->selector = NULL;
3371 /* delete any custom sinks we might have */
3372 if (group->audio_sink)
3373 gst_object_unref (group->audio_sink);
3374 group->audio_sink = NULL;
3375 if (group->video_sink)
3376 gst_object_unref (group->video_sink);
3377 group->video_sink = NULL;
3379 if (group->uridecodebin) {
3380 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3381 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3382 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3383 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3384 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3385 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3386 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3387 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3388 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3391 if (group->suburidecodebin) {
3392 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3393 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3394 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3395 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3397 /* Might already be removed because of errors */
3398 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3399 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3402 GST_SOURCE_GROUP_UNLOCK (group);
3407 /* setup the next group to play, this assumes the next_group is valid and
3408 * configured. It swaps out the current_group and activates the valid
3411 setup_next_source (GstPlayBin * playbin, GstState target)
3413 GstSourceGroup *new_group, *old_group;
3415 GST_DEBUG_OBJECT (playbin, "setup sources");
3417 /* see if there is a next group */
3418 GST_PLAY_BIN_LOCK (playbin);
3419 new_group = playbin->next_group;
3420 if (!new_group || !new_group->valid)
3423 /* first unlink the current source, if any */
3424 old_group = playbin->curr_group;
3425 if (old_group && old_group->valid) {
3426 gst_play_bin_update_cached_duration (playbin);
3427 /* unlink our pads with the sink */
3428 deactivate_group (playbin, old_group);
3429 old_group->valid = FALSE;
3432 /* swap old and new */
3433 playbin->curr_group = new_group;
3434 playbin->next_group = old_group;
3436 /* activate the new group */
3437 if (!activate_group (playbin, new_group, target))
3438 goto activate_failed;
3440 GST_PLAY_BIN_UNLOCK (playbin);
3447 GST_DEBUG_OBJECT (playbin, "no next group");
3448 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3449 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3450 GST_PLAY_BIN_UNLOCK (playbin);
3455 GST_DEBUG_OBJECT (playbin, "activate failed");
3456 GST_PLAY_BIN_UNLOCK (playbin);
3461 /* The group that is currently playing is copied again to the
3462 * next_group so that it will start playing the next time.
3465 save_current_group (GstPlayBin * playbin)
3467 GstSourceGroup *curr_group;
3469 GST_DEBUG_OBJECT (playbin, "save current group");
3471 /* see if there is a current group */
3472 GST_PLAY_BIN_LOCK (playbin);
3473 curr_group = playbin->curr_group;
3474 if (curr_group && curr_group->valid) {
3475 /* unlink our pads with the sink */
3476 deactivate_group (playbin, curr_group);
3478 /* swap old and new */
3479 playbin->curr_group = playbin->next_group;
3480 playbin->next_group = curr_group;
3481 GST_PLAY_BIN_UNLOCK (playbin);
3486 /* clear the locked state from all groups. This function is called before a
3487 * state change to NULL is performed on them. */
3489 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3491 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3494 GST_PLAY_BIN_LOCK (playbin);
3495 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3496 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3497 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3498 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3499 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3500 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3501 GST_PLAY_BIN_UNLOCK (playbin);
3506 static GstStateChangeReturn
3507 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3509 GstStateChangeReturn ret;
3510 GstPlayBin *playbin;
3512 playbin = GST_PLAY_BIN (element);
3514 switch (transition) {
3515 case GST_STATE_CHANGE_NULL_TO_READY:
3516 g_mutex_lock (playbin->elements_lock);
3517 gst_play_bin_update_elements_list (playbin);
3518 g_mutex_unlock (playbin->elements_lock);
3519 memset (&playbin->duration, 0, sizeof (playbin->duration));
3521 case GST_STATE_CHANGE_READY_TO_PAUSED:{
3524 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3525 memset (&playbin->duration, 0, sizeof (playbin->duration));
3526 g_atomic_int_set (&playbin->shutdown, 0);
3528 for (i = 0; i < 3; i++)
3529 gst_segment_init (&playbin->segments[i], GST_FORMAT_UNDEFINED);
3531 if (!setup_next_source (playbin, GST_STATE_READY))
3535 case GST_STATE_CHANGE_PAUSED_TO_READY:
3536 /* FIXME unlock our waiting groups */
3537 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3538 g_atomic_int_set (&playbin->shutdown, 1);
3539 memset (&playbin->duration, 0, sizeof (playbin->duration));
3541 /* wait for all callbacks to end by taking the lock.
3542 * No dynamic (critical) new callbacks will
3543 * be able to happen as we set the shutdown flag. */
3544 GST_PLAY_BIN_DYN_LOCK (playbin);
3545 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3546 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3548 case GST_STATE_CHANGE_READY_TO_NULL:{
3551 memset (&playbin->duration, 0, sizeof (playbin->duration));
3553 /* unlock so that all groups go to NULL */
3554 groups_set_locked_state (playbin, FALSE);
3556 for (i = 0; i < 2; i++) {
3557 if (playbin->groups[i].uridecodebin) {
3558 gst_element_set_state (playbin->groups[i].uridecodebin,
3560 gst_object_unref (playbin->groups[i].uridecodebin);
3561 playbin->groups[i].uridecodebin = NULL;
3563 if (playbin->groups[i].suburidecodebin) {
3564 gst_element_set_state (playbin->groups[i].suburidecodebin,
3566 gst_object_unref (playbin->groups[i].suburidecodebin);
3567 playbin->groups[i].suburidecodebin = NULL;
3576 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3577 if (ret == GST_STATE_CHANGE_FAILURE) {
3578 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
3579 GstSourceGroup *curr_group;
3581 curr_group = playbin->curr_group;
3582 if (curr_group && curr_group->valid) {
3583 /* unlink our pads with the sink */
3584 deactivate_group (playbin, curr_group);
3587 /* Swap current and next group back */
3588 playbin->curr_group = playbin->next_group;
3589 playbin->next_group = curr_group;
3594 switch (transition) {
3595 case GST_STATE_CHANGE_READY_TO_PAUSED:
3597 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3598 /* FIXME Release audio device when we implement that */
3600 case GST_STATE_CHANGE_PAUSED_TO_READY:
3601 save_current_group (playbin);
3603 case GST_STATE_CHANGE_READY_TO_NULL:
3604 /* make sure the groups don't perform a state change anymore until we
3605 * enable them again */
3606 groups_set_locked_state (playbin, TRUE);
3617 return GST_STATE_CHANGE_FAILURE;
3622 gst_play_bin2_plugin_init (GstPlugin * plugin)
3624 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
3626 g_type_class_ref (gst_input_selector_get_type ());
3627 g_type_class_ref (gst_selector_pad_get_type ());
3629 return gst_element_register (plugin, "playbin2", GST_RANK_NONE,