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 GstStaticCaps av_raw_caps = GST_STATIC_CAPS ("audio/x-raw-int; "
563 "video/x-raw-float; "
564 "video/x-raw-yuv; " "video/x-raw-rgb; " "video/x-raw-gray;");
566 #define REMOVE_SIGNAL(obj,id) \
568 g_signal_handler_disconnect (obj, id); \
573 gst_play_marshal_BUFFER__BOXED (GClosure * closure,
574 GValue * return_value G_GNUC_UNUSED,
575 guint n_param_values,
576 const GValue * param_values,
577 gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
579 typedef GstBuffer *(*GMarshalFunc_OBJECT__BOXED) (gpointer data1,
580 gpointer arg_1, gpointer data2);
581 register GMarshalFunc_OBJECT__BOXED callback;
582 register GCClosure *cc = (GCClosure *) closure;
583 register gpointer data1, data2;
586 g_return_if_fail (return_value != NULL);
587 g_return_if_fail (n_param_values == 2);
589 if (G_CCLOSURE_SWAP_DATA (closure)) {
590 data1 = closure->data;
591 data2 = g_value_peek_pointer (param_values + 0);
593 data1 = g_value_peek_pointer (param_values + 0);
594 data2 = closure->data;
597 (GMarshalFunc_OBJECT__BOXED) (marshal_data ? marshal_data : cc->callback);
599 v_return = callback (data1, g_value_get_boxed (param_values + 1), data2);
601 gst_value_take_buffer (return_value, v_return);
605 gst_play_bin_get_type (void)
607 static GType gst_play_bin_type = 0;
609 if (!gst_play_bin_type) {
610 static const GTypeInfo gst_play_bin_info = {
611 sizeof (GstPlayBinClass),
614 (GClassInitFunc) gst_play_bin_class_init,
619 (GInstanceInitFunc) gst_play_bin_init,
622 static const GInterfaceInfo svol_info = {
626 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
627 "GstPlayBin2", &gst_play_bin_info, 0);
629 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
633 return gst_play_bin_type;
637 gst_play_bin_class_init (GstPlayBinClass * klass)
639 GObjectClass *gobject_klass;
640 GstElementClass *gstelement_klass;
641 GstBinClass *gstbin_klass;
643 gobject_klass = (GObjectClass *) klass;
644 gstelement_klass = (GstElementClass *) klass;
645 gstbin_klass = (GstBinClass *) klass;
647 parent_class = g_type_class_peek_parent (klass);
649 gobject_klass->set_property = gst_play_bin_set_property;
650 gobject_klass->get_property = gst_play_bin_get_property;
652 gobject_klass->finalize = gst_play_bin_finalize;
657 * Set the next URI that playbin will play. This property can be set from the
658 * about-to-finish signal to queue the next media file.
660 g_object_class_install_property (gobject_klass, PROP_URI,
661 g_param_spec_string ("uri", "URI", "URI of the media to play",
662 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
667 * Set the next subtitle URI that playbin will play. This property can be
668 * set from the about-to-finish signal to queue the next subtitle media file.
670 g_object_class_install_property (gobject_klass, PROP_SUBURI,
671 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
672 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
674 g_object_class_install_property (gobject_klass, PROP_SOURCE,
675 g_param_spec_object ("source", "Source", "Source element",
676 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
681 * Control the behaviour of playbin.
683 g_object_class_install_property (gobject_klass, PROP_FLAGS,
684 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
685 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
686 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
689 * GstPlayBin2:n-video
691 * Get the total number of available video streams.
693 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
694 g_param_spec_int ("n-video", "Number Video",
695 "Total number of video streams", 0, G_MAXINT, 0,
696 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
698 * GstPlayBin2:current-video
700 * Get or set the currently playing video stream. By default the first video
701 * stream with data is played.
703 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
704 g_param_spec_int ("current-video", "Current Video",
705 "Currently playing video stream (-1 = auto)",
706 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
708 * GstPlayBin2:n-audio
710 * Get the total number of available audio streams.
712 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
713 g_param_spec_int ("n-audio", "Number Audio",
714 "Total number of audio streams", 0, G_MAXINT, 0,
715 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
717 * GstPlayBin2:current-audio
719 * Get or set the currently playing audio stream. By default the first audio
720 * stream with data is played.
722 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
723 g_param_spec_int ("current-audio", "Current audio",
724 "Currently playing audio stream (-1 = auto)",
725 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
729 * Get the total number of available subtitle streams.
731 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
732 g_param_spec_int ("n-text", "Number Text",
733 "Total number of text streams", 0, G_MAXINT, 0,
734 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
736 * GstPlayBin2:current-text:
738 * Get or set the currently playing subtitle stream. By default the first
739 * subtitle stream with data is played.
741 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
742 g_param_spec_int ("current-text", "Current Text",
743 "Currently playing text stream (-1 = auto)",
744 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
746 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
747 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
748 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
749 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
750 "be checked for an encoding to use. If that is not set either, "
751 "ISO-8859-15 will be assumed.", NULL,
752 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
754 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
755 g_param_spec_object ("video-sink", "Video Sink",
756 "the video output element to use (NULL = default sink)",
757 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
758 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
759 g_param_spec_object ("audio-sink", "Audio Sink",
760 "the audio output element to use (NULL = default sink)",
761 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
762 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
763 g_param_spec_object ("vis-plugin", "Vis plugin",
764 "the visualization element to use (NULL = default)",
765 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
766 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
767 g_param_spec_object ("text-sink", "Text plugin",
768 "the text output element to use (NULL = default textoverlay)",
769 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
772 * GstPlayBin2:volume:
774 * Get or set the current audio stream volume. 1.0 means 100%,
775 * 0.0 means mute. This uses a linear volume scale.
778 g_object_class_install_property (gobject_klass, PROP_VOLUME,
779 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
780 0.0, VOLUME_MAX_DOUBLE, 1.0,
781 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
782 g_object_class_install_property (gobject_klass, PROP_MUTE,
783 g_param_spec_boolean ("mute", "Mute",
784 "Mute the audio channel without changing the volume", FALSE,
785 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
789 * @playbin: a #GstPlayBin2
791 * Get the currently rendered or prerolled frame in the sink.
792 * The #GstCaps on the buffer will describe the format of the buffer.
794 g_object_class_install_property (gobject_klass, PROP_FRAME,
795 gst_param_spec_mini_object ("frame", "Frame",
796 "The last frame (NULL = no video available)",
797 GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
798 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
799 g_param_spec_string ("subtitle-font-desc",
800 "Subtitle font description",
801 "Pango font description of font "
802 "to be used for subtitle rendering", NULL,
803 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
805 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
806 g_param_spec_uint ("connection-speed", "Connection Speed",
807 "Network connection speed in kbps (0 = unknown)",
808 0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
809 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
811 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
812 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
813 "Buffer size when buffering network streams",
814 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
815 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
816 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
817 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
818 "Buffer duration when buffering network streams",
819 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
820 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
823 * GstPlayBin2::about-to-finish
824 * @playbin: a #GstPlayBin2
826 * This signal is emitted when the current uri is about to finish. You can
827 * set the uri and suburi to make sure that playback continues.
829 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
830 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
832 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
833 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
836 * GstPlayBin2::video-changed
837 * @playbin: a #GstPlayBin2
839 * This signal is emitted whenever the number or order of the video
840 * streams has changed. The application will most likely want to select
841 * a new video stream.
843 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
844 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
846 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
847 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
849 * GstPlayBin2::audio-changed
850 * @playbin: a #GstPlayBin2
852 * This signal is emitted whenever the number or order of the audio
853 * streams has changed. The application will most likely want to select
854 * a new audio stream.
856 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
857 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
859 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
860 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
862 * GstPlayBin2::text-changed
863 * @playbin: a #GstPlayBin2
865 * This signal is emitted whenever the number or order of the text
866 * streams has changed. The application will most likely want to select
869 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
870 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
872 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
873 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
876 * GstPlayBin2::video-tags-changed
877 * @playbin: a #GstPlayBin2
878 * @stream: stream index with changed tags
880 * This signal is emitted whenever the tags of a video stream have changed.
881 * The application will most likely want to get the new tags.
885 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
886 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
888 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
889 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
892 * GstPlayBin2::audio-tags-changed
893 * @playbin: a #GstPlayBin2
894 * @stream: stream index with changed tags
896 * This signal is emitted whenever the tags of an audio stream have changed.
897 * The application will most likely want to get the new tags.
901 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
902 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
904 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
905 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
908 * GstPlayBin2::text-tags-changed
909 * @playbin: a #GstPlayBin2
910 * @stream: stream index with changed tags
912 * This signal is emitted whenever the tags of a text stream have changed.
913 * The application will most likely want to get the new tags.
917 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
918 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
920 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
921 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
924 * GstPlayBin2::get-video-tags
925 * @playbin: a #GstPlayBin2
926 * @stream: a video stream number
928 * Action signal to retrieve the tags of a specific video stream number.
929 * This information can be used to select a stream.
931 * Returns: a GstTagList with tags or NULL when the stream number does not
934 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
935 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
936 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
937 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
938 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
940 * GstPlayBin2::get-audio-tags
941 * @playbin: a #GstPlayBin2
942 * @stream: an audio stream number
944 * Action signal to retrieve the tags of a specific audio stream number.
945 * This information can be used to select a stream.
947 * Returns: a GstTagList with tags or NULL when the stream number does not
950 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
951 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
952 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
953 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
954 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
956 * GstPlayBin2::get-text-tags
957 * @playbin: a #GstPlayBin2
958 * @stream: a text stream number
960 * Action signal to retrieve the tags of a specific text stream number.
961 * This information can be used to select a stream.
963 * Returns: a GstTagList with tags or NULL when the stream number does not
966 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
967 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
968 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
969 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
970 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
972 * GstPlayBin2::convert-frame
973 * @playbin: a #GstPlayBin2
974 * @caps: the target format of the frame
976 * Action signal to retrieve the currently playing video frame in the format
977 * specified by @caps.
978 * If @caps is %NULL, no conversion will be performed and this function is
979 * equivalent to the #GstPlayBin::frame property.
981 * Returns: a #GstBuffer of the current video frame converted to #caps.
982 * The caps on the buffer will describe the final layout of the buffer data.
983 * %NULL is returned when no current buffer can be retrieved or when the
986 gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
987 g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
988 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
989 G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
990 gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
993 * GstPlayBin2::get-video-pad
994 * @playbin: a #GstPlayBin2
995 * @stream: a video stream number
997 * Action signal to retrieve the stream-selector sinkpad for a specific
999 * This pad can be used for notifications of caps changes, stream-specific
1002 * Returns: a #GstPad, or NULL when the stream number does not exist.
1004 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1005 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1006 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1007 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1008 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1010 * GstPlayBin2::get-audio-pad
1011 * @playbin: a #GstPlayBin2
1012 * @stream: an audio stream number
1014 * Action signal to retrieve the stream-selector sinkpad for a specific
1016 * This pad can be used for notifications of caps changes, stream-specific
1019 * Returns: a #GstPad, or NULL when the stream number does not exist.
1021 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1022 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1023 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1024 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1025 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1027 * GstPlayBin2::get-text-pad
1028 * @playbin: a #GstPlayBin2
1029 * @stream: a text stream number
1031 * Action signal to retrieve the stream-selector sinkpad for a specific
1033 * This pad can be used for notifications of caps changes, stream-specific
1036 * Returns: a #GstPad, or NULL when the stream number does not exist.
1038 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1039 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1040 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1041 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1042 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1044 klass->get_video_tags = gst_play_bin_get_video_tags;
1045 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1046 klass->get_text_tags = gst_play_bin_get_text_tags;
1048 klass->convert_frame = gst_play_bin_convert_frame;
1050 klass->get_video_pad = gst_play_bin_get_video_pad;
1051 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1052 klass->get_text_pad = gst_play_bin_get_text_pad;
1054 gst_element_class_set_details_simple (gstelement_klass,
1055 "Player Bin 2", "Generic/Bin/Player",
1056 "Autoplug and play media from an uri",
1057 "Wim Taymans <wim.taymans@gmail.com>");
1059 gstelement_klass->change_state =
1060 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1061 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1063 gstbin_klass->handle_message =
1064 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1068 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1070 /* store the array for the different channels */
1071 group->video_channels = g_ptr_array_new ();
1072 group->audio_channels = g_ptr_array_new ();
1073 group->text_channels = g_ptr_array_new ();
1074 group->lock = g_mutex_new ();
1075 /* init selectors. The selector is found by finding the first prefix that
1076 * matches the media. */
1077 group->playbin = playbin;
1078 /* If you add any items to these lists, check that media_list[] is defined
1079 * above to be large enough to hold MAX(items)+1, so as to accomodate a
1080 * NULL terminator (set when the memory is zeroed on allocation) */
1081 group->selector[0].media_list[0] = "audio/x-raw-";
1082 group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
1083 group->selector[0].channels = group->audio_channels;
1084 group->selector[1].media_list[0] = "audio/";
1085 group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO;
1086 group->selector[1].channels = group->audio_channels;
1087 group->selector[2].media_list[0] = "text/";
1088 group->selector[2].media_list[1] = "application/x-subtitle";
1089 group->selector[2].media_list[2] = "application/x-ssa";
1090 group->selector[2].media_list[3] = "application/x-ass";
1091 group->selector[2].media_list[4] = "video/x-dvd-subpicture";
1092 group->selector[2].media_list[5] = "subpicture/";
1093 group->selector[2].media_list[6] = "subtitle/";
1094 group->selector[2].get_media_caps = gst_subtitle_overlay_create_factory_caps;
1095 group->selector[2].type = GST_PLAY_SINK_TYPE_TEXT;
1096 group->selector[2].channels = group->text_channels;
1097 group->selector[3].media_list[0] = "video/x-raw-";
1098 group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
1099 group->selector[3].channels = group->video_channels;
1100 group->selector[4].media_list[0] = "video/";
1101 group->selector[4].type = GST_PLAY_SINK_TYPE_VIDEO;
1102 group->selector[4].channels = group->video_channels;
1106 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1108 g_free (group->uri);
1109 g_free (group->suburi);
1110 g_ptr_array_free (group->video_channels, TRUE);
1111 g_ptr_array_free (group->audio_channels, TRUE);
1112 g_ptr_array_free (group->text_channels, TRUE);
1114 g_mutex_free (group->lock);
1115 if (group->audio_sink)
1116 gst_object_unref (group->audio_sink);
1117 group->audio_sink = NULL;
1118 if (group->video_sink)
1119 gst_object_unref (group->video_sink);
1120 group->video_sink = NULL;
1122 g_list_free (group->stream_changed_pending);
1123 group->stream_changed_pending = NULL;
1125 if (group->stream_changed_pending_lock)
1126 g_mutex_free (group->stream_changed_pending_lock);
1127 group->stream_changed_pending_lock = NULL;
1131 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1133 g_object_notify (G_OBJECT (playbin), "volume");
1137 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1139 g_object_notify (G_OBJECT (playbin), "mute");
1142 /* Must be called with elements lock! */
1144 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1146 if (!playbin->elements ||
1147 playbin->elements_cookie !=
1148 gst_default_registry_get_feature_list_cookie ()) {
1149 if (playbin->elements)
1150 g_value_array_free (playbin->elements);
1152 gst_factory_list_get_elements (GST_FACTORY_LIST_DECODER |
1153 GST_FACTORY_LIST_SINK);
1154 playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1159 gst_play_bin_init (GstPlayBin * playbin)
1161 playbin->lock = g_mutex_new ();
1162 playbin->dyn_lock = g_mutex_new ();
1164 /* assume we can create a selector */
1165 playbin->have_selector = TRUE;
1168 playbin->curr_group = &playbin->groups[0];
1169 playbin->next_group = &playbin->groups[1];
1170 init_group (playbin, &playbin->groups[0]);
1171 init_group (playbin, &playbin->groups[1]);
1173 /* first filter out the interesting element factories */
1174 playbin->elements_lock = g_mutex_new ();
1175 gst_play_bin_update_elements_list (playbin);
1176 GST_FACTORY_LIST_DEBUG (playbin->elements);
1179 playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
1180 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1181 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1182 /* Connect to notify::volume and notify::mute signals for proxying */
1183 g_signal_connect (playbin->playsink, "notify::volume",
1184 G_CALLBACK (notify_volume_cb), playbin);
1185 g_signal_connect (playbin->playsink, "notify::mute",
1186 G_CALLBACK (notify_mute_cb), playbin);
1188 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1189 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1190 playbin->current_text = DEFAULT_CURRENT_TEXT;
1192 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1193 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1197 gst_play_bin_finalize (GObject * object)
1199 GstPlayBin *playbin;
1201 playbin = GST_PLAY_BIN (object);
1203 free_group (playbin, &playbin->groups[0]);
1204 free_group (playbin, &playbin->groups[1]);
1206 if (playbin->source)
1207 gst_object_unref (playbin->source);
1208 if (playbin->video_sink)
1209 gst_object_unref (playbin->video_sink);
1210 if (playbin->audio_sink)
1211 gst_object_unref (playbin->audio_sink);
1212 if (playbin->text_sink)
1213 gst_object_unref (playbin->text_sink);
1215 g_value_array_free (playbin->elements);
1216 g_mutex_free (playbin->lock);
1217 g_mutex_free (playbin->dyn_lock);
1218 g_mutex_free (playbin->elements_lock);
1220 G_OBJECT_CLASS (parent_class)->finalize (object);
1224 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1226 GstSourceGroup *group;
1229 g_warning ("cannot set NULL uri");
1233 GST_PLAY_BIN_LOCK (playbin);
1234 group = playbin->next_group;
1236 GST_SOURCE_GROUP_LOCK (group);
1237 /* store the uri in the next group we will play */
1238 g_free (group->uri);
1239 group->uri = g_strdup (uri);
1240 group->valid = TRUE;
1241 GST_SOURCE_GROUP_UNLOCK (group);
1243 GST_DEBUG ("set new uri to %s", uri);
1244 GST_PLAY_BIN_UNLOCK (playbin);
1248 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1250 GstSourceGroup *group;
1252 GST_PLAY_BIN_LOCK (playbin);
1253 group = playbin->next_group;
1255 GST_SOURCE_GROUP_LOCK (group);
1256 g_free (group->suburi);
1257 group->suburi = g_strdup (suburi);
1258 GST_SOURCE_GROUP_UNLOCK (group);
1260 GST_DEBUG ("setting new .sub uri to %s", suburi);
1262 GST_PLAY_BIN_UNLOCK (playbin);
1266 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1268 gst_play_sink_set_flags (playbin->playsink, flags);
1269 gst_play_sink_reconfigure (playbin->playsink);
1273 gst_play_bin_get_flags (GstPlayBin * playbin)
1277 flags = gst_play_sink_get_flags (playbin->playsink);
1282 /* get the currently playing group or if nothing is playing, the next
1283 * group. Must be called with the PLAY_BIN_LOCK. */
1284 static GstSourceGroup *
1285 get_group (GstPlayBin * playbin)
1287 GstSourceGroup *result;
1289 if (!(result = playbin->curr_group))
1290 result = playbin->next_group;
1296 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1298 GstPad *sinkpad = NULL;
1299 GstSourceGroup *group;
1301 GST_PLAY_BIN_LOCK (playbin);
1302 group = get_group (playbin);
1303 if (stream < group->video_channels->len) {
1304 sinkpad = g_ptr_array_index (group->video_channels, stream);
1305 gst_object_ref (sinkpad);
1307 GST_PLAY_BIN_UNLOCK (playbin);
1313 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1315 GstPad *sinkpad = NULL;
1316 GstSourceGroup *group;
1318 GST_PLAY_BIN_LOCK (playbin);
1319 group = get_group (playbin);
1320 if (stream < group->audio_channels->len) {
1321 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1322 gst_object_ref (sinkpad);
1324 GST_PLAY_BIN_UNLOCK (playbin);
1330 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1332 GstPad *sinkpad = NULL;
1333 GstSourceGroup *group;
1335 GST_PLAY_BIN_LOCK (playbin);
1336 group = get_group (playbin);
1337 if (stream < group->text_channels->len) {
1338 sinkpad = g_ptr_array_index (group->text_channels, stream);
1339 gst_object_ref (sinkpad);
1341 GST_PLAY_BIN_UNLOCK (playbin);
1348 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1353 if (!channels || stream >= channels->len)
1356 sinkpad = g_ptr_array_index (channels, stream);
1357 g_object_get (sinkpad, "tags", &result, NULL);
1363 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1366 GstSourceGroup *group;
1368 GST_PLAY_BIN_LOCK (playbin);
1369 group = get_group (playbin);
1370 result = get_tags (playbin, group->video_channels, stream);
1371 GST_PLAY_BIN_UNLOCK (playbin);
1377 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1380 GstSourceGroup *group;
1382 GST_PLAY_BIN_LOCK (playbin);
1383 group = get_group (playbin);
1384 result = get_tags (playbin, group->audio_channels, stream);
1385 GST_PLAY_BIN_UNLOCK (playbin);
1391 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1394 GstSourceGroup *group;
1396 GST_PLAY_BIN_LOCK (playbin);
1397 group = get_group (playbin);
1398 result = get_tags (playbin, group->text_channels, stream);
1399 GST_PLAY_BIN_UNLOCK (playbin);
1405 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1409 result = gst_play_sink_get_last_frame (playbin->playsink);
1410 if (result != NULL && caps != NULL) {
1413 temp = gst_play_frame_conv_convert (result, caps);
1414 gst_buffer_unref (result);
1420 /* Returns current stream number, or -1 if none has been selected yet */
1422 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1424 /* Internal API cleanup would make this easier... */
1426 GstPad *pad, *current;
1427 GstObject *selector = NULL;
1430 for (i = 0; i < channels->len; i++) {
1431 pad = g_ptr_array_index (channels, i);
1432 if ((selector = gst_pad_get_parent (pad))) {
1433 g_object_get (selector, "active-pad", ¤t, NULL);
1434 gst_object_unref (selector);
1436 if (pad == current) {
1437 gst_object_unref (current);
1443 gst_object_unref (current);
1451 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1453 GstSourceGroup *group;
1454 GPtrArray *channels;
1457 GST_PLAY_BIN_LOCK (playbin);
1458 group = get_group (playbin);
1459 if (!(channels = group->video_channels))
1462 if (stream == -1 || channels->len <= stream) {
1465 /* take channel from selected stream */
1466 sinkpad = g_ptr_array_index (channels, stream);
1470 gst_object_ref (sinkpad);
1471 GST_PLAY_BIN_UNLOCK (playbin);
1474 GstObject *selector;
1476 if ((selector = gst_pad_get_parent (sinkpad))) {
1477 /* activate the selected pad */
1478 g_object_set (selector, "active-pad", sinkpad, NULL);
1479 gst_object_unref (selector);
1481 gst_object_unref (sinkpad);
1487 GST_PLAY_BIN_UNLOCK (playbin);
1493 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1495 GstSourceGroup *group;
1496 GPtrArray *channels;
1499 GST_PLAY_BIN_LOCK (playbin);
1500 group = get_group (playbin);
1501 if (!(channels = group->audio_channels))
1504 if (stream == -1 || channels->len <= stream) {
1507 /* take channel from selected stream */
1508 sinkpad = g_ptr_array_index (channels, stream);
1512 gst_object_ref (sinkpad);
1513 GST_PLAY_BIN_UNLOCK (playbin);
1516 GstObject *selector;
1518 if ((selector = gst_pad_get_parent (sinkpad))) {
1519 /* activate the selected pad */
1520 g_object_set (selector, "active-pad", sinkpad, NULL);
1521 gst_object_unref (selector);
1523 gst_object_unref (sinkpad);
1529 GST_PLAY_BIN_UNLOCK (playbin);
1535 _suburidecodebin_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
1537 GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
1541 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1543 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1546 if (it && gst_iterator_next (it, (gpointer) & sinkpad) == GST_ITERATOR_OK
1551 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1552 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1553 if (!gst_pad_send_event (sinkpad, event)) {
1555 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1556 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1557 if (!gst_pad_send_event (sinkpad, event))
1558 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1561 gst_object_unref (sinkpad);
1565 gst_iterator_free (it);
1569 gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
1572 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1573 gboolean done = FALSE;
1575 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1582 switch (gst_iterator_next (it, (gpointer) & sinkpad)) {
1583 case GST_ITERATOR_OK:
1584 gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
1586 gst_object_unref (sinkpad);
1588 case GST_ITERATOR_DONE:
1591 case GST_ITERATOR_RESYNC:
1592 gst_iterator_resync (it);
1594 case GST_ITERATOR_ERROR:
1599 gst_iterator_free (it);
1603 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1605 GstSourceGroup *group;
1606 GPtrArray *channels;
1609 GST_PLAY_BIN_LOCK (playbin);
1610 group = get_group (playbin);
1611 if (!(channels = group->text_channels))
1614 if (stream == -1 || channels->len <= stream) {
1617 /* take channel from selected stream */
1618 sinkpad = g_ptr_array_index (channels, stream);
1622 gst_object_ref (sinkpad);
1623 GST_PLAY_BIN_UNLOCK (playbin);
1626 GstObject *selector;
1628 if ((selector = gst_pad_get_parent (sinkpad))) {
1629 GstPad *old_sinkpad;
1631 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1633 if (old_sinkpad != sinkpad) {
1634 gboolean need_unblock, need_block, need_seek;
1635 GstPad *src, *peer = NULL, *oldpeer = NULL;
1636 GstElement *parent_element = NULL, *old_parent_element = NULL;
1638 /* Now check if we need to seek the suburidecodebin to the beginning
1639 * or if we need to block all suburidecodebin sinkpads or if we need
1640 * to unblock all suburidecodebin sinkpads
1643 peer = gst_pad_get_peer (sinkpad);
1645 oldpeer = gst_pad_get_peer (old_sinkpad);
1648 parent_element = gst_pad_get_parent_element (peer);
1650 old_parent_element = gst_pad_get_parent_element (oldpeer);
1652 need_block = (old_parent_element == group->suburidecodebin
1653 && parent_element != old_parent_element);
1654 need_unblock = (parent_element == group->suburidecodebin
1655 && parent_element != old_parent_element);
1656 need_seek = (parent_element == group->suburidecodebin);
1659 gst_object_unref (peer);
1661 gst_object_unref (oldpeer);
1663 gst_object_unref (parent_element);
1664 if (old_parent_element)
1665 gst_object_unref (old_parent_element);
1667 /* Block all suburidecodebin sinkpads */
1669 gst_play_bin_suburidecodebin_block (group->suburidecodebin, TRUE);
1671 /* activate the selected pad */
1672 g_object_set (selector, "active-pad", sinkpad, NULL);
1674 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1675 peer = gst_pad_get_peer (src);
1679 /* Flush the subtitle renderer to remove any
1680 * currently displayed subtitles. This event will
1681 * never travel outside subtitleoverlay!
1683 s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1684 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1685 gst_pad_send_event (peer, event);
1686 gst_object_unref (peer);
1688 gst_object_unref (src);
1690 /* Unblock pads if necessary */
1692 gst_play_bin_suburidecodebin_block (group->suburidecodebin, FALSE);
1694 /* seek to the beginning */
1696 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1698 gst_object_unref (selector);
1701 gst_object_unref (old_sinkpad);
1703 gst_object_unref (sinkpad);
1709 GST_PLAY_BIN_UNLOCK (playbin);
1715 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1716 const gchar * dbg, GstElement * sink)
1718 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1720 GST_PLAY_BIN_LOCK (playbin);
1721 if (*elem != sink) {
1726 gst_object_ref_sink (sink);
1730 gst_object_unref (old);
1732 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1733 GST_PLAY_BIN_UNLOCK (playbin);
1737 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1741 GST_PLAY_BIN_LOCK (playbin);
1743 /* set subtitles on all current and next decodebins. */
1744 if ((elem = playbin->groups[0].uridecodebin))
1745 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1746 if ((elem = playbin->groups[0].suburidecodebin))
1747 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1748 if ((elem = playbin->groups[1].uridecodebin))
1749 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1750 if ((elem = playbin->groups[1].suburidecodebin))
1751 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1753 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1754 GST_PLAY_BIN_UNLOCK (playbin);
1758 gst_play_bin_set_property (GObject * object, guint prop_id,
1759 const GValue * value, GParamSpec * pspec)
1761 GstPlayBin *playbin = GST_PLAY_BIN (object);
1765 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1768 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1771 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1773 case PROP_CURRENT_VIDEO:
1774 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1776 case PROP_CURRENT_AUDIO:
1777 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1779 case PROP_CURRENT_TEXT:
1780 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1782 case PROP_SUBTITLE_ENCODING:
1783 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1785 case PROP_VIDEO_SINK:
1786 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1787 g_value_get_object (value));
1789 case PROP_AUDIO_SINK:
1790 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1791 g_value_get_object (value));
1793 case PROP_VIS_PLUGIN:
1794 gst_play_sink_set_vis_plugin (playbin->playsink,
1795 g_value_get_object (value));
1797 case PROP_TEXT_SINK:
1798 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1799 g_value_get_object (value));
1802 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1805 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1807 case PROP_FONT_DESC:
1808 gst_play_sink_set_font_desc (playbin->playsink,
1809 g_value_get_string (value));
1811 case PROP_CONNECTION_SPEED:
1812 GST_PLAY_BIN_LOCK (playbin);
1813 playbin->connection_speed = g_value_get_uint (value) * 1000;
1814 GST_PLAY_BIN_UNLOCK (playbin);
1816 case PROP_BUFFER_SIZE:
1817 playbin->buffer_size = g_value_get_int (value);
1819 case PROP_BUFFER_DURATION:
1820 playbin->buffer_duration = g_value_get_int64 (value);
1823 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1829 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
1830 const gchar * dbg, GstPlaySinkType type)
1832 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
1834 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
1835 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
1836 dbg, sink, dbg, *elem);
1839 GST_PLAY_BIN_LOCK (playbin);
1841 gst_object_ref (sink);
1842 GST_PLAY_BIN_UNLOCK (playbin);
1849 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
1852 GstPlayBin *playbin = GST_PLAY_BIN (object);
1857 GstSourceGroup *group;
1859 GST_PLAY_BIN_LOCK (playbin);
1860 group = get_group (playbin);
1861 g_value_set_string (value, group->uri);
1862 GST_PLAY_BIN_UNLOCK (playbin);
1867 GstSourceGroup *group;
1869 GST_PLAY_BIN_LOCK (playbin);
1870 group = get_group (playbin);
1871 g_value_set_string (value, group->suburi);
1872 GST_PLAY_BIN_UNLOCK (playbin);
1877 GST_OBJECT_LOCK (playbin);
1878 g_value_set_object (value, playbin->source);
1879 GST_OBJECT_UNLOCK (playbin);
1883 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
1887 GstSourceGroup *group;
1890 GST_PLAY_BIN_LOCK (playbin);
1891 group = get_group (playbin);
1892 n_video = (group->video_channels ? group->video_channels->len : 0);
1893 g_value_set_int (value, n_video);
1894 GST_PLAY_BIN_UNLOCK (playbin);
1897 case PROP_CURRENT_VIDEO:
1898 GST_PLAY_BIN_LOCK (playbin);
1899 g_value_set_int (value, playbin->current_video);
1900 GST_PLAY_BIN_UNLOCK (playbin);
1904 GstSourceGroup *group;
1907 GST_PLAY_BIN_LOCK (playbin);
1908 group = get_group (playbin);
1909 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
1910 g_value_set_int (value, n_audio);
1911 GST_PLAY_BIN_UNLOCK (playbin);
1914 case PROP_CURRENT_AUDIO:
1915 GST_PLAY_BIN_LOCK (playbin);
1916 g_value_set_int (value, playbin->current_audio);
1917 GST_PLAY_BIN_UNLOCK (playbin);
1921 GstSourceGroup *group;
1924 GST_PLAY_BIN_LOCK (playbin);
1925 group = get_group (playbin);
1926 n_text = (group->text_channels ? group->text_channels->len : 0);
1927 g_value_set_int (value, n_text);
1928 GST_PLAY_BIN_UNLOCK (playbin);
1931 case PROP_CURRENT_TEXT:
1932 GST_PLAY_BIN_LOCK (playbin);
1933 g_value_set_int (value, playbin->current_text);
1934 GST_PLAY_BIN_UNLOCK (playbin);
1936 case PROP_SUBTITLE_ENCODING:
1937 GST_PLAY_BIN_LOCK (playbin);
1938 g_value_take_string (value,
1939 gst_play_sink_get_subtitle_encoding (playbin->playsink));
1940 GST_PLAY_BIN_UNLOCK (playbin);
1942 case PROP_VIDEO_SINK:
1943 g_value_take_object (value,
1944 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
1945 "video", GST_PLAY_SINK_TYPE_VIDEO));
1947 case PROP_AUDIO_SINK:
1948 g_value_take_object (value,
1949 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
1950 "audio", GST_PLAY_SINK_TYPE_AUDIO));
1952 case PROP_VIS_PLUGIN:
1953 g_value_take_object (value,
1954 gst_play_sink_get_vis_plugin (playbin->playsink));
1956 case PROP_TEXT_SINK:
1957 g_value_take_object (value,
1958 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
1959 "text", GST_PLAY_SINK_TYPE_TEXT));
1962 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
1965 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
1968 gst_value_take_buffer (value, gst_play_bin_convert_frame (playbin, NULL));
1970 case PROP_FONT_DESC:
1971 g_value_take_string (value,
1972 gst_play_sink_get_font_desc (playbin->playsink));
1974 case PROP_CONNECTION_SPEED:
1975 GST_PLAY_BIN_LOCK (playbin);
1976 g_value_set_uint (value, playbin->connection_speed / 1000);
1977 GST_PLAY_BIN_UNLOCK (playbin);
1979 case PROP_BUFFER_SIZE:
1980 GST_OBJECT_LOCK (playbin);
1981 g_value_set_int (value, playbin->buffer_size);
1982 GST_OBJECT_UNLOCK (playbin);
1984 case PROP_BUFFER_DURATION:
1985 GST_OBJECT_LOCK (playbin);
1986 g_value_set_int64 (value, playbin->buffer_duration);
1987 GST_OBJECT_UNLOCK (playbin);
1990 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1996 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
1997 gboolean valid, GstQuery * query)
2003 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2004 gst_query_parse_duration (query, &fmt, &duration);
2006 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2007 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2008 playbin->duration[i].valid = valid;
2009 playbin->duration[i].format = fmt;
2010 playbin->duration[i].duration = valid ? duration : -1;
2017 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2019 const GstFormat formats[] =
2020 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2025 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2026 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2027 query = gst_query_new_duration (formats[i]);
2029 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2031 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2032 gst_query_unref (query);
2037 gst_play_bin_query (GstElement * element, GstQuery * query)
2039 GstPlayBin *playbin = GST_PLAY_BIN (element);
2042 /* During a group switch we shouldn't allow duration queries
2043 * because it's not clear if the old or new group's duration
2044 * is returned and if the sinks are already playing new data
2045 * or old data. See bug #585969
2047 * While we're at it, also don't do any other queries during
2048 * a group switch or any other event that causes topology changes
2049 * by taking the playbin lock in any case.
2051 GST_PLAY_BIN_LOCK (playbin);
2053 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2054 GstSourceGroup *group = playbin->curr_group;
2057 GST_SOURCE_GROUP_LOCK (group);
2058 if (group->stream_changed_pending_lock) {
2059 g_mutex_lock (group->stream_changed_pending_lock);
2060 pending = group->pending || group->stream_changed_pending;
2061 g_mutex_unlock (group->stream_changed_pending_lock);
2063 pending = group->pending;
2070 gst_query_parse_duration (query, &fmt, NULL);
2071 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2072 if (fmt == playbin->duration[i].format) {
2073 ret = playbin->duration[i].valid;
2074 gst_query_set_duration (query, fmt,
2075 (ret ? playbin->duration[i].duration : -1));
2079 /* if nothing cached yet, we might as well request duration,
2080 * such as during initial startup */
2082 GST_DEBUG_OBJECT (playbin,
2083 "Taking cached duration because of pending group switch: %d", ret);
2084 GST_SOURCE_GROUP_UNLOCK (group);
2085 GST_PLAY_BIN_UNLOCK (playbin);
2089 GST_SOURCE_GROUP_UNLOCK (group);
2092 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2094 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2095 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2096 GST_PLAY_BIN_UNLOCK (playbin);
2101 /* mime types we are not handling on purpose right now, don't post a
2102 * missing-plugin message for these */
2103 static const gchar *blacklisted_mimes[] = {
2108 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2110 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2111 GstSourceGroup *group;
2113 if (gst_is_missing_plugin_message (msg)) {
2117 detail = gst_missing_plugin_message_get_installer_detail (msg);
2118 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2119 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2120 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2121 gst_message_unref (msg);
2127 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2128 const GstStructure *s = gst_message_get_structure (msg);
2130 /* Drop all stream-changed messages except the last one */
2131 if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2132 guint32 seqnum = gst_message_get_seqnum (msg);
2135 group = playbin->curr_group;
2136 g_mutex_lock (group->stream_changed_pending_lock);
2137 for (l = group->stream_changed_pending; l;) {
2138 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2140 if (l_seqnum == seqnum) {
2143 group->stream_changed_pending =
2144 g_list_delete_link (group->stream_changed_pending, l_prev);
2145 if (group->stream_changed_pending) {
2146 gst_message_unref (msg);
2154 g_mutex_unlock (group->stream_changed_pending_lock);
2156 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2157 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2158 GstObject *src = GST_OBJECT_CAST (msg->src);
2160 /* Ignore async state changes from the uridecodebin children,
2161 * see bug #602000. */
2162 group = playbin->curr_group;
2163 if (src && (group = playbin->curr_group) &&
2164 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2165 || (group->suburidecodebin
2166 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2167 GST_DEBUG_OBJECT (playbin,
2168 "Ignoring async state change of uridecodebin: %s",
2169 GST_OBJECT_NAME (src));
2170 gst_message_unref (msg);
2173 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2174 /* If we get an error of the subtitle uridecodebin transform
2175 * them into warnings and disable the subtitles */
2176 group = playbin->curr_group;
2177 if (group && group->suburidecodebin) {
2178 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2179 (group->suburidecodebin)))) {
2181 gchar *debug = NULL;
2182 GstMessage *new_msg;
2184 gboolean done = FALSE;
2186 gst_message_parse_error (msg, &err, &debug);
2187 new_msg = gst_message_new_warning (msg->src, err, debug);
2189 gst_message_unref (msg);
2194 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2195 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2196 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2197 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2199 it = gst_element_iterate_src_pads (group->suburidecodebin);
2200 while (it && !done) {
2202 GstIteratorResult res;
2204 res = gst_iterator_next (it, (gpointer) & p);
2207 case GST_ITERATOR_DONE:
2210 case GST_ITERATOR_OK:
2211 pad_removed_cb (NULL, p, group);
2212 gst_object_unref (p);
2215 case GST_ITERATOR_RESYNC:
2216 gst_iterator_resync (it);
2218 case GST_ITERATOR_ERROR:
2224 gst_iterator_free (it);
2226 gst_object_ref (group->suburidecodebin);
2227 gst_bin_remove (bin, group->suburidecodebin);
2228 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2230 if (group->sub_pending) {
2231 group->sub_pending = FALSE;
2232 no_more_pads_cb (NULL, group);
2239 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2243 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2244 GstPlayBin * playbin)
2246 const gchar *property;
2247 GstSourceGroup *group;
2248 GstSourceSelect *select = NULL;
2251 GST_PLAY_BIN_LOCK (playbin);
2252 group = get_group (playbin);
2254 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2255 if (selector == G_OBJECT (group->selector[i].selector)) {
2256 select = &group->selector[i];
2260 /* We got a pad-change after our group got switched out; no need to notify */
2262 GST_PLAY_BIN_UNLOCK (playbin);
2266 switch (select->type) {
2267 case GST_PLAY_SINK_TYPE_VIDEO:
2268 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2269 property = "current-video";
2270 playbin->current_video = get_current_stream_number (playbin,
2271 group->video_channels);
2273 case GST_PLAY_SINK_TYPE_AUDIO:
2274 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2275 property = "current-audio";
2276 playbin->current_audio = get_current_stream_number (playbin,
2277 group->audio_channels);
2279 case GST_PLAY_SINK_TYPE_TEXT:
2280 property = "current-text";
2281 playbin->current_text = get_current_stream_number (playbin,
2282 group->text_channels);
2287 GST_PLAY_BIN_UNLOCK (playbin);
2290 g_object_notify (G_OBJECT (playbin), property);
2294 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
2297 GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
2300 /* helper function to lookup stuff in lists */
2302 array_has_value (const gchar * values[], const gchar * value)
2306 for (i = 0; values[i]; i++) {
2307 if (g_str_has_prefix (value, values[i]))
2315 GstPlayBin *playbin;
2317 GstPlaySinkType type;
2321 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2323 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2326 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2327 " with stream id %d and type %d have changed",
2328 object, ntdata->stream_id, ntdata->type);
2330 switch (ntdata->type) {
2331 case GST_PLAY_SINK_TYPE_VIDEO:
2332 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2333 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2335 case GST_PLAY_SINK_TYPE_AUDIO:
2336 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2337 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2339 case GST_PLAY_SINK_TYPE_TEXT:
2340 signal = SIGNAL_TEXT_TAGS_CHANGED;
2348 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2354 GstPlayBin *playbin;
2355 GstSourceGroup *group;
2356 GstPlaySinkType type;
2357 } PlaySinkEventProbeData;
2360 _playsink_src_event_probe_cb (GstPad * pad, GstEvent * event,
2361 PlaySinkEventProbeData * data)
2363 if (GST_EVENT_TYPE (event) == GST_EVENT_QOS) {
2364 GstEvent *new_event;
2367 GstClockTimeDiff diff;
2368 GstClockTime group_start_accum =
2369 data->group->selector[data->type].group_start_accum;
2370 GstClockTime timestamp;
2372 s = (GstStructure *) gst_event_get_structure (event);
2373 if (gst_structure_has_field (s, "playbin2-adjusted-event"))
2376 /* If we have no group start accumulator yet, this is
2377 * a QOS event for the previous group or this stream
2378 * has a non-time segment.
2380 if (!GST_CLOCK_TIME_IS_VALID (group_start_accum))
2383 /* If the group start accumulator is 0, this is the first
2384 * group and we don't need to do everything below
2386 if (group_start_accum == 0)
2389 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
2391 /* If the running time timestamp is smaller than the accumulator,
2392 * the event is for a buffer from the previous group
2394 if (timestamp >= group_start_accum)
2395 timestamp -= group_start_accum;
2399 /* That case is invalid for QoS events, also it means that
2400 * we have switched the group but receive QoS events of
2401 * the previous group.
2403 if (diff < 0 && -diff > timestamp)
2406 new_event = gst_event_new_qos (proportion, diff, timestamp);
2407 s = (GstStructure *) gst_event_get_structure (new_event);
2408 gst_structure_set (s, "playbin2-adjusted-event", G_TYPE_BOOLEAN, TRUE,
2410 gst_pad_send_event (pad, new_event);
2419 _playsink_sink_event_probe_cb (GstPad * pad, GstEvent * event,
2420 PlaySinkEventProbeData * data)
2424 if (data->type == GST_PLAY_SINK_TYPE_VIDEO
2425 || data->type == GST_PLAY_SINK_TYPE_VIDEO_RAW)
2427 else if (data->type == GST_PLAY_SINK_TYPE_AUDIO
2428 || data->type == GST_PLAY_SINK_TYPE_AUDIO_RAW)
2430 else if (data->type == GST_PLAY_SINK_TYPE_TEXT)
2433 g_assert_not_reached ();
2435 if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
2436 GstPlayBin *playbin = data->playbin;
2437 GstSegment *segment;
2440 gdouble rate, applied_rate;
2441 gint64 start, stop, pos;
2443 segment = &playbin->segments[index];
2445 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
2446 &format, &start, &stop, &pos);
2447 if (segment->format != format)
2448 gst_segment_init (segment, format);
2449 gst_segment_set_newsegment_full (segment, update, rate, applied_rate,
2450 format, start, stop, pos);
2452 if (format != GST_FORMAT_TIME)
2453 data->group->selector[data->type].group_start_accum = GST_CLOCK_TIME_NONE;
2454 else if (!GST_CLOCK_TIME_IS_VALID (data->group->selector[data->
2455 type].group_start_accum))
2456 data->group->selector[data->type].group_start_accum = segment->accum;
2457 } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2458 gst_segment_init (&data->playbin->segments[index], GST_FORMAT_UNDEFINED);
2464 /* this function is called when a new pad is added to decodebin. We check the
2465 * type of the pad and add it to the selector element of the group.
2468 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2470 GstPlayBin *playbin;
2472 const GstStructure *s;
2475 GstPadLinkReturn res;
2476 GstSourceSelect *select = NULL;
2478 gboolean changed = FALSE;
2480 playbin = group->playbin;
2482 caps = gst_pad_get_caps_reffed (pad);
2483 s = gst_caps_get_structure (caps, 0);
2484 name = gst_structure_get_name (s);
2486 GST_DEBUG_OBJECT (playbin,
2487 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2488 GST_DEBUG_PAD_NAME (pad), caps, group);
2490 /* major type of the pad, this determines the selector to use */
2491 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2492 if (array_has_value (group->selector[i].media_list, name)) {
2493 select = &group->selector[i];
2495 } else if (group->selector[i].get_media_caps) {
2496 GstCaps *media_caps = group->selector[i].get_media_caps ();
2498 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2499 select = &group->selector[i];
2500 gst_caps_unref (media_caps);
2503 gst_caps_unref (media_caps);
2506 /* no selector found for the media type, don't bother linking it to a
2507 * selector. This will leave the pad unlinked and thus ignored. */
2511 GST_SOURCE_GROUP_LOCK (group);
2512 if (select->selector == NULL && playbin->have_selector) {
2513 /* no selector, create one */
2514 GST_DEBUG_OBJECT (playbin, "creating new selector");
2515 select->selector = g_object_new (GST_TYPE_INPUT_SELECTOR, NULL);
2516 /* the above can't fail, but we keep the error handling around for when
2517 * the selector plugin has moved to -base or -good and we stop using an
2518 * internal copy of input-selector */
2519 if (select->selector == NULL) {
2520 /* post the missing selector message only once */
2521 playbin->have_selector = FALSE;
2522 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2523 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2525 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2526 (_("Missing element '%s' - check your GStreamer installation."),
2527 "input-selector"), (NULL));
2529 g_signal_connect (select->selector, "notify::active-pad",
2530 G_CALLBACK (selector_active_pad_changed), playbin);
2532 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2533 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2534 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2538 if (select->srcpad == NULL) {
2539 PlaySinkEventProbeData *data = g_new (PlaySinkEventProbeData, 1);
2541 if (select->selector) {
2542 /* save source pad of the selector */
2543 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2545 /* no selector, use the pad as the source pad then */
2546 select->srcpad = gst_object_ref (pad);
2549 /* Install an event probe */
2550 data->playbin = playbin;
2551 data->group = group;
2552 data->type = select->type;
2553 select->src_event_probe_id =
2554 gst_pad_add_event_probe_full (select->srcpad,
2555 G_CALLBACK (_playsink_src_event_probe_cb), data,
2556 (GDestroyNotify) g_free);
2558 select->group_start_accum = -1;
2560 /* block the selector srcpad. It's possible that multiple decodebins start
2561 * pushing data into the selectors before we have a chance to collect all
2562 * streams and connect the sinks, resulting in not-linked errors. After we
2563 * configured the sinks we will unblock them all. */
2564 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2565 gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
2568 /* get sinkpad for the new stream */
2569 if (select->selector) {
2570 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2571 gulong notify_tags_handler = 0;
2572 NotifyTagsData *ntdata;
2574 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2575 GST_DEBUG_PAD_NAME (sinkpad));
2577 /* store the selector for the pad */
2578 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2580 /* connect to the notify::tags signal for our
2581 * own *-tags-changed signals
2583 ntdata = g_new0 (NotifyTagsData, 1);
2584 ntdata->playbin = playbin;
2585 ntdata->stream_id = select->channels->len;
2586 ntdata->type = select->type;
2588 notify_tags_handler =
2589 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2590 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2592 g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2593 (gpointer) notify_tags_handler);
2595 /* store the pad in the array */
2596 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2597 g_ptr_array_add (select->channels, sinkpad);
2599 res = gst_pad_link (pad, sinkpad);
2600 if (GST_PAD_LINK_FAILED (res))
2603 /* store selector pad so we can release it */
2604 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2607 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2608 GST_DEBUG_PAD_NAME (pad), select->selector);
2611 /* no selector, don't configure anything, we'll link the new pad directly to
2616 GST_SOURCE_GROUP_UNLOCK (group);
2620 gboolean always_ok = (decodebin == group->suburidecodebin);
2622 switch (select->type) {
2623 case GST_PLAY_SINK_TYPE_VIDEO:
2624 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2625 /* we want to return NOT_LINKED for unselected pads but only for pads
2626 * from the normal uridecodebin. This makes sure that subtitle streams
2627 * are not raced past audio/video from decodebin2's multiqueue.
2628 * For pads from suburidecodebin OK should always be returned, otherwise
2629 * it will most likely stop. */
2630 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2631 signal = SIGNAL_VIDEO_CHANGED;
2633 case GST_PLAY_SINK_TYPE_AUDIO:
2634 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2635 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2636 signal = SIGNAL_AUDIO_CHANGED;
2638 case GST_PLAY_SINK_TYPE_TEXT:
2639 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2640 signal = SIGNAL_TEXT_CHANGED;
2647 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2651 gst_caps_unref (caps);
2657 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2658 name, GST_DEBUG_PAD_NAME (pad));
2663 GST_ERROR_OBJECT (playbin,
2664 "failed to link pad %s:%s to selector, reason %d",
2665 GST_DEBUG_PAD_NAME (pad), res);
2666 GST_SOURCE_GROUP_UNLOCK (group);
2671 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2672 * the selector. This will make the selector select a new pad. */
2674 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2676 GstPlayBin *playbin;
2678 GstElement *selector;
2679 GstSourceSelect *select;
2681 playbin = group->playbin;
2683 GST_DEBUG_OBJECT (playbin,
2684 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2686 GST_SOURCE_GROUP_LOCK (group);
2687 /* get the selector sinkpad */
2688 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2691 if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2692 gulong notify_tags_handler;
2694 notify_tags_handler =
2695 (gulong) g_object_get_data (G_OBJECT (peer),
2696 "playbin2.notify_tags_handler");
2697 if (notify_tags_handler != 0)
2698 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2699 g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2701 /* remove the pad from the array */
2702 g_ptr_array_remove (select->channels, peer);
2703 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2706 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2707 gst_pad_unlink (pad, peer);
2709 /* get selector, this can be NULL when the element is removing the pads
2710 * because it's being disposed. */
2711 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2713 gst_object_unref (peer);
2717 /* release the pad to the selector, this will make the selector choose a new
2719 gst_element_release_request_pad (selector, peer);
2720 gst_object_unref (peer);
2722 gst_object_unref (selector);
2723 GST_SOURCE_GROUP_UNLOCK (group);
2730 GST_DEBUG_OBJECT (playbin, "pad not linked");
2731 GST_SOURCE_GROUP_UNLOCK (group);
2736 GST_DEBUG_OBJECT (playbin, "selector not found");
2737 GST_SOURCE_GROUP_UNLOCK (group);
2742 /* we get called when all pads are available and we must connect the sinks to
2744 * The main purpose of the code is to see if we have video/audio and subtitles
2745 * and pick the right pipelines to display them.
2747 * The selectors installed on the group tell us about the presence of
2748 * audio/video and subtitle streams. This allows us to see if we need
2749 * visualisation, video or/and audio.
2752 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2754 GstPlayBin *playbin;
2755 GstPadLinkReturn res;
2759 playbin = group->playbin;
2761 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2763 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2765 GST_SOURCE_GROUP_LOCK (group);
2766 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2767 GstSourceSelect *select = &group->selector[i];
2769 /* check if the specific media type was detected and thus has a selector
2770 * created for it. If there is the media type, get a sinkpad from the sink
2771 * and link it. We only do this if we have not yet requested the sinkpad
2773 if (select->srcpad && select->sinkpad == NULL) {
2774 PlaySinkEventProbeData *data = g_new (PlaySinkEventProbeData, 1);
2776 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2778 gst_play_sink_request_pad (playbin->playsink, select->type);
2780 /* Install an event probe */
2781 data->playbin = playbin;
2782 data->group = group;
2783 data->type = select->type;
2784 select->sink_event_probe_id =
2785 gst_pad_add_event_probe_full (select->sinkpad,
2786 G_CALLBACK (_playsink_sink_event_probe_cb), data,
2787 (GDestroyNotify) g_free);
2789 res = gst_pad_link (select->srcpad, select->sinkpad);
2790 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2791 select->media_list[0], res);
2792 if (res != GST_PAD_LINK_OK) {
2793 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2794 ("Internal playbin error."),
2795 ("Failed to link selector to sink. Error %d", res));
2799 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2800 group->pending - 1);
2802 if (group->pending > 0)
2805 if (group->suburidecodebin == decodebin)
2806 group->sub_pending = FALSE;
2808 if (group->pending == 0) {
2809 /* we are the last group to complete, we will configure the output and then
2810 * signal the other waiters. */
2811 GST_LOG_OBJECT (playbin, "last group complete");
2814 GST_LOG_OBJECT (playbin, "have more pending groups");
2817 GST_SOURCE_GROUP_UNLOCK (group);
2820 /* if we have custom sinks, configure them now */
2821 GST_SOURCE_GROUP_LOCK (group);
2822 if (group->audio_sink) {
2823 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2825 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2828 GST_INFO_OBJECT (playbin, "setting default audio sink %" GST_PTR_FORMAT,
2829 playbin->audio_sink);
2830 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2831 playbin->audio_sink);
2833 if (group->video_sink) {
2834 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2836 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2839 GST_INFO_OBJECT (playbin, "setting default video sink %" GST_PTR_FORMAT,
2840 playbin->video_sink);
2841 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2842 playbin->video_sink);
2844 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2845 playbin->text_sink);
2846 GST_SOURCE_GROUP_UNLOCK (group);
2848 GST_LOG_OBJECT (playbin, "reconfigure sink");
2849 /* we configure the modes if we were the last decodebin to complete. */
2850 gst_play_sink_reconfigure (playbin->playsink);
2852 /* signal the other decodebins that they can continue now. */
2853 GST_SOURCE_GROUP_LOCK (group);
2854 /* unblock all selectors */
2855 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2856 GstSourceSelect *select = &group->selector[i];
2858 /* Wait for stream-changed messages on all selectors except
2859 * the text selector because of the sparse nature of text streams.
2861 if (select->sinkpad && select->type != GST_PLAY_SINK_TYPE_TEXT) {
2867 s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2870 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2871 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2872 seqnum = gst_message_get_seqnum (msg);
2873 event = gst_event_new_sink_message (msg);
2874 g_mutex_lock (group->stream_changed_pending_lock);
2875 group->stream_changed_pending =
2876 g_list_prepend (group->stream_changed_pending,
2877 GUINT_TO_POINTER (seqnum));
2878 g_mutex_unlock (group->stream_changed_pending_lock);
2879 gst_pad_send_event (select->sinkpad, event);
2880 gst_message_unref (msg);
2883 if (select->srcpad) {
2884 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2886 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2890 GST_SOURCE_GROUP_UNLOCK (group);
2893 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
2899 GST_DEBUG ("ignoring, we are shutting down");
2900 /* Request a flushing pad from playsink that we then link to the selector.
2901 * Then we unblock the selectors so that they stop with a WRONG_STATE
2902 * instead of a NOT_LINKED error.
2904 GST_SOURCE_GROUP_LOCK (group);
2905 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
2906 GstSourceSelect *select = &group->selector[i];
2908 if (select->srcpad) {
2909 if (select->sinkpad == NULL) {
2910 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
2912 gst_play_sink_request_pad (playbin->playsink,
2913 GST_PLAY_SINK_TYPE_FLUSHING);
2914 res = gst_pad_link (select->srcpad, select->sinkpad);
2915 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
2917 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2919 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2923 GST_SOURCE_GROUP_UNLOCK (group);
2929 drained_cb (GstElement * decodebin, GstSourceGroup * group)
2931 GstPlayBin *playbin;
2933 playbin = group->playbin;
2935 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
2937 /* after this call, we should have a next group to activate or we EOS */
2938 g_signal_emit (G_OBJECT (playbin),
2939 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
2941 /* now activate the next group. If the app did not set a uri, this will
2942 * fail and we can do EOS */
2943 setup_next_source (playbin, GST_STATE_PAUSED);
2946 /* Called when we must provide a list of factories to plug to @pad with @caps.
2947 * We first check if we have a sink that can handle the format and if we do, we
2948 * return NULL, to expose the pad. If we have no sink (or the sink does not
2949 * work), we return the list of elements that can connect. */
2950 static GValueArray *
2951 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
2952 GstCaps * caps, GstSourceGroup * group)
2954 GstPlayBin *playbin;
2955 GValueArray *result;
2957 playbin = group->playbin;
2959 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
2960 group, GST_DEBUG_PAD_NAME (pad), caps);
2962 /* filter out the elements based on the caps. */
2963 g_mutex_lock (playbin->elements_lock);
2964 gst_play_bin_update_elements_list (playbin);
2965 result = gst_factory_list_filter (playbin->elements, caps);
2966 g_mutex_unlock (playbin->elements_lock);
2968 GST_DEBUG_OBJECT (playbin, "found factories %p", result);
2969 GST_FACTORY_LIST_DEBUG (result);
2974 /* autoplug-continue decides, if a pad has raw caps that can be exposed
2975 * directly or if further decoding is necessary. We use this to expose
2976 * supported subtitles directly */
2978 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
2979 GstSourceGroup * group)
2982 gboolean ret = FALSE;
2983 GstElement *text_sink;
2984 GstPad *text_sinkpad = NULL;
2987 (group->playbin->text_sink) ? gst_object_ref (group->
2988 playbin->text_sink) : NULL;
2990 text_sinkpad = gst_element_get_static_pad (text_sink, "sink");
2993 subcaps = gst_pad_get_caps_reffed (text_sinkpad);
2994 gst_object_unref (text_sinkpad);
2996 subcaps = gst_subtitle_overlay_create_factory_caps ();
3000 gst_object_unref (text_sink);
3002 ret = !gst_caps_can_intersect (subcaps, caps);
3003 gst_caps_unref (subcaps);
3005 GST_DEBUG_OBJECT (group->playbin,
3006 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3007 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3012 /* We are asked to select an element. See if the next element to check
3013 * is a sink. If this is the case, we see if the sink works by setting it to
3014 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3015 * expose the raw pad so that we can setup the mixers. */
3016 static GstAutoplugSelectResult
3017 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3018 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3020 GstPlayBin *playbin;
3021 GstElement *element;
3023 GstPlaySinkType type;
3026 playbin = group->playbin;
3028 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3029 group, GST_DEBUG_PAD_NAME (pad), caps);
3031 GST_DEBUG_OBJECT (playbin, "checking factory %s",
3032 GST_PLUGIN_FEATURE_NAME (factory));
3034 /* if it's not a sink, we just make decodebin try it */
3035 if (!gst_factory_list_is_type (factory, GST_FACTORY_LIST_SINK))
3036 return GST_AUTOPLUG_SELECT_TRY;
3038 /* it's a sink, see if an instance of it actually works */
3039 GST_DEBUG_OBJECT (playbin, "we found a sink");
3041 klass = gst_element_factory_get_klass (factory);
3043 /* figure out the klass */
3044 if (strstr (klass, "Audio")) {
3045 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3046 type = GST_PLAY_SINK_TYPE_AUDIO;
3047 sinkp = &group->audio_sink;
3048 } else if (strstr (klass, "Video")) {
3049 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3050 type = GST_PLAY_SINK_TYPE_VIDEO;
3051 sinkp = &group->video_sink;
3053 /* unknown klass, skip this element */
3054 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3055 return GST_AUTOPLUG_SELECT_SKIP;
3058 /* if we are asked to do visualisations and it's an audio sink, skip the
3059 * element. We can only do visualisations with raw sinks */
3060 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3061 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3062 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3063 return GST_AUTOPLUG_SELECT_SKIP;
3067 /* now see if we already have a sink element */
3068 GST_SOURCE_GROUP_LOCK (group);
3070 GST_DEBUG_OBJECT (playbin, "we already have a pending sink, expose pad");
3071 /* for now, just assume that we can link the pad to this same sink. FIXME,
3072 * check that we can link this new pad to this sink as well. */
3073 GST_SOURCE_GROUP_UNLOCK (group);
3074 return GST_AUTOPLUG_SELECT_EXPOSE;
3076 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3077 GST_SOURCE_GROUP_UNLOCK (group);
3079 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3080 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3081 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3082 return GST_AUTOPLUG_SELECT_SKIP;
3085 /* ... activate it ... We do this before adding it to the bin so that we
3086 * don't accidentally make it post error messages that will stop
3088 if ((gst_element_set_state (element,
3089 GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
3090 GST_WARNING_OBJECT (playbin, "Couldn't set %s to READY",
3091 GST_ELEMENT_NAME (element));
3092 gst_object_unref (element);
3093 return GST_AUTOPLUG_SELECT_SKIP;
3096 /* remember the sink in the group now, the element is floating, we take
3098 GST_SOURCE_GROUP_LOCK (group);
3099 if (*sinkp == NULL) {
3100 /* store the sink in the group, we will configure it later when we
3101 * reconfigure the sink */
3102 GST_DEBUG_OBJECT (playbin, "remember sink");
3103 gst_object_ref_sink (element);
3106 /* some other thread configured a sink while we were testing the sink, set
3107 * the sink back to NULL and assume we can use the other sink */
3108 GST_DEBUG_OBJECT (playbin, "another sink was found, expose pad");
3109 gst_element_set_state (element, GST_STATE_NULL);
3110 gst_object_unref (element);
3112 GST_SOURCE_GROUP_UNLOCK (group);
3114 /* tell decodebin to expose the pad because we are going to use this
3116 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3118 return GST_AUTOPLUG_SELECT_EXPOSE;
3122 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3123 GstSourceGroup * group)
3125 GstPlayBin *playbin;
3128 playbin = group->playbin;
3130 g_object_get (group->uridecodebin, "source", &source, NULL);
3132 GST_OBJECT_LOCK (playbin);
3133 if (playbin->source)
3134 gst_object_unref (playbin->source);
3135 playbin->source = source;
3136 GST_OBJECT_UNLOCK (playbin);
3138 g_object_notify (G_OBJECT (playbin), "source");
3141 /* must be called with the group lock */
3143 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3146 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3148 if (group->uridecodebin)
3149 gst_element_set_locked_state (group->uridecodebin, locked);
3150 if (group->suburidecodebin)
3151 gst_element_set_locked_state (group->suburidecodebin, locked);
3156 /* must be called with PLAY_BIN_LOCK */
3158 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3160 GstElement *uridecodebin;
3161 GstElement *suburidecodebin = NULL;
3164 g_return_val_if_fail (group->valid, FALSE);
3165 g_return_val_if_fail (!group->active, FALSE);
3167 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3169 GST_SOURCE_GROUP_LOCK (group);
3171 g_list_free (group->stream_changed_pending);
3172 group->stream_changed_pending = NULL;
3173 if (!group->stream_changed_pending_lock)
3174 group->stream_changed_pending_lock = g_mutex_new ();
3176 if (group->uridecodebin) {
3177 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3178 uridecodebin = group->uridecodebin;
3179 gst_element_set_state (uridecodebin, GST_STATE_READY);
3180 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3182 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3183 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3186 g_object_set (uridecodebin, "caps", gst_static_caps_get (&av_raw_caps),
3188 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3189 group->uridecodebin = gst_object_ref (uridecodebin);
3192 /* configure connection speed */
3193 g_object_set (uridecodebin, "connection-speed",
3194 playbin->connection_speed / 1000, NULL);
3196 flags = gst_play_sink_get_flags (playbin->playsink);
3198 /* configure download buffering */
3199 if (flags & GST_PLAY_FLAG_DOWNLOAD)
3200 g_object_set (uridecodebin, "download", TRUE, NULL);
3202 g_object_set (uridecodebin, "download", FALSE, NULL);
3205 g_object_set (uridecodebin, "uri", group->uri, NULL);
3206 /* configure buffering of demuxed/parsed data */
3207 if (flags & GST_PLAY_FLAG_BUFFERING)
3208 g_object_set (uridecodebin, "use-buffering", TRUE, NULL);
3210 g_object_set (uridecodebin, "use-buffering", FALSE, NULL);
3211 /* configure buffering parameters */
3212 g_object_set (uridecodebin, "buffer-duration", playbin->buffer_duration,
3214 g_object_set (uridecodebin, "buffer-size", playbin->buffer_size, NULL);
3216 /* connect pads and other things */
3217 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3218 G_CALLBACK (pad_added_cb), group);
3219 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3220 G_CALLBACK (pad_removed_cb), group);
3221 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3222 G_CALLBACK (no_more_pads_cb), group);
3223 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3224 G_CALLBACK (notify_source_cb), group);
3226 /* we have 1 pending no-more-pads */
3229 /* is called when the uridecodebin is out of data and we can switch to the
3232 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3235 /* will be called when a new media type is found. We return a list of decoders
3236 * including sinks for decodebin to try */
3237 group->autoplug_factories_id =
3238 g_signal_connect (uridecodebin, "autoplug-factories",
3239 G_CALLBACK (autoplug_factories_cb), group);
3240 group->autoplug_select_id =
3241 g_signal_connect (uridecodebin, "autoplug-select",
3242 G_CALLBACK (autoplug_select_cb), group);
3243 group->autoplug_continue_id =
3244 g_signal_connect (uridecodebin, "autoplug-continue",
3245 G_CALLBACK (autoplug_continue_cb), group);
3247 if (group->suburi) {
3249 if (group->suburidecodebin) {
3250 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3251 suburidecodebin = group->suburidecodebin;
3252 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3253 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3255 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3256 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3257 if (!suburidecodebin)
3259 g_object_set (uridecodebin, "caps", gst_static_caps_get (&av_raw_caps),
3261 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3262 group->suburidecodebin = gst_object_ref (suburidecodebin);
3265 /* configure connection speed */
3266 g_object_set (suburidecodebin, "connection-speed",
3267 playbin->connection_speed, NULL);
3269 g_object_set (suburidecodebin, "uri", group->suburi, NULL);
3271 /* connect pads and other things */
3272 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3273 G_CALLBACK (pad_added_cb), group);
3274 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3275 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3276 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3277 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3279 group->sub_autoplug_continue_id =
3280 g_signal_connect (suburidecodebin, "autoplug-continue",
3281 G_CALLBACK (autoplug_continue_cb), group);
3283 /* we have 2 pending no-more-pads */
3285 group->sub_pending = TRUE;
3287 group->sub_pending = FALSE;
3290 /* release the group lock before setting the state of the decodebins, they
3291 * might fire signals in this thread that we need to handle with the
3292 * group_lock taken. */
3293 GST_SOURCE_GROUP_UNLOCK (group);
3295 if (suburidecodebin) {
3296 if (gst_element_set_state (suburidecodebin,
3297 target) == GST_STATE_CHANGE_FAILURE) {
3298 GST_DEBUG_OBJECT (playbin,
3299 "failed state change of subtitle uridecodebin");
3300 GST_SOURCE_GROUP_LOCK (group);
3302 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3303 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3304 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3305 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3306 /* Might already be removed because of an error message */
3307 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3308 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3309 if (group->sub_pending) {
3311 group->sub_pending = FALSE;
3313 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3314 GST_SOURCE_GROUP_UNLOCK (group);
3317 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3318 goto uridecodebin_failure;
3320 GST_SOURCE_GROUP_LOCK (group);
3321 /* alow state changes of the playbin2 affect the group elements now */
3322 group_set_locked_state_unlocked (playbin, group, FALSE);
3323 group->active = TRUE;
3324 GST_SOURCE_GROUP_UNLOCK (group);
3333 GST_SOURCE_GROUP_UNLOCK (group);
3335 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3337 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3339 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3340 (_("Could not create \"uridecodebin\" element.")), (NULL));
3343 uridecodebin_failure:
3345 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3350 /* unlink a group of uridecodebins from the sink.
3351 * must be called with PLAY_BIN_LOCK */
3353 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3357 g_return_val_if_fail (group->valid, FALSE);
3358 g_return_val_if_fail (group->active, FALSE);
3360 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3362 GST_SOURCE_GROUP_LOCK (group);
3363 group->active = FALSE;
3364 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
3365 GstSourceSelect *select = &group->selector[i];
3367 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3369 if (select->srcpad) {
3370 if (select->sinkpad) {
3371 GST_LOG_OBJECT (playbin, "unlinking from sink");
3372 gst_pad_unlink (select->srcpad, select->sinkpad);
3374 if (select->sink_event_probe_id)
3375 gst_pad_remove_event_probe (select->sinkpad,
3376 select->sink_event_probe_id);
3377 select->sink_event_probe_id = 0;
3380 GST_LOG_OBJECT (playbin, "release sink pad");
3381 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3382 select->sinkpad = NULL;
3385 if (select->src_event_probe_id)
3386 gst_pad_remove_event_probe (select->srcpad, select->src_event_probe_id);
3387 select->src_event_probe_id = 0;
3389 gst_object_unref (select->srcpad);
3390 select->srcpad = NULL;
3393 if (select->selector) {
3396 /* release and unref requests pad from the selector */
3397 for (n = 0; n < select->channels->len; n++) {
3398 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3400 gst_element_release_request_pad (select->selector, sinkpad);
3401 gst_object_unref (sinkpad);
3403 g_ptr_array_set_size (select->channels, 0);
3405 gst_element_set_state (select->selector, GST_STATE_NULL);
3406 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3407 select->selector = NULL;
3410 /* delete any custom sinks we might have */
3411 if (group->audio_sink)
3412 gst_object_unref (group->audio_sink);
3413 group->audio_sink = NULL;
3414 if (group->video_sink)
3415 gst_object_unref (group->video_sink);
3416 group->video_sink = NULL;
3418 if (group->uridecodebin) {
3419 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3420 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3421 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3422 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3423 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3424 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3425 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3426 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3427 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3430 if (group->suburidecodebin) {
3431 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3432 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3433 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3434 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3436 /* Might already be removed because of errors */
3437 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3438 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3441 GST_SOURCE_GROUP_UNLOCK (group);
3446 /* setup the next group to play, this assumes the next_group is valid and
3447 * configured. It swaps out the current_group and activates the valid
3450 setup_next_source (GstPlayBin * playbin, GstState target)
3452 GstSourceGroup *new_group, *old_group;
3454 GST_DEBUG_OBJECT (playbin, "setup sources");
3456 /* see if there is a next group */
3457 GST_PLAY_BIN_LOCK (playbin);
3458 new_group = playbin->next_group;
3459 if (!new_group || !new_group->valid)
3462 /* first unlink the current source, if any */
3463 old_group = playbin->curr_group;
3464 if (old_group && old_group->valid) {
3465 gst_play_bin_update_cached_duration (playbin);
3466 /* unlink our pads with the sink */
3467 deactivate_group (playbin, old_group);
3468 old_group->valid = FALSE;
3471 /* swap old and new */
3472 playbin->curr_group = new_group;
3473 playbin->next_group = old_group;
3475 /* activate the new group */
3476 if (!activate_group (playbin, new_group, target))
3477 goto activate_failed;
3479 GST_PLAY_BIN_UNLOCK (playbin);
3486 GST_DEBUG_OBJECT (playbin, "no next group");
3487 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3488 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3489 GST_PLAY_BIN_UNLOCK (playbin);
3494 GST_DEBUG_OBJECT (playbin, "activate failed");
3495 GST_PLAY_BIN_UNLOCK (playbin);
3500 /* The group that is currently playing is copied again to the
3501 * next_group so that it will start playing the next time.
3504 save_current_group (GstPlayBin * playbin)
3506 GstSourceGroup *curr_group;
3508 GST_DEBUG_OBJECT (playbin, "save current group");
3510 /* see if there is a current group */
3511 GST_PLAY_BIN_LOCK (playbin);
3512 curr_group = playbin->curr_group;
3513 if (curr_group && curr_group->valid) {
3514 /* unlink our pads with the sink */
3515 deactivate_group (playbin, curr_group);
3517 /* swap old and new */
3518 playbin->curr_group = playbin->next_group;
3519 playbin->next_group = curr_group;
3520 GST_PLAY_BIN_UNLOCK (playbin);
3525 /* clear the locked state from all groups. This function is called before a
3526 * state change to NULL is performed on them. */
3528 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3530 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3533 GST_PLAY_BIN_LOCK (playbin);
3534 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3535 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3536 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3537 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3538 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3539 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3540 GST_PLAY_BIN_UNLOCK (playbin);
3545 static GstStateChangeReturn
3546 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3548 GstStateChangeReturn ret;
3549 GstPlayBin *playbin;
3551 playbin = GST_PLAY_BIN (element);
3553 switch (transition) {
3554 case GST_STATE_CHANGE_NULL_TO_READY:
3555 g_mutex_lock (playbin->elements_lock);
3556 gst_play_bin_update_elements_list (playbin);
3557 g_mutex_unlock (playbin->elements_lock);
3558 memset (&playbin->duration, 0, sizeof (playbin->duration));
3560 case GST_STATE_CHANGE_READY_TO_PAUSED:{
3563 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3564 memset (&playbin->duration, 0, sizeof (playbin->duration));
3565 g_atomic_int_set (&playbin->shutdown, 0);
3567 for (i = 0; i < 3; i++)
3568 gst_segment_init (&playbin->segments[i], GST_FORMAT_UNDEFINED);
3570 if (!setup_next_source (playbin, GST_STATE_READY))
3574 case GST_STATE_CHANGE_PAUSED_TO_READY:
3575 /* FIXME unlock our waiting groups */
3576 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3577 g_atomic_int_set (&playbin->shutdown, 1);
3578 memset (&playbin->duration, 0, sizeof (playbin->duration));
3580 /* wait for all callbacks to end by taking the lock.
3581 * No dynamic (critical) new callbacks will
3582 * be able to happen as we set the shutdown flag. */
3583 GST_PLAY_BIN_DYN_LOCK (playbin);
3584 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3585 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3587 case GST_STATE_CHANGE_READY_TO_NULL:{
3590 memset (&playbin->duration, 0, sizeof (playbin->duration));
3592 /* unlock so that all groups go to NULL */
3593 groups_set_locked_state (playbin, FALSE);
3595 for (i = 0; i < 2; i++) {
3596 if (playbin->groups[i].uridecodebin) {
3597 gst_element_set_state (playbin->groups[i].uridecodebin,
3599 gst_object_unref (playbin->groups[i].uridecodebin);
3600 playbin->groups[i].uridecodebin = NULL;
3602 if (playbin->groups[i].suburidecodebin) {
3603 gst_element_set_state (playbin->groups[i].suburidecodebin,
3605 gst_object_unref (playbin->groups[i].suburidecodebin);
3606 playbin->groups[i].suburidecodebin = NULL;
3615 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3616 if (ret == GST_STATE_CHANGE_FAILURE) {
3617 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
3618 GstSourceGroup *curr_group;
3620 curr_group = playbin->curr_group;
3621 if (curr_group && curr_group->valid) {
3622 /* unlink our pads with the sink */
3623 deactivate_group (playbin, curr_group);
3626 /* Swap current and next group back */
3627 playbin->curr_group = playbin->next_group;
3628 playbin->next_group = curr_group;
3633 switch (transition) {
3634 case GST_STATE_CHANGE_READY_TO_PAUSED:
3636 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3637 /* FIXME Release audio device when we implement that */
3639 case GST_STATE_CHANGE_PAUSED_TO_READY:
3640 save_current_group (playbin);
3642 case GST_STATE_CHANGE_READY_TO_NULL:
3643 /* make sure the groups don't perform a state change anymore until we
3644 * enable them again */
3645 groups_set_locked_state (playbin, TRUE);
3656 return GST_STATE_CHANGE_FAILURE;
3661 gst_play_bin2_plugin_init (GstPlugin * plugin)
3663 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
3665 g_type_class_ref (gst_input_selector_get_type ());
3666 g_type_class_ref (gst_selector_pad_get_type ());
3668 return gst_element_register (plugin, "playbin2", GST_RANK_NONE,