2 * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
3 * Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * SECTION:element-playbin2
24 * Playbin2 provides a stand-alone everything-in-one abstraction for an
25 * audio and/or video player.
27 * playbin2 is considered stable now. It is the prefered playback API now,
28 * and replaces the old #playbin element, which is no longer supported.
30 * It can handle both audio and video files and features
33 * automatic file type recognition and based on that automatic
34 * selection and usage of the right audio/video/subtitle demuxers/decoders
37 * visualisations for audio files
40 * subtitle support for video files. Subtitles can be store in external
44 * stream selection between different video/audio/subtitles streams
47 * meta info (tag) extraction
50 * easy access to the last video frame
53 * buffering when playing streams over a network
56 * volume control with mute option
61 * <title>Usage</title>
63 * A playbin2 element can be created just like any other element using
64 * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin2:uri
65 * property. This must be an absolute URI, relative file paths are not allowed.
66 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
68 * Playbin is a #GstPipeline. It will notify the application of everything
69 * that's happening (errors, end of stream, tags found, state changes, etc.)
70 * by posting messages on its #GstBus. The application needs to watch the
73 * Playback can be initiated by setting the element to PLAYING state using
74 * gst_element_set_state(). Note that the state change will take place in
75 * the background in a separate thread, when the function returns playback
76 * is probably not happening yet and any errors might not have occured yet.
77 * Applications using playbin should ideally be written to deal with things
78 * completely asynchroneous.
80 * When playback has finished (an EOS message has been received on the bus)
81 * or an error has occured (an ERROR message has been received on the bus) or
82 * the user wants to play a different track, playbin should be set back to
83 * READY or NULL state, then the #GstPlayBin2:uri property should be set to the
84 * new location and then playbin be set to PLAYING state again.
86 * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
87 * on the playbin element. Again, the seek will not be executed
88 * instantaneously, but will be done in a background thread. When the seek
89 * call returns the seek will most likely still be in process. An application
90 * may wait for the seek to finish (or fail) using gst_element_get_state() with
91 * -1 as the timeout, but this will block the user interface and is not
94 * Applications may query the current position and duration of the stream
95 * via gst_element_query_position() and gst_element_query_duration() and
96 * setting the format passed to GST_FORMAT_TIME. If the query was successful,
97 * the duration or position will have been returned in units of nanoseconds.
101 * <title>Advanced Usage: specifying the audio and video sink</title>
103 * By default, if no audio sink or video sink has been specified via the
104 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property, playbin will use the autoaudiosink
105 * and autovideosink elements to find the first-best available output method.
106 * This should work in most cases, but is not always desirable. Often either
107 * the user or application might want to specify more explicitly what to use
108 * for audio and video output.
110 * If the application wants more control over how audio or video should be
111 * output, it may create the audio/video sink elements itself (for example
112 * using gst_element_factory_make()) and provide them to playbin using the
113 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property.
115 * GNOME-based applications, for example, will usually want to create
116 * gconfaudiosink and gconfvideosink elements and make playbin use those,
117 * so that output happens to whatever the user has configured in the GNOME
118 * Multimedia System Selector configuration dialog.
120 * The sink elements do not necessarily need to be ready-made sinks. It is
121 * possible to create container elements that look like a sink to playbin,
122 * but in reality contain a number of custom elements linked together. This
123 * can be achieved by creating a #GstBin and putting elements in there and
124 * linking them, and then creating a sink #GstGhostPad for the bin and pointing
125 * it to the sink pad of the first element within the bin. This can be used
126 * for a number of purposes, for example to force output to a particular
127 * format or to modify or observe the data before it is output.
129 * It is also possible to 'suppress' audio and/or video output by using
130 * 'fakesink' elements (or capture it from there using the fakesink element's
131 * "handoff" signal, which, nota bene, is fired from the streaming thread!).
135 * <title>Retrieving Tags and Other Meta Data</title>
137 * Most of the common meta data (artist, title, etc.) can be retrieved by
138 * watching for TAG messages on the pipeline's bus (see above).
140 * Other more specific meta information like width/height/framerate of video
141 * streams or samplerate/number of channels of audio streams can be obtained
142 * from the negotiated caps on the sink pads of the sinks.
146 * <title>Buffering</title>
147 * Playbin handles buffering automatically for the most part, but applications
148 * need to handle parts of the buffering process as well. Whenever playbin is
149 * buffering, it will post BUFFERING messages on the bus with a percentage
150 * value that shows the progress of the buffering process. Applications need
151 * to set playbin to PLAYING or PAUSED state in response to these messages.
152 * They may also want to convey the buffering progress to the user in some
153 * way. Here is how to extract the percentage information from the message
154 * (requires GStreamer >= 0.10.11):
156 * switch (GST_MESSAGE_TYPE (msg)) {
157 * case GST_MESSAGE_BUFFERING: {
159 * gst_message_parse_buffering (msg, &percent);
160 * g_print ("Buffering (%%u percent done)", percent);
166 * Note that applications should keep/set the pipeline in the PAUSED state when
167 * a BUFFERING message is received with a buffer percent value < 100 and set
168 * the pipeline back to PLAYING state when a BUFFERING message with a value
169 * of 100 percent is received (if PLAYING is the desired state, that is).
172 * <title>Embedding the video window in your application</title>
173 * By default, playbin (or rather the video sinks used) will create their own
174 * window. Applications will usually want to force output to a window of their
175 * own, however. This can be done using the #GstXOverlay interface, which most
176 * video sinks implement. See the documentation there for more details.
179 * <title>Specifying which CD/DVD device to use</title>
180 * The device to use for CDs/DVDs needs to be set on the source element
181 * playbin creates before it is opened. The most generic way of doing this
182 * is to connect to playbin's "source-setup" (or "notify::source") signal,
183 * which will be emitted by playbin2 when it has created the source element
184 * for a particular URI. In the signal callback you can check if the source
185 * element has a "device" property and set it appropriately. In some cases
186 * the device can also be set as part of the URI, but it depends on the
187 * elements involved if this will work or not. For example, for DVD menu
188 * playback, the following syntax might work (if the resindvd plugin is used):
189 * dvd://[/path/to/device]
192 * <title>Handling redirects</title>
194 * Some elements may post 'redirect' messages on the bus to tell the
195 * application to open another location. These are element messages containing
196 * a structure named 'redirect' along with a 'new-location' field of string
197 * type. The new location may be a relative or an absolute URI. Examples
198 * for such redirects can be found in many quicktime movie trailers.
202 * <title>Examples</title>
204 * gst-launch -v playbin2 uri=file:///path/to/somefile.avi
205 * ]| This will play back the given AVI video file, given that the video and
206 * audio decoders required to decode the content are installed. Since no
207 * special audio sink or video sink is supplied (not possible via gst-launch),
208 * playbin will try to find a suitable audio and video sink automatically
209 * using the autoaudiosink and autovideosink elements.
211 * gst-launch -v playbin2 uri=cdda://4
212 * ]| This will play back track 4 on an audio CD in your disc drive (assuming
213 * the drive is detected automatically by the plugin).
215 * gst-launch -v playbin2 uri=dvd://
216 * ]| This will play back the DVD in your disc drive (assuming
217 * the drive is detected automatically by the plugin).
225 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
226 * with newer GLib versions (>= 2.31.0) */
227 #define GLIB_DISABLE_DEPRECATION_WARNINGS
232 #include <gst/gst-i18n-plugin.h>
233 #include <gst/pbutils/pbutils.h>
234 #include <gst/interfaces/streamvolume.h>
235 #include <gst/interfaces/xoverlay.h>
236 #include <gst/interfaces/navigation.h>
237 #include <gst/interfaces/colorbalance.h>
239 #include "gstplay-enum.h"
240 #include "gstplay-marshal.h"
241 #include "gstplayback.h"
242 #include "gstplaysink.h"
243 #include "gstsubtitleoverlay.h"
245 #include "gst/glib-compat-private.h"
247 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
248 #define GST_CAT_DEFAULT gst_play_bin_debug
250 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type())
251 #define GST_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
252 #define GST_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
253 #define GST_IS_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
254 #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
256 #define VOLUME_MAX_DOUBLE 10.0
258 typedef struct _GstPlayBin GstPlayBin;
259 typedef struct _GstPlayBinClass GstPlayBinClass;
260 typedef struct _GstSourceGroup GstSourceGroup;
261 typedef struct _GstSourceSelect GstSourceSelect;
263 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
265 /* has the info for a selector and provides the link to the sink */
266 struct _GstSourceSelect
268 const gchar *media_list[8]; /* the media types for the selector */
269 SourceSelectGetMediaCapsFunc get_media_caps; /* more complex caps for the selector */
270 GstPlaySinkType type; /* the sink pad type of the selector */
272 GstElement *selector; /* the selector */
274 GstPad *srcpad; /* the source pad of the selector */
275 GstPad *sinkpad; /* the sinkpad of the sink when the selector
278 GstEvent *sinkpad_delayed_event;
279 gulong sinkpad_data_probe;
282 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
283 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
284 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
288 PLAYBIN_STREAM_AUDIO = 0,
289 PLAYBIN_STREAM_VIDEO,
294 /* a structure to hold the objects for decoding a uri and the subtitle uri
296 struct _GstSourceGroup
302 gboolean valid; /* the group has valid info to start playback */
303 gboolean active; /* the group is active */
308 GValueArray *streaminfo;
311 GPtrArray *video_channels; /* links to selector pads */
312 GPtrArray *audio_channels; /* links to selector pads */
313 GPtrArray *text_channels; /* links to selector pads */
315 GstElement *audio_sink; /* autoplugged audio and video sinks */
316 GstElement *video_sink;
318 /* uridecodebins for uri and subtitle uri */
319 GstElement *uridecodebin;
320 GstElement *suburidecodebin;
322 gboolean sub_pending;
325 gulong pad_removed_id;
326 gulong no_more_pads_id;
327 gulong notify_source_id;
329 gulong autoplug_factories_id;
330 gulong autoplug_select_id;
331 gulong autoplug_continue_id;
333 gulong sub_pad_added_id;
334 gulong sub_pad_removed_id;
335 gulong sub_no_more_pads_id;
336 gulong sub_autoplug_continue_id;
338 GMutex *stream_changed_pending_lock;
339 GList *stream_changed_pending;
341 /* selectors for different streams */
342 GstSourceSelect selector[PLAYBIN_STREAM_LAST];
345 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
346 #define GST_PLAY_BIN_LOCK(bin) (g_static_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
347 #define GST_PLAY_BIN_UNLOCK(bin) (g_static_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
349 /* lock to protect dynamic callbacks, like no-more-pads */
350 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->dyn_lock)
351 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->dyn_lock)
353 /* lock for shutdown */
354 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
356 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
358 GST_PLAY_BIN_DYN_LOCK (bin); \
359 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
360 GST_PLAY_BIN_DYN_UNLOCK (bin); \
365 /* unlock for shutdown */
366 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
367 GST_PLAY_BIN_DYN_UNLOCK (bin); \
372 * playbin element structure
378 GStaticRecMutex lock; /* to protect group switching */
380 /* the groups, we use a double buffer to switch between current and next */
381 GstSourceGroup groups[2]; /* array with group info */
382 GstSourceGroup *curr_group; /* pointer to the currently playing group */
383 GstSourceGroup *next_group; /* pointer to the next group */
386 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
387 gint current_video; /* the currently selected stream */
388 gint current_audio; /* the currently selected stream */
389 gint current_text; /* the currently selected stream */
391 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
392 guint buffer_size; /* When buffering, the max buffer size (bytes) */
395 GstPlaySink *playsink;
397 /* the last activated source */
400 /* lock protecting dynamic adding/removing */
402 /* if we are shutting down or not */
405 GMutex *elements_lock;
406 guint32 elements_cookie;
407 GList *elements; /* factories we can use for selecting elements */
409 gboolean have_selector; /* set to FALSE when we fail to create an
410 * input-selector, so that we only post a
413 GstElement *audio_sink; /* configured audio sink, or NULL */
414 GstElement *video_sink; /* configured video sink, or NULL */
415 GstElement *text_sink; /* configured text sink, or NULL */
422 } duration[5]; /* cached durations */
424 guint64 ring_buffer_max_size; /* 0 means disabled */
427 struct _GstPlayBinClass
429 GstPipelineClass parent_class;
431 /* notify app that the current uri finished decoding and it is possible to
432 * queue a new one for gapless playback */
433 void (*about_to_finish) (GstPlayBin * playbin);
435 /* notify app that number of audio/video/text streams changed */
436 void (*video_changed) (GstPlayBin * playbin);
437 void (*audio_changed) (GstPlayBin * playbin);
438 void (*text_changed) (GstPlayBin * playbin);
440 /* notify app that the tags of audio/video/text streams changed */
441 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
442 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
443 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
445 /* get audio/video/text tags for a stream */
446 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
447 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
448 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
450 /* get the last video frame and convert it to the given caps */
451 GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
453 /* get audio/video/text pad for a stream */
454 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
455 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
456 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
460 #define DEFAULT_URI NULL
461 #define DEFAULT_SUBURI NULL
462 #define DEFAULT_SOURCE NULL
463 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
464 GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_SOFT_COLORBALANCE
465 #define DEFAULT_N_VIDEO 0
466 #define DEFAULT_CURRENT_VIDEO -1
467 #define DEFAULT_N_AUDIO 0
468 #define DEFAULT_CURRENT_AUDIO -1
469 #define DEFAULT_N_TEXT 0
470 #define DEFAULT_CURRENT_TEXT -1
471 #define DEFAULT_SUBTITLE_ENCODING NULL
472 #define DEFAULT_AUDIO_SINK NULL
473 #define DEFAULT_VIDEO_SINK NULL
474 #define DEFAULT_VIS_PLUGIN NULL
475 #define DEFAULT_TEXT_SINK NULL
476 #define DEFAULT_VOLUME 1.0
477 #define DEFAULT_MUTE FALSE
478 #define DEFAULT_FRAME NULL
479 #define DEFAULT_FONT_DESC NULL
480 #define DEFAULT_CONNECTION_SPEED 0
481 #define DEFAULT_BUFFER_DURATION -1
482 #define DEFAULT_BUFFER_SIZE -1
483 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
498 PROP_SUBTITLE_ENCODING,
507 PROP_CONNECTION_SPEED,
509 PROP_BUFFER_DURATION,
511 PROP_RING_BUFFER_MAX_SIZE,
518 SIGNAL_ABOUT_TO_FINISH,
519 SIGNAL_CONVERT_FRAME,
520 SIGNAL_VIDEO_CHANGED,
521 SIGNAL_AUDIO_CHANGED,
523 SIGNAL_VIDEO_TAGS_CHANGED,
524 SIGNAL_AUDIO_TAGS_CHANGED,
525 SIGNAL_TEXT_TAGS_CHANGED,
526 SIGNAL_GET_VIDEO_TAGS,
527 SIGNAL_GET_AUDIO_TAGS,
528 SIGNAL_GET_TEXT_TAGS,
529 SIGNAL_GET_VIDEO_PAD,
530 SIGNAL_GET_AUDIO_PAD,
536 static void gst_play_bin_class_init (GstPlayBinClass * klass);
537 static void gst_play_bin_init (GstPlayBin * playbin);
538 static void gst_play_bin_finalize (GObject * object);
540 static void gst_play_bin_set_property (GObject * object, guint prop_id,
541 const GValue * value, GParamSpec * spec);
542 static void gst_play_bin_get_property (GObject * object, guint prop_id,
543 GValue * value, GParamSpec * spec);
545 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
546 GstStateChange transition);
548 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
549 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
551 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
553 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
555 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
558 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
561 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
562 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
563 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
565 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
567 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
568 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
569 GstSourceGroup * group);
571 static void gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
573 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
576 static GstElementClass *parent_class;
578 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
580 #define REMOVE_SIGNAL(obj,id) \
582 g_signal_handler_disconnect (obj, id); \
586 static void gst_play_bin_implements_interface_init (gpointer g_iface,
587 gpointer g_iface_data);
588 static void gst_play_bin_xoverlay_init (gpointer g_iface,
589 gpointer g_iface_data);
590 static void gst_play_bin_navigation_init (gpointer g_iface,
591 gpointer g_iface_data);
592 static void gst_play_bin_colorbalance_init (gpointer g_iface,
593 gpointer g_iface_data);
596 gst_play_bin_get_type (void)
598 static GType gst_play_bin_type = 0;
600 if (!gst_play_bin_type) {
601 static const GTypeInfo gst_play_bin_info = {
602 sizeof (GstPlayBinClass),
605 (GClassInitFunc) gst_play_bin_class_init,
610 (GInstanceInitFunc) gst_play_bin_init,
613 static const GInterfaceInfo impl_info = {
614 gst_play_bin_implements_interface_init,
617 static const GInterfaceInfo svol_info = {
620 static const GInterfaceInfo xov_info = {
621 gst_play_bin_xoverlay_init,
624 static const GInterfaceInfo nav_info = {
625 gst_play_bin_navigation_init,
628 static const GInterfaceInfo col_info = {
629 gst_play_bin_colorbalance_init,
633 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
634 "GstPlayBin2", &gst_play_bin_info, 0);
636 g_type_add_interface_static (gst_play_bin_type,
637 GST_TYPE_IMPLEMENTS_INTERFACE, &impl_info);
638 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
640 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_X_OVERLAY,
642 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_NAVIGATION,
644 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_COLOR_BALANCE,
648 return gst_play_bin_type;
652 gst_play_bin_class_init (GstPlayBinClass * klass)
654 GObjectClass *gobject_klass;
655 GstElementClass *gstelement_klass;
656 GstBinClass *gstbin_klass;
658 gobject_klass = (GObjectClass *) klass;
659 gstelement_klass = (GstElementClass *) klass;
660 gstbin_klass = (GstBinClass *) klass;
662 parent_class = g_type_class_peek_parent (klass);
664 gobject_klass->set_property = gst_play_bin_set_property;
665 gobject_klass->get_property = gst_play_bin_get_property;
667 gobject_klass->finalize = gst_play_bin_finalize;
672 * Set the next URI that playbin will play. This property can be set from the
673 * about-to-finish signal to queue the next media file.
675 g_object_class_install_property (gobject_klass, PROP_URI,
676 g_param_spec_string ("uri", "URI", "URI of the media to play",
677 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
682 * Set the next subtitle URI that playbin will play. This property can be
683 * set from the about-to-finish signal to queue the next subtitle media file.
685 g_object_class_install_property (gobject_klass, PROP_SUBURI,
686 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
687 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
689 g_object_class_install_property (gobject_klass, PROP_SOURCE,
690 g_param_spec_object ("source", "Source", "Source element",
691 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
696 * Control the behaviour of playbin.
698 g_object_class_install_property (gobject_klass, PROP_FLAGS,
699 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
700 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
701 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
704 * GstPlayBin2:n-video
706 * Get the total number of available video streams.
708 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
709 g_param_spec_int ("n-video", "Number Video",
710 "Total number of video streams", 0, G_MAXINT, 0,
711 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
713 * GstPlayBin2:current-video
715 * Get or set the currently playing video stream. By default the first video
716 * stream with data is played.
718 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
719 g_param_spec_int ("current-video", "Current Video",
720 "Currently playing video stream (-1 = auto)",
721 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
723 * GstPlayBin2:n-audio
725 * Get the total number of available audio streams.
727 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
728 g_param_spec_int ("n-audio", "Number Audio",
729 "Total number of audio streams", 0, G_MAXINT, 0,
730 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
732 * GstPlayBin2:current-audio
734 * Get or set the currently playing audio stream. By default the first audio
735 * stream with data is played.
737 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
738 g_param_spec_int ("current-audio", "Current audio",
739 "Currently playing audio stream (-1 = auto)",
740 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
744 * Get the total number of available subtitle streams.
746 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
747 g_param_spec_int ("n-text", "Number Text",
748 "Total number of text streams", 0, G_MAXINT, 0,
749 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
751 * GstPlayBin2:current-text:
753 * Get or set the currently playing subtitle stream. By default the first
754 * subtitle stream with data is played.
756 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
757 g_param_spec_int ("current-text", "Current Text",
758 "Currently playing text stream (-1 = auto)",
759 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
761 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
762 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
763 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
764 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
765 "be checked for an encoding to use. If that is not set either, "
766 "ISO-8859-15 will be assumed.", NULL,
767 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
769 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
770 g_param_spec_object ("video-sink", "Video Sink",
771 "the video output element to use (NULL = default sink)",
772 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
773 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
774 g_param_spec_object ("audio-sink", "Audio Sink",
775 "the audio output element to use (NULL = default sink)",
776 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
777 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
778 g_param_spec_object ("vis-plugin", "Vis plugin",
779 "the visualization element to use (NULL = default)",
780 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
781 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
782 g_param_spec_object ("text-sink", "Text plugin",
783 "the text output element to use (NULL = default textoverlay)",
784 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
787 * GstPlayBin2:volume:
789 * Get or set the current audio stream volume. 1.0 means 100%,
790 * 0.0 means mute. This uses a linear volume scale.
793 g_object_class_install_property (gobject_klass, PROP_VOLUME,
794 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
795 0.0, VOLUME_MAX_DOUBLE, 1.0,
796 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
797 g_object_class_install_property (gobject_klass, PROP_MUTE,
798 g_param_spec_boolean ("mute", "Mute",
799 "Mute the audio channel without changing the volume", FALSE,
800 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
804 * @playbin: a #GstPlayBin2
806 * Get the currently rendered or prerolled frame in the video sink.
807 * The #GstCaps on the buffer will describe the format of the buffer.
809 g_object_class_install_property (gobject_klass, PROP_FRAME,
810 gst_param_spec_mini_object ("frame", "Frame",
811 "The last frame (NULL = no video available)",
812 GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
813 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
814 g_param_spec_string ("subtitle-font-desc",
815 "Subtitle font description",
816 "Pango font description of font "
817 "to be used for subtitle rendering", NULL,
818 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
820 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
821 g_param_spec_uint ("connection-speed", "Connection Speed",
822 "Network connection speed in kbps (0 = unknown)",
823 0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED,
824 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
826 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
827 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
828 "Buffer size when buffering network streams",
829 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
830 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
831 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
832 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
833 "Buffer duration when buffering network streams",
834 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
835 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
837 * GstPlayBin2:av-offset:
839 * Control the synchronisation offset between the audio and video streams.
840 * Positive values make the audio ahead of the video and negative values make
841 * the audio go behind the video.
845 g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
846 g_param_spec_int64 ("av-offset", "AV Offset",
847 "The synchronisation offset between audio and video in nanoseconds",
848 G_MININT64, G_MAXINT64, 0,
849 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
852 * GstQueue2:ring-buffer-max-size
854 * The maximum size of the ring buffer in bytes. If set to 0, the ring
855 * buffer is disabled. Default 0.
859 g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
860 g_param_spec_uint64 ("ring-buffer-max-size",
861 "Max. ring buffer size (bytes)",
862 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
863 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
864 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
867 * GstPlayBin2::about-to-finish
868 * @playbin: a #GstPlayBin2
870 * This signal is emitted when the current uri is about to finish. You can
871 * set the uri and suburi to make sure that playback continues.
873 * This signal is emitted from the context of a GStreamer streaming thread.
875 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
876 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
878 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
879 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
882 * GstPlayBin2::video-changed
883 * @playbin: a #GstPlayBin2
885 * This signal is emitted whenever the number or order of the video
886 * streams has changed. The application will most likely want to select
887 * a new video stream.
889 * This signal is usually emitted from the context of a GStreamer streaming
890 * thread. You can use gst_message_new_application() and
891 * gst_element_post_message() to notify your application's main thread.
893 /* FIXME 0.11: turn video-changed signal into message? */
894 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
895 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
897 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
898 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
900 * GstPlayBin2::audio-changed
901 * @playbin: a #GstPlayBin2
903 * This signal is emitted whenever the number or order of the audio
904 * streams has changed. The application will most likely want to select
905 * a new audio stream.
907 * This signal may be emitted from the context of a GStreamer streaming thread.
908 * You can use gst_message_new_application() and gst_element_post_message()
909 * to notify your application's main thread.
911 /* FIXME 0.11: turn audio-changed signal into message? */
912 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
913 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
915 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
916 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
918 * GstPlayBin2::text-changed
919 * @playbin: a #GstPlayBin2
921 * This signal is emitted whenever the number or order of the text
922 * streams has changed. The application will most likely want to select
925 * This signal may be emitted from the context of a GStreamer streaming thread.
926 * You can use gst_message_new_application() and gst_element_post_message()
927 * to notify your application's main thread.
929 /* FIXME 0.11: turn text-changed signal into message? */
930 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
931 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
933 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
934 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
937 * GstPlayBin2::video-tags-changed
938 * @playbin: a #GstPlayBin2
939 * @stream: stream index with changed tags
941 * This signal is emitted whenever the tags of a video stream have changed.
942 * The application will most likely want to get the new tags.
944 * This signal may be emitted from the context of a GStreamer streaming thread.
945 * You can use gst_message_new_application() and gst_element_post_message()
946 * to notify your application's main thread.
950 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
951 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
953 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
954 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
957 * GstPlayBin2::audio-tags-changed
958 * @playbin: a #GstPlayBin2
959 * @stream: stream index with changed tags
961 * This signal is emitted whenever the tags of an audio stream have changed.
962 * The application will most likely want to get the new tags.
964 * This signal may be emitted from the context of a GStreamer streaming thread.
965 * You can use gst_message_new_application() and gst_element_post_message()
966 * to notify your application's main thread.
970 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
971 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
973 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
974 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
977 * GstPlayBin2::text-tags-changed
978 * @playbin: a #GstPlayBin2
979 * @stream: stream index with changed tags
981 * This signal is emitted whenever the tags of a text stream have changed.
982 * The application will most likely want to get the new tags.
984 * This signal may be emitted from the context of a GStreamer streaming thread.
985 * You can use gst_message_new_application() and gst_element_post_message()
986 * to notify your application's main thread.
990 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
991 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
993 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
994 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
997 * GstPlayBin2::source-setup:
998 * @playbin: a #GstPlayBin2
999 * @source: source element
1001 * This signal is emitted after the source element has been created, so
1002 * it can be configured by setting additional properties (e.g. set a
1003 * proxy server for an http source, or set the device and read speed for
1004 * an audio cd source). This is functionally equivalent to connecting to
1005 * the notify::source signal, but more convenient.
1007 * This signal is usually emitted from the context of a GStreamer streaming
1012 gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
1013 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
1014 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1015 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
1018 * GstPlayBin2::get-video-tags
1019 * @playbin: a #GstPlayBin2
1020 * @stream: a video stream number
1022 * Action signal to retrieve the tags of a specific video stream number.
1023 * This information can be used to select a stream.
1025 * Returns: a GstTagList with tags or NULL when the stream number does not
1028 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
1029 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
1030 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1031 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
1032 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1034 * GstPlayBin2::get-audio-tags
1035 * @playbin: a #GstPlayBin2
1036 * @stream: an audio stream number
1038 * Action signal to retrieve the tags of a specific audio stream number.
1039 * This information can be used to select a stream.
1041 * Returns: a GstTagList with tags or NULL when the stream number does not
1044 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
1045 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
1046 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1047 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
1048 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1050 * GstPlayBin2::get-text-tags
1051 * @playbin: a #GstPlayBin2
1052 * @stream: a text stream number
1054 * Action signal to retrieve the tags of a specific text stream number.
1055 * This information can be used to select a stream.
1057 * Returns: a GstTagList with tags or NULL when the stream number does not
1060 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
1061 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
1062 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1063 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
1064 gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1066 * GstPlayBin2::convert-frame
1067 * @playbin: a #GstPlayBin2
1068 * @caps: the target format of the frame
1070 * Action signal to retrieve the currently playing video frame in the format
1071 * specified by @caps.
1072 * If @caps is %NULL, no conversion will be performed and this function is
1073 * equivalent to the #GstPlayBin::frame property.
1075 * Returns: a #GstBuffer of the current video frame converted to #caps.
1076 * The caps on the buffer will describe the final layout of the buffer data.
1077 * %NULL is returned when no current buffer can be retrieved or when the
1078 * conversion failed.
1080 gst_play_bin_signals[SIGNAL_CONVERT_FRAME] =
1081 g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
1082 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1083 G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
1084 gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
1087 * GstPlayBin2::get-video-pad
1088 * @playbin: a #GstPlayBin2
1089 * @stream: a video stream number
1091 * Action signal to retrieve the stream-selector sinkpad for a specific
1093 * This pad can be used for notifications of caps changes, stream-specific
1096 * Returns: a #GstPad, or NULL when the stream number does not exist.
1098 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1099 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1100 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1101 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1102 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1104 * GstPlayBin2::get-audio-pad
1105 * @playbin: a #GstPlayBin2
1106 * @stream: an audio stream number
1108 * Action signal to retrieve the stream-selector sinkpad for a specific
1110 * This pad can be used for notifications of caps changes, stream-specific
1113 * Returns: a #GstPad, or NULL when the stream number does not exist.
1115 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1116 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1117 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1118 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1119 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1121 * GstPlayBin2::get-text-pad
1122 * @playbin: a #GstPlayBin2
1123 * @stream: a text stream number
1125 * Action signal to retrieve the stream-selector sinkpad for a specific
1127 * This pad can be used for notifications of caps changes, stream-specific
1130 * Returns: a #GstPad, or NULL when the stream number does not exist.
1132 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1133 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1134 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1135 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1136 gst_play_marshal_OBJECT__INT, GST_TYPE_PAD, 1, G_TYPE_INT);
1138 klass->get_video_tags = gst_play_bin_get_video_tags;
1139 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1140 klass->get_text_tags = gst_play_bin_get_text_tags;
1142 klass->convert_frame = gst_play_bin_convert_frame;
1144 klass->get_video_pad = gst_play_bin_get_video_pad;
1145 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1146 klass->get_text_pad = gst_play_bin_get_text_pad;
1148 gst_element_class_set_details_simple (gstelement_klass,
1149 "Player Bin 2", "Generic/Bin/Player",
1150 "Autoplug and play media from an uri",
1151 "Wim Taymans <wim.taymans@gmail.com>");
1153 gstelement_klass->change_state =
1154 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1155 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1157 gstbin_klass->handle_message =
1158 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1162 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1166 /* store the array for the different channels */
1167 group->video_channels = g_ptr_array_new ();
1168 group->audio_channels = g_ptr_array_new ();
1169 group->text_channels = g_ptr_array_new ();
1170 group->lock = g_mutex_new ();
1171 /* init selectors. The selector is found by finding the first prefix that
1172 * matches the media. */
1173 group->playbin = playbin;
1174 /* If you add any items to these lists, check that media_list[] is defined
1175 * above to be large enough to hold MAX(items)+1, so as to accommodate a
1176 * NULL terminator (set when the memory is zeroed on allocation) */
1177 group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
1178 group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
1179 group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
1180 group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
1181 group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
1182 group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
1183 group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
1184 group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
1185 group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
1186 group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
1187 group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
1188 group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
1189 group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
1190 group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
1191 gst_subtitle_overlay_create_factory_caps;
1192 group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
1193 group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
1195 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1196 GstSourceSelect *select = &group->selector[n];
1197 select->sinkpad_delayed_event = NULL;
1198 select->sinkpad_data_probe = 0;
1203 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1207 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1208 GstSourceSelect *select = &group->selector[n];
1209 if (select->sinkpad && select->sinkpad_data_probe)
1210 gst_pad_remove_data_probe (select->sinkpad, select->sinkpad_data_probe);
1211 if (select->sinkpad_delayed_event)
1212 gst_event_unref (select->sinkpad_delayed_event);
1215 g_free (group->uri);
1216 g_free (group->suburi);
1217 g_ptr_array_free (group->video_channels, TRUE);
1218 g_ptr_array_free (group->audio_channels, TRUE);
1219 g_ptr_array_free (group->text_channels, TRUE);
1221 g_mutex_free (group->lock);
1222 if (group->audio_sink) {
1223 if (group->audio_sink != playbin->audio_sink)
1224 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1225 gst_object_unref (group->audio_sink);
1227 group->audio_sink = NULL;
1228 if (group->video_sink) {
1229 if (group->video_sink != playbin->video_sink)
1230 gst_element_set_state (group->video_sink, GST_STATE_NULL);
1231 gst_object_unref (group->video_sink);
1233 group->video_sink = NULL;
1235 g_list_free (group->stream_changed_pending);
1236 group->stream_changed_pending = NULL;
1238 if (group->stream_changed_pending_lock)
1239 g_mutex_free (group->stream_changed_pending_lock);
1240 group->stream_changed_pending_lock = NULL;
1244 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1246 g_object_notify (G_OBJECT (playbin), "volume");
1250 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1252 g_object_notify (G_OBJECT (playbin), "mute");
1256 colorbalance_value_changed_cb (GstColorBalance * balance,
1257 GstColorBalanceChannel * channel, gint value, GstPlayBin * playbin)
1259 gst_color_balance_value_changed (GST_COLOR_BALANCE (playbin), channel, value);
1262 /* Must be called with elements lock! */
1264 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1268 if (!playbin->elements ||
1269 playbin->elements_cookie !=
1270 gst_default_registry_get_feature_list_cookie ()) {
1271 if (playbin->elements)
1272 gst_plugin_feature_list_free (playbin->elements);
1274 gst_element_factory_list_get_elements
1275 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1277 gst_element_factory_list_get_elements
1278 (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1279 playbin->elements = g_list_concat (res, tmp);
1281 g_list_sort (playbin->elements, gst_plugin_feature_rank_compare_func);
1282 playbin->elements_cookie = gst_default_registry_get_feature_list_cookie ();
1287 gst_play_bin_init (GstPlayBin * playbin)
1289 g_static_rec_mutex_init (&playbin->lock);
1290 playbin->dyn_lock = g_mutex_new ();
1292 /* assume we can create a selector */
1293 playbin->have_selector = TRUE;
1296 playbin->curr_group = &playbin->groups[0];
1297 playbin->next_group = &playbin->groups[1];
1298 init_group (playbin, &playbin->groups[0]);
1299 init_group (playbin, &playbin->groups[1]);
1301 /* first filter out the interesting element factories */
1302 playbin->elements_lock = g_mutex_new ();
1306 g_object_new (GST_TYPE_PLAY_SINK, "name", "playsink", NULL);
1307 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1308 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1309 /* Connect to notify::volume and notify::mute signals for proxying */
1310 g_signal_connect (playbin->playsink, "notify::volume",
1311 G_CALLBACK (notify_volume_cb), playbin);
1312 g_signal_connect (playbin->playsink, "notify::mute",
1313 G_CALLBACK (notify_mute_cb), playbin);
1314 g_signal_connect (playbin->playsink, "value-changed",
1315 G_CALLBACK (colorbalance_value_changed_cb), playbin);
1317 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1318 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1319 playbin->current_text = DEFAULT_CURRENT_TEXT;
1321 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1322 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1323 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1327 gst_play_bin_finalize (GObject * object)
1329 GstPlayBin *playbin;
1331 playbin = GST_PLAY_BIN (object);
1333 free_group (playbin, &playbin->groups[0]);
1334 free_group (playbin, &playbin->groups[1]);
1336 if (playbin->source)
1337 gst_object_unref (playbin->source);
1338 if (playbin->video_sink) {
1339 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1340 gst_object_unref (playbin->video_sink);
1342 if (playbin->audio_sink) {
1343 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1344 gst_object_unref (playbin->audio_sink);
1346 if (playbin->text_sink) {
1347 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1348 gst_object_unref (playbin->text_sink);
1351 if (playbin->elements)
1352 gst_plugin_feature_list_free (playbin->elements);
1354 g_static_rec_mutex_free (&playbin->lock);
1355 g_mutex_free (playbin->dyn_lock);
1356 g_mutex_free (playbin->elements_lock);
1358 G_OBJECT_CLASS (parent_class)->finalize (object);
1362 gst_playbin_uri_is_valid (GstPlayBin * playbin, const gchar * uri)
1366 GST_LOG_OBJECT (playbin, "checking uri '%s'", uri);
1368 /* this just checks the protocol */
1369 if (!gst_uri_is_valid (uri))
1372 for (c = uri; *c != '\0'; ++c) {
1373 if (!g_ascii_isprint (*c))
1383 GST_WARNING_OBJECT (playbin, "uri '%s' not valid, character #%u",
1384 uri, (guint) ((guintptr) c - (guintptr) uri));
1390 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1392 GstSourceGroup *group;
1395 g_warning ("cannot set NULL uri");
1399 if (!gst_playbin_uri_is_valid (playbin, uri)) {
1400 if (g_str_has_prefix (uri, "file:")) {
1401 GST_WARNING_OBJECT (playbin, "not entirely correct file URI '%s' - make "
1402 "sure to escape spaces and non-ASCII characters properly and specify "
1403 "an absolute path. Use gst_filename_to_uri() to convert filenames "
1406 /* GST_ERROR_OBJECT (playbin, "malformed URI '%s'", uri); */
1410 GST_PLAY_BIN_LOCK (playbin);
1411 group = playbin->next_group;
1413 GST_SOURCE_GROUP_LOCK (group);
1414 /* store the uri in the next group we will play */
1415 g_free (group->uri);
1416 group->uri = g_strdup (uri);
1417 group->valid = TRUE;
1418 GST_SOURCE_GROUP_UNLOCK (group);
1420 GST_DEBUG ("set new uri to %s", uri);
1421 GST_PLAY_BIN_UNLOCK (playbin);
1425 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1427 GstSourceGroup *group;
1429 GST_PLAY_BIN_LOCK (playbin);
1430 group = playbin->next_group;
1432 GST_SOURCE_GROUP_LOCK (group);
1433 g_free (group->suburi);
1434 group->suburi = g_strdup (suburi);
1435 GST_SOURCE_GROUP_UNLOCK (group);
1437 GST_DEBUG ("setting new .sub uri to %s", suburi);
1439 GST_PLAY_BIN_UNLOCK (playbin);
1443 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1445 gst_play_sink_set_flags (playbin->playsink, flags);
1446 gst_play_sink_reconfigure (playbin->playsink);
1450 gst_play_bin_get_flags (GstPlayBin * playbin)
1454 flags = gst_play_sink_get_flags (playbin->playsink);
1459 /* get the currently playing group or if nothing is playing, the next
1460 * group. Must be called with the PLAY_BIN_LOCK. */
1461 static GstSourceGroup *
1462 get_group (GstPlayBin * playbin)
1464 GstSourceGroup *result;
1466 if (!(result = playbin->curr_group))
1467 result = playbin->next_group;
1473 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1475 GstPad *sinkpad = NULL;
1476 GstSourceGroup *group;
1478 GST_PLAY_BIN_LOCK (playbin);
1479 group = get_group (playbin);
1480 if (stream < group->video_channels->len) {
1481 sinkpad = g_ptr_array_index (group->video_channels, stream);
1482 gst_object_ref (sinkpad);
1484 GST_PLAY_BIN_UNLOCK (playbin);
1490 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1492 GstPad *sinkpad = NULL;
1493 GstSourceGroup *group;
1495 GST_PLAY_BIN_LOCK (playbin);
1496 group = get_group (playbin);
1497 if (stream < group->audio_channels->len) {
1498 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1499 gst_object_ref (sinkpad);
1501 GST_PLAY_BIN_UNLOCK (playbin);
1507 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1509 GstPad *sinkpad = NULL;
1510 GstSourceGroup *group;
1512 GST_PLAY_BIN_LOCK (playbin);
1513 group = get_group (playbin);
1514 if (stream < group->text_channels->len) {
1515 sinkpad = g_ptr_array_index (group->text_channels, stream);
1516 gst_object_ref (sinkpad);
1518 GST_PLAY_BIN_UNLOCK (playbin);
1525 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1530 if (!channels || stream >= channels->len)
1533 sinkpad = g_ptr_array_index (channels, stream);
1534 g_object_get (sinkpad, "tags", &result, NULL);
1540 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1543 GstSourceGroup *group;
1545 GST_PLAY_BIN_LOCK (playbin);
1546 group = get_group (playbin);
1547 result = get_tags (playbin, group->video_channels, stream);
1548 GST_PLAY_BIN_UNLOCK (playbin);
1554 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1557 GstSourceGroup *group;
1559 GST_PLAY_BIN_LOCK (playbin);
1560 group = get_group (playbin);
1561 result = get_tags (playbin, group->audio_channels, stream);
1562 GST_PLAY_BIN_UNLOCK (playbin);
1568 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1571 GstSourceGroup *group;
1573 GST_PLAY_BIN_LOCK (playbin);
1574 group = get_group (playbin);
1575 result = get_tags (playbin, group->text_channels, stream);
1576 GST_PLAY_BIN_UNLOCK (playbin);
1582 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1584 return gst_play_sink_convert_frame (playbin->playsink, caps);
1587 /* Returns current stream number, or -1 if none has been selected yet */
1589 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1591 /* Internal API cleanup would make this easier... */
1593 GstPad *pad, *current;
1594 GstObject *selector = NULL;
1597 for (i = 0; i < channels->len; i++) {
1598 pad = g_ptr_array_index (channels, i);
1599 if ((selector = gst_pad_get_parent (pad))) {
1600 g_object_get (selector, "active-pad", ¤t, NULL);
1601 gst_object_unref (selector);
1603 if (pad == current) {
1604 gst_object_unref (current);
1610 gst_object_unref (current);
1618 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1620 GstSourceGroup *group;
1621 GPtrArray *channels;
1624 GST_PLAY_BIN_LOCK (playbin);
1626 GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1627 playbin->current_video, stream);
1629 group = get_group (playbin);
1630 if (!(channels = group->video_channels))
1633 if (stream == -1 || channels->len <= stream) {
1636 /* take channel from selected stream */
1637 sinkpad = g_ptr_array_index (channels, stream);
1641 gst_object_ref (sinkpad);
1642 GST_PLAY_BIN_UNLOCK (playbin);
1645 GstObject *selector;
1647 if ((selector = gst_pad_get_parent (sinkpad))) {
1648 /* activate the selected pad */
1649 g_object_set (selector, "active-pad", sinkpad, NULL);
1650 gst_object_unref (selector);
1652 gst_object_unref (sinkpad);
1658 GST_PLAY_BIN_UNLOCK (playbin);
1659 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1665 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1667 GstSourceGroup *group;
1668 GPtrArray *channels;
1671 GST_PLAY_BIN_LOCK (playbin);
1673 GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1674 playbin->current_audio, stream);
1676 group = get_group (playbin);
1677 if (!(channels = group->audio_channels))
1680 if (stream == -1 || channels->len <= stream) {
1683 /* take channel from selected stream */
1684 sinkpad = g_ptr_array_index (channels, stream);
1688 gst_object_ref (sinkpad);
1689 GST_PLAY_BIN_UNLOCK (playbin);
1692 GstObject *selector;
1694 if ((selector = gst_pad_get_parent (sinkpad))) {
1695 /* activate the selected pad */
1696 g_object_set (selector, "active-pad", sinkpad, NULL);
1697 gst_object_unref (selector);
1699 gst_object_unref (sinkpad);
1705 GST_PLAY_BIN_UNLOCK (playbin);
1706 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1712 _suburidecodebin_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
1714 GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
1718 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1720 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1723 if (it && gst_iterator_next (it, (gpointer) & sinkpad) == GST_ITERATOR_OK
1728 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1729 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1730 if (!gst_pad_send_event (sinkpad, event)) {
1732 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1733 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1734 if (!gst_pad_send_event (sinkpad, event))
1735 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1738 gst_object_unref (sinkpad);
1742 gst_iterator_free (it);
1746 gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
1749 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1750 gboolean done = FALSE;
1752 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1759 switch (gst_iterator_next (it, (gpointer) & sinkpad)) {
1760 case GST_ITERATOR_OK:
1761 gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
1763 gst_object_unref (sinkpad);
1765 case GST_ITERATOR_DONE:
1768 case GST_ITERATOR_RESYNC:
1769 gst_iterator_resync (it);
1771 case GST_ITERATOR_ERROR:
1776 gst_iterator_free (it);
1780 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1782 GstSourceGroup *group;
1783 GPtrArray *channels;
1786 GST_PLAY_BIN_LOCK (playbin);
1788 GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1789 playbin->current_text, stream);
1791 group = get_group (playbin);
1792 if (!(channels = group->text_channels))
1795 if (stream == -1 || channels->len <= stream) {
1798 /* take channel from selected stream */
1799 sinkpad = g_ptr_array_index (channels, stream);
1803 gst_object_ref (sinkpad);
1804 GST_PLAY_BIN_UNLOCK (playbin);
1807 GstObject *selector;
1809 if ((selector = gst_pad_get_parent (sinkpad))) {
1810 GstPad *old_sinkpad;
1812 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1814 if (old_sinkpad != sinkpad) {
1815 gboolean need_unblock, need_block, need_seek;
1816 GstPad *src, *peer = NULL, *oldpeer = NULL;
1817 GstElement *parent_element = NULL, *old_parent_element = NULL;
1819 /* Now check if we need to seek the suburidecodebin to the beginning
1820 * or if we need to block all suburidecodebin sinkpads or if we need
1821 * to unblock all suburidecodebin sinkpads
1824 peer = gst_pad_get_peer (sinkpad);
1826 oldpeer = gst_pad_get_peer (old_sinkpad);
1829 parent_element = gst_pad_get_parent_element (peer);
1831 old_parent_element = gst_pad_get_parent_element (oldpeer);
1833 need_block = (old_parent_element == group->suburidecodebin
1834 && parent_element != old_parent_element);
1835 need_unblock = (parent_element == group->suburidecodebin
1836 && parent_element != old_parent_element);
1837 need_seek = (parent_element == group->suburidecodebin);
1840 gst_object_unref (peer);
1842 gst_object_unref (oldpeer);
1844 gst_object_unref (parent_element);
1845 if (old_parent_element)
1846 gst_object_unref (old_parent_element);
1848 /* Block all suburidecodebin sinkpads */
1850 gst_play_bin_suburidecodebin_block (group->suburidecodebin, TRUE);
1852 /* activate the selected pad */
1853 g_object_set (selector, "active-pad", sinkpad, NULL);
1855 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1856 peer = gst_pad_get_peer (src);
1860 /* Flush the subtitle renderer to remove any
1861 * currently displayed subtitles. This event will
1862 * never travel outside subtitleoverlay!
1864 s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1865 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1866 gst_pad_send_event (peer, event);
1867 gst_object_unref (peer);
1869 gst_object_unref (src);
1871 /* Unblock pads if necessary */
1873 gst_play_bin_suburidecodebin_block (group->suburidecodebin, FALSE);
1875 /* seek to the beginning */
1877 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1879 gst_object_unref (selector);
1882 gst_object_unref (old_sinkpad);
1884 gst_object_unref (sinkpad);
1890 GST_PLAY_BIN_UNLOCK (playbin);
1896 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1897 const gchar * dbg, GstElement * sink)
1899 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1901 GST_PLAY_BIN_LOCK (playbin);
1902 if (*elem != sink) {
1907 gst_object_ref_sink (sink);
1911 gst_object_unref (old);
1913 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1914 GST_PLAY_BIN_UNLOCK (playbin);
1918 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1922 GST_PLAY_BIN_LOCK (playbin);
1924 /* set subtitles on all current and next decodebins. */
1925 if ((elem = playbin->groups[0].uridecodebin))
1926 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1927 if ((elem = playbin->groups[0].suburidecodebin))
1928 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1929 if ((elem = playbin->groups[1].uridecodebin))
1930 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1931 if ((elem = playbin->groups[1].suburidecodebin))
1932 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1934 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1935 GST_PLAY_BIN_UNLOCK (playbin);
1939 gst_play_bin_set_property (GObject * object, guint prop_id,
1940 const GValue * value, GParamSpec * pspec)
1942 GstPlayBin *playbin = GST_PLAY_BIN (object);
1946 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1949 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1952 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1954 case PROP_CURRENT_VIDEO:
1955 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1957 case PROP_CURRENT_AUDIO:
1958 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1960 case PROP_CURRENT_TEXT:
1961 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1963 case PROP_SUBTITLE_ENCODING:
1964 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1966 case PROP_VIDEO_SINK:
1967 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1968 g_value_get_object (value));
1970 case PROP_AUDIO_SINK:
1971 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1972 g_value_get_object (value));
1974 case PROP_VIS_PLUGIN:
1975 gst_play_sink_set_vis_plugin (playbin->playsink,
1976 g_value_get_object (value));
1978 case PROP_TEXT_SINK:
1979 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1980 g_value_get_object (value));
1983 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1986 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1988 case PROP_FONT_DESC:
1989 gst_play_sink_set_font_desc (playbin->playsink,
1990 g_value_get_string (value));
1992 case PROP_CONNECTION_SPEED:
1993 GST_PLAY_BIN_LOCK (playbin);
1994 playbin->connection_speed = g_value_get_uint (value) * 1000;
1995 GST_PLAY_BIN_UNLOCK (playbin);
1997 case PROP_BUFFER_SIZE:
1998 playbin->buffer_size = g_value_get_int (value);
2000 case PROP_BUFFER_DURATION:
2001 playbin->buffer_duration = g_value_get_int64 (value);
2003 case PROP_AV_OFFSET:
2004 gst_play_sink_set_av_offset (playbin->playsink,
2005 g_value_get_int64 (value));
2007 case PROP_RING_BUFFER_MAX_SIZE:
2008 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
2011 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2017 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
2018 const gchar * dbg, GstPlaySinkType type)
2020 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
2022 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
2023 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
2024 dbg, sink, dbg, *elem);
2027 GST_PLAY_BIN_LOCK (playbin);
2029 gst_object_ref (sink);
2030 GST_PLAY_BIN_UNLOCK (playbin);
2037 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
2040 GstPlayBin *playbin = GST_PLAY_BIN (object);
2045 GstSourceGroup *group;
2047 GST_PLAY_BIN_LOCK (playbin);
2048 group = get_group (playbin);
2049 g_value_set_string (value, group->uri);
2050 GST_PLAY_BIN_UNLOCK (playbin);
2055 GstSourceGroup *group;
2057 GST_PLAY_BIN_LOCK (playbin);
2058 group = get_group (playbin);
2059 g_value_set_string (value, group->suburi);
2060 GST_PLAY_BIN_UNLOCK (playbin);
2065 GST_OBJECT_LOCK (playbin);
2066 g_value_set_object (value, playbin->source);
2067 GST_OBJECT_UNLOCK (playbin);
2071 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
2075 GstSourceGroup *group;
2078 GST_PLAY_BIN_LOCK (playbin);
2079 group = get_group (playbin);
2080 n_video = (group->video_channels ? group->video_channels->len : 0);
2081 g_value_set_int (value, n_video);
2082 GST_PLAY_BIN_UNLOCK (playbin);
2085 case PROP_CURRENT_VIDEO:
2086 GST_PLAY_BIN_LOCK (playbin);
2087 g_value_set_int (value, playbin->current_video);
2088 GST_PLAY_BIN_UNLOCK (playbin);
2092 GstSourceGroup *group;
2095 GST_PLAY_BIN_LOCK (playbin);
2096 group = get_group (playbin);
2097 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
2098 g_value_set_int (value, n_audio);
2099 GST_PLAY_BIN_UNLOCK (playbin);
2102 case PROP_CURRENT_AUDIO:
2103 GST_PLAY_BIN_LOCK (playbin);
2104 g_value_set_int (value, playbin->current_audio);
2105 GST_PLAY_BIN_UNLOCK (playbin);
2109 GstSourceGroup *group;
2112 GST_PLAY_BIN_LOCK (playbin);
2113 group = get_group (playbin);
2114 n_text = (group->text_channels ? group->text_channels->len : 0);
2115 g_value_set_int (value, n_text);
2116 GST_PLAY_BIN_UNLOCK (playbin);
2119 case PROP_CURRENT_TEXT:
2120 GST_PLAY_BIN_LOCK (playbin);
2121 g_value_set_int (value, playbin->current_text);
2122 GST_PLAY_BIN_UNLOCK (playbin);
2124 case PROP_SUBTITLE_ENCODING:
2125 GST_PLAY_BIN_LOCK (playbin);
2126 g_value_take_string (value,
2127 gst_play_sink_get_subtitle_encoding (playbin->playsink));
2128 GST_PLAY_BIN_UNLOCK (playbin);
2130 case PROP_VIDEO_SINK:
2131 g_value_take_object (value,
2132 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2133 "video", GST_PLAY_SINK_TYPE_VIDEO));
2135 case PROP_AUDIO_SINK:
2136 g_value_take_object (value,
2137 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2138 "audio", GST_PLAY_SINK_TYPE_AUDIO));
2140 case PROP_VIS_PLUGIN:
2141 g_value_take_object (value,
2142 gst_play_sink_get_vis_plugin (playbin->playsink));
2144 case PROP_TEXT_SINK:
2145 g_value_take_object (value,
2146 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2147 "text", GST_PLAY_SINK_TYPE_TEXT));
2150 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2153 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2156 gst_value_take_buffer (value,
2157 gst_play_sink_get_last_frame (playbin->playsink));
2159 case PROP_FONT_DESC:
2160 g_value_take_string (value,
2161 gst_play_sink_get_font_desc (playbin->playsink));
2163 case PROP_CONNECTION_SPEED:
2164 GST_PLAY_BIN_LOCK (playbin);
2165 g_value_set_uint (value, playbin->connection_speed / 1000);
2166 GST_PLAY_BIN_UNLOCK (playbin);
2168 case PROP_BUFFER_SIZE:
2169 GST_OBJECT_LOCK (playbin);
2170 g_value_set_int (value, playbin->buffer_size);
2171 GST_OBJECT_UNLOCK (playbin);
2173 case PROP_BUFFER_DURATION:
2174 GST_OBJECT_LOCK (playbin);
2175 g_value_set_int64 (value, playbin->buffer_duration);
2176 GST_OBJECT_UNLOCK (playbin);
2178 case PROP_AV_OFFSET:
2179 g_value_set_int64 (value,
2180 gst_play_sink_get_av_offset (playbin->playsink));
2182 case PROP_RING_BUFFER_MAX_SIZE:
2183 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2186 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2192 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2193 gboolean valid, GstQuery * query)
2199 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2200 gst_query_parse_duration (query, &fmt, &duration);
2202 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2203 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2204 playbin->duration[i].valid = valid;
2205 playbin->duration[i].format = fmt;
2206 playbin->duration[i].duration = valid ? duration : -1;
2213 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2215 const GstFormat formats[] =
2216 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2221 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2222 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2223 query = gst_query_new_duration (formats[i]);
2225 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2227 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2228 gst_query_unref (query);
2233 gst_play_bin_query (GstElement * element, GstQuery * query)
2235 GstPlayBin *playbin = GST_PLAY_BIN (element);
2238 /* During a group switch we shouldn't allow duration queries
2239 * because it's not clear if the old or new group's duration
2240 * is returned and if the sinks are already playing new data
2241 * or old data. See bug #585969
2243 * While we're at it, also don't do any other queries during
2244 * a group switch or any other event that causes topology changes
2245 * by taking the playbin lock in any case.
2247 GST_PLAY_BIN_LOCK (playbin);
2249 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2250 GstSourceGroup *group = playbin->curr_group;
2253 GST_SOURCE_GROUP_LOCK (group);
2254 if (group->stream_changed_pending_lock) {
2255 g_mutex_lock (group->stream_changed_pending_lock);
2256 pending = group->pending || group->stream_changed_pending;
2257 g_mutex_unlock (group->stream_changed_pending_lock);
2259 pending = group->pending;
2266 gst_query_parse_duration (query, &fmt, NULL);
2267 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2268 if (fmt == playbin->duration[i].format) {
2269 ret = playbin->duration[i].valid;
2270 gst_query_set_duration (query, fmt,
2271 (ret ? playbin->duration[i].duration : -1));
2275 /* if nothing cached yet, we might as well request duration,
2276 * such as during initial startup */
2278 GST_DEBUG_OBJECT (playbin,
2279 "Taking cached duration because of pending group switch: %d", ret);
2280 GST_SOURCE_GROUP_UNLOCK (group);
2281 GST_PLAY_BIN_UNLOCK (playbin);
2285 GST_SOURCE_GROUP_UNLOCK (group);
2288 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2290 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2291 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2292 GST_PLAY_BIN_UNLOCK (playbin);
2297 /* mime types we are not handling on purpose right now, don't post a
2298 * missing-plugin message for these */
2299 static const gchar *blacklisted_mimes[] = {
2304 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2306 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2307 GstSourceGroup *group;
2309 if (gst_is_missing_plugin_message (msg)) {
2313 detail = gst_missing_plugin_message_get_installer_detail (msg);
2314 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2315 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2316 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2317 gst_message_unref (msg);
2323 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2324 const GstStructure *s = gst_message_get_structure (msg);
2326 /* Drop all stream-changed messages except the last one */
2327 if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2328 guint32 seqnum = gst_message_get_seqnum (msg);
2331 group = playbin->curr_group;
2332 g_mutex_lock (group->stream_changed_pending_lock);
2333 for (l = group->stream_changed_pending; l;) {
2334 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2336 if (l_seqnum == seqnum) {
2339 group->stream_changed_pending =
2340 g_list_delete_link (group->stream_changed_pending, l_prev);
2341 if (group->stream_changed_pending) {
2342 gst_message_unref (msg);
2350 g_mutex_unlock (group->stream_changed_pending_lock);
2352 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2353 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2354 GstObject *src = GST_OBJECT_CAST (msg->src);
2356 /* Ignore async state changes from the uridecodebin children,
2357 * see bug #602000. */
2358 group = playbin->curr_group;
2359 if (src && (group = playbin->curr_group) &&
2360 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2361 || (group->suburidecodebin
2362 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2363 GST_DEBUG_OBJECT (playbin,
2364 "Ignoring async state change of uridecodebin: %s",
2365 GST_OBJECT_NAME (src));
2366 gst_message_unref (msg);
2369 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2370 /* If we get an error of the subtitle uridecodebin transform
2371 * them into warnings and disable the subtitles */
2372 group = playbin->curr_group;
2373 if (group && group->suburidecodebin) {
2374 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2375 (group->suburidecodebin)))) {
2377 gchar *debug = NULL;
2378 GstMessage *new_msg;
2380 gboolean done = FALSE;
2382 gst_message_parse_error (msg, &err, &debug);
2383 new_msg = gst_message_new_warning (msg->src, err, debug);
2385 gst_message_unref (msg);
2390 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2391 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2392 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2393 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2395 it = gst_element_iterate_src_pads (group->suburidecodebin);
2396 while (it && !done) {
2398 GstIteratorResult res;
2400 res = gst_iterator_next (it, (gpointer) & p);
2403 case GST_ITERATOR_DONE:
2406 case GST_ITERATOR_OK:
2407 pad_removed_cb (NULL, p, group);
2408 gst_object_unref (p);
2411 case GST_ITERATOR_RESYNC:
2412 gst_iterator_resync (it);
2414 case GST_ITERATOR_ERROR:
2420 gst_iterator_free (it);
2422 gst_object_ref (group->suburidecodebin);
2423 gst_bin_remove (bin, group->suburidecodebin);
2424 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2426 if (group->sub_pending) {
2427 group->sub_pending = FALSE;
2428 no_more_pads_cb (NULL, group);
2435 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2439 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2440 GstPlayBin * playbin)
2442 const gchar *property;
2443 GstSourceGroup *group;
2444 GstSourceSelect *select = NULL;
2447 GST_PLAY_BIN_LOCK (playbin);
2448 group = get_group (playbin);
2450 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2451 if (selector == G_OBJECT (group->selector[i].selector)) {
2452 select = &group->selector[i];
2456 /* We got a pad-change after our group got switched out; no need to notify */
2458 GST_PLAY_BIN_UNLOCK (playbin);
2462 switch (select->type) {
2463 case GST_PLAY_SINK_TYPE_VIDEO:
2464 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2465 property = "current-video";
2466 playbin->current_video = get_current_stream_number (playbin,
2467 group->video_channels);
2469 case GST_PLAY_SINK_TYPE_AUDIO:
2470 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2471 property = "current-audio";
2472 playbin->current_audio = get_current_stream_number (playbin,
2473 group->audio_channels);
2475 case GST_PLAY_SINK_TYPE_TEXT:
2476 property = "current-text";
2477 playbin->current_text = get_current_stream_number (playbin,
2478 group->text_channels);
2483 GST_PLAY_BIN_UNLOCK (playbin);
2486 g_object_notify (G_OBJECT (playbin), property);
2490 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
2493 GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
2496 /* this callback sends a delayed event once the pad becomes unblocked */
2498 stream_changed_data_probe (GstPad * pad, GstMiniObject * object, gpointer data)
2500 GstSourceSelect *select = (GstSourceSelect *) data;
2503 /* we need do this just once, so cleanup first */
2504 gst_pad_remove_data_probe (pad, select->sinkpad_data_probe);
2505 select->sinkpad_data_probe = 0;
2506 e = select->sinkpad_delayed_event;
2507 select->sinkpad_delayed_event = NULL;
2509 /* really, this should not happen */
2511 GST_WARNING ("Data probed called, but no delayed event");
2515 if (GST_IS_EVENT (object)
2516 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_NEWSEGMENT) {
2517 /* push the event first, then send the delayed one */
2518 gst_event_ref (GST_EVENT_CAST (object));
2519 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2520 gst_pad_send_event (pad, e);
2523 /* send delayed event, then allow the caller to go on */
2524 gst_pad_send_event (pad, e);
2529 /* helper function to lookup stuff in lists */
2531 array_has_value (const gchar * values[], const gchar * value, gboolean exact)
2535 for (i = 0; values[i]; i++) {
2536 if (exact && !strcmp (value, values[i]))
2538 if (!exact && g_str_has_prefix (value, values[i]))
2546 GstPlayBin *playbin;
2548 GstPlaySinkType type;
2552 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2554 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2557 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2558 " with stream id %d and type %d have changed",
2559 object, ntdata->stream_id, ntdata->type);
2561 switch (ntdata->type) {
2562 case GST_PLAY_SINK_TYPE_VIDEO:
2563 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2564 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2566 case GST_PLAY_SINK_TYPE_AUDIO:
2567 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2568 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2570 case GST_PLAY_SINK_TYPE_TEXT:
2571 signal = SIGNAL_TEXT_TAGS_CHANGED;
2579 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2583 /* this function is called when a new pad is added to decodebin. We check the
2584 * type of the pad and add it to the selector element of the group.
2587 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2589 GstPlayBin *playbin;
2591 const GstStructure *s;
2594 GstPadLinkReturn res;
2595 GstSourceSelect *select = NULL;
2597 gboolean changed = FALSE;
2599 playbin = group->playbin;
2601 caps = gst_pad_get_caps_reffed (pad);
2602 s = gst_caps_get_structure (caps, 0);
2603 name = gst_structure_get_name (s);
2605 GST_DEBUG_OBJECT (playbin,
2606 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2607 GST_DEBUG_PAD_NAME (pad), caps, group);
2609 /* major type of the pad, this determines the selector to use,
2610 try exact match first so we don't prematurely match video/
2611 for video/x-dvd-subpicture */
2612 for (pass = 0; !select && pass < 2; pass++) {
2613 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2614 if (array_has_value (group->selector[i].media_list, name, pass == 0)) {
2615 select = &group->selector[i];
2617 } else if (group->selector[i].get_media_caps) {
2618 GstCaps *media_caps = group->selector[i].get_media_caps ();
2620 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2621 select = &group->selector[i];
2622 gst_caps_unref (media_caps);
2625 gst_caps_unref (media_caps);
2629 /* no selector found for the media type, don't bother linking it to a
2630 * selector. This will leave the pad unlinked and thus ignored. */
2634 GST_SOURCE_GROUP_LOCK (group);
2635 if (select->selector == NULL && playbin->have_selector) {
2636 /* no selector, create one */
2637 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2638 select->selector = gst_element_factory_make ("input-selector", NULL);
2639 if (select->selector == NULL) {
2640 /* post the missing selector message only once */
2641 playbin->have_selector = FALSE;
2642 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2643 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2645 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2646 (_("Missing element '%s' - check your GStreamer installation."),
2647 "input-selector"), (NULL));
2649 g_object_set (select->selector, "sync-streams", TRUE, NULL);
2651 g_signal_connect (select->selector, "notify::active-pad",
2652 G_CALLBACK (selector_active_pad_changed), playbin);
2654 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2655 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2656 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2660 if (select->srcpad == NULL) {
2661 if (select->selector) {
2662 /* save source pad of the selector */
2663 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2665 /* no selector, use the pad as the source pad then */
2666 select->srcpad = gst_object_ref (pad);
2669 /* block the selector srcpad. It's possible that multiple decodebins start
2670 * pushing data into the selectors before we have a chance to collect all
2671 * streams and connect the sinks, resulting in not-linked errors. After we
2672 * configured the sinks we will unblock them all. */
2673 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2674 gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
2677 /* get sinkpad for the new stream */
2678 if (select->selector) {
2679 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2680 gulong notify_tags_handler = 0;
2681 NotifyTagsData *ntdata;
2683 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2684 GST_DEBUG_PAD_NAME (sinkpad));
2686 /* store the selector for the pad */
2687 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2689 /* connect to the notify::tags signal for our
2690 * own *-tags-changed signals
2692 ntdata = g_new0 (NotifyTagsData, 1);
2693 ntdata->playbin = playbin;
2694 ntdata->stream_id = select->channels->len;
2695 ntdata->type = select->type;
2697 notify_tags_handler =
2698 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2699 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2701 g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2702 (gpointer) (guintptr) notify_tags_handler);
2704 /* store the pad in the array */
2705 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2706 g_ptr_array_add (select->channels, sinkpad);
2708 res = gst_pad_link (pad, sinkpad);
2709 if (GST_PAD_LINK_FAILED (res))
2712 /* store selector pad so we can release it */
2713 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2716 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2717 GST_DEBUG_PAD_NAME (pad), select->selector);
2720 /* no selector, don't configure anything, we'll link the new pad directly to
2725 GST_SOURCE_GROUP_UNLOCK (group);
2729 gboolean always_ok = (decodebin == group->suburidecodebin);
2731 switch (select->type) {
2732 case GST_PLAY_SINK_TYPE_VIDEO:
2733 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2734 /* we want to return NOT_LINKED for unselected pads but only for pads
2735 * from the normal uridecodebin. This makes sure that subtitle streams
2736 * are not raced past audio/video from decodebin2's multiqueue.
2737 * For pads from suburidecodebin OK should always be returned, otherwise
2738 * it will most likely stop. */
2739 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2740 signal = SIGNAL_VIDEO_CHANGED;
2742 case GST_PLAY_SINK_TYPE_AUDIO:
2743 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2744 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2745 signal = SIGNAL_AUDIO_CHANGED;
2747 case GST_PLAY_SINK_TYPE_TEXT:
2748 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2749 signal = SIGNAL_TEXT_CHANGED;
2756 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2760 gst_caps_unref (caps);
2766 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2767 name, GST_DEBUG_PAD_NAME (pad));
2772 GST_ERROR_OBJECT (playbin,
2773 "failed to link pad %s:%s to selector, reason %d",
2774 GST_DEBUG_PAD_NAME (pad), res);
2775 GST_SOURCE_GROUP_UNLOCK (group);
2780 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2781 * the selector. This will make the selector select a new pad. */
2783 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2785 GstPlayBin *playbin;
2787 GstElement *selector;
2788 GstSourceSelect *select;
2790 playbin = group->playbin;
2792 GST_DEBUG_OBJECT (playbin,
2793 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2795 GST_SOURCE_GROUP_LOCK (group);
2796 /* get the selector sinkpad */
2797 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2800 if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2801 gulong notify_tags_handler;
2803 notify_tags_handler =
2804 (guintptr) g_object_get_data (G_OBJECT (peer),
2805 "playbin2.notify_tags_handler");
2806 if (notify_tags_handler != 0)
2807 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2808 g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2810 /* remove the pad from the array */
2811 g_ptr_array_remove (select->channels, peer);
2812 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2815 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2816 gst_pad_unlink (pad, peer);
2818 /* get selector, this can be NULL when the element is removing the pads
2819 * because it's being disposed. */
2820 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2822 gst_object_unref (peer);
2826 /* release the pad to the selector, this will make the selector choose a new
2828 gst_element_release_request_pad (selector, peer);
2829 gst_object_unref (peer);
2831 gst_object_unref (selector);
2832 GST_SOURCE_GROUP_UNLOCK (group);
2839 GST_DEBUG_OBJECT (playbin, "pad not linked");
2840 GST_SOURCE_GROUP_UNLOCK (group);
2845 GST_DEBUG_OBJECT (playbin, "selector not found");
2846 GST_SOURCE_GROUP_UNLOCK (group);
2851 /* we get called when all pads are available and we must connect the sinks to
2853 * The main purpose of the code is to see if we have video/audio and subtitles
2854 * and pick the right pipelines to display them.
2856 * The selectors installed on the group tell us about the presence of
2857 * audio/video and subtitle streams. This allows us to see if we need
2858 * visualisation, video or/and audio.
2861 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2863 GstPlayBin *playbin;
2864 GstPadLinkReturn res;
2868 playbin = group->playbin;
2870 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2872 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2874 GST_SOURCE_GROUP_LOCK (group);
2875 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2876 GstSourceSelect *select = &group->selector[i];
2878 /* check if the specific media type was detected and thus has a selector
2879 * created for it. If there is the media type, get a sinkpad from the sink
2880 * and link it. We only do this if we have not yet requested the sinkpad
2882 if (select->srcpad && select->sinkpad == NULL) {
2883 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2885 gst_play_sink_request_pad (playbin->playsink, select->type);
2887 res = gst_pad_link (select->srcpad, select->sinkpad);
2888 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2889 select->media_list[0], res);
2890 if (res != GST_PAD_LINK_OK) {
2891 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2892 ("Internal playbin error."),
2893 ("Failed to link selector to sink. Error %d", res));
2897 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2898 group->pending - 1);
2900 if (group->pending > 0)
2903 if (group->suburidecodebin == decodebin)
2904 group->sub_pending = FALSE;
2906 if (group->pending == 0) {
2907 /* we are the last group to complete, we will configure the output and then
2908 * signal the other waiters. */
2909 GST_LOG_OBJECT (playbin, "last group complete");
2912 GST_LOG_OBJECT (playbin, "have more pending groups");
2915 GST_SOURCE_GROUP_UNLOCK (group);
2918 /* if we have custom sinks, configure them now */
2919 GST_SOURCE_GROUP_LOCK (group);
2921 if (group->audio_sink) {
2922 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2924 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2928 if (group->video_sink) {
2929 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2931 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2935 if (playbin->text_sink) {
2936 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
2937 playbin->text_sink);
2938 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2939 playbin->text_sink);
2942 GST_SOURCE_GROUP_UNLOCK (group);
2944 /* signal the other decodebins that they can continue now. */
2945 GST_SOURCE_GROUP_LOCK (group);
2946 /* unblock all selectors */
2947 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2948 GstSourceSelect *select = &group->selector[i];
2950 /* All streamsynchronizer streams should see stream-changed message,
2951 * to arrange for blocking unblocking. */
2952 if (select->sinkpad) {
2958 s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2961 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2962 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2963 seqnum = gst_message_get_seqnum (msg);
2964 event = gst_event_new_sink_message (msg);
2965 g_mutex_lock (group->stream_changed_pending_lock);
2966 group->stream_changed_pending =
2967 g_list_prepend (group->stream_changed_pending,
2968 GUINT_TO_POINTER (seqnum));
2970 /* remove any data probe we might have, and replace */
2971 if (select->sinkpad_delayed_event)
2972 gst_event_unref (select->sinkpad_delayed_event);
2973 select->sinkpad_delayed_event = event;
2974 if (select->sinkpad_data_probe)
2975 gst_pad_remove_data_probe (select->sinkpad,
2976 select->sinkpad_data_probe);
2978 /* we go to the trouble of setting a probe on the pad to send
2979 the playbin2-stream-changed event as sending it here might
2980 find that the pad is blocked, so we'd block here, and the
2981 pad might not be linked yet. Additionally, sending it here
2982 apparently would be on the wrong thread */
2983 select->sinkpad_data_probe =
2984 gst_pad_add_data_probe (select->sinkpad,
2985 (GCallback) stream_changed_data_probe, (gpointer) select);
2987 g_mutex_unlock (group->stream_changed_pending_lock);
2988 gst_message_unref (msg);
2991 if (select->srcpad) {
2992 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2994 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2998 GST_SOURCE_GROUP_UNLOCK (group);
3001 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
3007 GST_DEBUG ("ignoring, we are shutting down");
3008 /* Request a flushing pad from playsink that we then link to the selector.
3009 * Then we unblock the selectors so that they stop with a WRONG_STATE
3010 * instead of a NOT_LINKED error.
3012 GST_SOURCE_GROUP_LOCK (group);
3013 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3014 GstSourceSelect *select = &group->selector[i];
3016 if (select->srcpad) {
3017 if (select->sinkpad == NULL) {
3018 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
3020 gst_play_sink_request_pad (playbin->playsink,
3021 GST_PLAY_SINK_TYPE_FLUSHING);
3022 res = gst_pad_link (select->srcpad, select->sinkpad);
3023 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
3025 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
3027 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
3031 GST_SOURCE_GROUP_UNLOCK (group);
3037 drained_cb (GstElement * decodebin, GstSourceGroup * group)
3039 GstPlayBin *playbin;
3041 playbin = group->playbin;
3043 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
3045 /* after this call, we should have a next group to activate or we EOS */
3046 g_signal_emit (G_OBJECT (playbin),
3047 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
3049 /* now activate the next group. If the app did not set a uri, this will
3050 * fail and we can do EOS */
3051 setup_next_source (playbin, GST_STATE_PAUSED);
3054 /* Like gst_element_factory_can_sink_any_caps() but doesn't
3055 * allow ANY caps on the sinkpad template */
3057 _factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps)
3059 const GList *templs;
3061 templs = gst_element_factory_get_static_pad_templates (factory);
3064 GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
3066 if (templ->direction == GST_PAD_SINK) {
3067 GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
3069 if (!gst_caps_is_any (templcaps)
3070 && gst_caps_can_intersect (templcaps, caps)) {
3071 gst_caps_unref (templcaps);
3074 gst_caps_unref (templcaps);
3076 templs = g_list_next (templs);
3082 /* Called when we must provide a list of factories to plug to @pad with @caps.
3083 * We first check if we have a sink that can handle the format and if we do, we
3084 * return NULL, to expose the pad. If we have no sink (or the sink does not
3085 * work), we return the list of elements that can connect. */
3086 static GValueArray *
3087 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
3088 GstCaps * caps, GstSourceGroup * group)
3090 GstPlayBin *playbin;
3091 GList *mylist, *tmp;
3092 GValueArray *result;
3094 playbin = group->playbin;
3096 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
3097 group, GST_DEBUG_PAD_NAME (pad), caps);
3099 /* filter out the elements based on the caps. */
3100 g_mutex_lock (playbin->elements_lock);
3101 gst_play_bin_update_elements_list (playbin);
3103 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
3105 g_mutex_unlock (playbin->elements_lock);
3107 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
3108 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
3110 /* 2 additional elements for the already set audio/video sinks */
3111 result = g_value_array_new (g_list_length (mylist) + 2);
3113 /* Check if we already have an audio/video sink and if this is the case
3114 * put it as the first element of the array */
3115 if (group->audio_sink) {
3116 GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
3118 if (factory && _factory_can_sink_caps (factory, caps)) {
3119 GValue val = { 0, };
3121 g_value_init (&val, G_TYPE_OBJECT);
3122 g_value_set_object (&val, factory);
3123 result = g_value_array_append (result, &val);
3124 g_value_unset (&val);
3128 if (group->video_sink) {
3129 GstElementFactory *factory = gst_element_get_factory (group->video_sink);
3131 if (factory && _factory_can_sink_caps (factory, caps)) {
3132 GValue val = { 0, };
3134 g_value_init (&val, G_TYPE_OBJECT);
3135 g_value_set_object (&val, factory);
3136 result = g_value_array_append (result, &val);
3137 g_value_unset (&val);
3141 for (tmp = mylist; tmp; tmp = tmp->next) {
3142 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
3143 GValue val = { 0, };
3145 if (group->audio_sink && gst_element_factory_list_is_type (factory,
3146 GST_ELEMENT_FACTORY_TYPE_SINK |
3147 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
3150 if (group->video_sink && gst_element_factory_list_is_type (factory,
3151 GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
3152 | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
3156 g_value_init (&val, G_TYPE_OBJECT);
3157 g_value_set_object (&val, factory);
3158 g_value_array_append (result, &val);
3159 g_value_unset (&val);
3161 gst_plugin_feature_list_free (mylist);
3166 /* autoplug-continue decides, if a pad has raw caps that can be exposed
3167 * directly or if further decoding is necessary. We use this to expose
3168 * supported subtitles directly */
3170 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
3171 * explicitly the caps it supports and if it claims to support ANY
3172 * caps it really should support everything */
3174 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
3175 GstSourceGroup * group)
3177 gboolean ret = TRUE;
3179 GstPad *sinkpad = NULL;
3181 GST_PLAY_BIN_LOCK (group->playbin);
3182 GST_SOURCE_GROUP_LOCK (group);
3184 if ((sink = group->playbin->text_sink))
3185 sinkpad = gst_element_get_static_pad (sink, "sink");
3189 /* Ignore errors here, if a custom sink fails to go
3190 * to READY things are wrong and will error out later
3192 if (GST_STATE (sink) < GST_STATE_READY)
3193 gst_element_set_state (sink, GST_STATE_READY);
3195 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3196 if (!gst_caps_is_any (sinkcaps))
3197 ret = !gst_pad_accept_caps (sinkpad, caps);
3198 gst_caps_unref (sinkcaps);
3199 gst_object_unref (sinkpad);
3201 GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3202 ret = !gst_caps_is_subset (caps, subcaps);
3203 gst_caps_unref (subcaps);
3205 /* If autoplugging can stop don't do additional checks */
3209 /* If this is from the subtitle uridecodebin we don't need to
3210 * check the audio and video sink */
3211 if (group->suburidecodebin
3212 && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3213 GST_OBJECT_CAST (group->suburidecodebin)))
3216 if ((sink = group->audio_sink)) {
3217 sinkpad = gst_element_get_static_pad (sink, "sink");
3221 /* Ignore errors here, if a custom sink fails to go
3222 * to READY things are wrong and will error out later
3224 if (GST_STATE (sink) < GST_STATE_READY)
3225 gst_element_set_state (sink, GST_STATE_READY);
3227 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3228 if (!gst_caps_is_any (sinkcaps))
3229 ret = !gst_pad_accept_caps (sinkpad, caps);
3230 gst_caps_unref (sinkcaps);
3231 gst_object_unref (sinkpad);
3237 if ((sink = group->video_sink)) {
3238 sinkpad = gst_element_get_static_pad (sink, "sink");
3242 /* Ignore errors here, if a custom sink fails to go
3243 * to READY things are wrong and will error out later
3245 if (GST_STATE (sink) < GST_STATE_READY)
3246 gst_element_set_state (sink, GST_STATE_READY);
3248 sinkcaps = gst_pad_get_caps_reffed (sinkpad);
3249 if (!gst_caps_is_any (sinkcaps))
3250 ret = !gst_pad_accept_caps (sinkpad, caps);
3251 gst_caps_unref (sinkcaps);
3252 gst_object_unref (sinkpad);
3257 GST_SOURCE_GROUP_UNLOCK (group);
3258 GST_PLAY_BIN_UNLOCK (group->playbin);
3260 GST_DEBUG_OBJECT (group->playbin,
3261 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3262 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3268 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3272 /* ... activate it ... We do this before adding it to the bin so that we
3273 * don't accidentally make it post error messages that will stop
3275 if (GST_STATE (sink) < GST_STATE_READY &&
3276 gst_element_set_state (sink,
3277 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3281 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3282 /* Got the sink pad, now let's see if the element actually does accept the
3283 * caps that we have */
3284 if (!gst_pad_accept_caps (sinkpad, caps)) {
3285 gst_object_unref (sinkpad);
3288 gst_object_unref (sinkpad);
3294 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw-int; "
3295 "audio/x-raw-float");
3296 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw-rgb; "
3297 "video/x-raw-yuv; " "video/x-raw-gray");
3299 /* We are asked to select an element. See if the next element to check
3300 * is a sink. If this is the case, we see if the sink works by setting it to
3301 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3302 * expose the raw pad so that we can setup the mixers. */
3303 static GstAutoplugSelectResult
3304 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3305 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3307 GstPlayBin *playbin;
3308 GstElement *element;
3310 GstPlaySinkType type;
3313 playbin = group->playbin;
3315 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3316 group, GST_DEBUG_PAD_NAME (pad), caps);
3318 GST_DEBUG_OBJECT (playbin, "checking factory %s",
3319 GST_PLUGIN_FEATURE_NAME (factory));
3321 /* if it's not a sink, we make sure the element is compatible with
3323 if (!gst_element_factory_list_is_type (factory,
3324 GST_ELEMENT_FACTORY_TYPE_SINK)) {
3325 gboolean isvideodec = gst_element_factory_list_is_type (factory,
3326 GST_ELEMENT_FACTORY_TYPE_DECODER |
3327 GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
3328 GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
3329 gboolean isaudiodec = gst_element_factory_list_is_type (factory,
3330 GST_ELEMENT_FACTORY_TYPE_DECODER |
3331 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
3333 /* If it is a decoder and we have a fixed sink for the media
3334 * type it outputs, check that the decoder is compatible with this sink */
3335 if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) {
3336 gboolean compatible = TRUE;
3342 sink = group->audio_sink;
3344 sink = group->video_sink;
3346 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3347 GstPlayFlags flags = gst_play_bin_get_flags (playbin);
3349 (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) :
3350 gst_static_caps_get (&raw_video_caps);
3352 caps = gst_pad_get_caps_reffed (sinkpad);
3354 /* If the sink supports raw audio/video, we first check
3355 * if the decoder could output any raw audio/video format
3356 * and assume it is compatible with the sink then. We don't
3357 * do a complete compatibility check here if converters
3358 * are plugged between the decoder and the sink because
3359 * the converters will convert between raw formats and
3360 * even if the decoder format is not supported by the decoder
3361 * a converter will convert it.
3363 * We assume here that the converters can convert between
3366 if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO)
3367 && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec
3368 && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO)
3369 && gst_caps_can_intersect (caps, raw_caps))) {
3370 compatible = gst_element_factory_can_src_any_caps (factory, raw_caps)
3371 || gst_element_factory_can_src_any_caps (factory, caps);
3373 compatible = gst_element_factory_can_src_any_caps (factory, caps);
3376 gst_object_unref (sinkpad);
3377 gst_caps_unref (caps);
3381 return GST_AUTOPLUG_SELECT_TRY;
3383 GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink",
3384 GST_PLUGIN_FEATURE_NAME (factory));
3386 return GST_AUTOPLUG_SELECT_SKIP;
3388 return GST_AUTOPLUG_SELECT_TRY;
3391 /* it's a sink, see if an instance of it actually works */
3392 GST_DEBUG_OBJECT (playbin, "we found a sink");
3394 klass = gst_element_factory_get_klass (factory);
3396 /* figure out the klass */
3397 if (strstr (klass, "Audio")) {
3398 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3399 type = GST_PLAY_SINK_TYPE_AUDIO;
3400 sinkp = &group->audio_sink;
3401 } else if (strstr (klass, "Video")) {
3402 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3403 type = GST_PLAY_SINK_TYPE_VIDEO;
3404 sinkp = &group->video_sink;
3406 /* unknown klass, skip this element */
3407 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3408 return GST_AUTOPLUG_SELECT_SKIP;
3411 /* if we are asked to do visualisations and it's an audio sink, skip the
3412 * element. We can only do visualisations with raw sinks */
3413 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3414 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3415 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3416 return GST_AUTOPLUG_SELECT_SKIP;
3420 /* now see if we already have a sink element */
3421 GST_SOURCE_GROUP_LOCK (group);
3423 GstElement *sink = gst_object_ref (*sinkp);
3425 if (sink_accepts_caps (sink, caps)) {
3426 GST_DEBUG_OBJECT (playbin,
3427 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3428 GST_ELEMENT_NAME (sink), caps);
3429 gst_object_unref (sink);
3430 GST_SOURCE_GROUP_UNLOCK (group);
3431 return GST_AUTOPLUG_SELECT_EXPOSE;
3433 GST_DEBUG_OBJECT (playbin,
3434 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3435 GST_ELEMENT_NAME (sink), caps);
3436 gst_object_unref (sink);
3437 GST_SOURCE_GROUP_UNLOCK (group);
3438 return GST_AUTOPLUG_SELECT_SKIP;
3441 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3443 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3444 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3445 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3446 GST_SOURCE_GROUP_UNLOCK (group);
3447 return GST_AUTOPLUG_SELECT_SKIP;
3450 /* Check if the selected sink actually supports the
3451 * caps and can be set to READY*/
3452 if (!sink_accepts_caps (element, caps)) {
3453 gst_element_set_state (element, GST_STATE_NULL);
3454 gst_object_unref (element);
3455 GST_SOURCE_GROUP_UNLOCK (group);
3456 return GST_AUTOPLUG_SELECT_SKIP;
3459 /* remember the sink in the group now, the element is floating, we take
3462 * store the sink in the group, we will configure it later when we
3463 * reconfigure the sink */
3464 GST_DEBUG_OBJECT (playbin, "remember sink");
3465 gst_object_ref_sink (element);
3467 GST_SOURCE_GROUP_UNLOCK (group);
3469 /* tell decodebin to expose the pad because we are going to use this
3471 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3473 return GST_AUTOPLUG_SELECT_EXPOSE;
3477 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3478 GstSourceGroup * group)
3480 GstPlayBin *playbin;
3483 playbin = group->playbin;
3485 g_object_get (group->uridecodebin, "source", &source, NULL);
3487 GST_OBJECT_LOCK (playbin);
3488 if (playbin->source)
3489 gst_object_unref (playbin->source);
3490 playbin->source = source;
3491 GST_OBJECT_UNLOCK (playbin);
3493 g_object_notify (G_OBJECT (playbin), "source");
3495 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3496 0, playbin->source);
3499 /* must be called with the group lock */
3501 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3504 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3506 if (group->uridecodebin)
3507 gst_element_set_locked_state (group->uridecodebin, locked);
3508 if (group->suburidecodebin)
3509 gst_element_set_locked_state (group->suburidecodebin, locked);
3514 /* must be called with PLAY_BIN_LOCK */
3516 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3518 GstElement *uridecodebin;
3519 GstElement *suburidecodebin = NULL;
3522 g_return_val_if_fail (group->valid, FALSE);
3523 g_return_val_if_fail (!group->active, FALSE);
3525 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3527 GST_SOURCE_GROUP_LOCK (group);
3529 /* First set up the custom sources */
3530 if (playbin->audio_sink)
3531 group->audio_sink = gst_object_ref (playbin->audio_sink);
3532 if (playbin->video_sink)
3533 group->video_sink = gst_object_ref (playbin->video_sink);
3535 g_list_free (group->stream_changed_pending);
3536 group->stream_changed_pending = NULL;
3537 if (!group->stream_changed_pending_lock)
3538 group->stream_changed_pending_lock = g_mutex_new ();
3540 if (group->uridecodebin) {
3541 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3542 uridecodebin = group->uridecodebin;
3543 gst_element_set_state (uridecodebin, GST_STATE_READY);
3544 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
3546 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3547 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3550 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3551 group->uridecodebin = gst_object_ref (uridecodebin);
3554 flags = gst_play_sink_get_flags (playbin->playsink);
3556 g_object_set (uridecodebin,
3557 /* configure connection speed */
3558 "connection-speed", playbin->connection_speed / 1000,
3561 /* configure download buffering */
3562 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3563 /* configure buffering of demuxed/parsed data */
3564 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3565 /* configure buffering parameters */
3566 "buffer-duration", playbin->buffer_duration,
3567 "buffer-size", playbin->buffer_size,
3568 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3570 /* connect pads and other things */
3571 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3572 G_CALLBACK (pad_added_cb), group);
3573 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3574 G_CALLBACK (pad_removed_cb), group);
3575 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3576 G_CALLBACK (no_more_pads_cb), group);
3577 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3578 G_CALLBACK (notify_source_cb), group);
3580 /* we have 1 pending no-more-pads */
3583 /* is called when the uridecodebin is out of data and we can switch to the
3586 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3589 /* will be called when a new media type is found. We return a list of decoders
3590 * including sinks for decodebin to try */
3591 group->autoplug_factories_id =
3592 g_signal_connect (uridecodebin, "autoplug-factories",
3593 G_CALLBACK (autoplug_factories_cb), group);
3594 group->autoplug_select_id =
3595 g_signal_connect (uridecodebin, "autoplug-select",
3596 G_CALLBACK (autoplug_select_cb), group);
3597 group->autoplug_continue_id =
3598 g_signal_connect (uridecodebin, "autoplug-continue",
3599 G_CALLBACK (autoplug_continue_cb), group);
3601 if (group->suburi) {
3603 if (group->suburidecodebin) {
3604 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3605 suburidecodebin = group->suburidecodebin;
3606 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3607 gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
3609 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3610 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3611 if (!suburidecodebin)
3614 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3615 group->suburidecodebin = gst_object_ref (suburidecodebin);
3618 g_object_set (suburidecodebin,
3619 /* configure connection speed */
3620 "connection-speed", playbin->connection_speed,
3622 "uri", group->suburi, NULL);
3624 /* connect pads and other things */
3625 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3626 G_CALLBACK (pad_added_cb), group);
3627 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3628 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3629 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3630 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3632 group->sub_autoplug_continue_id =
3633 g_signal_connect (suburidecodebin, "autoplug-continue",
3634 G_CALLBACK (autoplug_continue_cb), group);
3636 /* we have 2 pending no-more-pads */
3638 group->sub_pending = TRUE;
3640 group->sub_pending = FALSE;
3643 /* release the group lock before setting the state of the decodebins, they
3644 * might fire signals in this thread that we need to handle with the
3645 * group_lock taken. */
3646 GST_SOURCE_GROUP_UNLOCK (group);
3648 if (suburidecodebin) {
3649 if (gst_element_set_state (suburidecodebin,
3650 target) == GST_STATE_CHANGE_FAILURE) {
3651 GST_DEBUG_OBJECT (playbin,
3652 "failed state change of subtitle uridecodebin");
3653 GST_SOURCE_GROUP_LOCK (group);
3655 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3656 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3657 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3658 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3659 /* Might already be removed because of an error message */
3660 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3661 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3662 if (group->sub_pending) {
3664 group->sub_pending = FALSE;
3666 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3667 GST_SOURCE_GROUP_UNLOCK (group);
3670 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3671 goto uridecodebin_failure;
3673 GST_SOURCE_GROUP_LOCK (group);
3674 /* alow state changes of the playbin2 affect the group elements now */
3675 group_set_locked_state_unlocked (playbin, group, FALSE);
3676 group->active = TRUE;
3677 GST_SOURCE_GROUP_UNLOCK (group);
3686 /* delete any custom sinks we might have */
3687 if (group->audio_sink) {
3688 /* If this is a automatically created sink set it to NULL */
3689 if (group->audio_sink != playbin->audio_sink)
3690 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3691 gst_object_unref (group->audio_sink);
3693 group->audio_sink = NULL;
3694 if (group->video_sink) {
3695 /* If this is a automatically created sink set it to NULL */
3696 if (group->video_sink != playbin->video_sink)
3697 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3698 gst_object_unref (group->video_sink);
3700 group->video_sink = NULL;
3702 GST_SOURCE_GROUP_UNLOCK (group);
3704 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3706 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3708 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3709 (_("Could not create \"uridecodebin\" element.")), (NULL));
3712 uridecodebin_failure:
3714 /* delete any custom sinks we might have */
3715 if (group->audio_sink) {
3716 /* If this is a automatically created sink set it to NULL */
3717 if (group->audio_sink != playbin->audio_sink)
3718 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3719 gst_object_unref (group->audio_sink);
3721 group->audio_sink = NULL;
3722 if (group->video_sink) {
3723 /* If this is a automatically created sink set it to NULL */
3724 if (group->video_sink != playbin->video_sink)
3725 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3726 gst_object_unref (group->video_sink);
3728 group->video_sink = NULL;
3730 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3735 /* unlink a group of uridecodebins from the sink.
3736 * must be called with PLAY_BIN_LOCK */
3738 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3742 g_return_val_if_fail (group->valid, FALSE);
3743 g_return_val_if_fail (group->active, FALSE);
3745 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3747 GST_SOURCE_GROUP_LOCK (group);
3748 group->active = FALSE;
3749 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3750 GstSourceSelect *select = &group->selector[i];
3752 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3754 if (select->srcpad) {
3755 if (select->sinkpad) {
3756 GST_LOG_OBJECT (playbin, "unlinking from sink");
3757 gst_pad_unlink (select->srcpad, select->sinkpad);
3760 GST_LOG_OBJECT (playbin, "release sink pad");
3761 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3762 select->sinkpad = NULL;
3765 gst_object_unref (select->srcpad);
3766 select->srcpad = NULL;
3769 if (select->selector) {
3772 /* release and unref requests pad from the selector */
3773 for (n = 0; n < select->channels->len; n++) {
3774 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3776 gst_element_release_request_pad (select->selector, sinkpad);
3777 gst_object_unref (sinkpad);
3779 g_ptr_array_set_size (select->channels, 0);
3781 gst_element_set_state (select->selector, GST_STATE_NULL);
3782 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3783 select->selector = NULL;
3786 /* delete any custom sinks we might have */
3787 if (group->audio_sink) {
3788 /* If this is a automatically created sink set it to NULL */
3789 if (group->audio_sink != playbin->audio_sink)
3790 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3791 gst_object_unref (group->audio_sink);
3793 group->audio_sink = NULL;
3794 if (group->video_sink) {
3795 /* If this is a automatically created sink set it to NULL */
3796 if (group->video_sink != playbin->video_sink)
3797 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3798 gst_object_unref (group->video_sink);
3800 group->video_sink = NULL;
3802 if (group->uridecodebin) {
3803 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3804 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3805 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3806 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3807 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3808 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3809 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3810 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3811 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3814 if (group->suburidecodebin) {
3815 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3816 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3817 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3818 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3820 /* Might already be removed because of errors */
3821 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3822 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3825 GST_SOURCE_GROUP_UNLOCK (group);
3830 /* setup the next group to play, this assumes the next_group is valid and
3831 * configured. It swaps out the current_group and activates the valid
3834 setup_next_source (GstPlayBin * playbin, GstState target)
3836 GstSourceGroup *new_group, *old_group;
3838 GST_DEBUG_OBJECT (playbin, "setup sources");
3840 /* see if there is a next group */
3841 GST_PLAY_BIN_LOCK (playbin);
3842 new_group = playbin->next_group;
3843 if (!new_group || !new_group->valid)
3846 /* first unlink the current source, if any */
3847 old_group = playbin->curr_group;
3848 if (old_group && old_group->valid && old_group->active) {
3849 gst_play_bin_update_cached_duration (playbin);
3850 /* unlink our pads with the sink */
3851 deactivate_group (playbin, old_group);
3852 old_group->valid = FALSE;
3855 /* swap old and new */
3856 playbin->curr_group = new_group;
3857 playbin->next_group = old_group;
3859 /* activate the new group */
3860 if (!activate_group (playbin, new_group, target))
3861 goto activate_failed;
3863 GST_PLAY_BIN_UNLOCK (playbin);
3870 GST_DEBUG_OBJECT (playbin, "no next group");
3871 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3872 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3873 GST_PLAY_BIN_UNLOCK (playbin);
3878 GST_DEBUG_OBJECT (playbin, "activate failed");
3879 GST_PLAY_BIN_UNLOCK (playbin);
3884 /* The group that is currently playing is copied again to the
3885 * next_group so that it will start playing the next time.
3888 save_current_group (GstPlayBin * playbin)
3890 GstSourceGroup *curr_group;
3892 GST_DEBUG_OBJECT (playbin, "save current group");
3894 /* see if there is a current group */
3895 GST_PLAY_BIN_LOCK (playbin);
3896 curr_group = playbin->curr_group;
3897 if (curr_group && curr_group->valid && curr_group->active) {
3898 /* unlink our pads with the sink */
3899 deactivate_group (playbin, curr_group);
3901 /* swap old and new */
3902 playbin->curr_group = playbin->next_group;
3903 playbin->next_group = curr_group;
3904 GST_PLAY_BIN_UNLOCK (playbin);
3909 /* clear the locked state from all groups. This function is called before a
3910 * state change to NULL is performed on them. */
3912 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3914 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3917 GST_PLAY_BIN_LOCK (playbin);
3918 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3919 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3920 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3921 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3922 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3923 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3924 GST_PLAY_BIN_UNLOCK (playbin);
3929 static GstStateChangeReturn
3930 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3932 GstStateChangeReturn ret;
3933 GstPlayBin *playbin;
3934 gboolean do_save = FALSE;
3936 playbin = GST_PLAY_BIN (element);
3938 switch (transition) {
3939 case GST_STATE_CHANGE_NULL_TO_READY:
3940 memset (&playbin->duration, 0, sizeof (playbin->duration));
3942 case GST_STATE_CHANGE_READY_TO_PAUSED:
3943 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3944 memset (&playbin->duration, 0, sizeof (playbin->duration));
3945 g_atomic_int_set (&playbin->shutdown, 0);
3947 if (!setup_next_source (playbin, GST_STATE_READY)) {
3948 ret = GST_STATE_CHANGE_FAILURE;
3952 case GST_STATE_CHANGE_PAUSED_TO_READY:
3954 /* FIXME unlock our waiting groups */
3955 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3956 g_atomic_int_set (&playbin->shutdown, 1);
3957 memset (&playbin->duration, 0, sizeof (playbin->duration));
3959 /* wait for all callbacks to end by taking the lock.
3960 * No dynamic (critical) new callbacks will
3961 * be able to happen as we set the shutdown flag. */
3962 GST_PLAY_BIN_DYN_LOCK (playbin);
3963 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3964 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3967 case GST_STATE_CHANGE_READY_TO_NULL:
3968 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3969 * an no state change PAUSED to READY passes here,
3970 * though it is a nice-to-have ... */
3971 if (!g_atomic_int_get (&playbin->shutdown)) {
3975 memset (&playbin->duration, 0, sizeof (playbin->duration));
3977 /* unlock so that all groups go to NULL */
3978 groups_set_locked_state (playbin, FALSE);
3984 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3985 if (ret == GST_STATE_CHANGE_FAILURE)
3988 switch (transition) {
3989 case GST_STATE_CHANGE_READY_TO_PAUSED:
3991 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3992 /* FIXME Release audio device when we implement that */
3994 case GST_STATE_CHANGE_PAUSED_TO_READY:
3995 save_current_group (playbin);
3997 case GST_STATE_CHANGE_READY_TO_NULL:
4001 /* also do missed state change down to READY */
4003 save_current_group (playbin);
4004 /* Deactive the groups, set the uridecodebins to NULL
4007 for (i = 0; i < 2; i++) {
4008 if (playbin->groups[i].active && playbin->groups[i].valid) {
4009 deactivate_group (playbin, &playbin->groups[i]);
4010 playbin->groups[i].valid = FALSE;
4013 if (playbin->groups[i].uridecodebin) {
4014 gst_element_set_state (playbin->groups[i].uridecodebin,
4016 gst_object_unref (playbin->groups[i].uridecodebin);
4017 playbin->groups[i].uridecodebin = NULL;
4020 if (playbin->groups[i].suburidecodebin) {
4021 gst_element_set_state (playbin->groups[i].suburidecodebin,
4023 gst_object_unref (playbin->groups[i].suburidecodebin);
4024 playbin->groups[i].suburidecodebin = NULL;
4028 /* Set our sinks back to NULL, they might not be child of playbin */
4029 if (playbin->audio_sink)
4030 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
4031 if (playbin->video_sink)
4032 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
4033 if (playbin->text_sink)
4034 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
4036 /* make sure the groups don't perform a state change anymore until we
4037 * enable them again */
4038 groups_set_locked_state (playbin, TRUE);
4050 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
4051 GstSourceGroup *curr_group;
4053 curr_group = playbin->curr_group;
4054 if (curr_group && curr_group->active && curr_group->valid) {
4055 /* unlink our pads with the sink */
4056 deactivate_group (playbin, curr_group);
4057 curr_group->valid = FALSE;
4060 /* Swap current and next group back */
4061 playbin->curr_group = playbin->next_group;
4062 playbin->next_group = curr_group;
4069 gst_play_bin_xoverlay_expose (GstXOverlay * overlay)
4071 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4073 gst_x_overlay_expose (GST_X_OVERLAY (playbin->playsink));
4077 gst_play_bin_xoverlay_handle_events (GstXOverlay * overlay,
4078 gboolean handle_events)
4080 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4082 gst_x_overlay_handle_events (GST_X_OVERLAY (playbin->playsink),
4087 gst_play_bin_xoverlay_set_render_rectangle (GstXOverlay * overlay, gint x,
4088 gint y, gint width, gint height)
4090 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4092 gst_x_overlay_set_render_rectangle (GST_X_OVERLAY (playbin->playsink), x, y,
4097 gst_play_bin_xoverlay_set_window_handle (GstXOverlay * overlay, guintptr handle)
4099 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4101 gst_x_overlay_set_window_handle (GST_X_OVERLAY (playbin->playsink), handle);
4105 gst_play_bin_xoverlay_init (gpointer g_iface, gpointer g_iface_data)
4107 GstXOverlayClass *iface = (GstXOverlayClass *) g_iface;
4108 iface->expose = gst_play_bin_xoverlay_expose;
4109 iface->handle_events = gst_play_bin_xoverlay_handle_events;
4110 iface->set_render_rectangle = gst_play_bin_xoverlay_set_render_rectangle;
4111 iface->set_window_handle = gst_play_bin_xoverlay_set_window_handle;
4115 gst_play_bin_implements_interface_supported (GstImplementsInterface * iface,
4118 if (type == GST_TYPE_X_OVERLAY || type == GST_TYPE_STREAM_VOLUME ||
4119 type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE)
4126 gst_play_bin_implements_interface_init (gpointer g_iface, gpointer g_iface_data)
4128 GstImplementsInterfaceClass *iface = (GstImplementsInterfaceClass *) g_iface;
4129 iface->supported = gst_play_bin_implements_interface_supported;
4133 gst_play_bin_navigation_send_event (GstNavigation * navigation,
4134 GstStructure * structure)
4136 GstPlayBin *playbin = GST_PLAY_BIN (navigation);
4138 gst_navigation_send_event (GST_NAVIGATION (playbin->playsink), structure);
4142 gst_play_bin_navigation_init (gpointer g_iface, gpointer g_iface_data)
4144 GstNavigationInterface *iface = (GstNavigationInterface *) g_iface;
4146 iface->send_event = gst_play_bin_navigation_send_event;
4149 static const GList *
4150 gst_play_bin_colorbalance_list_channels (GstColorBalance * balance)
4152 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4155 gst_color_balance_list_channels (GST_COLOR_BALANCE (playbin->playsink));
4159 gst_play_bin_colorbalance_set_value (GstColorBalance * balance,
4160 GstColorBalanceChannel * channel, gint value)
4162 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4164 gst_color_balance_set_value (GST_COLOR_BALANCE (playbin->playsink), channel,
4169 gst_play_bin_colorbalance_get_value (GstColorBalance * balance,
4170 GstColorBalanceChannel * channel)
4172 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4174 return gst_color_balance_get_value (GST_COLOR_BALANCE (playbin->playsink),
4178 static GstColorBalanceType
4179 gst_play_bin_colorbalance_get_balance_type (GstColorBalance * balance)
4181 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4184 gst_color_balance_get_balance_type (GST_COLOR_BALANCE
4185 (playbin->playsink));
4189 gst_play_bin_colorbalance_init (gpointer g_iface, gpointer g_iface_data)
4191 GstColorBalanceClass *iface = (GstColorBalanceClass *) g_iface;
4193 iface->list_channels = gst_play_bin_colorbalance_list_channels;
4194 iface->set_value = gst_play_bin_colorbalance_set_value;
4195 iface->get_value = gst_play_bin_colorbalance_get_value;
4196 iface->get_balance_type = gst_play_bin_colorbalance_get_balance_type;
4200 gst_play_bin2_plugin_init (GstPlugin * plugin)
4202 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
4204 return gst_element_register (plugin, "playbin2", GST_RANK_NONE,