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", "send-event-mode",
1308 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1309 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1310 /* Connect to notify::volume and notify::mute signals for proxying */
1311 g_signal_connect (playbin->playsink, "notify::volume",
1312 G_CALLBACK (notify_volume_cb), playbin);
1313 g_signal_connect (playbin->playsink, "notify::mute",
1314 G_CALLBACK (notify_mute_cb), playbin);
1315 g_signal_connect (playbin->playsink, "value-changed",
1316 G_CALLBACK (colorbalance_value_changed_cb), playbin);
1318 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1319 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1320 playbin->current_text = DEFAULT_CURRENT_TEXT;
1322 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1323 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1324 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1328 gst_play_bin_finalize (GObject * object)
1330 GstPlayBin *playbin;
1332 playbin = GST_PLAY_BIN (object);
1334 free_group (playbin, &playbin->groups[0]);
1335 free_group (playbin, &playbin->groups[1]);
1337 if (playbin->source)
1338 gst_object_unref (playbin->source);
1339 if (playbin->video_sink) {
1340 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1341 gst_object_unref (playbin->video_sink);
1343 if (playbin->audio_sink) {
1344 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1345 gst_object_unref (playbin->audio_sink);
1347 if (playbin->text_sink) {
1348 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1349 gst_object_unref (playbin->text_sink);
1352 if (playbin->elements)
1353 gst_plugin_feature_list_free (playbin->elements);
1355 g_static_rec_mutex_free (&playbin->lock);
1356 g_mutex_free (playbin->dyn_lock);
1357 g_mutex_free (playbin->elements_lock);
1359 G_OBJECT_CLASS (parent_class)->finalize (object);
1363 gst_playbin_uri_is_valid (GstPlayBin * playbin, const gchar * uri)
1367 GST_LOG_OBJECT (playbin, "checking uri '%s'", uri);
1369 /* this just checks the protocol */
1370 if (!gst_uri_is_valid (uri))
1373 for (c = uri; *c != '\0'; ++c) {
1374 if (!g_ascii_isprint (*c))
1384 GST_WARNING_OBJECT (playbin, "uri '%s' not valid, character #%u",
1385 uri, (guint) ((guintptr) c - (guintptr) uri));
1391 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1393 GstSourceGroup *group;
1396 g_warning ("cannot set NULL uri");
1400 if (!gst_playbin_uri_is_valid (playbin, uri)) {
1401 if (g_str_has_prefix (uri, "file:")) {
1402 GST_WARNING_OBJECT (playbin, "not entirely correct file URI '%s' - make "
1403 "sure to escape spaces and non-ASCII characters properly and specify "
1404 "an absolute path. Use gst_filename_to_uri() to convert filenames "
1407 /* GST_ERROR_OBJECT (playbin, "malformed URI '%s'", uri); */
1411 GST_PLAY_BIN_LOCK (playbin);
1412 group = playbin->next_group;
1414 GST_SOURCE_GROUP_LOCK (group);
1415 /* store the uri in the next group we will play */
1416 g_free (group->uri);
1417 group->uri = g_strdup (uri);
1418 group->valid = TRUE;
1419 GST_SOURCE_GROUP_UNLOCK (group);
1421 GST_DEBUG ("set new uri to %s", uri);
1422 GST_PLAY_BIN_UNLOCK (playbin);
1426 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1428 GstSourceGroup *group;
1430 GST_PLAY_BIN_LOCK (playbin);
1431 group = playbin->next_group;
1433 GST_SOURCE_GROUP_LOCK (group);
1434 g_free (group->suburi);
1435 group->suburi = g_strdup (suburi);
1436 GST_SOURCE_GROUP_UNLOCK (group);
1438 GST_DEBUG ("setting new .sub uri to %s", suburi);
1440 GST_PLAY_BIN_UNLOCK (playbin);
1444 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1446 gst_play_sink_set_flags (playbin->playsink, flags);
1447 gst_play_sink_reconfigure (playbin->playsink);
1451 gst_play_bin_get_flags (GstPlayBin * playbin)
1455 flags = gst_play_sink_get_flags (playbin->playsink);
1460 /* get the currently playing group or if nothing is playing, the next
1461 * group. Must be called with the PLAY_BIN_LOCK. */
1462 static GstSourceGroup *
1463 get_group (GstPlayBin * playbin)
1465 GstSourceGroup *result;
1467 if (!(result = playbin->curr_group))
1468 result = playbin->next_group;
1474 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1476 GstPad *sinkpad = NULL;
1477 GstSourceGroup *group;
1479 GST_PLAY_BIN_LOCK (playbin);
1480 group = get_group (playbin);
1481 if (stream < group->video_channels->len) {
1482 sinkpad = g_ptr_array_index (group->video_channels, stream);
1483 gst_object_ref (sinkpad);
1485 GST_PLAY_BIN_UNLOCK (playbin);
1491 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1493 GstPad *sinkpad = NULL;
1494 GstSourceGroup *group;
1496 GST_PLAY_BIN_LOCK (playbin);
1497 group = get_group (playbin);
1498 if (stream < group->audio_channels->len) {
1499 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1500 gst_object_ref (sinkpad);
1502 GST_PLAY_BIN_UNLOCK (playbin);
1508 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1510 GstPad *sinkpad = NULL;
1511 GstSourceGroup *group;
1513 GST_PLAY_BIN_LOCK (playbin);
1514 group = get_group (playbin);
1515 if (stream < group->text_channels->len) {
1516 sinkpad = g_ptr_array_index (group->text_channels, stream);
1517 gst_object_ref (sinkpad);
1519 GST_PLAY_BIN_UNLOCK (playbin);
1526 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1531 if (!channels || stream >= channels->len)
1534 sinkpad = g_ptr_array_index (channels, stream);
1535 g_object_get (sinkpad, "tags", &result, NULL);
1541 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1544 GstSourceGroup *group;
1546 GST_PLAY_BIN_LOCK (playbin);
1547 group = get_group (playbin);
1548 result = get_tags (playbin, group->video_channels, stream);
1549 GST_PLAY_BIN_UNLOCK (playbin);
1555 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1558 GstSourceGroup *group;
1560 GST_PLAY_BIN_LOCK (playbin);
1561 group = get_group (playbin);
1562 result = get_tags (playbin, group->audio_channels, stream);
1563 GST_PLAY_BIN_UNLOCK (playbin);
1569 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1572 GstSourceGroup *group;
1574 GST_PLAY_BIN_LOCK (playbin);
1575 group = get_group (playbin);
1576 result = get_tags (playbin, group->text_channels, stream);
1577 GST_PLAY_BIN_UNLOCK (playbin);
1583 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
1585 return gst_play_sink_convert_frame (playbin->playsink, caps);
1588 /* Returns current stream number, or -1 if none has been selected yet */
1590 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1592 /* Internal API cleanup would make this easier... */
1594 GstPad *pad, *current;
1595 GstObject *selector = NULL;
1598 for (i = 0; i < channels->len; i++) {
1599 pad = g_ptr_array_index (channels, i);
1600 if ((selector = gst_pad_get_parent (pad))) {
1601 g_object_get (selector, "active-pad", ¤t, NULL);
1602 gst_object_unref (selector);
1604 if (pad == current) {
1605 gst_object_unref (current);
1611 gst_object_unref (current);
1619 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1621 GstSourceGroup *group;
1622 GPtrArray *channels;
1625 GST_PLAY_BIN_LOCK (playbin);
1627 GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1628 playbin->current_video, stream);
1630 group = get_group (playbin);
1631 if (!(channels = group->video_channels))
1634 if (stream == -1 || channels->len <= stream) {
1637 /* take channel from selected stream */
1638 sinkpad = g_ptr_array_index (channels, stream);
1642 gst_object_ref (sinkpad);
1643 GST_PLAY_BIN_UNLOCK (playbin);
1646 GstObject *selector;
1648 if ((selector = gst_pad_get_parent (sinkpad))) {
1649 /* activate the selected pad */
1650 g_object_set (selector, "active-pad", sinkpad, NULL);
1651 gst_object_unref (selector);
1653 gst_object_unref (sinkpad);
1659 GST_PLAY_BIN_UNLOCK (playbin);
1660 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1666 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1668 GstSourceGroup *group;
1669 GPtrArray *channels;
1672 GST_PLAY_BIN_LOCK (playbin);
1674 GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1675 playbin->current_audio, stream);
1677 group = get_group (playbin);
1678 if (!(channels = group->audio_channels))
1681 if (stream == -1 || channels->len <= stream) {
1684 /* take channel from selected stream */
1685 sinkpad = g_ptr_array_index (channels, stream);
1689 gst_object_ref (sinkpad);
1690 GST_PLAY_BIN_UNLOCK (playbin);
1693 GstObject *selector;
1695 if ((selector = gst_pad_get_parent (sinkpad))) {
1696 /* activate the selected pad */
1697 g_object_set (selector, "active-pad", sinkpad, NULL);
1698 gst_object_unref (selector);
1700 gst_object_unref (sinkpad);
1706 GST_PLAY_BIN_UNLOCK (playbin);
1707 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1713 _suburidecodebin_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
1715 GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
1719 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1721 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1724 if (it && gst_iterator_next (it, (gpointer) & sinkpad) == GST_ITERATOR_OK
1729 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1730 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1731 if (!gst_pad_send_event (sinkpad, event)) {
1733 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1734 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1735 if (!gst_pad_send_event (sinkpad, event))
1736 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1739 gst_object_unref (sinkpad);
1743 gst_iterator_free (it);
1747 gst_play_bin_suburidecodebin_block (GstElement * suburidecodebin,
1750 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1751 gboolean done = FALSE;
1753 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1760 switch (gst_iterator_next (it, (gpointer) & sinkpad)) {
1761 case GST_ITERATOR_OK:
1762 gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
1764 gst_object_unref (sinkpad);
1766 case GST_ITERATOR_DONE:
1769 case GST_ITERATOR_RESYNC:
1770 gst_iterator_resync (it);
1772 case GST_ITERATOR_ERROR:
1777 gst_iterator_free (it);
1781 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1783 GstSourceGroup *group;
1784 GPtrArray *channels;
1787 GST_PLAY_BIN_LOCK (playbin);
1789 GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1790 playbin->current_text, stream);
1792 group = get_group (playbin);
1793 if (!(channels = group->text_channels))
1796 if (stream == -1 || channels->len <= stream) {
1799 /* take channel from selected stream */
1800 sinkpad = g_ptr_array_index (channels, stream);
1804 gst_object_ref (sinkpad);
1805 GST_PLAY_BIN_UNLOCK (playbin);
1808 GstObject *selector;
1810 if ((selector = gst_pad_get_parent (sinkpad))) {
1811 GstPad *old_sinkpad;
1813 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1815 if (old_sinkpad != sinkpad) {
1816 gboolean need_unblock, need_block, need_seek;
1817 GstPad *src, *peer = NULL, *oldpeer = NULL;
1818 GstElement *parent_element = NULL, *old_parent_element = NULL;
1820 /* Now check if we need to seek the suburidecodebin to the beginning
1821 * or if we need to block all suburidecodebin sinkpads or if we need
1822 * to unblock all suburidecodebin sinkpads
1825 peer = gst_pad_get_peer (sinkpad);
1827 oldpeer = gst_pad_get_peer (old_sinkpad);
1830 parent_element = gst_pad_get_parent_element (peer);
1832 old_parent_element = gst_pad_get_parent_element (oldpeer);
1834 need_block = (old_parent_element == group->suburidecodebin
1835 && parent_element != old_parent_element);
1836 need_unblock = (parent_element == group->suburidecodebin
1837 && parent_element != old_parent_element);
1838 need_seek = (parent_element == group->suburidecodebin);
1841 gst_object_unref (peer);
1843 gst_object_unref (oldpeer);
1845 gst_object_unref (parent_element);
1846 if (old_parent_element)
1847 gst_object_unref (old_parent_element);
1849 /* Block all suburidecodebin sinkpads */
1851 gst_play_bin_suburidecodebin_block (group->suburidecodebin, TRUE);
1853 /* activate the selected pad */
1854 g_object_set (selector, "active-pad", sinkpad, NULL);
1856 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1857 peer = gst_pad_get_peer (src);
1861 /* Flush the subtitle renderer to remove any
1862 * currently displayed subtitles. This event will
1863 * never travel outside subtitleoverlay!
1865 s = gst_structure_empty_new ("subtitleoverlay-flush-subtitle");
1866 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1867 gst_pad_send_event (peer, event);
1868 gst_object_unref (peer);
1870 gst_object_unref (src);
1872 /* Unblock pads if necessary */
1874 gst_play_bin_suburidecodebin_block (group->suburidecodebin, FALSE);
1876 /* seek to the beginning */
1878 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1880 gst_object_unref (selector);
1883 gst_object_unref (old_sinkpad);
1885 gst_object_unref (sinkpad);
1891 GST_PLAY_BIN_UNLOCK (playbin);
1897 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1898 const gchar * dbg, GstElement * sink)
1900 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1902 GST_PLAY_BIN_LOCK (playbin);
1903 if (*elem != sink) {
1908 gst_object_ref_sink (sink);
1912 gst_object_unref (old);
1914 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1915 GST_PLAY_BIN_UNLOCK (playbin);
1919 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1923 GST_PLAY_BIN_LOCK (playbin);
1925 /* set subtitles on all current and next decodebins. */
1926 if ((elem = playbin->groups[0].uridecodebin))
1927 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1928 if ((elem = playbin->groups[0].suburidecodebin))
1929 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1930 if ((elem = playbin->groups[1].uridecodebin))
1931 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1932 if ((elem = playbin->groups[1].suburidecodebin))
1933 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1935 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1936 GST_PLAY_BIN_UNLOCK (playbin);
1940 gst_play_bin_set_property (GObject * object, guint prop_id,
1941 const GValue * value, GParamSpec * pspec)
1943 GstPlayBin *playbin = GST_PLAY_BIN (object);
1947 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1950 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1953 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1955 case PROP_CURRENT_VIDEO:
1956 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1958 case PROP_CURRENT_AUDIO:
1959 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1961 case PROP_CURRENT_TEXT:
1962 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1964 case PROP_SUBTITLE_ENCODING:
1965 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1967 case PROP_VIDEO_SINK:
1968 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1969 g_value_get_object (value));
1971 case PROP_AUDIO_SINK:
1972 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1973 g_value_get_object (value));
1975 case PROP_VIS_PLUGIN:
1976 gst_play_sink_set_vis_plugin (playbin->playsink,
1977 g_value_get_object (value));
1979 case PROP_TEXT_SINK:
1980 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1981 g_value_get_object (value));
1984 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1987 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1989 case PROP_FONT_DESC:
1990 gst_play_sink_set_font_desc (playbin->playsink,
1991 g_value_get_string (value));
1993 case PROP_CONNECTION_SPEED:
1994 GST_PLAY_BIN_LOCK (playbin);
1995 playbin->connection_speed = g_value_get_uint (value) * 1000;
1996 GST_PLAY_BIN_UNLOCK (playbin);
1998 case PROP_BUFFER_SIZE:
1999 playbin->buffer_size = g_value_get_int (value);
2001 case PROP_BUFFER_DURATION:
2002 playbin->buffer_duration = g_value_get_int64 (value);
2004 case PROP_AV_OFFSET:
2005 gst_play_sink_set_av_offset (playbin->playsink,
2006 g_value_get_int64 (value));
2008 case PROP_RING_BUFFER_MAX_SIZE:
2009 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
2012 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2018 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
2019 const gchar * dbg, GstPlaySinkType type)
2021 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
2023 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
2024 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
2025 dbg, sink, dbg, *elem);
2028 GST_PLAY_BIN_LOCK (playbin);
2030 gst_object_ref (sink);
2031 GST_PLAY_BIN_UNLOCK (playbin);
2038 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
2041 GstPlayBin *playbin = GST_PLAY_BIN (object);
2046 GstSourceGroup *group;
2048 GST_PLAY_BIN_LOCK (playbin);
2049 group = get_group (playbin);
2050 g_value_set_string (value, group->uri);
2051 GST_PLAY_BIN_UNLOCK (playbin);
2056 GstSourceGroup *group;
2058 GST_PLAY_BIN_LOCK (playbin);
2059 group = get_group (playbin);
2060 g_value_set_string (value, group->suburi);
2061 GST_PLAY_BIN_UNLOCK (playbin);
2066 GST_OBJECT_LOCK (playbin);
2067 g_value_set_object (value, playbin->source);
2068 GST_OBJECT_UNLOCK (playbin);
2072 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
2076 GstSourceGroup *group;
2079 GST_PLAY_BIN_LOCK (playbin);
2080 group = get_group (playbin);
2081 n_video = (group->video_channels ? group->video_channels->len : 0);
2082 g_value_set_int (value, n_video);
2083 GST_PLAY_BIN_UNLOCK (playbin);
2086 case PROP_CURRENT_VIDEO:
2087 GST_PLAY_BIN_LOCK (playbin);
2088 g_value_set_int (value, playbin->current_video);
2089 GST_PLAY_BIN_UNLOCK (playbin);
2093 GstSourceGroup *group;
2096 GST_PLAY_BIN_LOCK (playbin);
2097 group = get_group (playbin);
2098 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
2099 g_value_set_int (value, n_audio);
2100 GST_PLAY_BIN_UNLOCK (playbin);
2103 case PROP_CURRENT_AUDIO:
2104 GST_PLAY_BIN_LOCK (playbin);
2105 g_value_set_int (value, playbin->current_audio);
2106 GST_PLAY_BIN_UNLOCK (playbin);
2110 GstSourceGroup *group;
2113 GST_PLAY_BIN_LOCK (playbin);
2114 group = get_group (playbin);
2115 n_text = (group->text_channels ? group->text_channels->len : 0);
2116 g_value_set_int (value, n_text);
2117 GST_PLAY_BIN_UNLOCK (playbin);
2120 case PROP_CURRENT_TEXT:
2121 GST_PLAY_BIN_LOCK (playbin);
2122 g_value_set_int (value, playbin->current_text);
2123 GST_PLAY_BIN_UNLOCK (playbin);
2125 case PROP_SUBTITLE_ENCODING:
2126 GST_PLAY_BIN_LOCK (playbin);
2127 g_value_take_string (value,
2128 gst_play_sink_get_subtitle_encoding (playbin->playsink));
2129 GST_PLAY_BIN_UNLOCK (playbin);
2131 case PROP_VIDEO_SINK:
2132 g_value_take_object (value,
2133 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2134 "video", GST_PLAY_SINK_TYPE_VIDEO));
2136 case PROP_AUDIO_SINK:
2137 g_value_take_object (value,
2138 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2139 "audio", GST_PLAY_SINK_TYPE_AUDIO));
2141 case PROP_VIS_PLUGIN:
2142 g_value_take_object (value,
2143 gst_play_sink_get_vis_plugin (playbin->playsink));
2145 case PROP_TEXT_SINK:
2146 g_value_take_object (value,
2147 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2148 "text", GST_PLAY_SINK_TYPE_TEXT));
2151 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2154 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2157 gst_value_take_buffer (value,
2158 gst_play_sink_get_last_frame (playbin->playsink));
2160 case PROP_FONT_DESC:
2161 g_value_take_string (value,
2162 gst_play_sink_get_font_desc (playbin->playsink));
2164 case PROP_CONNECTION_SPEED:
2165 GST_PLAY_BIN_LOCK (playbin);
2166 g_value_set_uint (value, playbin->connection_speed / 1000);
2167 GST_PLAY_BIN_UNLOCK (playbin);
2169 case PROP_BUFFER_SIZE:
2170 GST_OBJECT_LOCK (playbin);
2171 g_value_set_int (value, playbin->buffer_size);
2172 GST_OBJECT_UNLOCK (playbin);
2174 case PROP_BUFFER_DURATION:
2175 GST_OBJECT_LOCK (playbin);
2176 g_value_set_int64 (value, playbin->buffer_duration);
2177 GST_OBJECT_UNLOCK (playbin);
2179 case PROP_AV_OFFSET:
2180 g_value_set_int64 (value,
2181 gst_play_sink_get_av_offset (playbin->playsink));
2183 case PROP_RING_BUFFER_MAX_SIZE:
2184 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2187 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2193 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2194 gboolean valid, GstQuery * query)
2200 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2201 gst_query_parse_duration (query, &fmt, &duration);
2203 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2204 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2205 playbin->duration[i].valid = valid;
2206 playbin->duration[i].format = fmt;
2207 playbin->duration[i].duration = valid ? duration : -1;
2214 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2216 const GstFormat formats[] =
2217 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2222 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2223 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2224 query = gst_query_new_duration (formats[i]);
2226 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2228 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2229 gst_query_unref (query);
2234 gst_play_bin_query (GstElement * element, GstQuery * query)
2236 GstPlayBin *playbin = GST_PLAY_BIN (element);
2239 /* During a group switch we shouldn't allow duration queries
2240 * because it's not clear if the old or new group's duration
2241 * is returned and if the sinks are already playing new data
2242 * or old data. See bug #585969
2244 * While we're at it, also don't do any other queries during
2245 * a group switch or any other event that causes topology changes
2246 * by taking the playbin lock in any case.
2248 GST_PLAY_BIN_LOCK (playbin);
2250 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2251 GstSourceGroup *group = playbin->curr_group;
2254 GST_SOURCE_GROUP_LOCK (group);
2255 if (group->stream_changed_pending_lock) {
2256 g_mutex_lock (group->stream_changed_pending_lock);
2257 pending = group->pending || group->stream_changed_pending;
2258 g_mutex_unlock (group->stream_changed_pending_lock);
2260 pending = group->pending;
2267 gst_query_parse_duration (query, &fmt, NULL);
2268 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2269 if (fmt == playbin->duration[i].format) {
2270 ret = playbin->duration[i].valid;
2271 gst_query_set_duration (query, fmt,
2272 (ret ? playbin->duration[i].duration : -1));
2276 /* if nothing cached yet, we might as well request duration,
2277 * such as during initial startup */
2279 GST_DEBUG_OBJECT (playbin,
2280 "Taking cached duration because of pending group switch: %d", ret);
2281 GST_SOURCE_GROUP_UNLOCK (group);
2282 GST_PLAY_BIN_UNLOCK (playbin);
2286 GST_SOURCE_GROUP_UNLOCK (group);
2289 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2291 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2292 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2293 GST_PLAY_BIN_UNLOCK (playbin);
2298 /* mime types we are not handling on purpose right now, don't post a
2299 * missing-plugin message for these */
2300 static const gchar *blacklisted_mimes[] = {
2305 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2307 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2308 GstSourceGroup *group;
2310 if (gst_is_missing_plugin_message (msg)) {
2314 detail = gst_missing_plugin_message_get_installer_detail (msg);
2315 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2316 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2317 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2318 gst_message_unref (msg);
2324 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2325 const GstStructure *s = gst_message_get_structure (msg);
2327 /* Drop all stream-changed messages except the last one */
2328 if (strcmp ("playbin2-stream-changed", gst_structure_get_name (s)) == 0) {
2329 guint32 seqnum = gst_message_get_seqnum (msg);
2332 group = playbin->curr_group;
2333 g_mutex_lock (group->stream_changed_pending_lock);
2334 for (l = group->stream_changed_pending; l;) {
2335 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2337 if (l_seqnum == seqnum) {
2340 group->stream_changed_pending =
2341 g_list_delete_link (group->stream_changed_pending, l_prev);
2342 if (group->stream_changed_pending) {
2343 gst_message_unref (msg);
2351 g_mutex_unlock (group->stream_changed_pending_lock);
2353 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2354 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2355 GstObject *src = GST_OBJECT_CAST (msg->src);
2357 /* Ignore async state changes from the uridecodebin children,
2358 * see bug #602000. */
2359 group = playbin->curr_group;
2360 if (src && (group = playbin->curr_group) &&
2361 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2362 || (group->suburidecodebin
2363 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2364 GST_DEBUG_OBJECT (playbin,
2365 "Ignoring async state change of uridecodebin: %s",
2366 GST_OBJECT_NAME (src));
2367 gst_message_unref (msg);
2370 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2371 /* If we get an error of the subtitle uridecodebin transform
2372 * them into warnings and disable the subtitles */
2373 group = playbin->curr_group;
2374 if (group && group->suburidecodebin) {
2375 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2376 (group->suburidecodebin)))) {
2378 gchar *debug = NULL;
2379 GstMessage *new_msg;
2381 gboolean done = FALSE;
2383 gst_message_parse_error (msg, &err, &debug);
2384 new_msg = gst_message_new_warning (msg->src, err, debug);
2386 gst_message_unref (msg);
2391 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2392 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2393 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2394 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2396 it = gst_element_iterate_src_pads (group->suburidecodebin);
2397 while (it && !done) {
2399 GstIteratorResult res;
2401 res = gst_iterator_next (it, (gpointer) & p);
2404 case GST_ITERATOR_DONE:
2407 case GST_ITERATOR_OK:
2408 pad_removed_cb (NULL, p, group);
2409 gst_object_unref (p);
2412 case GST_ITERATOR_RESYNC:
2413 gst_iterator_resync (it);
2415 case GST_ITERATOR_ERROR:
2421 gst_iterator_free (it);
2423 gst_object_ref (group->suburidecodebin);
2424 gst_bin_remove (bin, group->suburidecodebin);
2425 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2427 if (group->sub_pending) {
2428 group->sub_pending = FALSE;
2429 no_more_pads_cb (NULL, group);
2436 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2440 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2441 GstPlayBin * playbin)
2443 const gchar *property;
2444 GstSourceGroup *group;
2445 GstSourceSelect *select = NULL;
2448 GST_PLAY_BIN_LOCK (playbin);
2449 group = get_group (playbin);
2451 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2452 if (selector == G_OBJECT (group->selector[i].selector)) {
2453 select = &group->selector[i];
2457 /* We got a pad-change after our group got switched out; no need to notify */
2459 GST_PLAY_BIN_UNLOCK (playbin);
2463 switch (select->type) {
2464 case GST_PLAY_SINK_TYPE_VIDEO:
2465 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2466 property = "current-video";
2467 playbin->current_video = get_current_stream_number (playbin,
2468 group->video_channels);
2470 case GST_PLAY_SINK_TYPE_AUDIO:
2471 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2472 property = "current-audio";
2473 playbin->current_audio = get_current_stream_number (playbin,
2474 group->audio_channels);
2476 case GST_PLAY_SINK_TYPE_TEXT:
2477 property = "current-text";
2478 playbin->current_text = get_current_stream_number (playbin,
2479 group->text_channels);
2484 GST_PLAY_BIN_UNLOCK (playbin);
2487 g_object_notify (G_OBJECT (playbin), property);
2491 selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
2494 GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
2497 /* this callback sends a delayed event once the pad becomes unblocked */
2499 stream_changed_data_probe (GstPad * pad, GstMiniObject * object, gpointer data)
2501 GstSourceSelect *select = (GstSourceSelect *) data;
2504 /* we need do this just once, so cleanup first */
2505 gst_pad_remove_data_probe (pad, select->sinkpad_data_probe);
2506 select->sinkpad_data_probe = 0;
2507 e = select->sinkpad_delayed_event;
2508 select->sinkpad_delayed_event = NULL;
2510 /* really, this should not happen */
2512 GST_WARNING ("Data probed called, but no delayed event");
2516 if (GST_IS_EVENT (object)
2517 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_NEWSEGMENT) {
2518 /* push the event first, then send the delayed one */
2519 gst_event_ref (GST_EVENT_CAST (object));
2520 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2521 gst_pad_send_event (pad, e);
2524 /* send delayed event, then allow the caller to go on */
2525 gst_pad_send_event (pad, e);
2530 /* helper function to lookup stuff in lists */
2532 array_has_value (const gchar * values[], const gchar * value, gboolean exact)
2536 for (i = 0; values[i]; i++) {
2537 if (exact && !strcmp (value, values[i]))
2539 if (!exact && g_str_has_prefix (value, values[i]))
2547 GstPlayBin *playbin;
2549 GstPlaySinkType type;
2553 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2555 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2558 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2559 " with stream id %d and type %d have changed",
2560 object, ntdata->stream_id, ntdata->type);
2562 switch (ntdata->type) {
2563 case GST_PLAY_SINK_TYPE_VIDEO:
2564 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2565 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2567 case GST_PLAY_SINK_TYPE_AUDIO:
2568 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2569 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2571 case GST_PLAY_SINK_TYPE_TEXT:
2572 signal = SIGNAL_TEXT_TAGS_CHANGED;
2580 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2584 /* this function is called when a new pad is added to decodebin. We check the
2585 * type of the pad and add it to the selector element of the group.
2588 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2590 GstPlayBin *playbin;
2592 const GstStructure *s;
2595 GstPadLinkReturn res;
2596 GstSourceSelect *select = NULL;
2598 gboolean changed = FALSE;
2600 playbin = group->playbin;
2602 caps = gst_pad_get_caps_reffed (pad);
2603 s = gst_caps_get_structure (caps, 0);
2604 name = gst_structure_get_name (s);
2606 GST_DEBUG_OBJECT (playbin,
2607 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2608 GST_DEBUG_PAD_NAME (pad), caps, group);
2610 /* major type of the pad, this determines the selector to use,
2611 try exact match first so we don't prematurely match video/
2612 for video/x-dvd-subpicture */
2613 for (pass = 0; !select && pass < 2; pass++) {
2614 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2615 if (array_has_value (group->selector[i].media_list, name, pass == 0)) {
2616 select = &group->selector[i];
2618 } else if (group->selector[i].get_media_caps) {
2619 GstCaps *media_caps = group->selector[i].get_media_caps ();
2621 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2622 select = &group->selector[i];
2623 gst_caps_unref (media_caps);
2626 gst_caps_unref (media_caps);
2630 /* no selector found for the media type, don't bother linking it to a
2631 * selector. This will leave the pad unlinked and thus ignored. */
2635 GST_SOURCE_GROUP_LOCK (group);
2636 if (select->selector == NULL && playbin->have_selector) {
2637 /* no selector, create one */
2638 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2639 select->selector = gst_element_factory_make ("input-selector", NULL);
2640 if (select->selector == NULL) {
2641 /* post the missing selector message only once */
2642 playbin->have_selector = FALSE;
2643 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2644 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2646 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2647 (_("Missing element '%s' - check your GStreamer installation."),
2648 "input-selector"), (NULL));
2650 g_object_set (select->selector, "sync-streams", TRUE, NULL);
2652 g_signal_connect (select->selector, "notify::active-pad",
2653 G_CALLBACK (selector_active_pad_changed), playbin);
2655 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2656 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2657 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2661 if (select->srcpad == NULL) {
2662 if (select->selector) {
2663 /* save source pad of the selector */
2664 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2666 /* no selector, use the pad as the source pad then */
2667 select->srcpad = gst_object_ref (pad);
2670 /* block the selector srcpad. It's possible that multiple decodebins start
2671 * pushing data into the selectors before we have a chance to collect all
2672 * streams and connect the sinks, resulting in not-linked errors. After we
2673 * configured the sinks we will unblock them all. */
2674 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2675 gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL);
2678 /* get sinkpad for the new stream */
2679 if (select->selector) {
2680 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
2681 gulong notify_tags_handler = 0;
2682 NotifyTagsData *ntdata;
2684 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2685 GST_DEBUG_PAD_NAME (sinkpad));
2687 /* store the selector for the pad */
2688 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
2690 /* connect to the notify::tags signal for our
2691 * own *-tags-changed signals
2693 ntdata = g_new0 (NotifyTagsData, 1);
2694 ntdata->playbin = playbin;
2695 ntdata->stream_id = select->channels->len;
2696 ntdata->type = select->type;
2698 notify_tags_handler =
2699 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2700 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2702 g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler",
2703 (gpointer) (guintptr) notify_tags_handler);
2705 /* store the pad in the array */
2706 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2707 g_ptr_array_add (select->channels, sinkpad);
2709 res = gst_pad_link (pad, sinkpad);
2710 if (GST_PAD_LINK_FAILED (res))
2713 /* store selector pad so we can release it */
2714 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
2717 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2718 GST_DEBUG_PAD_NAME (pad), select->selector);
2721 /* no selector, don't configure anything, we'll link the new pad directly to
2726 GST_SOURCE_GROUP_UNLOCK (group);
2730 gboolean always_ok = (decodebin == group->suburidecodebin);
2732 switch (select->type) {
2733 case GST_PLAY_SINK_TYPE_VIDEO:
2734 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2735 /* we want to return NOT_LINKED for unselected pads but only for pads
2736 * from the normal uridecodebin. This makes sure that subtitle streams
2737 * are not raced past audio/video from decodebin2's multiqueue.
2738 * For pads from suburidecodebin OK should always be returned, otherwise
2739 * it will most likely stop. */
2740 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2741 signal = SIGNAL_VIDEO_CHANGED;
2743 case GST_PLAY_SINK_TYPE_AUDIO:
2744 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2745 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2746 signal = SIGNAL_AUDIO_CHANGED;
2748 case GST_PLAY_SINK_TYPE_TEXT:
2749 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2750 signal = SIGNAL_TEXT_CHANGED;
2757 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2761 gst_caps_unref (caps);
2767 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2768 name, GST_DEBUG_PAD_NAME (pad));
2773 GST_ERROR_OBJECT (playbin,
2774 "failed to link pad %s:%s to selector, reason %d",
2775 GST_DEBUG_PAD_NAME (pad), res);
2776 GST_SOURCE_GROUP_UNLOCK (group);
2781 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2782 * the selector. This will make the selector select a new pad. */
2784 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2786 GstPlayBin *playbin;
2788 GstElement *selector;
2789 GstSourceSelect *select;
2791 playbin = group->playbin;
2793 GST_DEBUG_OBJECT (playbin,
2794 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2796 GST_SOURCE_GROUP_LOCK (group);
2797 /* get the selector sinkpad */
2798 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
2801 if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
2802 gulong notify_tags_handler;
2804 notify_tags_handler =
2805 (guintptr) g_object_get_data (G_OBJECT (peer),
2806 "playbin2.notify_tags_handler");
2807 if (notify_tags_handler != 0)
2808 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2809 g_object_set_data (G_OBJECT (peer), "playbin2.notify_tags_handler", NULL);
2811 /* remove the pad from the array */
2812 g_ptr_array_remove (select->channels, peer);
2813 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2816 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2817 gst_pad_unlink (pad, peer);
2819 /* get selector, this can be NULL when the element is removing the pads
2820 * because it's being disposed. */
2821 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2823 gst_object_unref (peer);
2827 /* release the pad to the selector, this will make the selector choose a new
2829 gst_element_release_request_pad (selector, peer);
2830 gst_object_unref (peer);
2832 gst_object_unref (selector);
2833 GST_SOURCE_GROUP_UNLOCK (group);
2840 GST_DEBUG_OBJECT (playbin, "pad not linked");
2841 GST_SOURCE_GROUP_UNLOCK (group);
2846 GST_DEBUG_OBJECT (playbin, "selector not found");
2847 GST_SOURCE_GROUP_UNLOCK (group);
2852 /* we get called when all pads are available and we must connect the sinks to
2854 * The main purpose of the code is to see if we have video/audio and subtitles
2855 * and pick the right pipelines to display them.
2857 * The selectors installed on the group tell us about the presence of
2858 * audio/video and subtitle streams. This allows us to see if we need
2859 * visualisation, video or/and audio.
2862 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2864 GstPlayBin *playbin;
2865 GstPadLinkReturn res;
2869 playbin = group->playbin;
2871 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2873 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2875 GST_SOURCE_GROUP_LOCK (group);
2876 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2877 GstSourceSelect *select = &group->selector[i];
2879 /* check if the specific media type was detected and thus has a selector
2880 * created for it. If there is the media type, get a sinkpad from the sink
2881 * and link it. We only do this if we have not yet requested the sinkpad
2883 if (select->srcpad && select->sinkpad == NULL) {
2884 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2886 gst_play_sink_request_pad (playbin->playsink, select->type);
2888 res = gst_pad_link (select->srcpad, select->sinkpad);
2889 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2890 select->media_list[0], res);
2891 if (res != GST_PAD_LINK_OK) {
2892 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2893 ("Internal playbin error."),
2894 ("Failed to link selector to sink. Error %d", res));
2898 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2899 group->pending - 1);
2901 if (group->pending > 0)
2904 if (group->suburidecodebin == decodebin)
2905 group->sub_pending = FALSE;
2907 if (group->pending == 0) {
2908 /* we are the last group to complete, we will configure the output and then
2909 * signal the other waiters. */
2910 GST_LOG_OBJECT (playbin, "last group complete");
2913 GST_LOG_OBJECT (playbin, "have more pending groups");
2916 GST_SOURCE_GROUP_UNLOCK (group);
2919 /* if we have custom sinks, configure them now */
2920 GST_SOURCE_GROUP_LOCK (group);
2922 if (group->audio_sink) {
2923 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2925 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2929 if (group->video_sink) {
2930 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2932 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2936 if (playbin->text_sink) {
2937 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
2938 playbin->text_sink);
2939 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2940 playbin->text_sink);
2943 GST_SOURCE_GROUP_UNLOCK (group);
2945 /* signal the other decodebins that they can continue now. */
2946 GST_SOURCE_GROUP_LOCK (group);
2947 /* unblock all selectors */
2948 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2949 GstSourceSelect *select = &group->selector[i];
2951 /* All streamsynchronizer streams should see stream-changed message,
2952 * to arrange for blocking unblocking. */
2953 if (select->sinkpad) {
2959 s = gst_structure_new ("playbin2-stream-changed", "uri", G_TYPE_STRING,
2962 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2963 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2964 seqnum = gst_message_get_seqnum (msg);
2965 event = gst_event_new_sink_message (msg);
2966 g_mutex_lock (group->stream_changed_pending_lock);
2967 group->stream_changed_pending =
2968 g_list_prepend (group->stream_changed_pending,
2969 GUINT_TO_POINTER (seqnum));
2971 /* remove any data probe we might have, and replace */
2972 if (select->sinkpad_delayed_event)
2973 gst_event_unref (select->sinkpad_delayed_event);
2974 select->sinkpad_delayed_event = event;
2975 if (select->sinkpad_data_probe)
2976 gst_pad_remove_data_probe (select->sinkpad,
2977 select->sinkpad_data_probe);
2979 /* we go to the trouble of setting a probe on the pad to send
2980 the playbin2-stream-changed event as sending it here might
2981 find that the pad is blocked, so we'd block here, and the
2982 pad might not be linked yet. Additionally, sending it here
2983 apparently would be on the wrong thread */
2984 select->sinkpad_data_probe =
2985 gst_pad_add_data_probe (select->sinkpad,
2986 (GCallback) stream_changed_data_probe, (gpointer) select);
2988 g_mutex_unlock (group->stream_changed_pending_lock);
2989 gst_message_unref (msg);
2992 if (select->srcpad) {
2993 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2995 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
2999 GST_SOURCE_GROUP_UNLOCK (group);
3002 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
3008 GST_DEBUG ("ignoring, we are shutting down");
3009 /* Request a flushing pad from playsink that we then link to the selector.
3010 * Then we unblock the selectors so that they stop with a WRONG_STATE
3011 * instead of a NOT_LINKED error.
3013 GST_SOURCE_GROUP_LOCK (group);
3014 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3015 GstSourceSelect *select = &group->selector[i];
3017 if (select->srcpad) {
3018 if (select->sinkpad == NULL) {
3019 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
3021 gst_play_sink_request_pad (playbin->playsink,
3022 GST_PLAY_SINK_TYPE_FLUSHING);
3023 res = gst_pad_link (select->srcpad, select->sinkpad);
3024 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
3026 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
3028 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked,
3032 GST_SOURCE_GROUP_UNLOCK (group);
3038 drained_cb (GstElement * decodebin, GstSourceGroup * group)
3040 GstPlayBin *playbin;
3042 playbin = group->playbin;
3044 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
3046 /* after this call, we should have a next group to activate or we EOS */
3047 g_signal_emit (G_OBJECT (playbin),
3048 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
3050 /* now activate the next group. If the app did not set a uri, this will
3051 * fail and we can do EOS */
3052 setup_next_source (playbin, GST_STATE_PAUSED);
3055 /* Like gst_element_factory_can_sink_any_caps() but doesn't
3056 * allow ANY caps on the sinkpad template */
3058 _factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps)
3060 const GList *templs;
3062 templs = gst_element_factory_get_static_pad_templates (factory);
3065 GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
3067 if (templ->direction == GST_PAD_SINK) {
3068 GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
3070 if (!gst_caps_is_any (templcaps)
3071 && gst_caps_can_intersect (templcaps, caps)) {
3072 gst_caps_unref (templcaps);
3075 gst_caps_unref (templcaps);
3077 templs = g_list_next (templs);
3083 /* Called when we must provide a list of factories to plug to @pad with @caps.
3084 * We first check if we have a sink that can handle the format and if we do, we
3085 * return NULL, to expose the pad. If we have no sink (or the sink does not
3086 * work), we return the list of elements that can connect. */
3087 static GValueArray *
3088 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
3089 GstCaps * caps, GstSourceGroup * group)
3091 GstPlayBin *playbin;
3092 GList *mylist, *tmp;
3093 GValueArray *result;
3095 playbin = group->playbin;
3097 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
3098 group, GST_DEBUG_PAD_NAME (pad), caps);
3100 /* filter out the elements based on the caps. */
3101 g_mutex_lock (playbin->elements_lock);
3102 gst_play_bin_update_elements_list (playbin);
3104 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
3106 g_mutex_unlock (playbin->elements_lock);
3108 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
3109 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
3111 /* 2 additional elements for the already set audio/video sinks */
3112 result = g_value_array_new (g_list_length (mylist) + 2);
3114 /* Check if we already have an audio/video sink and if this is the case
3115 * put it as the first element of the array */
3116 if (group->audio_sink) {
3117 GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
3119 if (factory && _factory_can_sink_caps (factory, caps)) {
3120 GValue val = { 0, };
3122 g_value_init (&val, G_TYPE_OBJECT);
3123 g_value_set_object (&val, factory);
3124 result = g_value_array_append (result, &val);
3125 g_value_unset (&val);
3129 if (group->video_sink) {
3130 GstElementFactory *factory = gst_element_get_factory (group->video_sink);
3132 if (factory && _factory_can_sink_caps (factory, caps)) {
3133 GValue val = { 0, };
3135 g_value_init (&val, G_TYPE_OBJECT);
3136 g_value_set_object (&val, factory);
3137 result = g_value_array_append (result, &val);
3138 g_value_unset (&val);
3142 for (tmp = mylist; tmp; tmp = tmp->next) {
3143 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
3144 GValue val = { 0, };
3146 if (group->audio_sink && gst_element_factory_list_is_type (factory,
3147 GST_ELEMENT_FACTORY_TYPE_SINK |
3148 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
3151 if (group->video_sink && gst_element_factory_list_is_type (factory,
3152 GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
3153 | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
3157 g_value_init (&val, G_TYPE_OBJECT);
3158 g_value_set_object (&val, factory);
3159 g_value_array_append (result, &val);
3160 g_value_unset (&val);
3162 gst_plugin_feature_list_free (mylist);
3167 /* autoplug-continue decides, if a pad has raw caps that can be exposed
3168 * directly or if further decoding is necessary. We use this to expose
3169 * supported subtitles directly */
3171 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
3172 * explicitly the caps it supports and if it claims to support ANY
3173 * caps it really should support everything */
3175 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
3176 GstSourceGroup * group)
3178 gboolean ret = TRUE;
3180 GstPad *sinkpad = NULL;
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);
3259 GST_DEBUG_OBJECT (group->playbin,
3260 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3261 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3267 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3271 /* ... activate it ... We do this before adding it to the bin so that we
3272 * don't accidentally make it post error messages that will stop
3274 if (GST_STATE (sink) < GST_STATE_READY &&
3275 gst_element_set_state (sink,
3276 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3280 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3281 /* Got the sink pad, now let's see if the element actually does accept the
3282 * caps that we have */
3283 if (!gst_pad_accept_caps (sinkpad, caps)) {
3284 gst_object_unref (sinkpad);
3287 gst_object_unref (sinkpad);
3293 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw-int; "
3294 "audio/x-raw-float");
3295 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw-rgb; "
3296 "video/x-raw-yuv; " "video/x-raw-gray");
3298 /* We are asked to select an element. See if the next element to check
3299 * is a sink. If this is the case, we see if the sink works by setting it to
3300 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3301 * expose the raw pad so that we can setup the mixers. */
3302 static GstAutoplugSelectResult
3303 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3304 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3306 GstPlayBin *playbin;
3307 GstElement *element;
3309 GstPlaySinkType type;
3312 playbin = group->playbin;
3314 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3315 group, GST_DEBUG_PAD_NAME (pad), caps);
3317 GST_DEBUG_OBJECT (playbin, "checking factory %s",
3318 GST_PLUGIN_FEATURE_NAME (factory));
3320 /* if it's not a sink, we make sure the element is compatible with
3322 if (!gst_element_factory_list_is_type (factory,
3323 GST_ELEMENT_FACTORY_TYPE_SINK)) {
3324 gboolean isvideodec = gst_element_factory_list_is_type (factory,
3325 GST_ELEMENT_FACTORY_TYPE_DECODER |
3326 GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
3327 GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
3328 gboolean isaudiodec = gst_element_factory_list_is_type (factory,
3329 GST_ELEMENT_FACTORY_TYPE_DECODER |
3330 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
3332 /* If it is a decoder and we have a fixed sink for the media
3333 * type it outputs, check that the decoder is compatible with this sink */
3334 if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) {
3335 gboolean compatible = TRUE;
3341 sink = group->audio_sink;
3343 sink = group->video_sink;
3345 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3346 GstPlayFlags flags = gst_play_bin_get_flags (playbin);
3348 (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) :
3349 gst_static_caps_get (&raw_video_caps);
3351 caps = gst_pad_get_caps_reffed (sinkpad);
3353 /* If the sink supports raw audio/video, we first check
3354 * if the decoder could output any raw audio/video format
3355 * and assume it is compatible with the sink then. We don't
3356 * do a complete compatibility check here if converters
3357 * are plugged between the decoder and the sink because
3358 * the converters will convert between raw formats and
3359 * even if the decoder format is not supported by the decoder
3360 * a converter will convert it.
3362 * We assume here that the converters can convert between
3365 if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO)
3366 && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec
3367 && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO)
3368 && gst_caps_can_intersect (caps, raw_caps))) {
3369 compatible = gst_element_factory_can_src_any_caps (factory, raw_caps)
3370 || gst_element_factory_can_src_any_caps (factory, caps);
3372 compatible = gst_element_factory_can_src_any_caps (factory, caps);
3375 gst_object_unref (sinkpad);
3376 gst_caps_unref (caps);
3380 return GST_AUTOPLUG_SELECT_TRY;
3382 GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink",
3383 GST_PLUGIN_FEATURE_NAME (factory));
3385 return GST_AUTOPLUG_SELECT_SKIP;
3387 return GST_AUTOPLUG_SELECT_TRY;
3390 /* it's a sink, see if an instance of it actually works */
3391 GST_DEBUG_OBJECT (playbin, "we found a sink");
3393 klass = gst_element_factory_get_klass (factory);
3395 /* figure out the klass */
3396 if (strstr (klass, "Audio")) {
3397 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3398 type = GST_PLAY_SINK_TYPE_AUDIO;
3399 sinkp = &group->audio_sink;
3400 } else if (strstr (klass, "Video")) {
3401 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3402 type = GST_PLAY_SINK_TYPE_VIDEO;
3403 sinkp = &group->video_sink;
3405 /* unknown klass, skip this element */
3406 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3407 return GST_AUTOPLUG_SELECT_SKIP;
3410 /* if we are asked to do visualisations and it's an audio sink, skip the
3411 * element. We can only do visualisations with raw sinks */
3412 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3413 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3414 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3415 return GST_AUTOPLUG_SELECT_SKIP;
3419 /* now see if we already have a sink element */
3420 GST_SOURCE_GROUP_LOCK (group);
3422 GstElement *sink = gst_object_ref (*sinkp);
3424 if (sink_accepts_caps (sink, caps)) {
3425 GST_DEBUG_OBJECT (playbin,
3426 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3427 GST_ELEMENT_NAME (sink), caps);
3428 gst_object_unref (sink);
3429 GST_SOURCE_GROUP_UNLOCK (group);
3430 return GST_AUTOPLUG_SELECT_EXPOSE;
3432 GST_DEBUG_OBJECT (playbin,
3433 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3434 GST_ELEMENT_NAME (sink), caps);
3435 gst_object_unref (sink);
3436 GST_SOURCE_GROUP_UNLOCK (group);
3437 return GST_AUTOPLUG_SELECT_SKIP;
3440 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3442 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3443 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3444 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3445 GST_SOURCE_GROUP_UNLOCK (group);
3446 return GST_AUTOPLUG_SELECT_SKIP;
3449 /* Check if the selected sink actually supports the
3450 * caps and can be set to READY*/
3451 if (!sink_accepts_caps (element, caps)) {
3452 gst_element_set_state (element, GST_STATE_NULL);
3453 gst_object_unref (element);
3454 GST_SOURCE_GROUP_UNLOCK (group);
3455 return GST_AUTOPLUG_SELECT_SKIP;
3458 /* remember the sink in the group now, the element is floating, we take
3461 * store the sink in the group, we will configure it later when we
3462 * reconfigure the sink */
3463 GST_DEBUG_OBJECT (playbin, "remember sink");
3464 gst_object_ref_sink (element);
3466 GST_SOURCE_GROUP_UNLOCK (group);
3468 /* tell decodebin to expose the pad because we are going to use this
3470 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3472 return GST_AUTOPLUG_SELECT_EXPOSE;
3476 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3477 GstSourceGroup * group)
3479 GstPlayBin *playbin;
3482 playbin = group->playbin;
3484 g_object_get (group->uridecodebin, "source", &source, NULL);
3486 GST_OBJECT_LOCK (playbin);
3487 if (playbin->source)
3488 gst_object_unref (playbin->source);
3489 playbin->source = source;
3490 GST_OBJECT_UNLOCK (playbin);
3492 g_object_notify (G_OBJECT (playbin), "source");
3494 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3495 0, playbin->source);
3498 /* must be called with the group lock */
3500 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3503 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3505 if (group->uridecodebin)
3506 gst_element_set_locked_state (group->uridecodebin, locked);
3507 if (group->suburidecodebin)
3508 gst_element_set_locked_state (group->suburidecodebin, locked);
3513 /* must be called with PLAY_BIN_LOCK */
3515 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3517 GstElement *uridecodebin;
3518 GstElement *suburidecodebin = NULL;
3521 g_return_val_if_fail (group->valid, FALSE);
3522 g_return_val_if_fail (!group->active, FALSE);
3524 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3526 GST_SOURCE_GROUP_LOCK (group);
3528 /* First set up the custom sources */
3529 if (playbin->audio_sink)
3530 group->audio_sink = gst_object_ref (playbin->audio_sink);
3531 if (playbin->video_sink)
3532 group->video_sink = gst_object_ref (playbin->video_sink);
3534 g_list_free (group->stream_changed_pending);
3535 group->stream_changed_pending = NULL;
3536 if (!group->stream_changed_pending_lock)
3537 group->stream_changed_pending_lock = g_mutex_new ();
3539 if (group->uridecodebin) {
3540 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3541 uridecodebin = group->uridecodebin;
3542 gst_element_set_state (uridecodebin, GST_STATE_READY);
3543 /* no need to take extra ref, we already have one
3544 * and the bin will add one since it is no longer floating,
3545 * as it was at least added once before (below) */
3546 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3548 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3549 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3552 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3553 group->uridecodebin = gst_object_ref (uridecodebin);
3556 flags = gst_play_sink_get_flags (playbin->playsink);
3558 g_object_set (uridecodebin,
3559 /* configure connection speed */
3560 "connection-speed", playbin->connection_speed / 1000,
3563 /* configure download buffering */
3564 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3565 /* configure buffering of demuxed/parsed data */
3566 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3567 /* configure buffering parameters */
3568 "buffer-duration", playbin->buffer_duration,
3569 "buffer-size", playbin->buffer_size,
3570 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3572 /* connect pads and other things */
3573 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3574 G_CALLBACK (pad_added_cb), group);
3575 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3576 G_CALLBACK (pad_removed_cb), group);
3577 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3578 G_CALLBACK (no_more_pads_cb), group);
3579 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3580 G_CALLBACK (notify_source_cb), group);
3582 /* we have 1 pending no-more-pads */
3585 /* is called when the uridecodebin is out of data and we can switch to the
3588 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3591 /* will be called when a new media type is found. We return a list of decoders
3592 * including sinks for decodebin to try */
3593 group->autoplug_factories_id =
3594 g_signal_connect (uridecodebin, "autoplug-factories",
3595 G_CALLBACK (autoplug_factories_cb), group);
3596 group->autoplug_select_id =
3597 g_signal_connect (uridecodebin, "autoplug-select",
3598 G_CALLBACK (autoplug_select_cb), group);
3599 group->autoplug_continue_id =
3600 g_signal_connect (uridecodebin, "autoplug-continue",
3601 G_CALLBACK (autoplug_continue_cb), group);
3603 if (group->suburi) {
3605 if (group->suburidecodebin) {
3606 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3607 suburidecodebin = group->suburidecodebin;
3608 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3609 /* no need to take extra ref, we already have one
3610 * and the bin will add one since it is no longer floating,
3611 * as it was at least added once before (below) */
3612 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3614 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3615 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3616 if (!suburidecodebin)
3619 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3620 group->suburidecodebin = gst_object_ref (suburidecodebin);
3623 g_object_set (suburidecodebin,
3624 /* configure connection speed */
3625 "connection-speed", playbin->connection_speed,
3627 "uri", group->suburi, NULL);
3629 /* connect pads and other things */
3630 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3631 G_CALLBACK (pad_added_cb), group);
3632 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3633 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3634 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3635 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3637 group->sub_autoplug_continue_id =
3638 g_signal_connect (suburidecodebin, "autoplug-continue",
3639 G_CALLBACK (autoplug_continue_cb), group);
3641 /* we have 2 pending no-more-pads */
3643 group->sub_pending = TRUE;
3645 group->sub_pending = FALSE;
3648 /* release the group lock before setting the state of the decodebins, they
3649 * might fire signals in this thread that we need to handle with the
3650 * group_lock taken. */
3651 GST_SOURCE_GROUP_UNLOCK (group);
3653 if (suburidecodebin) {
3654 if (gst_element_set_state (suburidecodebin,
3655 target) == GST_STATE_CHANGE_FAILURE) {
3656 GST_DEBUG_OBJECT (playbin,
3657 "failed state change of subtitle uridecodebin");
3658 GST_SOURCE_GROUP_LOCK (group);
3660 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3661 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3662 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3663 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3664 /* Might already be removed because of an error message */
3665 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3666 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3667 if (group->sub_pending) {
3669 group->sub_pending = FALSE;
3671 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3672 GST_SOURCE_GROUP_UNLOCK (group);
3675 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3676 goto uridecodebin_failure;
3678 GST_SOURCE_GROUP_LOCK (group);
3679 /* alow state changes of the playbin2 affect the group elements now */
3680 group_set_locked_state_unlocked (playbin, group, FALSE);
3681 group->active = TRUE;
3682 GST_SOURCE_GROUP_UNLOCK (group);
3691 /* delete any custom sinks we might have */
3692 if (group->audio_sink) {
3693 /* If this is a automatically created sink set it to NULL */
3694 if (group->audio_sink != playbin->audio_sink)
3695 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3696 gst_object_unref (group->audio_sink);
3698 group->audio_sink = NULL;
3699 if (group->video_sink) {
3700 /* If this is a automatically created sink set it to NULL */
3701 if (group->video_sink != playbin->video_sink)
3702 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3703 gst_object_unref (group->video_sink);
3705 group->video_sink = NULL;
3707 GST_SOURCE_GROUP_UNLOCK (group);
3709 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3711 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3713 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3714 (_("Could not create \"uridecodebin\" element.")), (NULL));
3717 uridecodebin_failure:
3719 /* delete any custom sinks we might have */
3720 if (group->audio_sink) {
3721 /* If this is a automatically created sink set it to NULL */
3722 if (group->audio_sink != playbin->audio_sink)
3723 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3724 gst_object_unref (group->audio_sink);
3726 group->audio_sink = NULL;
3727 if (group->video_sink) {
3728 /* If this is a automatically created sink set it to NULL */
3729 if (group->video_sink != playbin->video_sink)
3730 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3731 gst_object_unref (group->video_sink);
3733 group->video_sink = NULL;
3735 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3740 /* unlink a group of uridecodebins from the sink.
3741 * must be called with PLAY_BIN_LOCK */
3743 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3747 g_return_val_if_fail (group->valid, FALSE);
3748 g_return_val_if_fail (group->active, FALSE);
3750 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3752 GST_SOURCE_GROUP_LOCK (group);
3753 group->active = FALSE;
3754 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3755 GstSourceSelect *select = &group->selector[i];
3757 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3759 if (select->srcpad) {
3760 if (select->sinkpad) {
3761 GST_LOG_OBJECT (playbin, "unlinking from sink");
3762 gst_pad_unlink (select->srcpad, select->sinkpad);
3765 GST_LOG_OBJECT (playbin, "release sink pad");
3766 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3767 select->sinkpad = NULL;
3770 gst_object_unref (select->srcpad);
3771 select->srcpad = NULL;
3774 if (select->selector) {
3777 /* release and unref requests pad from the selector */
3778 for (n = 0; n < select->channels->len; n++) {
3779 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3781 gst_element_release_request_pad (select->selector, sinkpad);
3782 gst_object_unref (sinkpad);
3784 g_ptr_array_set_size (select->channels, 0);
3786 gst_element_set_state (select->selector, GST_STATE_NULL);
3787 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3788 select->selector = NULL;
3791 /* delete any custom sinks we might have */
3792 if (group->audio_sink) {
3793 /* If this is a automatically created sink set it to NULL */
3794 if (group->audio_sink != playbin->audio_sink)
3795 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3796 gst_object_unref (group->audio_sink);
3798 group->audio_sink = NULL;
3799 if (group->video_sink) {
3800 /* If this is a automatically created sink set it to NULL */
3801 if (group->video_sink != playbin->video_sink)
3802 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3803 gst_object_unref (group->video_sink);
3805 group->video_sink = NULL;
3807 if (group->uridecodebin) {
3808 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3809 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3810 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3811 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3812 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3813 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3814 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3815 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3816 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3819 if (group->suburidecodebin) {
3820 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3821 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3822 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3823 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3825 /* Might already be removed because of errors */
3826 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3827 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3830 GST_SOURCE_GROUP_UNLOCK (group);
3835 /* setup the next group to play, this assumes the next_group is valid and
3836 * configured. It swaps out the current_group and activates the valid
3839 setup_next_source (GstPlayBin * playbin, GstState target)
3841 GstSourceGroup *new_group, *old_group;
3843 GST_DEBUG_OBJECT (playbin, "setup sources");
3845 /* see if there is a next group */
3846 GST_PLAY_BIN_LOCK (playbin);
3847 new_group = playbin->next_group;
3848 if (!new_group || !new_group->valid)
3851 /* first unlink the current source, if any */
3852 old_group = playbin->curr_group;
3853 if (old_group && old_group->valid && old_group->active) {
3854 gst_play_bin_update_cached_duration (playbin);
3855 /* unlink our pads with the sink */
3856 deactivate_group (playbin, old_group);
3857 old_group->valid = FALSE;
3860 /* swap old and new */
3861 playbin->curr_group = new_group;
3862 playbin->next_group = old_group;
3864 /* activate the new group */
3865 if (!activate_group (playbin, new_group, target))
3866 goto activate_failed;
3868 GST_PLAY_BIN_UNLOCK (playbin);
3875 GST_DEBUG_OBJECT (playbin, "no next group");
3876 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3877 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3878 GST_PLAY_BIN_UNLOCK (playbin);
3883 GST_DEBUG_OBJECT (playbin, "activate failed");
3884 GST_PLAY_BIN_UNLOCK (playbin);
3889 /* The group that is currently playing is copied again to the
3890 * next_group so that it will start playing the next time.
3893 save_current_group (GstPlayBin * playbin)
3895 GstSourceGroup *curr_group;
3897 GST_DEBUG_OBJECT (playbin, "save current group");
3899 /* see if there is a current group */
3900 GST_PLAY_BIN_LOCK (playbin);
3901 curr_group = playbin->curr_group;
3902 if (curr_group && curr_group->valid && curr_group->active) {
3903 /* unlink our pads with the sink */
3904 deactivate_group (playbin, curr_group);
3906 /* swap old and new */
3907 playbin->curr_group = playbin->next_group;
3908 playbin->next_group = curr_group;
3909 GST_PLAY_BIN_UNLOCK (playbin);
3914 /* clear the locked state from all groups. This function is called before a
3915 * state change to NULL is performed on them. */
3917 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3919 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3922 GST_PLAY_BIN_LOCK (playbin);
3923 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3924 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3925 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3926 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3927 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3928 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3929 GST_PLAY_BIN_UNLOCK (playbin);
3934 static GstStateChangeReturn
3935 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3937 GstStateChangeReturn ret;
3938 GstPlayBin *playbin;
3939 gboolean do_save = FALSE;
3941 playbin = GST_PLAY_BIN (element);
3943 switch (transition) {
3944 case GST_STATE_CHANGE_NULL_TO_READY:
3945 memset (&playbin->duration, 0, sizeof (playbin->duration));
3947 case GST_STATE_CHANGE_READY_TO_PAUSED:
3948 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3949 memset (&playbin->duration, 0, sizeof (playbin->duration));
3950 g_atomic_int_set (&playbin->shutdown, 0);
3952 if (!setup_next_source (playbin, GST_STATE_READY)) {
3953 ret = GST_STATE_CHANGE_FAILURE;
3957 case GST_STATE_CHANGE_PAUSED_TO_READY:
3959 /* FIXME unlock our waiting groups */
3960 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3961 g_atomic_int_set (&playbin->shutdown, 1);
3962 memset (&playbin->duration, 0, sizeof (playbin->duration));
3964 /* wait for all callbacks to end by taking the lock.
3965 * No dynamic (critical) new callbacks will
3966 * be able to happen as we set the shutdown flag. */
3967 GST_PLAY_BIN_DYN_LOCK (playbin);
3968 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3969 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3972 case GST_STATE_CHANGE_READY_TO_NULL:
3973 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3974 * an no state change PAUSED to READY passes here,
3975 * though it is a nice-to-have ... */
3976 if (!g_atomic_int_get (&playbin->shutdown)) {
3980 memset (&playbin->duration, 0, sizeof (playbin->duration));
3982 /* unlock so that all groups go to NULL */
3983 groups_set_locked_state (playbin, FALSE);
3989 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3990 if (ret == GST_STATE_CHANGE_FAILURE)
3993 switch (transition) {
3994 case GST_STATE_CHANGE_READY_TO_PAUSED:
3996 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3997 /* FIXME Release audio device when we implement that */
3999 case GST_STATE_CHANGE_PAUSED_TO_READY:
4000 save_current_group (playbin);
4002 case GST_STATE_CHANGE_READY_TO_NULL:
4006 /* also do missed state change down to READY */
4008 save_current_group (playbin);
4009 /* Deactive the groups, set the uridecodebins to NULL
4012 for (i = 0; i < 2; i++) {
4013 if (playbin->groups[i].active && playbin->groups[i].valid) {
4014 deactivate_group (playbin, &playbin->groups[i]);
4015 playbin->groups[i].valid = FALSE;
4018 if (playbin->groups[i].uridecodebin) {
4019 gst_element_set_state (playbin->groups[i].uridecodebin,
4021 gst_object_unref (playbin->groups[i].uridecodebin);
4022 playbin->groups[i].uridecodebin = NULL;
4025 if (playbin->groups[i].suburidecodebin) {
4026 gst_element_set_state (playbin->groups[i].suburidecodebin,
4028 gst_object_unref (playbin->groups[i].suburidecodebin);
4029 playbin->groups[i].suburidecodebin = NULL;
4033 /* Set our sinks back to NULL, they might not be child of playbin */
4034 if (playbin->audio_sink)
4035 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
4036 if (playbin->video_sink)
4037 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
4038 if (playbin->text_sink)
4039 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
4041 /* make sure the groups don't perform a state change anymore until we
4042 * enable them again */
4043 groups_set_locked_state (playbin, TRUE);
4055 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
4056 GstSourceGroup *curr_group;
4058 curr_group = playbin->curr_group;
4059 if (curr_group && curr_group->active && curr_group->valid) {
4060 /* unlink our pads with the sink */
4061 deactivate_group (playbin, curr_group);
4062 curr_group->valid = FALSE;
4065 /* Swap current and next group back */
4066 playbin->curr_group = playbin->next_group;
4067 playbin->next_group = curr_group;
4074 gst_play_bin_xoverlay_expose (GstXOverlay * overlay)
4076 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4078 gst_x_overlay_expose (GST_X_OVERLAY (playbin->playsink));
4082 gst_play_bin_xoverlay_handle_events (GstXOverlay * overlay,
4083 gboolean handle_events)
4085 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4087 gst_x_overlay_handle_events (GST_X_OVERLAY (playbin->playsink),
4092 gst_play_bin_xoverlay_set_render_rectangle (GstXOverlay * overlay, gint x,
4093 gint y, gint width, gint height)
4095 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4097 gst_x_overlay_set_render_rectangle (GST_X_OVERLAY (playbin->playsink), x, y,
4102 gst_play_bin_xoverlay_set_window_handle (GstXOverlay * overlay, guintptr handle)
4104 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4106 gst_x_overlay_set_window_handle (GST_X_OVERLAY (playbin->playsink), handle);
4110 gst_play_bin_xoverlay_init (gpointer g_iface, gpointer g_iface_data)
4112 GstXOverlayClass *iface = (GstXOverlayClass *) g_iface;
4113 iface->expose = gst_play_bin_xoverlay_expose;
4114 iface->handle_events = gst_play_bin_xoverlay_handle_events;
4115 iface->set_render_rectangle = gst_play_bin_xoverlay_set_render_rectangle;
4116 iface->set_window_handle = gst_play_bin_xoverlay_set_window_handle;
4120 gst_play_bin_implements_interface_supported (GstImplementsInterface * iface,
4123 if (type == GST_TYPE_X_OVERLAY || type == GST_TYPE_STREAM_VOLUME ||
4124 type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE)
4131 gst_play_bin_implements_interface_init (gpointer g_iface, gpointer g_iface_data)
4133 GstImplementsInterfaceClass *iface = (GstImplementsInterfaceClass *) g_iface;
4134 iface->supported = gst_play_bin_implements_interface_supported;
4138 gst_play_bin_navigation_send_event (GstNavigation * navigation,
4139 GstStructure * structure)
4141 GstPlayBin *playbin = GST_PLAY_BIN (navigation);
4143 gst_navigation_send_event (GST_NAVIGATION (playbin->playsink), structure);
4147 gst_play_bin_navigation_init (gpointer g_iface, gpointer g_iface_data)
4149 GstNavigationInterface *iface = (GstNavigationInterface *) g_iface;
4151 iface->send_event = gst_play_bin_navigation_send_event;
4154 static const GList *
4155 gst_play_bin_colorbalance_list_channels (GstColorBalance * balance)
4157 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4160 gst_color_balance_list_channels (GST_COLOR_BALANCE (playbin->playsink));
4164 gst_play_bin_colorbalance_set_value (GstColorBalance * balance,
4165 GstColorBalanceChannel * channel, gint value)
4167 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4169 gst_color_balance_set_value (GST_COLOR_BALANCE (playbin->playsink), channel,
4174 gst_play_bin_colorbalance_get_value (GstColorBalance * balance,
4175 GstColorBalanceChannel * channel)
4177 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4179 return gst_color_balance_get_value (GST_COLOR_BALANCE (playbin->playsink),
4183 static GstColorBalanceType
4184 gst_play_bin_colorbalance_get_balance_type (GstColorBalance * balance)
4186 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4189 gst_color_balance_get_balance_type (GST_COLOR_BALANCE
4190 (playbin->playsink));
4194 gst_play_bin_colorbalance_init (gpointer g_iface, gpointer g_iface_data)
4196 GstColorBalanceClass *iface = (GstColorBalanceClass *) g_iface;
4198 iface->list_channels = gst_play_bin_colorbalance_list_channels;
4199 iface->set_value = gst_play_bin_colorbalance_set_value;
4200 iface->get_value = gst_play_bin_colorbalance_get_value;
4201 iface->get_balance_type = gst_play_bin_colorbalance_get_balance_type;
4205 gst_play_bin2_plugin_init (GstPlugin * plugin)
4207 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
4209 return gst_element_register (plugin, "playbin2", GST_RANK_NONE,