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-playbin
24 * Playbin provides a stand-alone everything-in-one abstraction for an
25 * audio and/or video player.
27 * Playbin can handle both audio and video files and features
30 * automatic file type recognition and based on that automatic
31 * selection and usage of the right audio/video/subtitle demuxers/decoders
34 * visualisations for audio files
37 * subtitle support for video files. Subtitles can be store in external
41 * stream selection between different video/audio/subtitles streams
44 * meta info (tag) extraction
47 * easy access to the last video sample
50 * buffering when playing streams over a network
53 * volume control with mute option
58 * <title>Usage</title>
60 * A playbin element can be created just like any other element using
61 * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin:uri
62 * property. This must be an absolute URI, relative file paths are not allowed.
63 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
65 * Playbin is a #GstPipeline. It will notify the application of everything
66 * that's happening (errors, end of stream, tags found, state changes, etc.)
67 * by posting messages on its #GstBus. The application needs to watch the
70 * Playback can be initiated by setting the element to PLAYING state using
71 * gst_element_set_state(). Note that the state change will take place in
72 * the background in a separate thread, when the function returns playback
73 * is probably not happening yet and any errors might not have occured yet.
74 * Applications using playbin should ideally be written to deal with things
75 * completely asynchroneous.
77 * When playback has finished (an EOS message has been received on the bus)
78 * or an error has occured (an ERROR message has been received on the bus) or
79 * the user wants to play a different track, playbin should be set back to
80 * READY or NULL state, then the #GstPlayBin:uri property should be set to the
81 * new location and then playbin be set to PLAYING state again.
83 * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
84 * on the playbin element. Again, the seek will not be executed
85 * instantaneously, but will be done in a background thread. When the seek
86 * call returns the seek will most likely still be in process. An application
87 * may wait for the seek to finish (or fail) using gst_element_get_state() with
88 * -1 as the timeout, but this will block the user interface and is not
91 * Applications may query the current position and duration of the stream
92 * via gst_element_query_position() and gst_element_query_duration() and
93 * setting the format passed to GST_FORMAT_TIME. If the query was successful,
94 * the duration or position will have been returned in units of nanoseconds.
98 * <title>Advanced Usage: specifying the audio and video sink</title>
100 * By default, if no audio sink or video sink has been specified via the
101 * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property, playbin will use the autoaudiosink
102 * and autovideosink elements to find the first-best available output method.
103 * This should work in most cases, but is not always desirable. Often either
104 * the user or application might want to specify more explicitly what to use
105 * for audio and video output.
107 * If the application wants more control over how audio or video should be
108 * output, it may create the audio/video sink elements itself (for example
109 * using gst_element_factory_make()) and provide them to playbin using the
110 * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property.
112 * GNOME-based applications, for example, will usually want to create
113 * gconfaudiosink and gconfvideosink elements and make playbin use those,
114 * so that output happens to whatever the user has configured in the GNOME
115 * Multimedia System Selector configuration dialog.
117 * The sink elements do not necessarily need to be ready-made sinks. It is
118 * possible to create container elements that look like a sink to playbin,
119 * but in reality contain a number of custom elements linked together. This
120 * can be achieved by creating a #GstBin and putting elements in there and
121 * linking them, and then creating a sink #GstGhostPad for the bin and pointing
122 * it to the sink pad of the first element within the bin. This can be used
123 * for a number of purposes, for example to force output to a particular
124 * format or to modify or observe the data before it is output.
126 * It is also possible to 'suppress' audio and/or video output by using
127 * 'fakesink' elements (or capture it from there using the fakesink element's
128 * "handoff" signal, which, nota bene, is fired from the streaming thread!).
132 * <title>Retrieving Tags and Other Meta Data</title>
134 * Most of the common meta data (artist, title, etc.) can be retrieved by
135 * watching for TAG messages on the pipeline's bus (see above).
137 * Other more specific meta information like width/height/framerate of video
138 * streams or samplerate/number of channels of audio streams can be obtained
139 * from the negotiated caps on the sink pads of the sinks.
143 * <title>Buffering</title>
144 * Playbin handles buffering automatically for the most part, but applications
145 * need to handle parts of the buffering process as well. Whenever playbin is
146 * buffering, it will post BUFFERING messages on the bus with a percentage
147 * value that shows the progress of the buffering process. Applications need
148 * to set playbin to PLAYING or PAUSED state in response to these messages.
149 * They may also want to convey the buffering progress to the user in some
150 * way. Here is how to extract the percentage information from the message
151 * (requires GStreamer >= 0.10.11):
153 * switch (GST_MESSAGE_TYPE (msg)) {
154 * case GST_MESSAGE_BUFFERING: {
156 * gst_message_parse_buffering (msg, &percent);
157 * g_print ("Buffering (%%u percent done)", percent);
163 * Note that applications should keep/set the pipeline in the PAUSED state when
164 * a BUFFERING message is received with a buffer percent value < 100 and set
165 * the pipeline back to PLAYING state when a BUFFERING message with a value
166 * of 100 percent is received (if PLAYING is the desired state, that is).
169 * <title>Embedding the video window in your application</title>
170 * By default, playbin (or rather the video sinks used) will create their own
171 * window. Applications will usually want to force output to a window of their
172 * own, however. This can be done using the #GstVideoOverlay interface, which most
173 * video sinks implement. See the documentation there for more details.
176 * <title>Specifying which CD/DVD device to use</title>
177 * The device to use for CDs/DVDs needs to be set on the source element
178 * playbin creates before it is opened. The most generic way of doing this
179 * is to connect to playbin's "source-setup" (or "notify::source") signal,
180 * which will be emitted by playbin2 when it has created the source element
181 * for a particular URI. In the signal callback you can check if the source
182 * element has a "device" property and set it appropriately. In some cases
183 * the device can also be set as part of the URI, but it depends on the
184 * elements involved if this will work or not. For example, for DVD menu
185 * playback, the following syntax might work (if the resindvd plugin is used):
186 * dvd://[/path/to/device]
189 * <title>Handling redirects</title>
191 * Some elements may post 'redirect' messages on the bus to tell the
192 * application to open another location. These are element messages containing
193 * a structure named 'redirect' along with a 'new-location' field of string
194 * type. The new location may be a relative or an absolute URI. Examples
195 * for such redirects can be found in many quicktime movie trailers.
199 * <title>Examples</title>
201 * gst-launch -v playbin2 uri=file:///path/to/somefile.avi
202 * ]| This will play back the given AVI video file, given that the video and
203 * audio decoders required to decode the content are installed. Since no
204 * special audio sink or video sink is supplied (not possible via gst-launch),
205 * playbin will try to find a suitable audio and video sink automatically
206 * using the autoaudiosink and autovideosink elements.
208 * gst-launch -v playbin2 uri=cdda://4
209 * ]| This will play back track 4 on an audio CD in your disc drive (assuming
210 * the drive is detected automatically by the plugin).
212 * gst-launch -v playbin2 uri=dvd://
213 * ]| This will play back the DVD in your disc drive (assuming
214 * the drive is detected automatically by the plugin).
218 /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
219 * with newer GLib versions (>= 2.31.0) */
220 #define GLIB_DISABLE_DEPRECATION_WARNINGS
229 #include <gst/gst-i18n-plugin.h>
230 #include <gst/pbutils/pbutils.h>
231 #include <gst/audio/streamvolume.h>
232 #include <gst/video/videooverlay.h>
233 #include <gst/video/navigation.h>
234 #include <gst/video/colorbalance.h>
235 #include "gstplay-enum.h"
236 #include "gstplayback.h"
237 #include "gstplaysink.h"
238 #include "gstsubtitleoverlay.h"
239 #include "gst/glib-compat-private.h"
240 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
241 #define GST_CAT_DEFAULT gst_play_bin_debug
243 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type())
244 #define GST_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
245 #define GST_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
246 #define GST_IS_PLAY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
247 #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
249 #define VOLUME_MAX_DOUBLE 10.0
251 typedef struct _GstPlayBin GstPlayBin;
252 typedef struct _GstPlayBinClass GstPlayBinClass;
253 typedef struct _GstSourceGroup GstSourceGroup;
254 typedef struct _GstSourceSelect GstSourceSelect;
256 typedef GstCaps *(*SourceSelectGetMediaCapsFunc) (void);
258 /* has the info for a selector and provides the link to the sink */
259 struct _GstSourceSelect
261 const gchar *media_list[8]; /* the media types for the selector */
262 SourceSelectGetMediaCapsFunc get_media_caps; /* more complex caps for the selector */
263 GstPlaySinkType type; /* the sink pad type of the selector */
265 GstElement *selector; /* the selector */
267 GstPad *srcpad; /* the source pad of the selector */
268 GstPad *sinkpad; /* the sinkpad of the sink when the selector
271 GstEvent *sinkpad_delayed_event;
272 gulong sinkpad_data_probe;
276 #define GST_SOURCE_GROUP_GET_LOCK(group) (&((GstSourceGroup*)(group))->lock)
277 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
278 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
282 PLAYBIN_STREAM_AUDIO = 0,
283 PLAYBIN_STREAM_VIDEO,
288 /* a structure to hold the objects for decoding a uri and the subtitle uri
290 struct _GstSourceGroup
296 gboolean valid; /* the group has valid info to start playback */
297 gboolean active; /* the group is active */
302 GValueArray *streaminfo;
305 GPtrArray *video_channels; /* links to selector pads */
306 GPtrArray *audio_channels; /* links to selector pads */
307 GPtrArray *text_channels; /* links to selector pads */
309 GstElement *audio_sink; /* autoplugged audio and video sinks */
310 GstElement *video_sink;
312 /* uridecodebins for uri and subtitle uri */
313 GstElement *uridecodebin;
314 GstElement *suburidecodebin;
316 gboolean sub_pending;
319 gulong pad_removed_id;
320 gulong no_more_pads_id;
321 gulong notify_source_id;
323 gulong autoplug_factories_id;
324 gulong autoplug_select_id;
325 gulong autoplug_continue_id;
327 gulong sub_pad_added_id;
328 gulong sub_pad_removed_id;
329 gulong sub_no_more_pads_id;
330 gulong sub_autoplug_continue_id;
334 GMutex stream_changed_pending_lock;
335 GList *stream_changed_pending;
337 /* selectors for different streams */
338 GstSourceSelect selector[PLAYBIN_STREAM_LAST];
341 #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock)
342 #define GST_PLAY_BIN_LOCK(bin) (g_rec_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
343 #define GST_PLAY_BIN_UNLOCK(bin) (g_rec_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
345 /* lock to protect dynamic callbacks, like no-more-pads */
346 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock (&(bin)->dyn_lock)
347 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock (&(bin)->dyn_lock)
349 /* lock for shutdown */
350 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \
352 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
354 GST_PLAY_BIN_DYN_LOCK (bin); \
355 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
356 GST_PLAY_BIN_DYN_UNLOCK (bin); \
361 /* unlock for shutdown */
362 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \
363 GST_PLAY_BIN_DYN_UNLOCK (bin); \
368 * playbin element structure
374 GRecMutex lock; /* to protect group switching */
376 /* the groups, we use a double buffer to switch between current and next */
377 GstSourceGroup groups[2]; /* array with group info */
378 GstSourceGroup *curr_group; /* pointer to the currently playing group */
379 GstSourceGroup *next_group; /* pointer to the next group */
382 guint64 connection_speed; /* connection speed in bits/sec (0 = unknown) */
383 gint current_video; /* the currently selected stream */
384 gint current_audio; /* the currently selected stream */
385 gint current_text; /* the currently selected stream */
387 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */
388 guint buffer_size; /* When buffering, the max buffer size (bytes) */
391 GstPlaySink *playsink;
393 /* the last activated source */
396 /* lock protecting dynamic adding/removing */
398 /* if we are shutting down or not */
401 GMutex elements_lock;
402 guint32 elements_cookie;
403 GList *elements; /* factories we can use for selecting elements */
405 gboolean have_selector; /* set to FALSE when we fail to create an
406 * input-selector, so that we only post a
409 GstElement *audio_sink; /* configured audio sink, or NULL */
410 GstElement *video_sink; /* configured video sink, or NULL */
411 GstElement *text_sink; /* configured text sink, or NULL */
418 } duration[5]; /* cached durations */
420 guint64 ring_buffer_max_size; /* 0 means disabled */
423 struct _GstPlayBinClass
425 GstPipelineClass parent_class;
427 /* notify app that the current uri finished decoding and it is possible to
428 * queue a new one for gapless playback */
429 void (*about_to_finish) (GstPlayBin * playbin);
431 /* notify app that number of audio/video/text streams changed */
432 void (*video_changed) (GstPlayBin * playbin);
433 void (*audio_changed) (GstPlayBin * playbin);
434 void (*text_changed) (GstPlayBin * playbin);
436 /* notify app that the tags of audio/video/text streams changed */
437 void (*video_tags_changed) (GstPlayBin * playbin, gint stream);
438 void (*audio_tags_changed) (GstPlayBin * playbin, gint stream);
439 void (*text_tags_changed) (GstPlayBin * playbin, gint stream);
441 /* get audio/video/text tags for a stream */
442 GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
443 GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
444 GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
446 /* get the last video sample and convert it to the given caps */
447 GstSample *(*convert_sample) (GstPlayBin * playbin, GstCaps * caps);
449 /* get audio/video/text pad for a stream */
450 GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream);
451 GstPad *(*get_audio_pad) (GstPlayBin * playbin, gint stream);
452 GstPad *(*get_text_pad) (GstPlayBin * playbin, gint stream);
456 #define DEFAULT_URI NULL
457 #define DEFAULT_SUBURI NULL
458 #define DEFAULT_SOURCE NULL
459 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
460 GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_SOFT_COLORBALANCE
461 #define DEFAULT_N_VIDEO 0
462 #define DEFAULT_CURRENT_VIDEO -1
463 #define DEFAULT_N_AUDIO 0
464 #define DEFAULT_CURRENT_AUDIO -1
465 #define DEFAULT_N_TEXT 0
466 #define DEFAULT_CURRENT_TEXT -1
467 #define DEFAULT_SUBTITLE_ENCODING NULL
468 #define DEFAULT_AUDIO_SINK NULL
469 #define DEFAULT_VIDEO_SINK NULL
470 #define DEFAULT_VIS_PLUGIN NULL
471 #define DEFAULT_TEXT_SINK NULL
472 #define DEFAULT_VOLUME 1.0
473 #define DEFAULT_MUTE FALSE
474 #define DEFAULT_FRAME NULL
475 #define DEFAULT_FONT_DESC NULL
476 #define DEFAULT_CONNECTION_SPEED 0
477 #define DEFAULT_BUFFER_DURATION -1
478 #define DEFAULT_BUFFER_SIZE -1
479 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
494 PROP_SUBTITLE_ENCODING,
503 PROP_CONNECTION_SPEED,
505 PROP_BUFFER_DURATION,
507 PROP_RING_BUFFER_MAX_SIZE,
514 SIGNAL_ABOUT_TO_FINISH,
515 SIGNAL_CONVERT_SAMPLE,
516 SIGNAL_VIDEO_CHANGED,
517 SIGNAL_AUDIO_CHANGED,
519 SIGNAL_VIDEO_TAGS_CHANGED,
520 SIGNAL_AUDIO_TAGS_CHANGED,
521 SIGNAL_TEXT_TAGS_CHANGED,
522 SIGNAL_GET_VIDEO_TAGS,
523 SIGNAL_GET_AUDIO_TAGS,
524 SIGNAL_GET_TEXT_TAGS,
525 SIGNAL_GET_VIDEO_PAD,
526 SIGNAL_GET_AUDIO_PAD,
532 static void gst_play_bin_class_init (GstPlayBinClass * klass);
533 static void gst_play_bin_init (GstPlayBin * playbin);
534 static void gst_play_bin_finalize (GObject * object);
536 static void gst_play_bin_set_property (GObject * object, guint prop_id,
537 const GValue * value, GParamSpec * spec);
538 static void gst_play_bin_get_property (GObject * object, guint prop_id,
539 GValue * value, GParamSpec * spec);
541 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
542 GstStateChange transition);
544 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
545 static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
547 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
549 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
551 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
554 static GstSample *gst_play_bin_convert_sample (GstPlayBin * playbin,
557 static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream);
558 static GstPad *gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream);
559 static GstPad *gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream);
561 static gboolean setup_next_source (GstPlayBin * playbin, GstState target);
563 static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group);
564 static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
565 GstSourceGroup * group);
567 static void gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
568 GstElement * suburidecodebin, gboolean block);
569 static void gst_play_bin_suburidecodebin_seek_to_start (GstElement *
572 static GstElementClass *parent_class;
574 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
576 #define REMOVE_SIGNAL(obj,id) \
578 g_signal_handler_disconnect (obj, id); \
582 static void gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data);
583 static void gst_play_bin_navigation_init (gpointer g_iface,
584 gpointer g_iface_data);
585 static void gst_play_bin_colorbalance_init (gpointer g_iface,
586 gpointer g_iface_data);
589 gst_play_bin_get_type (void)
591 static GType gst_play_bin_type = 0;
593 if (!gst_play_bin_type) {
594 static const GTypeInfo gst_play_bin_info = {
595 sizeof (GstPlayBinClass),
598 (GClassInitFunc) gst_play_bin_class_init,
603 (GInstanceInitFunc) gst_play_bin_init,
606 static const GInterfaceInfo svol_info = {
609 static const GInterfaceInfo ov_info = {
610 gst_play_bin_overlay_init,
613 static const GInterfaceInfo nav_info = {
614 gst_play_bin_navigation_init,
617 static const GInterfaceInfo col_info = {
618 gst_play_bin_colorbalance_init,
622 gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
623 "GstPlayBin", &gst_play_bin_info, 0);
625 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
627 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_VIDEO_OVERLAY,
629 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_NAVIGATION,
631 g_type_add_interface_static (gst_play_bin_type, GST_TYPE_COLOR_BALANCE,
635 return gst_play_bin_type;
639 gst_play_bin_class_init (GstPlayBinClass * klass)
641 GObjectClass *gobject_klass;
642 GstElementClass *gstelement_klass;
643 GstBinClass *gstbin_klass;
645 gobject_klass = (GObjectClass *) klass;
646 gstelement_klass = (GstElementClass *) klass;
647 gstbin_klass = (GstBinClass *) klass;
649 parent_class = g_type_class_peek_parent (klass);
651 gobject_klass->set_property = gst_play_bin_set_property;
652 gobject_klass->get_property = gst_play_bin_get_property;
654 gobject_klass->finalize = gst_play_bin_finalize;
659 * Set the next URI that playbin will play. This property can be set from the
660 * about-to-finish signal to queue the next media file.
662 g_object_class_install_property (gobject_klass, PROP_URI,
663 g_param_spec_string ("uri", "URI", "URI of the media to play",
664 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
669 * Set the next subtitle URI that playbin will play. This property can be
670 * set from the about-to-finish signal to queue the next subtitle media file.
672 g_object_class_install_property (gobject_klass, PROP_SUBURI,
673 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
674 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
676 g_object_class_install_property (gobject_klass, PROP_SOURCE,
677 g_param_spec_object ("source", "Source", "Source element",
678 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
683 * Control the behaviour of playbin.
685 g_object_class_install_property (gobject_klass, PROP_FLAGS,
686 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
687 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS,
688 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
693 * Get the total number of available video streams.
695 g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
696 g_param_spec_int ("n-video", "Number Video",
697 "Total number of video streams", 0, G_MAXINT, 0,
698 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
700 * GstPlayBin:current-video
702 * Get or set the currently playing video stream. By default the first video
703 * stream with data is played.
705 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
706 g_param_spec_int ("current-video", "Current Video",
707 "Currently playing video stream (-1 = auto)",
708 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
712 * Get the total number of available audio streams.
714 g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
715 g_param_spec_int ("n-audio", "Number Audio",
716 "Total number of audio streams", 0, G_MAXINT, 0,
717 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
719 * GstPlayBin:current-audio
721 * Get or set the currently playing audio stream. By default the first audio
722 * stream with data is played.
724 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
725 g_param_spec_int ("current-audio", "Current audio",
726 "Currently playing audio stream (-1 = auto)",
727 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
731 * Get the total number of available subtitle streams.
733 g_object_class_install_property (gobject_klass, PROP_N_TEXT,
734 g_param_spec_int ("n-text", "Number Text",
735 "Total number of text streams", 0, G_MAXINT, 0,
736 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
738 * GstPlayBin:current-text:
740 * Get or set the currently playing subtitle stream. By default the first
741 * subtitle stream with data is played.
743 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
744 g_param_spec_int ("current-text", "Current Text",
745 "Currently playing text stream (-1 = auto)",
746 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
748 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
749 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
750 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
751 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
752 "be checked for an encoding to use. If that is not set either, "
753 "ISO-8859-15 will be assumed.", NULL,
754 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
756 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
757 g_param_spec_object ("video-sink", "Video Sink",
758 "the video output element to use (NULL = default sink)",
759 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
760 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
761 g_param_spec_object ("audio-sink", "Audio Sink",
762 "the audio output element to use (NULL = default sink)",
763 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
764 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
765 g_param_spec_object ("vis-plugin", "Vis plugin",
766 "the visualization element to use (NULL = default)",
767 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
768 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK,
769 g_param_spec_object ("text-sink", "Text plugin",
770 "the text output element to use (NULL = default textoverlay)",
771 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
776 * Get or set the current audio stream volume. 1.0 means 100%,
777 * 0.0 means mute. This uses a linear volume scale.
780 g_object_class_install_property (gobject_klass, PROP_VOLUME,
781 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%",
782 0.0, VOLUME_MAX_DOUBLE, 1.0,
783 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
784 g_object_class_install_property (gobject_klass, PROP_MUTE,
785 g_param_spec_boolean ("mute", "Mute",
786 "Mute the audio channel without changing the volume", FALSE,
787 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
791 * @playbin: a #GstPlayBin
793 * Get the currently rendered or prerolled sample in the video sink.
794 * The #GstCaps in the sample will describe the format of the buffer.
796 g_object_class_install_property (gobject_klass, PROP_SAMPLE,
797 g_param_spec_boxed ("sample", "Sample",
798 "The last sample (NULL = no video available)",
799 GST_TYPE_SAMPLE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
801 g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
802 g_param_spec_string ("subtitle-font-desc",
803 "Subtitle font description",
804 "Pango font description of font "
805 "to be used for subtitle rendering", NULL,
806 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
808 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
809 g_param_spec_uint64 ("connection-speed", "Connection Speed",
810 "Network connection speed in kbps (0 = unknown)",
811 0, G_MAXUINT64 / 1000, DEFAULT_CONNECTION_SPEED,
812 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
814 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE,
815 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
816 "Buffer size when buffering network streams",
817 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
818 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
819 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION,
820 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
821 "Buffer duration when buffering network streams",
822 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
823 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
825 * GstPlayBin:av-offset:
827 * Control the synchronisation offset between the audio and video streams.
828 * Positive values make the audio ahead of the video and negative values make
829 * the audio go behind the video.
833 g_object_class_install_property (gobject_klass, PROP_AV_OFFSET,
834 g_param_spec_int64 ("av-offset", "AV Offset",
835 "The synchronisation offset between audio and video in nanoseconds",
836 G_MININT64, G_MAXINT64, 0,
837 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
840 * GstQueue2:ring-buffer-max-size
842 * The maximum size of the ring buffer in bytes. If set to 0, the ring
843 * buffer is disabled. Default 0.
847 g_object_class_install_property (gobject_klass, PROP_RING_BUFFER_MAX_SIZE,
848 g_param_spec_uint64 ("ring-buffer-max-size",
849 "Max. ring buffer size (bytes)",
850 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
851 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
852 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
855 * GstPlayBin::about-to-finish
856 * @playbin: a #GstPlayBin
858 * This signal is emitted when the current uri is about to finish. You can
859 * set the uri and suburi to make sure that playback continues.
861 * This signal is emitted from the context of a GStreamer streaming thread.
863 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
864 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
866 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
867 g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
870 * GstPlayBin::video-changed
871 * @playbin: a #GstPlayBin
873 * This signal is emitted whenever the number or order of the video
874 * streams has changed. The application will most likely want to select
875 * a new video stream.
877 * This signal is usually emitted from the context of a GStreamer streaming
878 * thread. You can use gst_message_new_application() and
879 * gst_element_post_message() to notify your application's main thread.
881 /* FIXME 0.11: turn video-changed signal into message? */
882 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
883 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
885 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
886 g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
888 * GstPlayBin::audio-changed
889 * @playbin: a #GstPlayBin
891 * This signal is emitted whenever the number or order of the audio
892 * streams has changed. The application will most likely want to select
893 * a new audio stream.
895 * This signal may be emitted from the context of a GStreamer streaming thread.
896 * You can use gst_message_new_application() and gst_element_post_message()
897 * to notify your application's main thread.
899 /* FIXME 0.11: turn audio-changed signal into message? */
900 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
901 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
903 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
904 g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
906 * GstPlayBin::text-changed
907 * @playbin: a #GstPlayBin
909 * This signal is emitted whenever the number or order of the text
910 * streams has changed. The application will most likely want to select
913 * This signal may be emitted from the context of a GStreamer streaming thread.
914 * You can use gst_message_new_application() and gst_element_post_message()
915 * to notify your application's main thread.
917 /* FIXME 0.11: turn text-changed signal into message? */
918 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
919 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
921 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
922 g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
925 * GstPlayBin::video-tags-changed
926 * @playbin: a #GstPlayBin
927 * @stream: stream index with changed tags
929 * This signal is emitted whenever the tags of a video stream have changed.
930 * The application will most likely want to get the new tags.
932 * This signal may be emitted from the context of a GStreamer streaming thread.
933 * You can use gst_message_new_application() and gst_element_post_message()
934 * to notify your application's main thread.
938 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] =
939 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass),
941 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL,
942 g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
945 * GstPlayBin::audio-tags-changed
946 * @playbin: a #GstPlayBin
947 * @stream: stream index with changed tags
949 * This signal is emitted whenever the tags of an audio stream have changed.
950 * The application will most likely want to get the new tags.
952 * This signal may be emitted from the context of a GStreamer streaming thread.
953 * You can use gst_message_new_application() and gst_element_post_message()
954 * to notify your application's main thread.
958 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] =
959 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass),
961 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL,
962 g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
965 * GstPlayBin::text-tags-changed
966 * @playbin: a #GstPlayBin
967 * @stream: stream index with changed tags
969 * This signal is emitted whenever the tags of a text stream have changed.
970 * The application will most likely want to get the new tags.
972 * This signal may be emitted from the context of a GStreamer streaming thread.
973 * You can use gst_message_new_application() and gst_element_post_message()
974 * to notify your application's main thread.
978 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] =
979 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass),
981 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL,
982 g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_INT);
985 * GstPlayBin::source-setup:
986 * @playbin: a #GstPlayBin
987 * @source: source element
989 * This signal is emitted after the source element has been created, so
990 * it can be configured by setting additional properties (e.g. set a
991 * proxy server for an http source, or set the device and read speed for
992 * an audio cd source). This is functionally equivalent to connecting to
993 * the notify::source signal, but more convenient.
995 * This signal is usually emitted from the context of a GStreamer streaming
1000 gst_play_bin_signals[SIGNAL_SOURCE_SETUP] =
1001 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
1002 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1003 g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
1006 * GstPlayBin::get-video-tags
1007 * @playbin: a #GstPlayBin
1008 * @stream: a video stream number
1010 * Action signal to retrieve the tags of a specific video stream number.
1011 * This information can be used to select a stream.
1013 * Returns: a GstTagList with tags or NULL when the stream number does not
1016 gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
1017 g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
1018 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1019 G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
1020 g_cclosure_marshal_generic, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1022 * GstPlayBin::get-audio-tags
1023 * @playbin: a #GstPlayBin
1024 * @stream: an audio stream number
1026 * Action signal to retrieve the tags of a specific audio stream number.
1027 * This information can be used to select a stream.
1029 * Returns: a GstTagList with tags or NULL when the stream number does not
1032 gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
1033 g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
1034 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1035 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
1036 g_cclosure_marshal_generic, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1038 * GstPlayBin::get-text-tags
1039 * @playbin: a #GstPlayBin
1040 * @stream: a text stream number
1042 * Action signal to retrieve the tags of a specific text stream number.
1043 * This information can be used to select a stream.
1045 * Returns: a GstTagList with tags or NULL when the stream number does not
1048 gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
1049 g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
1050 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1051 G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
1052 g_cclosure_marshal_generic, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
1054 * GstPlayBin::convert-sample
1055 * @playbin: a #GstPlayBin
1056 * @caps: the target format of the frame
1058 * Action signal to retrieve the currently playing video frame in the format
1059 * specified by @caps.
1060 * If @caps is %NULL, no conversion will be performed and this function is
1061 * equivalent to the #GstPlayBin::frame property.
1063 * Returns: a #GstBuffer of the current video frame converted to #caps.
1064 * The caps on the buffer will describe the final layout of the buffer data.
1065 * %NULL is returned when no current buffer can be retrieved or when the
1066 * conversion failed.
1068 gst_play_bin_signals[SIGNAL_CONVERT_SAMPLE] =
1069 g_signal_new ("convert-sample", G_TYPE_FROM_CLASS (klass),
1070 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1071 G_STRUCT_OFFSET (GstPlayBinClass, convert_sample), NULL, NULL,
1072 g_cclosure_marshal_generic, GST_TYPE_SAMPLE, 1, GST_TYPE_CAPS);
1075 * GstPlayBin::get-video-pad
1076 * @playbin: a #GstPlayBin
1077 * @stream: a video stream number
1079 * Action signal to retrieve the stream-selector sinkpad for a specific
1081 * This pad can be used for notifications of caps changes, stream-specific
1084 * Returns: a #GstPad, or NULL when the stream number does not exist.
1086 gst_play_bin_signals[SIGNAL_GET_VIDEO_PAD] =
1087 g_signal_new ("get-video-pad", G_TYPE_FROM_CLASS (klass),
1088 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1089 G_STRUCT_OFFSET (GstPlayBinClass, get_video_pad), NULL, NULL,
1090 g_cclosure_marshal_generic, GST_TYPE_PAD, 1, G_TYPE_INT);
1092 * GstPlayBin::get-audio-pad
1093 * @playbin: a #GstPlayBin
1094 * @stream: an audio stream number
1096 * Action signal to retrieve the stream-selector sinkpad for a specific
1098 * This pad can be used for notifications of caps changes, stream-specific
1101 * Returns: a #GstPad, or NULL when the stream number does not exist.
1103 gst_play_bin_signals[SIGNAL_GET_AUDIO_PAD] =
1104 g_signal_new ("get-audio-pad", G_TYPE_FROM_CLASS (klass),
1105 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1106 G_STRUCT_OFFSET (GstPlayBinClass, get_audio_pad), NULL, NULL,
1107 g_cclosure_marshal_generic, GST_TYPE_PAD, 1, G_TYPE_INT);
1109 * GstPlayBin::get-text-pad
1110 * @playbin: a #GstPlayBin
1111 * @stream: a text stream number
1113 * Action signal to retrieve the stream-selector sinkpad for a specific
1115 * This pad can be used for notifications of caps changes, stream-specific
1118 * Returns: a #GstPad, or NULL when the stream number does not exist.
1120 gst_play_bin_signals[SIGNAL_GET_TEXT_PAD] =
1121 g_signal_new ("get-text-pad", G_TYPE_FROM_CLASS (klass),
1122 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1123 G_STRUCT_OFFSET (GstPlayBinClass, get_text_pad), NULL, NULL,
1124 g_cclosure_marshal_generic, GST_TYPE_PAD, 1, G_TYPE_INT);
1126 klass->get_video_tags = gst_play_bin_get_video_tags;
1127 klass->get_audio_tags = gst_play_bin_get_audio_tags;
1128 klass->get_text_tags = gst_play_bin_get_text_tags;
1130 klass->convert_sample = gst_play_bin_convert_sample;
1132 klass->get_video_pad = gst_play_bin_get_video_pad;
1133 klass->get_audio_pad = gst_play_bin_get_audio_pad;
1134 klass->get_text_pad = gst_play_bin_get_text_pad;
1136 gst_element_class_set_static_metadata (gstelement_klass,
1137 "Player Bin 2", "Generic/Bin/Player",
1138 "Autoplug and play media from an uri",
1139 "Wim Taymans <wim.taymans@gmail.com>");
1141 gstelement_klass->change_state =
1142 GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
1143 gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
1145 gstbin_klass->handle_message =
1146 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
1150 init_group (GstPlayBin * playbin, GstSourceGroup * group)
1154 /* store the array for the different channels */
1155 group->video_channels = g_ptr_array_new ();
1156 group->audio_channels = g_ptr_array_new ();
1157 group->text_channels = g_ptr_array_new ();
1158 g_mutex_init (&group->lock);
1159 /* init selectors. The selector is found by finding the first prefix that
1160 * matches the media. */
1161 group->playbin = playbin;
1162 /* If you add any items to these lists, check that media_list[] is defined
1163 * above to be large enough to hold MAX(items)+1, so as to accommodate a
1164 * NULL terminator (set when the memory is zeroed on allocation) */
1165 group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/";
1166 group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
1167 group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels;
1168 group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/";
1169 group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
1170 group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels;
1171 group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/";
1172 group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle";
1173 group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa";
1174 group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass";
1175 group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture";
1176 group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/";
1177 group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/";
1178 group->selector[PLAYBIN_STREAM_TEXT].get_media_caps =
1179 gst_subtitle_overlay_create_factory_caps;
1180 group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
1181 group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels;
1183 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1184 GstSourceSelect *select = &group->selector[n];
1185 select->sinkpad_delayed_event = NULL;
1186 select->sinkpad_data_probe = 0;
1191 free_group (GstPlayBin * playbin, GstSourceGroup * group)
1195 for (n = 0; n < PLAYBIN_STREAM_LAST; n++) {
1196 GstSourceSelect *select = &group->selector[n];
1197 if (select->sinkpad && select->sinkpad_data_probe)
1198 gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
1199 if (select->sinkpad_delayed_event)
1200 gst_event_unref (select->sinkpad_delayed_event);
1203 g_free (group->uri);
1204 g_free (group->suburi);
1205 g_ptr_array_free (group->video_channels, TRUE);
1206 g_ptr_array_free (group->audio_channels, TRUE);
1207 g_ptr_array_free (group->text_channels, TRUE);
1209 g_mutex_clear (&group->lock);
1210 if (group->audio_sink) {
1211 if (group->audio_sink != playbin->audio_sink)
1212 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
1213 gst_object_unref (group->audio_sink);
1215 group->audio_sink = NULL;
1216 if (group->video_sink) {
1217 if (group->video_sink != playbin->video_sink)
1218 gst_element_set_state (group->video_sink, GST_STATE_NULL);
1219 gst_object_unref (group->video_sink);
1221 group->video_sink = NULL;
1223 g_list_free (group->stream_changed_pending);
1224 group->stream_changed_pending = NULL;
1226 if (group->stream_changed_pending_lock.p)
1227 g_mutex_clear (&group->stream_changed_pending_lock);
1228 group->stream_changed_pending_lock.p = NULL;
1232 notify_volume_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1234 g_object_notify (G_OBJECT (playbin), "volume");
1238 notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
1240 g_object_notify (G_OBJECT (playbin), "mute");
1244 colorbalance_value_changed_cb (GstColorBalance * balance,
1245 GstColorBalanceChannel * channel, gint value, GstPlayBin * playbin)
1247 gst_color_balance_value_changed (GST_COLOR_BALANCE (playbin), channel, value);
1250 /* Must be called with elements lock! */
1252 gst_play_bin_update_elements_list (GstPlayBin * playbin)
1257 cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
1258 if (!playbin->elements || playbin->elements_cookie != cookie) {
1259 if (playbin->elements)
1260 gst_plugin_feature_list_free (playbin->elements);
1262 gst_element_factory_list_get_elements
1263 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1265 gst_element_factory_list_get_elements
1266 (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
1267 playbin->elements = g_list_concat (res, tmp);
1269 g_list_sort (playbin->elements, gst_plugin_feature_rank_compare_func);
1270 playbin->elements_cookie = cookie;
1275 gst_play_bin_init (GstPlayBin * playbin)
1277 g_rec_mutex_init (&playbin->lock);
1278 g_mutex_init (&playbin->dyn_lock);
1280 /* assume we can create a selector */
1281 playbin->have_selector = TRUE;
1284 playbin->curr_group = &playbin->groups[0];
1285 playbin->next_group = &playbin->groups[1];
1286 init_group (playbin, &playbin->groups[0]);
1287 init_group (playbin, &playbin->groups[1]);
1289 /* first filter out the interesting element factories */
1290 g_mutex_init (&playbin->elements_lock);
1294 g_object_new (GST_TYPE_PLAY_SINK, "name", "playsink", "send-event-mode",
1296 gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
1297 gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
1298 /* Connect to notify::volume and notify::mute signals for proxying */
1299 g_signal_connect (playbin->playsink, "notify::volume",
1300 G_CALLBACK (notify_volume_cb), playbin);
1301 g_signal_connect (playbin->playsink, "notify::mute",
1302 G_CALLBACK (notify_mute_cb), playbin);
1303 g_signal_connect (playbin->playsink, "value-changed",
1304 G_CALLBACK (colorbalance_value_changed_cb), playbin);
1306 playbin->current_video = DEFAULT_CURRENT_VIDEO;
1307 playbin->current_audio = DEFAULT_CURRENT_AUDIO;
1308 playbin->current_text = DEFAULT_CURRENT_TEXT;
1310 playbin->buffer_duration = DEFAULT_BUFFER_DURATION;
1311 playbin->buffer_size = DEFAULT_BUFFER_SIZE;
1312 playbin->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
1316 gst_play_bin_finalize (GObject * object)
1318 GstPlayBin *playbin;
1320 playbin = GST_PLAY_BIN (object);
1322 free_group (playbin, &playbin->groups[0]);
1323 free_group (playbin, &playbin->groups[1]);
1325 if (playbin->source)
1326 gst_object_unref (playbin->source);
1327 if (playbin->video_sink) {
1328 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
1329 gst_object_unref (playbin->video_sink);
1331 if (playbin->audio_sink) {
1332 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
1333 gst_object_unref (playbin->audio_sink);
1335 if (playbin->text_sink) {
1336 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
1337 gst_object_unref (playbin->text_sink);
1340 if (playbin->elements)
1341 gst_plugin_feature_list_free (playbin->elements);
1343 g_rec_mutex_clear (&playbin->lock);
1344 g_mutex_clear (&playbin->dyn_lock);
1345 g_mutex_clear (&playbin->elements_lock);
1347 G_OBJECT_CLASS (parent_class)->finalize (object);
1351 gst_playbin_uri_is_valid (GstPlayBin * playbin, const gchar * uri)
1355 GST_LOG_OBJECT (playbin, "checking uri '%s'", uri);
1357 /* this just checks the protocol */
1358 if (!gst_uri_is_valid (uri))
1361 for (c = uri; *c != '\0'; ++c) {
1362 if (!g_ascii_isprint (*c))
1372 GST_WARNING_OBJECT (playbin, "uri '%s' not valid, character #%u",
1373 uri, (guint) ((guintptr) c - (guintptr) uri));
1379 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
1381 GstSourceGroup *group;
1384 g_warning ("cannot set NULL uri");
1388 if (!gst_playbin_uri_is_valid (playbin, uri)) {
1389 if (g_str_has_prefix (uri, "file:")) {
1390 GST_WARNING_OBJECT (playbin, "not entirely correct file URI '%s' - make "
1391 "sure to escape spaces and non-ASCII characters properly and specify "
1392 "an absolute path. Use gst_filename_to_uri() to convert filenames "
1395 /* GST_ERROR_OBJECT (playbin, "malformed URI '%s'", uri); */
1399 GST_PLAY_BIN_LOCK (playbin);
1400 group = playbin->next_group;
1402 GST_SOURCE_GROUP_LOCK (group);
1403 /* store the uri in the next group we will play */
1404 g_free (group->uri);
1405 group->uri = g_strdup (uri);
1406 group->valid = TRUE;
1407 GST_SOURCE_GROUP_UNLOCK (group);
1409 GST_DEBUG ("set new uri to %s", uri);
1410 GST_PLAY_BIN_UNLOCK (playbin);
1414 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
1416 GstSourceGroup *group;
1418 GST_PLAY_BIN_LOCK (playbin);
1419 group = playbin->next_group;
1421 GST_SOURCE_GROUP_LOCK (group);
1422 g_free (group->suburi);
1423 group->suburi = g_strdup (suburi);
1424 GST_SOURCE_GROUP_UNLOCK (group);
1426 GST_DEBUG ("setting new .sub uri to %s", suburi);
1428 GST_PLAY_BIN_UNLOCK (playbin);
1432 gst_play_bin_set_flags (GstPlayBin * playbin, GstPlayFlags flags)
1434 gst_play_sink_set_flags (playbin->playsink, flags);
1435 gst_play_sink_reconfigure (playbin->playsink);
1439 gst_play_bin_get_flags (GstPlayBin * playbin)
1443 flags = gst_play_sink_get_flags (playbin->playsink);
1448 /* get the currently playing group or if nothing is playing, the next
1449 * group. Must be called with the PLAY_BIN_LOCK. */
1450 static GstSourceGroup *
1451 get_group (GstPlayBin * playbin)
1453 GstSourceGroup *result;
1455 if (!(result = playbin->curr_group))
1456 result = playbin->next_group;
1462 gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream)
1464 GstPad *sinkpad = NULL;
1465 GstSourceGroup *group;
1467 GST_PLAY_BIN_LOCK (playbin);
1468 group = get_group (playbin);
1469 if (stream < group->video_channels->len) {
1470 sinkpad = g_ptr_array_index (group->video_channels, stream);
1471 gst_object_ref (sinkpad);
1473 GST_PLAY_BIN_UNLOCK (playbin);
1479 gst_play_bin_get_audio_pad (GstPlayBin * playbin, gint stream)
1481 GstPad *sinkpad = NULL;
1482 GstSourceGroup *group;
1484 GST_PLAY_BIN_LOCK (playbin);
1485 group = get_group (playbin);
1486 if (stream < group->audio_channels->len) {
1487 sinkpad = g_ptr_array_index (group->audio_channels, stream);
1488 gst_object_ref (sinkpad);
1490 GST_PLAY_BIN_UNLOCK (playbin);
1496 gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
1498 GstPad *sinkpad = NULL;
1499 GstSourceGroup *group;
1501 GST_PLAY_BIN_LOCK (playbin);
1502 group = get_group (playbin);
1503 if (stream < group->text_channels->len) {
1504 sinkpad = g_ptr_array_index (group->text_channels, stream);
1505 gst_object_ref (sinkpad);
1507 GST_PLAY_BIN_UNLOCK (playbin);
1514 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
1519 if (!channels || stream >= channels->len)
1522 sinkpad = g_ptr_array_index (channels, stream);
1523 g_object_get (sinkpad, "tags", &result, NULL);
1529 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
1532 GstSourceGroup *group;
1534 GST_PLAY_BIN_LOCK (playbin);
1535 group = get_group (playbin);
1536 result = get_tags (playbin, group->video_channels, stream);
1537 GST_PLAY_BIN_UNLOCK (playbin);
1543 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
1546 GstSourceGroup *group;
1548 GST_PLAY_BIN_LOCK (playbin);
1549 group = get_group (playbin);
1550 result = get_tags (playbin, group->audio_channels, stream);
1551 GST_PLAY_BIN_UNLOCK (playbin);
1557 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
1560 GstSourceGroup *group;
1562 GST_PLAY_BIN_LOCK (playbin);
1563 group = get_group (playbin);
1564 result = get_tags (playbin, group->text_channels, stream);
1565 GST_PLAY_BIN_UNLOCK (playbin);
1571 gst_play_bin_convert_sample (GstPlayBin * playbin, GstCaps * caps)
1573 return gst_play_sink_convert_sample (playbin->playsink, caps);
1576 /* Returns current stream number, or -1 if none has been selected yet */
1578 get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
1580 /* Internal API cleanup would make this easier... */
1582 GstPad *pad, *current;
1583 GstObject *selector = NULL;
1586 for (i = 0; i < channels->len; i++) {
1587 pad = g_ptr_array_index (channels, i);
1588 if ((selector = gst_pad_get_parent (pad))) {
1589 g_object_get (selector, "active-pad", ¤t, NULL);
1590 gst_object_unref (selector);
1592 if (pad == current) {
1593 gst_object_unref (current);
1599 gst_object_unref (current);
1607 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
1609 GstSourceGroup *group;
1610 GPtrArray *channels;
1613 GST_PLAY_BIN_LOCK (playbin);
1615 GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d",
1616 playbin->current_video, stream);
1618 group = get_group (playbin);
1619 if (!(channels = group->video_channels))
1622 if (stream == -1 || channels->len <= stream) {
1625 /* take channel from selected stream */
1626 sinkpad = g_ptr_array_index (channels, stream);
1630 gst_object_ref (sinkpad);
1631 GST_PLAY_BIN_UNLOCK (playbin);
1634 GstObject *selector;
1636 if ((selector = gst_pad_get_parent (sinkpad))) {
1637 /* activate the selected pad */
1638 g_object_set (selector, "active-pad", sinkpad, NULL);
1639 gst_object_unref (selector);
1641 gst_object_unref (sinkpad);
1647 GST_PLAY_BIN_UNLOCK (playbin);
1648 GST_DEBUG_OBJECT (playbin, "can't switch video, we have no channels");
1654 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
1656 GstSourceGroup *group;
1657 GPtrArray *channels;
1660 GST_PLAY_BIN_LOCK (playbin);
1662 GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d",
1663 playbin->current_audio, stream);
1665 group = get_group (playbin);
1666 if (!(channels = group->audio_channels))
1669 if (stream == -1 || channels->len <= stream) {
1672 /* take channel from selected stream */
1673 sinkpad = g_ptr_array_index (channels, stream);
1677 gst_object_ref (sinkpad);
1678 GST_PLAY_BIN_UNLOCK (playbin);
1681 GstObject *selector;
1683 if ((selector = gst_pad_get_parent (sinkpad))) {
1684 /* activate the selected pad */
1685 g_object_set (selector, "active-pad", sinkpad, NULL);
1686 gst_object_unref (selector);
1688 gst_object_unref (sinkpad);
1694 GST_PLAY_BIN_UNLOCK (playbin);
1695 GST_DEBUG_OBJECT (playbin, "can't switch audio, we have no channels");
1701 gst_play_bin_suburidecodebin_seek_to_start (GstElement * suburidecodebin)
1703 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1705 GValue item = { 0, };
1707 if (it && gst_iterator_next (it, &item) == GST_ITERATOR_OK
1708 && ((sinkpad = g_value_get_object (&item)) != NULL)) {
1712 gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
1713 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1714 if (!gst_pad_send_event (sinkpad, event)) {
1716 gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
1717 GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
1718 if (!gst_pad_send_event (sinkpad, event))
1719 GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
1722 g_value_unset (&item);
1726 gst_iterator_free (it);
1730 gst_play_bin_suburidecodebin_block (GstSourceGroup * group,
1731 GstElement * suburidecodebin, gboolean block)
1733 GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
1734 gboolean done = FALSE;
1735 GValue item = { 0, };
1737 GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
1744 switch (gst_iterator_next (it, &item)) {
1745 case GST_ITERATOR_OK:
1746 sinkpad = g_value_get_object (&item);
1749 gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1751 } else if (group->block_id) {
1752 gst_pad_remove_probe (sinkpad, group->block_id);
1753 group->block_id = 0;
1755 g_value_reset (&item);
1757 case GST_ITERATOR_DONE:
1760 case GST_ITERATOR_RESYNC:
1761 gst_iterator_resync (it);
1763 case GST_ITERATOR_ERROR:
1768 g_value_unset (&item);
1769 gst_iterator_free (it);
1773 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
1775 GstSourceGroup *group;
1776 GPtrArray *channels;
1779 GST_PLAY_BIN_LOCK (playbin);
1781 GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d",
1782 playbin->current_text, stream);
1784 group = get_group (playbin);
1785 if (!(channels = group->text_channels))
1788 if (stream == -1 || channels->len <= stream) {
1791 /* take channel from selected stream */
1792 sinkpad = g_ptr_array_index (channels, stream);
1796 gst_object_ref (sinkpad);
1797 GST_PLAY_BIN_UNLOCK (playbin);
1800 GstObject *selector;
1802 if ((selector = gst_pad_get_parent (sinkpad))) {
1803 GstPad *old_sinkpad;
1805 g_object_get (selector, "active-pad", &old_sinkpad, NULL);
1807 if (old_sinkpad != sinkpad) {
1808 gboolean need_unblock, need_block, need_seek;
1809 GstPad *src, *peer = NULL, *oldpeer = NULL;
1810 GstElement *parent_element = NULL, *old_parent_element = NULL;
1812 /* Now check if we need to seek the suburidecodebin to the beginning
1813 * or if we need to block all suburidecodebin sinkpads or if we need
1814 * to unblock all suburidecodebin sinkpads
1817 peer = gst_pad_get_peer (sinkpad);
1819 oldpeer = gst_pad_get_peer (old_sinkpad);
1822 parent_element = gst_pad_get_parent_element (peer);
1824 old_parent_element = gst_pad_get_parent_element (oldpeer);
1826 need_block = (old_parent_element == group->suburidecodebin
1827 && parent_element != old_parent_element);
1828 need_unblock = (parent_element == group->suburidecodebin
1829 && parent_element != old_parent_element);
1830 need_seek = (parent_element == group->suburidecodebin);
1833 gst_object_unref (peer);
1835 gst_object_unref (oldpeer);
1837 gst_object_unref (parent_element);
1838 if (old_parent_element)
1839 gst_object_unref (old_parent_element);
1841 /* Block all suburidecodebin sinkpads */
1843 gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1846 /* activate the selected pad */
1847 g_object_set (selector, "active-pad", sinkpad, NULL);
1849 src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
1850 peer = gst_pad_get_peer (src);
1854 /* Flush the subtitle renderer to remove any
1855 * currently displayed subtitles. This event will
1856 * never travel outside subtitleoverlay!
1858 s = gst_structure_new_empty ("subtitleoverlay-flush-subtitle");
1859 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
1860 gst_pad_send_event (peer, event);
1861 gst_object_unref (peer);
1863 gst_object_unref (src);
1865 /* Unblock pads if necessary */
1867 gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
1870 /* seek to the beginning */
1872 gst_play_bin_suburidecodebin_seek_to_start (group->suburidecodebin);
1874 gst_object_unref (selector);
1877 gst_object_unref (old_sinkpad);
1879 gst_object_unref (sinkpad);
1885 GST_PLAY_BIN_UNLOCK (playbin);
1891 gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
1892 const gchar * dbg, GstElement * sink)
1894 GST_INFO_OBJECT (playbin, "Setting %s sink to %" GST_PTR_FORMAT, dbg, sink);
1896 GST_PLAY_BIN_LOCK (playbin);
1897 if (*elem != sink) {
1902 gst_object_ref_sink (sink);
1906 gst_object_unref (old);
1908 GST_LOG_OBJECT (playbin, "%s sink now %" GST_PTR_FORMAT, dbg, *elem);
1909 GST_PLAY_BIN_UNLOCK (playbin);
1913 gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
1917 GST_PLAY_BIN_LOCK (playbin);
1919 /* set subtitles on all current and next decodebins. */
1920 if ((elem = playbin->groups[0].uridecodebin))
1921 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1922 if ((elem = playbin->groups[0].suburidecodebin))
1923 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1924 if ((elem = playbin->groups[1].uridecodebin))
1925 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1926 if ((elem = playbin->groups[1].suburidecodebin))
1927 g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
1929 gst_play_sink_set_subtitle_encoding (playbin->playsink, encoding);
1930 GST_PLAY_BIN_UNLOCK (playbin);
1934 gst_play_bin_set_property (GObject * object, guint prop_id,
1935 const GValue * value, GParamSpec * pspec)
1937 GstPlayBin *playbin = GST_PLAY_BIN (object);
1941 gst_play_bin_set_uri (playbin, g_value_get_string (value));
1944 gst_play_bin_set_suburi (playbin, g_value_get_string (value));
1947 gst_play_bin_set_flags (playbin, g_value_get_flags (value));
1949 case PROP_CURRENT_VIDEO:
1950 gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
1952 case PROP_CURRENT_AUDIO:
1953 gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
1955 case PROP_CURRENT_TEXT:
1956 gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
1958 case PROP_SUBTITLE_ENCODING:
1959 gst_play_bin_set_encoding (playbin, g_value_get_string (value));
1961 case PROP_VIDEO_SINK:
1962 gst_play_bin_set_sink (playbin, &playbin->video_sink, "video",
1963 g_value_get_object (value));
1965 case PROP_AUDIO_SINK:
1966 gst_play_bin_set_sink (playbin, &playbin->audio_sink, "audio",
1967 g_value_get_object (value));
1969 case PROP_VIS_PLUGIN:
1970 gst_play_sink_set_vis_plugin (playbin->playsink,
1971 g_value_get_object (value));
1973 case PROP_TEXT_SINK:
1974 gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
1975 g_value_get_object (value));
1978 gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
1981 gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
1983 case PROP_FONT_DESC:
1984 gst_play_sink_set_font_desc (playbin->playsink,
1985 g_value_get_string (value));
1987 case PROP_CONNECTION_SPEED:
1988 GST_PLAY_BIN_LOCK (playbin);
1989 playbin->connection_speed = g_value_get_uint64 (value) * 1000;
1990 GST_PLAY_BIN_UNLOCK (playbin);
1992 case PROP_BUFFER_SIZE:
1993 playbin->buffer_size = g_value_get_int (value);
1995 case PROP_BUFFER_DURATION:
1996 playbin->buffer_duration = g_value_get_int64 (value);
1998 case PROP_AV_OFFSET:
1999 gst_play_sink_set_av_offset (playbin->playsink,
2000 g_value_get_int64 (value));
2002 case PROP_RING_BUFFER_MAX_SIZE:
2003 playbin->ring_buffer_max_size = g_value_get_uint64 (value);
2006 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2012 gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
2013 const gchar * dbg, GstPlaySinkType type)
2015 GstElement *sink = gst_play_sink_get_sink (playbin->playsink, type);
2017 GST_LOG_OBJECT (playbin, "play_sink_get_sink() returned %s sink %"
2018 GST_PTR_FORMAT ", the originally set %s sink is %" GST_PTR_FORMAT,
2019 dbg, sink, dbg, *elem);
2022 GST_PLAY_BIN_LOCK (playbin);
2024 gst_object_ref (sink);
2025 GST_PLAY_BIN_UNLOCK (playbin);
2032 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
2035 GstPlayBin *playbin = GST_PLAY_BIN (object);
2040 GstSourceGroup *group;
2042 GST_PLAY_BIN_LOCK (playbin);
2043 group = get_group (playbin);
2044 g_value_set_string (value, group->uri);
2045 GST_PLAY_BIN_UNLOCK (playbin);
2050 GstSourceGroup *group;
2052 GST_PLAY_BIN_LOCK (playbin);
2053 group = get_group (playbin);
2054 g_value_set_string (value, group->suburi);
2055 GST_PLAY_BIN_UNLOCK (playbin);
2060 GST_OBJECT_LOCK (playbin);
2061 g_value_set_object (value, playbin->source);
2062 GST_OBJECT_UNLOCK (playbin);
2066 g_value_set_flags (value, gst_play_bin_get_flags (playbin));
2070 GstSourceGroup *group;
2073 GST_PLAY_BIN_LOCK (playbin);
2074 group = get_group (playbin);
2075 n_video = (group->video_channels ? group->video_channels->len : 0);
2076 g_value_set_int (value, n_video);
2077 GST_PLAY_BIN_UNLOCK (playbin);
2080 case PROP_CURRENT_VIDEO:
2081 GST_PLAY_BIN_LOCK (playbin);
2082 g_value_set_int (value, playbin->current_video);
2083 GST_PLAY_BIN_UNLOCK (playbin);
2087 GstSourceGroup *group;
2090 GST_PLAY_BIN_LOCK (playbin);
2091 group = get_group (playbin);
2092 n_audio = (group->audio_channels ? group->audio_channels->len : 0);
2093 g_value_set_int (value, n_audio);
2094 GST_PLAY_BIN_UNLOCK (playbin);
2097 case PROP_CURRENT_AUDIO:
2098 GST_PLAY_BIN_LOCK (playbin);
2099 g_value_set_int (value, playbin->current_audio);
2100 GST_PLAY_BIN_UNLOCK (playbin);
2104 GstSourceGroup *group;
2107 GST_PLAY_BIN_LOCK (playbin);
2108 group = get_group (playbin);
2109 n_text = (group->text_channels ? group->text_channels->len : 0);
2110 g_value_set_int (value, n_text);
2111 GST_PLAY_BIN_UNLOCK (playbin);
2114 case PROP_CURRENT_TEXT:
2115 GST_PLAY_BIN_LOCK (playbin);
2116 g_value_set_int (value, playbin->current_text);
2117 GST_PLAY_BIN_UNLOCK (playbin);
2119 case PROP_SUBTITLE_ENCODING:
2120 GST_PLAY_BIN_LOCK (playbin);
2121 g_value_take_string (value,
2122 gst_play_sink_get_subtitle_encoding (playbin->playsink));
2123 GST_PLAY_BIN_UNLOCK (playbin);
2125 case PROP_VIDEO_SINK:
2126 g_value_take_object (value,
2127 gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
2128 "video", GST_PLAY_SINK_TYPE_VIDEO));
2130 case PROP_AUDIO_SINK:
2131 g_value_take_object (value,
2132 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink,
2133 "audio", GST_PLAY_SINK_TYPE_AUDIO));
2135 case PROP_VIS_PLUGIN:
2136 g_value_take_object (value,
2137 gst_play_sink_get_vis_plugin (playbin->playsink));
2139 case PROP_TEXT_SINK:
2140 g_value_take_object (value,
2141 gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
2142 "text", GST_PLAY_SINK_TYPE_TEXT));
2145 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
2148 g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
2151 gst_value_take_sample (value,
2152 gst_play_sink_get_last_sample (playbin->playsink));
2154 case PROP_FONT_DESC:
2155 g_value_take_string (value,
2156 gst_play_sink_get_font_desc (playbin->playsink));
2158 case PROP_CONNECTION_SPEED:
2159 GST_PLAY_BIN_LOCK (playbin);
2160 g_value_set_uint64 (value, playbin->connection_speed / 1000);
2161 GST_PLAY_BIN_UNLOCK (playbin);
2163 case PROP_BUFFER_SIZE:
2164 GST_OBJECT_LOCK (playbin);
2165 g_value_set_int (value, playbin->buffer_size);
2166 GST_OBJECT_UNLOCK (playbin);
2168 case PROP_BUFFER_DURATION:
2169 GST_OBJECT_LOCK (playbin);
2170 g_value_set_int64 (value, playbin->buffer_duration);
2171 GST_OBJECT_UNLOCK (playbin);
2173 case PROP_AV_OFFSET:
2174 g_value_set_int64 (value,
2175 gst_play_sink_get_av_offset (playbin->playsink));
2177 case PROP_RING_BUFFER_MAX_SIZE:
2178 g_value_set_uint64 (value, playbin->ring_buffer_max_size);
2181 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2187 gst_play_bin_update_cached_duration_from_query (GstPlayBin * playbin,
2188 gboolean valid, GstQuery * query)
2194 GST_DEBUG_OBJECT (playbin, "Updating cached duration from query");
2195 gst_query_parse_duration (query, &fmt, &duration);
2197 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2198 if (playbin->duration[i].format == 0 || fmt == playbin->duration[i].format) {
2199 playbin->duration[i].valid = valid;
2200 playbin->duration[i].format = fmt;
2201 playbin->duration[i].duration = valid ? duration : -1;
2208 gst_play_bin_update_cached_duration (GstPlayBin * playbin)
2210 const GstFormat formats[] =
2211 { GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT };
2216 GST_DEBUG_OBJECT (playbin, "Updating cached durations before group switch");
2217 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
2218 query = gst_query_new_duration (formats[i]);
2220 GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT_CAST (playbin),
2222 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2223 gst_query_unref (query);
2228 gst_play_bin_query (GstElement * element, GstQuery * query)
2230 GstPlayBin *playbin = GST_PLAY_BIN (element);
2233 /* During a group switch we shouldn't allow duration queries
2234 * because it's not clear if the old or new group's duration
2235 * is returned and if the sinks are already playing new data
2236 * or old data. See bug #585969
2238 * While we're at it, also don't do any other queries during
2239 * a group switch or any other event that causes topology changes
2240 * by taking the playbin lock in any case.
2242 GST_PLAY_BIN_LOCK (playbin);
2244 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
2245 GstSourceGroup *group = playbin->curr_group;
2248 GST_SOURCE_GROUP_LOCK (group);
2249 if (group->stream_changed_pending_lock.p) {
2250 g_mutex_lock (&group->stream_changed_pending_lock);
2251 pending = group->pending || group->stream_changed_pending;
2252 g_mutex_unlock (&group->stream_changed_pending_lock);
2254 pending = group->pending;
2261 gst_query_parse_duration (query, &fmt, NULL);
2262 for (i = 0; i < G_N_ELEMENTS (playbin->duration); i++) {
2263 if (fmt == playbin->duration[i].format) {
2264 ret = playbin->duration[i].valid;
2265 gst_query_set_duration (query, fmt,
2266 (ret ? playbin->duration[i].duration : -1));
2270 /* if nothing cached yet, we might as well request duration,
2271 * such as during initial startup */
2273 GST_DEBUG_OBJECT (playbin,
2274 "Taking cached duration because of pending group switch: %d", ret);
2275 GST_SOURCE_GROUP_UNLOCK (group);
2276 GST_PLAY_BIN_UNLOCK (playbin);
2280 GST_SOURCE_GROUP_UNLOCK (group);
2283 ret = GST_ELEMENT_CLASS (parent_class)->query (element, query);
2285 if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION)
2286 gst_play_bin_update_cached_duration_from_query (playbin, ret, query);
2287 GST_PLAY_BIN_UNLOCK (playbin);
2292 /* mime types we are not handling on purpose right now, don't post a
2293 * missing-plugin message for these */
2294 static const gchar *blacklisted_mimes[] = {
2299 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
2301 GstPlayBin *playbin = GST_PLAY_BIN (bin);
2302 GstSourceGroup *group;
2304 if (gst_is_missing_plugin_message (msg)) {
2308 detail = gst_missing_plugin_message_get_installer_detail (msg);
2309 for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
2310 if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
2311 GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
2312 gst_message_unref (msg);
2318 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
2319 const GstStructure *s = gst_message_get_structure (msg);
2321 /* Drop all stream-changed messages except the last one */
2322 if (strcmp ("playbin-stream-changed", gst_structure_get_name (s)) == 0) {
2323 guint32 seqnum = gst_message_get_seqnum (msg);
2326 group = playbin->curr_group;
2327 g_mutex_lock (&group->stream_changed_pending_lock);
2328 for (l = group->stream_changed_pending; l;) {
2329 guint32 l_seqnum = GPOINTER_TO_UINT (l->data);
2331 if (l_seqnum == seqnum) {
2334 group->stream_changed_pending =
2335 g_list_delete_link (group->stream_changed_pending, l_prev);
2336 if (group->stream_changed_pending) {
2337 gst_message_unref (msg);
2345 g_mutex_unlock (&group->stream_changed_pending_lock);
2347 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_START ||
2348 GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) {
2349 GstObject *src = GST_OBJECT_CAST (msg->src);
2351 /* Ignore async state changes from the uridecodebin children,
2352 * see bug #602000. */
2353 group = playbin->curr_group;
2354 if (src && (group = playbin->curr_group) &&
2355 ((group->uridecodebin && src == GST_OBJECT_CAST (group->uridecodebin))
2356 || (group->suburidecodebin
2357 && src == GST_OBJECT_CAST (group->suburidecodebin)))) {
2358 GST_DEBUG_OBJECT (playbin,
2359 "Ignoring async state change of uridecodebin: %s",
2360 GST_OBJECT_NAME (src));
2361 gst_message_unref (msg);
2364 } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
2365 /* If we get an error of the subtitle uridecodebin transform
2366 * them into warnings and disable the subtitles */
2367 group = playbin->curr_group;
2368 if (group && group->suburidecodebin) {
2369 if (G_UNLIKELY (gst_object_has_ancestor (msg->src, GST_OBJECT_CAST
2370 (group->suburidecodebin)))) {
2372 gchar *debug = NULL;
2373 GstMessage *new_msg;
2375 gboolean done = FALSE;
2376 GValue item = { 0, };
2378 gst_message_parse_error (msg, &err, &debug);
2379 new_msg = gst_message_new_warning (msg->src, err, debug);
2381 gst_message_unref (msg);
2386 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
2387 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
2388 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
2389 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
2391 it = gst_element_iterate_src_pads (group->suburidecodebin);
2392 while (it && !done) {
2394 GstIteratorResult res;
2396 res = gst_iterator_next (it, &item);
2399 case GST_ITERATOR_DONE:
2402 case GST_ITERATOR_OK:
2403 p = g_value_get_object (&item);
2404 pad_removed_cb (NULL, p, group);
2405 g_value_reset (&item);
2408 case GST_ITERATOR_RESYNC:
2409 gst_iterator_resync (it);
2411 case GST_ITERATOR_ERROR:
2416 g_value_unset (&item);
2418 gst_iterator_free (it);
2420 gst_object_ref (group->suburidecodebin);
2421 gst_bin_remove (bin, group->suburidecodebin);
2422 gst_element_set_locked_state (group->suburidecodebin, FALSE);
2424 if (group->sub_pending) {
2425 group->sub_pending = FALSE;
2426 no_more_pads_cb (NULL, group);
2433 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2437 selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
2438 GstPlayBin * playbin)
2440 const gchar *property;
2441 GstSourceGroup *group;
2442 GstSourceSelect *select = NULL;
2445 GST_PLAY_BIN_LOCK (playbin);
2446 group = get_group (playbin);
2448 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2449 if (selector == G_OBJECT (group->selector[i].selector)) {
2450 select = &group->selector[i];
2454 /* We got a pad-change after our group got switched out; no need to notify */
2456 GST_PLAY_BIN_UNLOCK (playbin);
2460 switch (select->type) {
2461 case GST_PLAY_SINK_TYPE_VIDEO:
2462 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2463 property = "current-video";
2464 playbin->current_video = get_current_stream_number (playbin,
2465 group->video_channels);
2467 case GST_PLAY_SINK_TYPE_AUDIO:
2468 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2469 property = "current-audio";
2470 playbin->current_audio = get_current_stream_number (playbin,
2471 group->audio_channels);
2473 case GST_PLAY_SINK_TYPE_TEXT:
2474 property = "current-text";
2475 playbin->current_text = get_current_stream_number (playbin,
2476 group->text_channels);
2481 GST_PLAY_BIN_UNLOCK (playbin);
2484 g_object_notify (G_OBJECT (playbin), property);
2487 /* this callback sends a delayed event once the pad becomes unblocked */
2488 static GstPadProbeReturn
2489 stream_changed_data_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
2491 GstMiniObject *object = GST_PAD_PROBE_INFO_DATA (info);
2492 GstSourceSelect *select = (GstSourceSelect *) data;
2495 /* we need do this just once, so cleanup first */
2496 gst_pad_remove_probe (pad, select->sinkpad_data_probe);
2497 select->sinkpad_data_probe = 0;
2498 e = select->sinkpad_delayed_event;
2499 select->sinkpad_delayed_event = NULL;
2501 /* really, this should not happen */
2503 GST_WARNING ("Data probed called, but no delayed event");
2504 return GST_PAD_PROBE_OK;
2507 if (GST_IS_EVENT (object)
2508 && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_SEGMENT) {
2509 /* push the event first, then send the delayed one */
2510 gst_event_ref (GST_EVENT_CAST (object));
2511 gst_pad_send_event (pad, GST_EVENT_CAST (object));
2512 gst_pad_send_event (pad, e);
2513 return GST_PAD_PROBE_DROP;
2515 /* send delayed event, then allow the caller to go on */
2516 gst_pad_send_event (pad, e);
2517 return GST_PAD_PROBE_OK;
2521 /* helper function to lookup stuff in lists */
2523 array_has_value (const gchar * values[], const gchar * value, gboolean exact)
2527 for (i = 0; values[i]; i++) {
2528 if (exact && !strcmp (value, values[i]))
2530 if (!exact && g_str_has_prefix (value, values[i]))
2538 GstPlayBin *playbin;
2540 GstPlaySinkType type;
2544 notify_tags_cb (GObject * object, GParamSpec * pspec, gpointer user_data)
2546 NotifyTagsData *ntdata = (NotifyTagsData *) user_data;
2549 GST_DEBUG_OBJECT (ntdata->playbin, "Tags on pad %" GST_PTR_FORMAT
2550 " with stream id %d and type %d have changed",
2551 object, ntdata->stream_id, ntdata->type);
2553 switch (ntdata->type) {
2554 case GST_PLAY_SINK_TYPE_VIDEO:
2555 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2556 signal = SIGNAL_VIDEO_TAGS_CHANGED;
2558 case GST_PLAY_SINK_TYPE_AUDIO:
2559 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2560 signal = SIGNAL_AUDIO_TAGS_CHANGED;
2562 case GST_PLAY_SINK_TYPE_TEXT:
2563 signal = SIGNAL_TEXT_TAGS_CHANGED;
2571 g_signal_emit (G_OBJECT (ntdata->playbin), gst_play_bin_signals[signal], 0,
2575 /* this function is called when a new pad is added to decodebin. We check the
2576 * type of the pad and add it to the selector element of the group.
2579 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2581 GstPlayBin *playbin;
2583 const GstStructure *s;
2586 GstPadLinkReturn res;
2587 GstSourceSelect *select = NULL;
2589 gboolean changed = FALSE;
2591 playbin = group->playbin;
2593 caps = gst_pad_query_caps (pad, NULL);
2594 s = gst_caps_get_structure (caps, 0);
2595 name = gst_structure_get_name (s);
2597 GST_DEBUG_OBJECT (playbin,
2598 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
2599 GST_DEBUG_PAD_NAME (pad), caps, group);
2601 /* major type of the pad, this determines the selector to use,
2602 try exact match first so we don't prematurely match video/
2603 for video/x-dvd-subpicture */
2604 for (pass = 0; !select && pass < 2; pass++) {
2605 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2606 if (array_has_value (group->selector[i].media_list, name, pass == 0)) {
2607 select = &group->selector[i];
2609 } else if (group->selector[i].get_media_caps) {
2610 GstCaps *media_caps = group->selector[i].get_media_caps ();
2612 if (media_caps && gst_caps_can_intersect (media_caps, caps)) {
2613 select = &group->selector[i];
2614 gst_caps_unref (media_caps);
2617 gst_caps_unref (media_caps);
2621 /* no selector found for the media type, don't bother linking it to a
2622 * selector. This will leave the pad unlinked and thus ignored. */
2626 GST_SOURCE_GROUP_LOCK (group);
2627 if (select->selector == NULL && playbin->have_selector) {
2628 /* no selector, create one */
2629 GST_DEBUG_OBJECT (playbin, "creating new input selector");
2630 select->selector = gst_element_factory_make ("input-selector", NULL);
2631 if (select->selector == NULL) {
2632 /* post the missing selector message only once */
2633 playbin->have_selector = FALSE;
2634 gst_element_post_message (GST_ELEMENT_CAST (playbin),
2635 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
2637 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN,
2638 (_("Missing element '%s' - check your GStreamer installation."),
2639 "input-selector"), (NULL));
2641 g_object_set (select->selector, "sync-streams", TRUE, NULL);
2643 g_signal_connect (select->selector, "notify::active-pad",
2644 G_CALLBACK (selector_active_pad_changed), playbin);
2646 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
2647 gst_bin_add (GST_BIN_CAST (playbin), select->selector);
2648 gst_element_set_state (select->selector, GST_STATE_PAUSED);
2652 if (select->srcpad == NULL) {
2653 if (select->selector) {
2654 /* save source pad of the selector */
2655 select->srcpad = gst_element_get_static_pad (select->selector, "src");
2657 /* no selector, use the pad as the source pad then */
2658 select->srcpad = gst_object_ref (pad);
2661 /* block the selector srcpad. It's possible that multiple decodebins start
2662 * pushing data into the selectors before we have a chance to collect all
2663 * streams and connect the sinks, resulting in not-linked errors. After we
2664 * configured the sinks we will unblock them all. */
2665 GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, select->srcpad);
2667 gst_pad_add_probe (select->srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2671 /* get sinkpad for the new stream */
2672 if (select->selector) {
2673 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink_%u"))) {
2674 gulong notify_tags_handler = 0;
2675 NotifyTagsData *ntdata;
2677 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
2678 GST_DEBUG_PAD_NAME (sinkpad));
2680 /* store the selector for the pad */
2681 g_object_set_data (G_OBJECT (sinkpad), "playbin.select", select);
2683 /* connect to the notify::tags signal for our
2684 * own *-tags-changed signals
2686 ntdata = g_new0 (NotifyTagsData, 1);
2687 ntdata->playbin = playbin;
2688 ntdata->stream_id = select->channels->len;
2689 ntdata->type = select->type;
2691 notify_tags_handler =
2692 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
2693 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
2695 g_object_set_data (G_OBJECT (sinkpad), "playbin.notify_tags_handler",
2696 (gpointer) (guintptr) notify_tags_handler);
2698 /* store the pad in the array */
2699 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
2700 g_ptr_array_add (select->channels, sinkpad);
2702 res = gst_pad_link (pad, sinkpad);
2703 if (GST_PAD_LINK_FAILED (res))
2706 /* store selector pad so we can release it */
2707 g_object_set_data (G_OBJECT (pad), "playbin.sinkpad", sinkpad);
2710 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
2711 GST_DEBUG_PAD_NAME (pad), select->selector);
2714 /* no selector, don't configure anything, we'll link the new pad directly to
2719 GST_SOURCE_GROUP_UNLOCK (group);
2723 gboolean always_ok = (decodebin == group->suburidecodebin);
2725 switch (select->type) {
2726 case GST_PLAY_SINK_TYPE_VIDEO:
2727 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
2728 /* we want to return NOT_LINKED for unselected pads but only for pads
2729 * from the normal uridecodebin. This makes sure that subtitle streams
2730 * are not raced past audio/video from decodebin's multiqueue.
2731 * For pads from suburidecodebin OK should always be returned, otherwise
2732 * it will most likely stop. */
2733 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2734 signal = SIGNAL_VIDEO_CHANGED;
2736 case GST_PLAY_SINK_TYPE_AUDIO:
2737 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
2738 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2739 signal = SIGNAL_AUDIO_CHANGED;
2741 case GST_PLAY_SINK_TYPE_TEXT:
2742 g_object_set (sinkpad, "always-ok", always_ok, NULL);
2743 signal = SIGNAL_TEXT_CHANGED;
2750 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
2754 gst_caps_unref (caps);
2760 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
2761 name, GST_DEBUG_PAD_NAME (pad));
2766 GST_ERROR_OBJECT (playbin,
2767 "failed to link pad %s:%s to selector, reason %d",
2768 GST_DEBUG_PAD_NAME (pad), res);
2769 GST_SOURCE_GROUP_UNLOCK (group);
2774 /* called when a pad is removed from the uridecodebin. We unlink the pad from
2775 * the selector. This will make the selector select a new pad. */
2777 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
2779 GstPlayBin *playbin;
2781 GstElement *selector;
2782 GstSourceSelect *select;
2784 playbin = group->playbin;
2786 GST_DEBUG_OBJECT (playbin,
2787 "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
2789 GST_SOURCE_GROUP_LOCK (group);
2790 /* get the selector sinkpad */
2791 if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin.sinkpad")))
2794 if ((select = g_object_get_data (G_OBJECT (peer), "playbin.select"))) {
2795 gulong notify_tags_handler;
2797 notify_tags_handler =
2798 (guintptr) g_object_get_data (G_OBJECT (peer),
2799 "playbin.notify_tags_handler");
2800 if (notify_tags_handler != 0)
2801 g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
2802 g_object_set_data (G_OBJECT (peer), "playbin.notify_tags_handler", NULL);
2804 /* remove the pad from the array */
2805 g_ptr_array_remove (select->channels, peer);
2806 GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
2809 /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
2810 gst_pad_unlink (pad, peer);
2812 /* get selector, this can be NULL when the element is removing the pads
2813 * because it's being disposed. */
2814 selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
2816 gst_object_unref (peer);
2820 /* release the pad to the selector, this will make the selector choose a new
2822 gst_element_release_request_pad (selector, peer);
2823 gst_object_unref (peer);
2825 gst_object_unref (selector);
2826 GST_SOURCE_GROUP_UNLOCK (group);
2833 GST_DEBUG_OBJECT (playbin, "pad not linked");
2834 GST_SOURCE_GROUP_UNLOCK (group);
2839 GST_DEBUG_OBJECT (playbin, "selector not found");
2840 GST_SOURCE_GROUP_UNLOCK (group);
2845 /* we get called when all pads are available and we must connect the sinks to
2847 * The main purpose of the code is to see if we have video/audio and subtitles
2848 * and pick the right pipelines to display them.
2850 * The selectors installed on the group tell us about the presence of
2851 * audio/video and subtitle streams. This allows us to see if we need
2852 * visualisation, video or/and audio.
2855 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
2857 GstPlayBin *playbin;
2858 GstPadLinkReturn res;
2862 playbin = group->playbin;
2864 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
2866 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown);
2868 GST_SOURCE_GROUP_LOCK (group);
2869 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2870 GstSourceSelect *select = &group->selector[i];
2872 /* check if the specific media type was detected and thus has a selector
2873 * created for it. If there is the media type, get a sinkpad from the sink
2874 * and link it. We only do this if we have not yet requested the sinkpad
2876 if (select->srcpad && select->sinkpad == NULL) {
2877 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type);
2879 gst_play_sink_request_pad (playbin->playsink, select->type);
2881 res = gst_pad_link (select->srcpad, select->sinkpad);
2882 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
2883 select->media_list[0], res);
2884 if (res != GST_PAD_LINK_OK) {
2885 GST_ELEMENT_ERROR (playbin, CORE, PAD,
2886 ("Internal playbin error."),
2887 ("Failed to link selector to sink. Error %d", res));
2891 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
2892 group->pending - 1);
2894 if (group->pending > 0)
2897 if (group->suburidecodebin == decodebin)
2898 group->sub_pending = FALSE;
2900 if (group->pending == 0) {
2901 /* we are the last group to complete, we will configure the output and then
2902 * signal the other waiters. */
2903 GST_LOG_OBJECT (playbin, "last group complete");
2906 GST_LOG_OBJECT (playbin, "have more pending groups");
2909 GST_SOURCE_GROUP_UNLOCK (group);
2912 /* if we have custom sinks, configure them now */
2913 GST_SOURCE_GROUP_LOCK (group);
2915 if (group->audio_sink) {
2916 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
2918 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
2922 if (group->video_sink) {
2923 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
2925 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
2929 if (playbin->text_sink) {
2930 GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
2931 playbin->text_sink);
2932 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
2933 playbin->text_sink);
2936 GST_SOURCE_GROUP_UNLOCK (group);
2938 /* signal the other decodebins that they can continue now. */
2939 GST_SOURCE_GROUP_LOCK (group);
2940 /* unblock all selectors */
2941 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
2942 GstSourceSelect *select = &group->selector[i];
2944 /* All streamsynchronizer streams should see stream-changed message,
2945 * to arrange for blocking unblocking. */
2946 if (select->sinkpad) {
2952 s = gst_structure_new ("playbin-stream-changed", "uri", G_TYPE_STRING,
2955 gst_structure_set (s, "suburi", G_TYPE_STRING, group->suburi, NULL);
2956 msg = gst_message_new_element (GST_OBJECT_CAST (playbin), s);
2957 seqnum = gst_message_get_seqnum (msg);
2958 event = gst_event_new_sink_message (msg);
2959 g_mutex_lock (&group->stream_changed_pending_lock);
2960 group->stream_changed_pending =
2961 g_list_prepend (group->stream_changed_pending,
2962 GUINT_TO_POINTER (seqnum));
2964 /* remove any data probe we might have, and replace */
2965 if (select->sinkpad_delayed_event)
2966 gst_event_unref (select->sinkpad_delayed_event);
2967 select->sinkpad_delayed_event = event;
2968 if (select->sinkpad_data_probe)
2969 gst_pad_remove_probe (select->sinkpad, select->sinkpad_data_probe);
2971 /* we go to the trouble of setting a probe on the pad to send
2972 the playbin-stream-changed event as sending it here might
2973 find that the pad is blocked, so we'd block here, and the
2974 pad might not be linked yet. Additionally, sending it here
2975 apparently would be on the wrong thread */
2976 select->sinkpad_data_probe =
2977 gst_pad_add_probe (select->sinkpad,
2978 GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
2979 stream_changed_data_probe, (gpointer) select, NULL);
2981 g_mutex_unlock (&group->stream_changed_pending_lock);
2982 gst_message_unref (msg);
2985 if (select->srcpad) {
2986 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
2988 if (select->block_id) {
2989 gst_pad_remove_probe (select->srcpad, select->block_id);
2990 select->block_id = 0;
2994 GST_SOURCE_GROUP_UNLOCK (group);
2997 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin);
3003 GST_DEBUG ("ignoring, we are shutting down");
3004 /* Request a flushing pad from playsink that we then link to the selector.
3005 * Then we unblock the selectors so that they stop with a WRONG_STATE
3006 * instead of a NOT_LINKED error.
3008 GST_SOURCE_GROUP_LOCK (group);
3009 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3010 GstSourceSelect *select = &group->selector[i];
3012 if (select->srcpad) {
3013 if (select->sinkpad == NULL) {
3014 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
3016 gst_play_sink_request_pad (playbin->playsink,
3017 GST_PLAY_SINK_TYPE_FLUSHING);
3018 res = gst_pad_link (select->srcpad, select->sinkpad);
3019 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
3021 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
3023 if (select->block_id) {
3024 gst_pad_remove_probe (select->srcpad, select->block_id);
3025 select->block_id = 0;
3029 GST_SOURCE_GROUP_UNLOCK (group);
3035 drained_cb (GstElement * decodebin, GstSourceGroup * group)
3037 GstPlayBin *playbin;
3039 playbin = group->playbin;
3041 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
3043 /* after this call, we should have a next group to activate or we EOS */
3044 g_signal_emit (G_OBJECT (playbin),
3045 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
3047 /* now activate the next group. If the app did not set a uri, this will
3048 * fail and we can do EOS */
3049 setup_next_source (playbin, GST_STATE_PAUSED);
3052 /* Like gst_element_factory_can_sink_any_caps() but doesn't
3053 * allow ANY caps on the sinkpad template */
3055 _factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps)
3057 const GList *templs;
3059 templs = gst_element_factory_get_static_pad_templates (factory);
3062 GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
3064 if (templ->direction == GST_PAD_SINK) {
3065 GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
3067 if (!gst_caps_is_any (templcaps)
3068 && gst_caps_can_intersect (templcaps, caps)) {
3069 gst_caps_unref (templcaps);
3072 gst_caps_unref (templcaps);
3074 templs = g_list_next (templs);
3080 /* Called when we must provide a list of factories to plug to @pad with @caps.
3081 * We first check if we have a sink that can handle the format and if we do, we
3082 * return NULL, to expose the pad. If we have no sink (or the sink does not
3083 * work), we return the list of elements that can connect. */
3084 static GValueArray *
3085 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
3086 GstCaps * caps, GstSourceGroup * group)
3088 GstPlayBin *playbin;
3089 GList *mylist, *tmp;
3090 GValueArray *result;
3092 playbin = group->playbin;
3094 GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
3095 group, GST_DEBUG_PAD_NAME (pad), caps);
3097 /* filter out the elements based on the caps. */
3098 g_mutex_lock (&playbin->elements_lock);
3099 gst_play_bin_update_elements_list (playbin);
3101 gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
3103 g_mutex_unlock (&playbin->elements_lock);
3105 GST_DEBUG_OBJECT (playbin, "found factories %p", mylist);
3106 GST_PLUGIN_FEATURE_LIST_DEBUG (mylist);
3108 /* 2 additional elements for the already set audio/video sinks */
3109 result = g_value_array_new (g_list_length (mylist) + 2);
3111 /* Check if we already have an audio/video sink and if this is the case
3112 * put it as the first element of the array */
3113 if (group->audio_sink) {
3114 GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
3116 if (factory && _factory_can_sink_caps (factory, caps)) {
3117 GValue val = { 0, };
3119 g_value_init (&val, G_TYPE_OBJECT);
3120 g_value_set_object (&val, factory);
3121 result = g_value_array_append (result, &val);
3122 g_value_unset (&val);
3126 if (group->video_sink) {
3127 GstElementFactory *factory = gst_element_get_factory (group->video_sink);
3129 if (factory && _factory_can_sink_caps (factory, caps)) {
3130 GValue val = { 0, };
3132 g_value_init (&val, G_TYPE_OBJECT);
3133 g_value_set_object (&val, factory);
3134 result = g_value_array_append (result, &val);
3135 g_value_unset (&val);
3139 for (tmp = mylist; tmp; tmp = tmp->next) {
3140 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
3141 GValue val = { 0, };
3143 if (group->audio_sink && gst_element_factory_list_is_type (factory,
3144 GST_ELEMENT_FACTORY_TYPE_SINK |
3145 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
3148 if (group->video_sink && gst_element_factory_list_is_type (factory,
3149 GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
3150 | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
3154 g_value_init (&val, G_TYPE_OBJECT);
3155 g_value_set_object (&val, factory);
3156 g_value_array_append (result, &val);
3157 g_value_unset (&val);
3159 gst_plugin_feature_list_free (mylist);
3164 /* autoplug-continue decides, if a pad has raw caps that can be exposed
3165 * directly or if further decoding is necessary. We use this to expose
3166 * supported subtitles directly */
3168 /* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
3169 * explicitly the caps it supports and if it claims to support ANY
3170 * caps it really should support everything */
3172 autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
3173 GstSourceGroup * group)
3175 gboolean ret = TRUE;
3177 GstPad *sinkpad = NULL;
3179 GST_PLAY_BIN_LOCK (group->playbin);
3180 GST_SOURCE_GROUP_LOCK (group);
3182 if ((sink = group->playbin->text_sink))
3183 sinkpad = gst_element_get_static_pad (sink, "sink");
3187 /* Ignore errors here, if a custom sink fails to go
3188 * to READY things are wrong and will error out later
3190 if (GST_STATE (sink) < GST_STATE_READY)
3191 gst_element_set_state (sink, GST_STATE_READY);
3193 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3194 if (!gst_caps_is_any (sinkcaps))
3195 ret = !gst_pad_query_accept_caps (sinkpad, caps);
3196 gst_caps_unref (sinkcaps);
3197 gst_object_unref (sinkpad);
3199 GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
3200 ret = !gst_caps_is_subset (caps, subcaps);
3201 gst_caps_unref (subcaps);
3203 /* If autoplugging can stop don't do additional checks */
3207 /* If this is from the subtitle uridecodebin we don't need to
3208 * check the audio and video sink */
3209 if (group->suburidecodebin
3210 && gst_object_has_ancestor (GST_OBJECT_CAST (element),
3211 GST_OBJECT_CAST (group->suburidecodebin)))
3214 if ((sink = group->audio_sink)) {
3215 sinkpad = gst_element_get_static_pad (sink, "sink");
3219 /* Ignore errors here, if a custom sink fails to go
3220 * to READY things are wrong and will error out later
3222 if (GST_STATE (sink) < GST_STATE_READY)
3223 gst_element_set_state (sink, GST_STATE_READY);
3225 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3226 if (!gst_caps_is_any (sinkcaps))
3227 ret = !gst_pad_query_accept_caps (sinkpad, caps);
3228 gst_caps_unref (sinkcaps);
3229 gst_object_unref (sinkpad);
3235 if ((sink = group->video_sink)) {
3236 sinkpad = gst_element_get_static_pad (sink, "sink");
3240 /* Ignore errors here, if a custom sink fails to go
3241 * to READY things are wrong and will error out later
3243 if (GST_STATE (sink) < GST_STATE_READY)
3244 gst_element_set_state (sink, GST_STATE_READY);
3246 sinkcaps = gst_pad_query_caps (sinkpad, NULL);
3247 if (!gst_caps_is_any (sinkcaps))
3248 ret = !gst_pad_query_accept_caps (sinkpad, caps);
3249 gst_caps_unref (sinkcaps);
3250 gst_object_unref (sinkpad);
3255 GST_SOURCE_GROUP_UNLOCK (group);
3256 GST_PLAY_BIN_UNLOCK (group->playbin);
3258 GST_DEBUG_OBJECT (group->playbin,
3259 "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
3260 group, GST_DEBUG_PAD_NAME (pad), caps, ret);
3266 sink_accepts_caps (GstElement * sink, GstCaps * caps)
3270 /* ... activate it ... We do this before adding it to the bin so that we
3271 * don't accidentally make it post error messages that will stop
3273 if (GST_STATE (sink) < GST_STATE_READY &&
3274 gst_element_set_state (sink,
3275 GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
3279 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3280 /* Got the sink pad, now let's see if the element actually does accept the
3281 * caps that we have */
3282 if (!gst_pad_query_accept_caps (sinkpad, caps)) {
3283 gst_object_unref (sinkpad);
3286 gst_object_unref (sinkpad);
3292 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw");
3293 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw");
3295 /* We are asked to select an element. See if the next element to check
3296 * is a sink. If this is the case, we see if the sink works by setting it to
3297 * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
3298 * expose the raw pad so that we can setup the mixers. */
3299 static GstAutoplugSelectResult
3300 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
3301 GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
3303 GstPlayBin *playbin;
3304 GstElement *element;
3306 GstPlaySinkType type;
3309 playbin = group->playbin;
3311 GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
3312 group, GST_DEBUG_PAD_NAME (pad), caps);
3314 GST_DEBUG_OBJECT (playbin, "checking factory %s", GST_OBJECT_NAME (factory));
3316 /* if it's not a sink, we make sure the element is compatible with
3318 if (!gst_element_factory_list_is_type (factory,
3319 GST_ELEMENT_FACTORY_TYPE_SINK)) {
3320 gboolean isvideodec = gst_element_factory_list_is_type (factory,
3321 GST_ELEMENT_FACTORY_TYPE_DECODER |
3322 GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
3323 GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
3324 gboolean isaudiodec = gst_element_factory_list_is_type (factory,
3325 GST_ELEMENT_FACTORY_TYPE_DECODER |
3326 GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
3328 /* If it is a decoder and we have a fixed sink for the media
3329 * type it outputs, check that the decoder is compatible with this sink */
3330 if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) {
3331 gboolean compatible = TRUE;
3337 sink = group->audio_sink;
3339 sink = group->video_sink;
3341 if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
3342 GstPlayFlags flags = gst_play_bin_get_flags (playbin);
3344 (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) :
3345 gst_static_caps_get (&raw_video_caps);
3347 caps = gst_pad_query_caps (sinkpad, NULL);
3349 /* If the sink supports raw audio/video, we first check
3350 * if the decoder could output any raw audio/video format
3351 * and assume it is compatible with the sink then. We don't
3352 * do a complete compatibility check here if converters
3353 * are plugged between the decoder and the sink because
3354 * the converters will convert between raw formats and
3355 * even if the decoder format is not supported by the decoder
3356 * a converter will convert it.
3358 * We assume here that the converters can convert between
3361 if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO)
3362 && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec
3363 && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO)
3364 && gst_caps_can_intersect (caps, raw_caps))) {
3365 compatible = gst_element_factory_can_src_any_caps (factory, raw_caps)
3366 || gst_element_factory_can_src_any_caps (factory, caps);
3368 compatible = gst_element_factory_can_src_any_caps (factory, caps);
3371 gst_object_unref (sinkpad);
3372 gst_caps_unref (caps);
3376 return GST_AUTOPLUG_SELECT_TRY;
3378 GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink",
3379 GST_OBJECT_NAME (factory));
3381 return GST_AUTOPLUG_SELECT_SKIP;
3383 return GST_AUTOPLUG_SELECT_TRY;
3386 /* it's a sink, see if an instance of it actually works */
3387 GST_DEBUG_OBJECT (playbin, "we found a sink");
3389 klass = gst_element_factory_get_klass (factory);
3391 /* figure out the klass */
3392 if (strstr (klass, "Audio")) {
3393 GST_DEBUG_OBJECT (playbin, "we found an audio sink");
3394 type = GST_PLAY_SINK_TYPE_AUDIO;
3395 sinkp = &group->audio_sink;
3396 } else if (strstr (klass, "Video")) {
3397 GST_DEBUG_OBJECT (playbin, "we found a video sink");
3398 type = GST_PLAY_SINK_TYPE_VIDEO;
3399 sinkp = &group->video_sink;
3401 /* unknown klass, skip this element */
3402 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
3403 return GST_AUTOPLUG_SELECT_SKIP;
3406 /* if we are asked to do visualisations and it's an audio sink, skip the
3407 * element. We can only do visualisations with raw sinks */
3408 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
3409 if (type == GST_PLAY_SINK_TYPE_AUDIO) {
3410 GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
3411 return GST_AUTOPLUG_SELECT_SKIP;
3415 /* now see if we already have a sink element */
3416 GST_SOURCE_GROUP_LOCK (group);
3418 GstElement *sink = gst_object_ref (*sinkp);
3420 if (sink_accepts_caps (sink, caps)) {
3421 GST_DEBUG_OBJECT (playbin,
3422 "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
3423 GST_ELEMENT_NAME (sink), caps);
3424 gst_object_unref (sink);
3425 GST_SOURCE_GROUP_UNLOCK (group);
3426 return GST_AUTOPLUG_SELECT_EXPOSE;
3428 GST_DEBUG_OBJECT (playbin,
3429 "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
3430 GST_ELEMENT_NAME (sink), caps);
3431 gst_object_unref (sink);
3432 GST_SOURCE_GROUP_UNLOCK (group);
3433 return GST_AUTOPLUG_SELECT_SKIP;
3436 GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create one");
3438 if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
3439 GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
3440 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
3441 GST_SOURCE_GROUP_UNLOCK (group);
3442 return GST_AUTOPLUG_SELECT_SKIP;
3445 /* Check if the selected sink actually supports the
3446 * caps and can be set to READY*/
3447 if (!sink_accepts_caps (element, caps)) {
3448 gst_element_set_state (element, GST_STATE_NULL);
3449 gst_object_unref (element);
3450 GST_SOURCE_GROUP_UNLOCK (group);
3451 return GST_AUTOPLUG_SELECT_SKIP;
3454 /* remember the sink in the group now, the element is floating, we take
3457 * store the sink in the group, we will configure it later when we
3458 * reconfigure the sink */
3459 GST_DEBUG_OBJECT (playbin, "remember sink");
3460 gst_object_ref_sink (element);
3462 GST_SOURCE_GROUP_UNLOCK (group);
3464 /* tell decodebin to expose the pad because we are going to use this
3466 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
3468 return GST_AUTOPLUG_SELECT_EXPOSE;
3472 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec,
3473 GstSourceGroup * group)
3475 GstPlayBin *playbin;
3478 playbin = group->playbin;
3480 g_object_get (group->uridecodebin, "source", &source, NULL);
3482 GST_OBJECT_LOCK (playbin);
3483 if (playbin->source)
3484 gst_object_unref (playbin->source);
3485 playbin->source = source;
3486 GST_OBJECT_UNLOCK (playbin);
3488 g_object_notify (G_OBJECT (playbin), "source");
3490 g_signal_emit (playbin, gst_play_bin_signals[SIGNAL_SOURCE_SETUP],
3491 0, playbin->source);
3494 /* must be called with the group lock */
3496 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group,
3499 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
3501 if (group->uridecodebin)
3502 gst_element_set_locked_state (group->uridecodebin, locked);
3503 if (group->suburidecodebin)
3504 gst_element_set_locked_state (group->suburidecodebin, locked);
3509 /* must be called with PLAY_BIN_LOCK */
3511 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
3513 GstElement *uridecodebin;
3514 GstElement *suburidecodebin = NULL;
3517 g_return_val_if_fail (group->valid, FALSE);
3518 g_return_val_if_fail (!group->active, FALSE);
3520 GST_DEBUG_OBJECT (playbin, "activating group %p", group);
3522 GST_SOURCE_GROUP_LOCK (group);
3524 /* First set up the custom sources */
3525 if (playbin->audio_sink)
3526 group->audio_sink = gst_object_ref (playbin->audio_sink);
3527 if (playbin->video_sink)
3528 group->video_sink = gst_object_ref (playbin->video_sink);
3530 g_list_free (group->stream_changed_pending);
3531 group->stream_changed_pending = NULL;
3532 if (!group->stream_changed_pending_lock.p)
3533 g_mutex_init (&group->stream_changed_pending_lock);
3535 if (group->uridecodebin) {
3536 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
3537 uridecodebin = group->uridecodebin;
3538 gst_element_set_state (uridecodebin, GST_STATE_READY);
3539 /* no need to take extra ref, we already have one
3540 * and the bin will add one since it is no longer floating,
3541 * as it was at least added once before (below) */
3542 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3544 GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
3545 uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
3548 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
3549 group->uridecodebin = gst_object_ref (uridecodebin);
3552 flags = gst_play_sink_get_flags (playbin->playsink);
3554 g_object_set (uridecodebin,
3555 /* configure connection speed */
3556 "connection-speed", playbin->connection_speed / 1000,
3559 /* configure download buffering */
3560 "download", ((flags & GST_PLAY_FLAG_DOWNLOAD) != 0),
3561 /* configure buffering of demuxed/parsed data */
3562 "use-buffering", ((flags & GST_PLAY_FLAG_BUFFERING) != 0),
3563 /* configure buffering parameters */
3564 "buffer-duration", playbin->buffer_duration,
3565 "buffer-size", playbin->buffer_size,
3566 "ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
3568 /* connect pads and other things */
3569 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
3570 G_CALLBACK (pad_added_cb), group);
3571 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed",
3572 G_CALLBACK (pad_removed_cb), group);
3573 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads",
3574 G_CALLBACK (no_more_pads_cb), group);
3575 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source",
3576 G_CALLBACK (notify_source_cb), group);
3578 /* we have 1 pending no-more-pads */
3581 /* is called when the uridecodebin is out of data and we can switch to the
3584 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
3587 /* will be called when a new media type is found. We return a list of decoders
3588 * including sinks for decodebin to try */
3589 group->autoplug_factories_id =
3590 g_signal_connect (uridecodebin, "autoplug-factories",
3591 G_CALLBACK (autoplug_factories_cb), group);
3592 group->autoplug_select_id =
3593 g_signal_connect (uridecodebin, "autoplug-select",
3594 G_CALLBACK (autoplug_select_cb), group);
3595 group->autoplug_continue_id =
3596 g_signal_connect (uridecodebin, "autoplug-continue",
3597 G_CALLBACK (autoplug_continue_cb), group);
3599 if (group->suburi) {
3601 if (group->suburidecodebin) {
3602 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
3603 suburidecodebin = group->suburidecodebin;
3604 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3605 /* no need to take extra ref, we already have one
3606 * and the bin will add one since it is no longer floating,
3607 * as it was at least added once before (below) */
3608 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3610 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
3611 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
3612 if (!suburidecodebin)
3615 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
3616 group->suburidecodebin = gst_object_ref (suburidecodebin);
3619 g_object_set (suburidecodebin,
3620 /* configure connection speed */
3621 "connection-speed", playbin->connection_speed,
3623 "uri", group->suburi, NULL);
3625 /* connect pads and other things */
3626 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added",
3627 G_CALLBACK (pad_added_cb), group);
3628 group->sub_pad_removed_id = g_signal_connect (suburidecodebin,
3629 "pad-removed", G_CALLBACK (pad_removed_cb), group);
3630 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin,
3631 "no-more-pads", G_CALLBACK (no_more_pads_cb), group);
3633 group->sub_autoplug_continue_id =
3634 g_signal_connect (suburidecodebin, "autoplug-continue",
3635 G_CALLBACK (autoplug_continue_cb), group);
3637 /* we have 2 pending no-more-pads */
3639 group->sub_pending = TRUE;
3641 group->sub_pending = FALSE;
3644 /* release the group lock before setting the state of the decodebins, they
3645 * might fire signals in this thread that we need to handle with the
3646 * group_lock taken. */
3647 GST_SOURCE_GROUP_UNLOCK (group);
3649 if (suburidecodebin) {
3650 if (gst_element_set_state (suburidecodebin,
3651 target) == GST_STATE_CHANGE_FAILURE) {
3652 GST_DEBUG_OBJECT (playbin,
3653 "failed state change of subtitle uridecodebin");
3654 GST_SOURCE_GROUP_LOCK (group);
3656 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3657 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3658 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3659 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3660 /* Might already be removed because of an error message */
3661 if (GST_OBJECT_PARENT (suburidecodebin) == GST_OBJECT_CAST (playbin))
3662 gst_bin_remove (GST_BIN_CAST (playbin), suburidecodebin);
3663 if (group->sub_pending) {
3665 group->sub_pending = FALSE;
3667 gst_element_set_state (suburidecodebin, GST_STATE_READY);
3668 GST_SOURCE_GROUP_UNLOCK (group);
3671 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE)
3672 goto uridecodebin_failure;
3674 GST_SOURCE_GROUP_LOCK (group);
3675 /* alow state changes of the playbin affect the group elements now */
3676 group_set_locked_state_unlocked (playbin, group, FALSE);
3677 group->active = TRUE;
3678 GST_SOURCE_GROUP_UNLOCK (group);
3687 /* delete any custom sinks we might have */
3688 if (group->audio_sink) {
3689 /* If this is a automatically created sink set it to NULL */
3690 if (group->audio_sink != playbin->audio_sink)
3691 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3692 gst_object_unref (group->audio_sink);
3694 group->audio_sink = NULL;
3695 if (group->video_sink) {
3696 /* If this is a automatically created sink set it to NULL */
3697 if (group->video_sink != playbin->video_sink)
3698 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3699 gst_object_unref (group->video_sink);
3701 group->video_sink = NULL;
3703 GST_SOURCE_GROUP_UNLOCK (group);
3705 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
3707 gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
3709 GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
3710 (_("Could not create \"uridecodebin\" element.")), (NULL));
3713 uridecodebin_failure:
3715 /* delete any custom sinks we might have */
3716 if (group->audio_sink) {
3717 /* If this is a automatically created sink set it to NULL */
3718 if (group->audio_sink != playbin->audio_sink)
3719 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3720 gst_object_unref (group->audio_sink);
3722 group->audio_sink = NULL;
3723 if (group->video_sink) {
3724 /* If this is a automatically created sink set it to NULL */
3725 if (group->video_sink != playbin->video_sink)
3726 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3727 gst_object_unref (group->video_sink);
3729 group->video_sink = NULL;
3731 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
3736 /* unlink a group of uridecodebins from the sink.
3737 * must be called with PLAY_BIN_LOCK */
3739 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
3743 g_return_val_if_fail (group->valid, FALSE);
3744 g_return_val_if_fail (group->active, FALSE);
3746 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
3748 GST_SOURCE_GROUP_LOCK (group);
3749 group->active = FALSE;
3750 for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
3751 GstSourceSelect *select = &group->selector[i];
3753 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]);
3755 if (select->srcpad) {
3756 if (select->sinkpad) {
3757 GST_LOG_OBJECT (playbin, "unlinking from sink");
3758 gst_pad_unlink (select->srcpad, select->sinkpad);
3761 GST_LOG_OBJECT (playbin, "release sink pad");
3762 gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
3763 select->sinkpad = NULL;
3766 gst_object_unref (select->srcpad);
3767 select->srcpad = NULL;
3770 if (select->selector) {
3773 /* release and unref requests pad from the selector */
3774 for (n = 0; n < select->channels->len; n++) {
3775 GstPad *sinkpad = g_ptr_array_index (select->channels, n);
3777 gst_element_release_request_pad (select->selector, sinkpad);
3778 gst_object_unref (sinkpad);
3780 g_ptr_array_set_size (select->channels, 0);
3782 gst_element_set_state (select->selector, GST_STATE_NULL);
3783 gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
3784 select->selector = NULL;
3787 /* delete any custom sinks we might have */
3788 if (group->audio_sink) {
3789 /* If this is a automatically created sink set it to NULL */
3790 if (group->audio_sink != playbin->audio_sink)
3791 gst_element_set_state (group->audio_sink, GST_STATE_NULL);
3792 gst_object_unref (group->audio_sink);
3794 group->audio_sink = NULL;
3795 if (group->video_sink) {
3796 /* If this is a automatically created sink set it to NULL */
3797 if (group->video_sink != playbin->video_sink)
3798 gst_element_set_state (group->video_sink, GST_STATE_NULL);
3799 gst_object_unref (group->video_sink);
3801 group->video_sink = NULL;
3803 if (group->uridecodebin) {
3804 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
3805 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
3806 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id);
3807 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
3808 REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
3809 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
3810 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
3811 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
3812 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
3815 if (group->suburidecodebin) {
3816 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id);
3817 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id);
3818 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id);
3819 REMOVE_SIGNAL (group->suburidecodebin, group->sub_autoplug_continue_id);
3821 /* Might already be removed because of errors */
3822 if (GST_OBJECT_PARENT (group->suburidecodebin) == GST_OBJECT_CAST (playbin))
3823 gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
3826 GST_SOURCE_GROUP_UNLOCK (group);
3831 /* setup the next group to play, this assumes the next_group is valid and
3832 * configured. It swaps out the current_group and activates the valid
3835 setup_next_source (GstPlayBin * playbin, GstState target)
3837 GstSourceGroup *new_group, *old_group;
3839 GST_DEBUG_OBJECT (playbin, "setup sources");
3841 /* see if there is a next group */
3842 GST_PLAY_BIN_LOCK (playbin);
3843 new_group = playbin->next_group;
3844 if (!new_group || !new_group->valid)
3847 /* first unlink the current source, if any */
3848 old_group = playbin->curr_group;
3849 if (old_group && old_group->valid && old_group->active) {
3850 gst_play_bin_update_cached_duration (playbin);
3851 /* unlink our pads with the sink */
3852 deactivate_group (playbin, old_group);
3853 old_group->valid = FALSE;
3856 /* swap old and new */
3857 playbin->curr_group = new_group;
3858 playbin->next_group = old_group;
3860 /* activate the new group */
3861 if (!activate_group (playbin, new_group, target))
3862 goto activate_failed;
3864 GST_PLAY_BIN_UNLOCK (playbin);
3871 GST_DEBUG_OBJECT (playbin, "no next group");
3872 if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
3873 GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
3874 GST_PLAY_BIN_UNLOCK (playbin);
3879 GST_DEBUG_OBJECT (playbin, "activate failed");
3880 GST_PLAY_BIN_UNLOCK (playbin);
3885 /* The group that is currently playing is copied again to the
3886 * next_group so that it will start playing the next time.
3889 save_current_group (GstPlayBin * playbin)
3891 GstSourceGroup *curr_group;
3893 GST_DEBUG_OBJECT (playbin, "save current group");
3895 /* see if there is a current group */
3896 GST_PLAY_BIN_LOCK (playbin);
3897 curr_group = playbin->curr_group;
3898 if (curr_group && curr_group->valid && curr_group->active) {
3899 /* unlink our pads with the sink */
3900 deactivate_group (playbin, curr_group);
3902 /* swap old and new */
3903 playbin->curr_group = playbin->next_group;
3904 playbin->next_group = curr_group;
3905 GST_PLAY_BIN_UNLOCK (playbin);
3910 /* clear the locked state from all groups. This function is called before a
3911 * state change to NULL is performed on them. */
3913 groups_set_locked_state (GstPlayBin * playbin, gboolean locked)
3915 GST_DEBUG_OBJECT (playbin, "setting locked state to %d on all groups",
3918 GST_PLAY_BIN_LOCK (playbin);
3919 GST_SOURCE_GROUP_LOCK (playbin->curr_group);
3920 group_set_locked_state_unlocked (playbin, playbin->curr_group, locked);
3921 GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
3922 GST_SOURCE_GROUP_LOCK (playbin->next_group);
3923 group_set_locked_state_unlocked (playbin, playbin->next_group, locked);
3924 GST_SOURCE_GROUP_UNLOCK (playbin->next_group);
3925 GST_PLAY_BIN_UNLOCK (playbin);
3930 static GstStateChangeReturn
3931 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
3933 GstStateChangeReturn ret;
3934 GstPlayBin *playbin;
3935 gboolean do_save = FALSE;
3937 playbin = GST_PLAY_BIN (element);
3939 switch (transition) {
3940 case GST_STATE_CHANGE_NULL_TO_READY:
3941 memset (&playbin->duration, 0, sizeof (playbin->duration));
3943 case GST_STATE_CHANGE_READY_TO_PAUSED:
3944 GST_LOG_OBJECT (playbin, "clearing shutdown flag");
3945 memset (&playbin->duration, 0, sizeof (playbin->duration));
3946 g_atomic_int_set (&playbin->shutdown, 0);
3948 if (!setup_next_source (playbin, GST_STATE_READY)) {
3949 ret = GST_STATE_CHANGE_FAILURE;
3953 case GST_STATE_CHANGE_PAUSED_TO_READY:
3955 /* FIXME unlock our waiting groups */
3956 GST_LOG_OBJECT (playbin, "setting shutdown flag");
3957 g_atomic_int_set (&playbin->shutdown, 1);
3958 memset (&playbin->duration, 0, sizeof (playbin->duration));
3960 /* wait for all callbacks to end by taking the lock.
3961 * No dynamic (critical) new callbacks will
3962 * be able to happen as we set the shutdown flag. */
3963 GST_PLAY_BIN_DYN_LOCK (playbin);
3964 GST_LOG_OBJECT (playbin, "dynamic lock taken, we can continue shutdown");
3965 GST_PLAY_BIN_DYN_UNLOCK (playbin);
3968 case GST_STATE_CHANGE_READY_TO_NULL:
3969 /* we go async to PAUSED, so if that fails, we never make it to PAUSED
3970 * an no state change PAUSED to READY passes here,
3971 * though it is a nice-to-have ... */
3972 if (!g_atomic_int_get (&playbin->shutdown)) {
3976 memset (&playbin->duration, 0, sizeof (playbin->duration));
3978 /* unlock so that all groups go to NULL */
3979 groups_set_locked_state (playbin, FALSE);
3985 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3986 if (ret == GST_STATE_CHANGE_FAILURE)
3989 switch (transition) {
3990 case GST_STATE_CHANGE_READY_TO_PAUSED:
3992 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3993 /* FIXME Release audio device when we implement that */
3995 case GST_STATE_CHANGE_PAUSED_TO_READY:
3996 save_current_group (playbin);
3998 case GST_STATE_CHANGE_READY_TO_NULL:
4002 /* also do missed state change down to READY */
4004 save_current_group (playbin);
4005 /* Deactive the groups, set the uridecodebins to NULL
4008 for (i = 0; i < 2; i++) {
4009 if (playbin->groups[i].active && playbin->groups[i].valid) {
4010 deactivate_group (playbin, &playbin->groups[i]);
4011 playbin->groups[i].valid = FALSE;
4014 if (playbin->groups[i].uridecodebin) {
4015 gst_element_set_state (playbin->groups[i].uridecodebin,
4017 gst_object_unref (playbin->groups[i].uridecodebin);
4018 playbin->groups[i].uridecodebin = NULL;
4021 if (playbin->groups[i].suburidecodebin) {
4022 gst_element_set_state (playbin->groups[i].suburidecodebin,
4024 gst_object_unref (playbin->groups[i].suburidecodebin);
4025 playbin->groups[i].suburidecodebin = NULL;
4029 /* Set our sinks back to NULL, they might not be child of playbin */
4030 if (playbin->audio_sink)
4031 gst_element_set_state (playbin->audio_sink, GST_STATE_NULL);
4032 if (playbin->video_sink)
4033 gst_element_set_state (playbin->video_sink, GST_STATE_NULL);
4034 if (playbin->text_sink)
4035 gst_element_set_state (playbin->text_sink, GST_STATE_NULL);
4037 /* make sure the groups don't perform a state change anymore until we
4038 * enable them again */
4039 groups_set_locked_state (playbin, TRUE);
4051 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED) {
4052 GstSourceGroup *curr_group;
4054 curr_group = playbin->curr_group;
4055 if (curr_group && curr_group->active && curr_group->valid) {
4056 /* unlink our pads with the sink */
4057 deactivate_group (playbin, curr_group);
4058 curr_group->valid = FALSE;
4061 /* Swap current and next group back */
4062 playbin->curr_group = playbin->next_group;
4063 playbin->next_group = curr_group;
4070 gst_play_bin_overlay_expose (GstVideoOverlay * overlay)
4072 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4074 gst_video_overlay_expose (GST_VIDEO_OVERLAY (playbin->playsink));
4078 gst_play_bin_overlay_handle_events (GstVideoOverlay * overlay,
4079 gboolean handle_events)
4081 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4083 gst_video_overlay_handle_events (GST_VIDEO_OVERLAY (playbin->playsink),
4088 gst_play_bin_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x,
4089 gint y, gint width, gint height)
4091 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4093 gst_video_overlay_set_render_rectangle (GST_VIDEO_OVERLAY (playbin->playsink),
4094 x, y, width, height);
4098 gst_play_bin_overlay_set_window_handle (GstVideoOverlay * overlay,
4101 GstPlayBin *playbin = GST_PLAY_BIN (overlay);
4103 gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (playbin->playsink),
4108 gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data)
4110 GstVideoOverlayInterface *iface = (GstVideoOverlayInterface *) g_iface;
4111 iface->expose = gst_play_bin_overlay_expose;
4112 iface->handle_events = gst_play_bin_overlay_handle_events;
4113 iface->set_render_rectangle = gst_play_bin_overlay_set_render_rectangle;
4114 iface->set_window_handle = gst_play_bin_overlay_set_window_handle;
4118 gst_play_bin_navigation_send_event (GstNavigation * navigation,
4119 GstStructure * structure)
4121 GstPlayBin *playbin = GST_PLAY_BIN (navigation);
4123 gst_navigation_send_event (GST_NAVIGATION (playbin->playsink), structure);
4127 gst_play_bin_navigation_init (gpointer g_iface, gpointer g_iface_data)
4129 GstNavigationInterface *iface = (GstNavigationInterface *) g_iface;
4131 iface->send_event = gst_play_bin_navigation_send_event;
4134 static const GList *
4135 gst_play_bin_colorbalance_list_channels (GstColorBalance * balance)
4137 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4140 gst_color_balance_list_channels (GST_COLOR_BALANCE (playbin->playsink));
4144 gst_play_bin_colorbalance_set_value (GstColorBalance * balance,
4145 GstColorBalanceChannel * channel, gint value)
4147 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4149 gst_color_balance_set_value (GST_COLOR_BALANCE (playbin->playsink), channel,
4154 gst_play_bin_colorbalance_get_value (GstColorBalance * balance,
4155 GstColorBalanceChannel * channel)
4157 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4159 return gst_color_balance_get_value (GST_COLOR_BALANCE (playbin->playsink),
4163 static GstColorBalanceType
4164 gst_play_bin_colorbalance_get_balance_type (GstColorBalance * balance)
4166 GstPlayBin *playbin = GST_PLAY_BIN (balance);
4169 gst_color_balance_get_balance_type (GST_COLOR_BALANCE
4170 (playbin->playsink));
4174 gst_play_bin_colorbalance_init (gpointer g_iface, gpointer g_iface_data)
4176 GstColorBalanceInterface *iface = (GstColorBalanceInterface *) g_iface;
4178 iface->list_channels = gst_play_bin_colorbalance_list_channels;
4179 iface->set_value = gst_play_bin_colorbalance_set_value;
4180 iface->get_value = gst_play_bin_colorbalance_get_value;
4181 iface->get_balance_type = gst_play_bin_colorbalance_get_balance_type;
4185 gst_play_bin2_plugin_init (GstPlugin * plugin)
4187 GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin", 0, "play bin");
4189 return gst_element_register (plugin, "playbin", GST_RANK_NONE,