2 * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
27 #include <gst/gst-i18n-plugin.h>
28 #include <gst/pbutils/pbutils.h>
30 #include "gstplaysink.h"
32 GST_DEBUG_CATEGORY_STATIC (gst_play_sink_debug);
33 #define GST_CAT_DEFAULT gst_play_sink_debug
35 #define VOLUME_MAX_DOUBLE 10.0
37 #define GST_PLAY_CHAIN(c) (GstPlayChain *)(c)
39 /* holds the common data fields for the audio and video pipelines. We keep them
40 * in a structure to more easily have all the info available. */
43 GstPlaySink *playsink;
57 GstElement *volume; /* element with the volume property */
58 GstElement *mute; /* element with the mute property */
80 GstPad *blockpad; /* srcpad of resample, used for switching the vis */
81 GstPad *vissinkpad; /* visualisation sinkpad, */
83 GstPad *vissrcpad; /* visualisation srcpad, */
84 GstPad *srcpad; /* outgoing srcpad, used to connect to the next
96 GstPad *srcpad; /* outgoing srcpad, used to connect to the next
100 #define GST_PLAY_SINK_GET_LOCK(playsink) (((GstPlaySink *)playsink)->lock)
101 #define GST_PLAY_SINK_LOCK(playsink) g_mutex_lock (GST_PLAY_SINK_GET_LOCK (playsink))
102 #define GST_PLAY_SINK_UNLOCK(playsink) g_mutex_unlock (GST_PLAY_SINK_GET_LOCK (playsink))
112 GstPlayAudioChain *audiochain;
113 GstPlayVideoChain *videochain;
114 GstPlayVisChain *vischain;
115 GstPlayTextChain *textchain;
118 gboolean audio_pad_raw;
119 GstElement *audio_tee;
120 GstPad *audio_tee_sink;
121 GstPad *audio_tee_asrc;
122 GstPad *audio_tee_vissrc;
125 gboolean video_pad_raw;
130 GstElement *audio_sink;
131 GstElement *video_sink;
132 GstElement *visualisation;
135 gchar *font_desc; /* font description */
136 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
139 struct _GstPlaySinkClass
141 GstBinClass parent_class;
164 static void gst_play_sink_class_init (GstPlaySinkClass * klass);
165 static void gst_play_sink_init (GstPlaySink * playsink);
166 static void gst_play_sink_dispose (GObject * object);
167 static void gst_play_sink_finalize (GObject * object);
169 static gboolean gst_play_sink_send_event (GstElement * element,
171 static GstStateChangeReturn gst_play_sink_change_state (GstElement * element,
172 GstStateChange transition);
174 /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */
176 static const GstElementDetails gst_play_sink_details =
177 GST_ELEMENT_DETAILS ("Player Sink",
178 "Generic/Bin/Player",
179 "Autoplug and play media from an uri",
180 "Wim Taymans <wim.taymans@gmail.com>");
182 G_DEFINE_TYPE (GstPlaySink, gst_play_sink, GST_TYPE_BIN);
185 gst_play_sink_class_init (GstPlaySinkClass * klass)
187 GObjectClass *gobject_klass;
188 GstElementClass *gstelement_klass;
189 GstBinClass *gstbin_klass;
191 gobject_klass = (GObjectClass *) klass;
192 gstelement_klass = (GstElementClass *) klass;
193 gstbin_klass = (GstBinClass *) klass;
195 gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_sink_dispose);
196 gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_sink_finalize);
198 gst_element_class_set_details (gstelement_klass, &gst_play_sink_details);
200 gstelement_klass->change_state =
201 GST_DEBUG_FUNCPTR (gst_play_sink_change_state);
202 gstelement_klass->send_event = GST_DEBUG_FUNCPTR (gst_play_sink_send_event);
204 GST_DEBUG_CATEGORY_INIT (gst_play_sink_debug, "playsink", 0, "play bin");
208 gst_play_sink_init (GstPlaySink * playsink)
211 playsink->video_sink = NULL;
212 playsink->audio_sink = NULL;
213 playsink->visualisation = NULL;
214 playsink->volume = 1.0;
215 playsink->font_desc = NULL;
216 playsink->flags = GST_PLAY_FLAG_SOFT_VOLUME;
218 playsink->lock = g_mutex_new ();
222 free_chain (GstPlayChain * chain)
226 gst_object_unref (chain->bin);
232 gst_play_sink_dispose (GObject * object)
234 GstPlaySink *playsink;
236 playsink = GST_PLAY_SINK (object);
238 if (playsink->audio_sink != NULL) {
239 gst_element_set_state (playsink->audio_sink, GST_STATE_NULL);
240 gst_object_unref (playsink->audio_sink);
241 playsink->audio_sink = NULL;
243 if (playsink->video_sink != NULL) {
244 gst_element_set_state (playsink->video_sink, GST_STATE_NULL);
245 gst_object_unref (playsink->video_sink);
246 playsink->video_sink = NULL;
248 if (playsink->visualisation != NULL) {
249 gst_element_set_state (playsink->visualisation, GST_STATE_NULL);
250 gst_object_unref (playsink->visualisation);
251 playsink->visualisation = NULL;
254 free_chain ((GstPlayChain *) playsink->videochain);
255 playsink->videochain = NULL;
256 free_chain ((GstPlayChain *) playsink->audiochain);
257 playsink->audiochain = NULL;
258 free_chain ((GstPlayChain *) playsink->vischain);
259 playsink->vischain = NULL;
260 free_chain ((GstPlayChain *) playsink->textchain);
261 playsink->textchain = NULL;
264 if (playsink->audio_tee_sink) {
265 gst_object_unref (playsink->audio_tee_sink);
266 playsink->audio_tee_sink = NULL;
269 if (playsink->audio_tee_vissrc) {
270 gst_element_release_request_pad (playsink->audio_tee,
271 playsink->audio_tee_vissrc);
272 gst_object_unref (playsink->audio_tee_vissrc);
273 playsink->audio_tee_vissrc = NULL;
276 if (playsink->audio_tee_asrc) {
277 gst_element_release_request_pad (playsink->audio_tee,
278 playsink->audio_tee_asrc);
279 gst_object_unref (playsink->audio_tee_asrc);
280 playsink->audio_tee_asrc = NULL;
283 g_free (playsink->font_desc);
284 playsink->font_desc = NULL;
286 G_OBJECT_CLASS (gst_play_sink_parent_class)->dispose (object);
290 gst_play_sink_finalize (GObject * object)
292 GstPlaySink *playsink;
294 playsink = GST_PLAY_SINK (object);
296 g_mutex_free (playsink->lock);
298 G_OBJECT_CLASS (gst_play_sink_parent_class)->finalize (object);
302 gst_play_sink_set_video_sink (GstPlaySink * playsink, GstElement * sink)
304 GST_PLAY_SINK_LOCK (playsink);
305 if (playsink->video_sink)
306 gst_object_unref (playsink->video_sink);
309 gst_object_ref (sink);
310 gst_object_sink (sink);
312 playsink->video_sink = sink;
313 GST_PLAY_SINK_UNLOCK (playsink);
317 gst_play_sink_get_video_sink (GstPlaySink * playsink)
319 GstElement *result = NULL;
320 GstPlayVideoChain *chain;
322 GST_PLAY_SINK_LOCK (playsink);
323 if ((chain = (GstPlayVideoChain *) playsink->videochain)) {
324 /* we have an active chain, get the sink */
326 result = gst_object_ref (chain->sink);
328 /* nothing found, return last configured sink */
329 if (result == NULL && playsink->video_sink)
330 result = gst_object_ref (playsink->video_sink);
331 GST_PLAY_SINK_UNLOCK (playsink);
337 gst_play_sink_set_audio_sink (GstPlaySink * playsink, GstElement * sink)
339 GST_PLAY_SINK_LOCK (playsink);
340 if (playsink->audio_sink)
341 gst_object_unref (playsink->audio_sink);
344 gst_object_ref (sink);
345 gst_object_sink (sink);
347 playsink->audio_sink = sink;
348 GST_PLAY_SINK_UNLOCK (playsink);
352 gst_play_sink_get_audio_sink (GstPlaySink * playsink)
354 GstElement *result = NULL;
355 GstPlayAudioChain *chain;
357 GST_PLAY_SINK_LOCK (playsink);
358 if ((chain = (GstPlayAudioChain *) playsink->audiochain)) {
359 /* we have an active chain, get the sink */
361 result = gst_object_ref (chain->sink);
363 /* nothing found, return last configured sink */
364 if (result == NULL && playsink->audio_sink)
365 result = gst_object_ref (playsink->audio_sink);
366 GST_PLAY_SINK_UNLOCK (playsink);
372 gst_play_sink_vis_unblocked (GstPad * tee_pad, gboolean blocked,
375 GstPlaySink *playsink;
377 playsink = GST_PLAY_SINK (user_data);
378 /* nothing to do here, we need a dummy callback here to make the async call
380 GST_DEBUG_OBJECT (playsink, "vis pad unblocked");
384 gst_play_sink_vis_blocked (GstPad * tee_pad, gboolean blocked,
387 GstPlaySink *playsink;
388 GstPlayVisChain *chain;
390 playsink = GST_PLAY_SINK (user_data);
392 GST_PLAY_SINK_LOCK (playsink);
393 GST_DEBUG_OBJECT (playsink, "vis pad blocked");
394 /* now try to change the plugin in the running vis chain */
395 if (!(chain = (GstPlayVisChain *) playsink->vischain))
398 /* unlink the old plugin and unghost the pad */
399 gst_pad_unlink (chain->blockpad, chain->vissinkpad);
400 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (chain->srcpad), NULL);
402 /* set the old plugin to NULL and remove */
403 gst_element_set_state (chain->vis, GST_STATE_NULL);
404 gst_bin_remove (GST_BIN_CAST (chain->chain.bin), chain->vis);
406 /* add new plugin and set state to playing */
407 chain->vis = gst_object_ref (playsink->visualisation);
408 gst_bin_add (GST_BIN_CAST (chain->chain.bin), chain->vis);
409 gst_element_set_state (chain->vis, GST_STATE_PLAYING);
412 chain->vissinkpad = gst_element_get_static_pad (chain->vis, "sink");
413 chain->vissrcpad = gst_element_get_static_pad (chain->vis, "src");
416 gst_pad_link (chain->blockpad, chain->vissinkpad);
417 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (chain->srcpad),
421 /* Unblock the pad */
422 gst_pad_set_blocked_async (tee_pad, FALSE, gst_play_sink_vis_unblocked,
424 GST_PLAY_SINK_UNLOCK (playsink);
428 gst_play_sink_set_vis_plugin (GstPlaySink * playsink, GstElement * vis)
430 GstPlayVisChain *chain;
432 /* setting NULL means creating the default vis plugin */
434 vis = gst_element_factory_make ("goom", "vis");
436 /* simply return if we don't have a vis plugin here */
440 GST_PLAY_SINK_LOCK (playsink);
441 /* first store the new vis */
442 if (playsink->visualisation)
443 gst_object_unref (playsink->visualisation);
444 playsink->visualisation = gst_object_ref (vis);
446 /* now try to change the plugin in the running vis chain, if we have no chain,
447 * we don't bother, any future vis chain will be created with the new vis
449 if (!(chain = (GstPlayVisChain *) playsink->vischain))
452 /* block the pad, the next time the callback is called we can change the
453 * visualisation. It's possible that this never happens or that the pad was
454 * already blocked. If the callback never happens, we don't have new data so
455 * we don't need the new vis plugin. If the pad was already blocked, the
456 * function returns FALSE but the previous pad block will do the right thing
458 GST_DEBUG_OBJECT (playsink, "blocking vis pad");
459 gst_pad_set_blocked_async (chain->blockpad, TRUE, gst_play_sink_vis_blocked,
462 GST_PLAY_SINK_UNLOCK (playsink);
468 gst_play_sink_get_vis_plugin (GstPlaySink * playsink)
470 GstElement *result = NULL;
471 GstPlayVisChain *chain;
473 GST_PLAY_SINK_LOCK (playsink);
474 if ((chain = (GstPlayVisChain *) playsink->vischain)) {
475 /* we have an active chain, get the sink */
477 result = gst_object_ref (chain->vis);
479 /* nothing found, return last configured sink */
480 if (result == NULL && playsink->visualisation)
481 result = gst_object_ref (playsink->visualisation);
482 GST_PLAY_SINK_UNLOCK (playsink);
488 gst_play_sink_set_volume (GstPlaySink * playsink, gdouble volume)
490 GstPlayAudioChain *chain;
492 GST_PLAY_SINK_LOCK (playsink);
493 playsink->volume = volume;
494 chain = (GstPlayAudioChain *) playsink->audiochain;
495 if (chain && chain->volume) {
496 /* if there is a mute element or we are not muted, set the volume */
497 if (chain->mute || !playsink->mute)
498 g_object_set (chain->volume, "volume", volume, NULL);
500 GST_PLAY_SINK_UNLOCK (playsink);
504 gst_play_sink_get_volume (GstPlaySink * playsink)
507 GstPlayAudioChain *chain;
509 GST_PLAY_SINK_LOCK (playsink);
510 chain = (GstPlayAudioChain *) playsink->audiochain;
511 result = playsink->volume;
512 if (chain && chain->volume) {
513 if (chain->mute || !playsink->mute) {
514 g_object_get (chain->volume, "volume", &result, NULL);
515 playsink->volume = result;
518 GST_PLAY_SINK_UNLOCK (playsink);
524 gst_play_sink_set_mute (GstPlaySink * playsink, gboolean mute)
526 GstPlayAudioChain *chain;
528 GST_PLAY_SINK_LOCK (playsink);
529 playsink->mute = mute;
530 chain = (GstPlayAudioChain *) playsink->audiochain;
533 g_object_set (chain->mute, "mute", mute, NULL);
534 } else if (chain->volume) {
536 g_object_set (chain->volume, "volume", (gdouble) 0.0, NULL);
538 g_object_set (chain->volume, "volume", (gdouble) playsink->volume,
542 GST_PLAY_SINK_UNLOCK (playsink);
546 gst_play_sink_get_mute (GstPlaySink * playsink)
549 GstPlayAudioChain *chain;
551 GST_PLAY_SINK_LOCK (playsink);
552 chain = (GstPlayAudioChain *) playsink->audiochain;
553 if (chain && chain->mute) {
554 g_object_get (chain->mute, "mute", &result, NULL);
555 playsink->mute = result;
557 result = playsink->mute;
559 GST_PLAY_SINK_UNLOCK (playsink);
565 post_missing_element_message (GstPlaySink * playsink, const gchar * name)
569 msg = gst_missing_element_message_new (GST_ELEMENT_CAST (playsink), name);
570 gst_element_post_message (GST_ELEMENT_CAST (playsink), msg);
574 add_chain (GstPlayChain * chain, gboolean add)
576 if (chain->added == add)
580 gst_bin_add (GST_BIN_CAST (chain->playsink), chain->bin);
582 gst_bin_remove (GST_BIN_CAST (chain->playsink), chain->bin);
590 activate_chain (GstPlayChain * chain, gboolean activate)
592 if (chain->activated == activate)
596 gst_element_set_state (chain->bin, GST_STATE_PAUSED);
598 gst_element_set_state (chain->bin, GST_STATE_NULL);
600 chain->activated = activate;
606 find_property (GstElement * element, const gchar * name)
610 if (g_object_class_find_property (G_OBJECT_GET_CLASS (element), name)) {
612 GST_DEBUG_OBJECT (element, "found %s property", name);
614 GST_DEBUG_OBJECT (element, "did not find %s property", name);
616 gst_object_unref (element);
621 /* find an object in the hierarchy with a property named @name */
623 gst_play_sink_find_property (GstPlaySink * playsink, GstElement * obj,
626 GstElement *result = NULL;
629 if (GST_IS_BIN (obj)) {
630 it = gst_bin_iterate_recurse (GST_BIN_CAST (obj));
631 result = gst_iterator_find_custom (it,
632 (GCompareFunc) find_property, (gpointer) name);
633 gst_iterator_free (it);
635 if (g_object_class_find_property (G_OBJECT_GET_CLASS (obj), name)) {
637 gst_object_ref (obj);
643 /* try to change the state of an element. This function returns the element when
644 * the state change could be performed. When this function returns NULL an error
645 * occured and the element is unreffed. */
647 try_element (GstPlaySink * playsink, GstElement * element)
649 GstStateChangeReturn ret;
652 ret = gst_element_set_state (element, GST_STATE_READY);
653 if (ret == GST_STATE_CHANGE_FAILURE) {
654 GST_DEBUG_OBJECT (playsink, "failed state change..");
655 gst_element_set_state (element, GST_STATE_NULL);
656 gst_object_unref (element);
663 /* make the element (bin) that contains the elements needed to perform
666 * +------------------------------------------------------------+
668 * | +-------+ +----------+ +----------+ +---------+ |
669 * | | queue | |colorspace| |videoscale| |videosink| |
670 * | +-sink src-sink src-sink src-sink | |
671 * | | +-------+ +----------+ +----------+ +---------+ |
673 * +------------------------------------------------------------+
676 static GstPlayVideoChain *
677 gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
679 GstPlayVideoChain *chain;
682 GstElement *prev, *elem;
684 chain = g_new0 (GstPlayVideoChain, 1);
685 chain->chain.playsink = playsink;
686 chain->chain.raw = raw;
688 GST_DEBUG_OBJECT (playsink, "making video chain %p", chain);
690 if (playsink->video_sink) {
691 GST_DEBUG_OBJECT (playsink, "trying configured videosink");
692 elem = gst_object_ref (playsink->video_sink);
693 chain->sink = try_element (playsink, elem);
695 if (chain->sink == NULL) {
696 GST_DEBUG_OBJECT (playsink, "trying autovideosink");
697 elem = gst_element_factory_make ("autovideosink", "videosink");
698 chain->sink = try_element (playsink, elem);
700 if (chain->sink == NULL) {
701 GST_DEBUG_OBJECT (playsink, "trying xvimagesink");
702 elem = gst_element_factory_make ("xvimagesink", "videosink");
703 chain->sink = try_element (playsink, elem);
705 if (chain->sink == NULL)
708 /* if we can disable async behaviour of the sink, we can avoid adding a
709 * queue for the audio chain. We can't use the deep property here because the
710 * sink might change it's internal sink element later. */
711 if (g_object_class_find_property (G_OBJECT_GET_CLASS (chain->sink), "async")) {
712 GST_DEBUG_OBJECT (playsink, "setting async property to %d on video sink",
714 g_object_set (chain->sink, "async", async, NULL);
715 chain->async = async;
717 GST_DEBUG_OBJECT (playsink, "no async property on the sink");
721 /* create a bin to hold objects, as we create them we add them to this bin so
722 * that when something goes wrong we only need to unref the bin */
723 chain->chain.bin = gst_bin_new ("vbin");
724 bin = GST_BIN_CAST (chain->chain.bin);
725 gst_object_ref (bin);
726 gst_object_sink (bin);
727 gst_bin_add (bin, chain->sink);
729 /* decouple decoder from sink, this improves playback quite a lot since the
730 * decoder can continue while the sink blocks for synchronisation. We don't
731 * need a lot of buffers as this consumes a lot of memory and we don't want
732 * too little because else we would be context switching too quickly. */
733 chain->queue = gst_element_factory_make ("queue", "vqueue");
734 g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3,
735 "max-size-bytes", 0, "max-size-time", (gint64) 0, NULL);
736 gst_bin_add (bin, chain->queue);
740 GST_DEBUG_OBJECT (playsink, "creating ffmpegcolorspace");
741 chain->conv = gst_element_factory_make ("ffmpegcolorspace", "vconv");
742 if (chain->conv == NULL) {
743 post_missing_element_message (playsink, "ffmpegcolorspace");
744 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
745 (_("Missing element '%s' - check your GStreamer installation."),
746 "ffmpegcolorspace"), (NULL));
748 gst_bin_add (bin, chain->conv);
749 if (!gst_element_link_pads (prev, "src", chain->conv, "sink"))
755 GST_DEBUG_OBJECT (playsink, "creating videoscale");
756 chain->scale = gst_element_factory_make ("videoscale", "vscale");
757 if (chain->scale == NULL) {
758 post_missing_element_message (playsink, "videoscale");
759 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
760 (_("Missing element '%s' - check your GStreamer installation."),
761 "videoscale"), ("possibly a liboil version mismatch?"));
763 gst_bin_add (bin, chain->scale);
764 if (!gst_element_link_pads (prev, "src", chain->scale, "sink"))
771 /* be more careful with the pad from the custom sink element, it might not
773 if (!gst_element_link_pads (prev, "src", chain->sink, NULL))
776 pad = gst_element_get_static_pad (chain->queue, "sink");
777 chain->sinkpad = gst_ghost_pad_new ("sink", pad);
778 gst_object_unref (pad);
780 gst_element_add_pad (chain->chain.bin, chain->sinkpad);
787 post_missing_element_message (playsink, "autovideosink");
788 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
789 (_("Both autovideosink and xvimagesink elements are missing.")),
791 free_chain ((GstPlayChain *) chain);
796 GST_ELEMENT_ERROR (playsink, CORE, PAD,
797 (NULL), ("Failed to configure the video sink."));
798 free_chain ((GstPlayChain *) chain);
803 /* make an element for playback of video with subtitles embedded.
805 * +----------------------------------------------+
806 * | tbin +-------------+ |
807 * | +-----+ | textoverlay | |
808 * | | csp | +--video_sink | |
809 * video_sink-sink src+ +-text_sink src--+ |
810 * | +-----+ | +-------------+ +-- src
811 * text_sink-------------+ |
812 * +----------------------------------------------+
814 static GstPlayTextChain *
815 gen_text_chain (GstPlaySink * playsink)
817 GstPlayTextChain *chain;
821 chain = g_new0 (GstPlayTextChain, 1);
822 chain->chain.playsink = playsink;
824 GST_DEBUG_OBJECT (playsink, "making text chain %p", chain);
826 chain->chain.bin = gst_bin_new ("tbin");
827 bin = GST_BIN_CAST (chain->chain.bin);
828 gst_object_ref (bin);
829 gst_object_sink (bin);
831 chain->conv = gst_element_factory_make ("ffmpegcolorspace", "tconv");
832 if (chain->conv == NULL)
834 gst_bin_add (bin, chain->conv);
836 chain->overlay = gst_element_factory_make ("textoverlay", "overlay");
837 if (chain->overlay == NULL)
839 gst_bin_add (bin, chain->overlay);
841 /* Set some parameters */
842 g_object_set (G_OBJECT (chain->overlay),
843 "halign", "center", "valign", "bottom", NULL);
844 if (playsink->font_desc) {
845 g_object_set (G_OBJECT (chain->overlay), "font-desc", playsink->font_desc,
848 g_object_set (G_OBJECT (chain->overlay), "wait-text", FALSE, NULL);
851 gst_element_link_pads (chain->conv, "src", chain->overlay, "video_sink");
853 /* Add ghost pads on the subtitle bin */
854 pad = gst_element_get_static_pad (chain->overlay, "text_sink");
855 chain->textsinkpad = gst_ghost_pad_new ("text_sink", pad);
856 gst_object_unref (pad);
857 gst_element_add_pad (chain->chain.bin, chain->textsinkpad);
859 pad = gst_element_get_static_pad (chain->conv, "sink");
860 chain->videosinkpad = gst_ghost_pad_new ("sink", pad);
861 gst_object_unref (pad);
862 gst_element_add_pad (chain->chain.bin, chain->videosinkpad);
864 pad = gst_element_get_static_pad (chain->overlay, "src");
865 chain->srcpad = gst_ghost_pad_new ("src", pad);
866 gst_object_unref (pad);
867 gst_element_add_pad (chain->chain.bin, chain->srcpad);
874 post_missing_element_message (playsink, "ffmpegcolorspace");
875 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
876 (_("Missing element '%s' - check your GStreamer installation."),
877 "ffmpegcolorspace"), (NULL));
878 free_chain ((GstPlayChain *) chain);
883 post_missing_element_message (playsink, "textoverlay");
884 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
885 (_("Missing element '%s' - check your GStreamer installation."),
886 "textoverlay"), (NULL));
887 free_chain ((GstPlayChain *) chain);
892 /* make the chain that contains the elements needed to perform
895 * We add a tee as the first element so that we can link the visualisation chain
896 * to it when requested.
898 * +-------------------------------------------------------------+
900 * | +---------+ +----------+ +---------+ +---------+ |
901 * | |audioconv| |audioscale| | volume | |audiosink| |
902 * | +-srck src-sink src-sink src-sink | |
903 * | | +---------+ +----------+ +---------+ +---------+ |
905 * +-------------------------------------------------------------+
907 static GstPlayAudioChain *
908 gen_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue)
910 GstPlayAudioChain *chain;
912 gboolean have_volume;
914 GstElement *head, *prev, *elem;
916 chain = g_new0 (GstPlayAudioChain, 1);
917 chain->chain.playsink = playsink;
918 chain->chain.raw = raw;
920 GST_DEBUG_OBJECT (playsink, "making audio chain %p", chain);
922 if (playsink->audio_sink) {
923 GST_DEBUG_OBJECT (playsink, "trying configured audiosink");
924 elem = gst_object_ref (playsink->audio_sink);
925 chain->sink = try_element (playsink, elem);
927 if (chain->sink == NULL) {
928 GST_DEBUG_OBJECT (playsink, "trying autoaudiosink");
929 elem = gst_element_factory_make ("autoaudiosink", "audiosink");
930 chain->sink = try_element (playsink, elem);
932 if (chain->sink == NULL) {
933 GST_DEBUG_OBJECT (playsink, "trying alsasink");
934 elem = gst_element_factory_make ("alsasink", "audiosink");
935 chain->sink = try_element (playsink, elem);
937 if (chain->sink == NULL)
941 chain->chain.bin = gst_bin_new ("abin");
942 bin = GST_BIN_CAST (chain->chain.bin);
943 gst_object_ref (bin);
944 gst_object_sink (bin);
945 gst_bin_add (bin, chain->sink);
948 /* we have to add a queue when we need to decouple for the video sink in
950 GST_DEBUG_OBJECT (playsink, "adding audio queue");
951 chain->queue = gst_element_factory_make ("queue", "aqueue");
952 gst_bin_add (bin, chain->queue);
953 prev = head = chain->queue;
959 /* check if the sink has the volume property, if it does we don't need to
960 * add a volume element. */
961 if (g_object_class_find_property (G_OBJECT_GET_CLASS (chain->sink), "volume")) {
962 GST_DEBUG_OBJECT (playsink, "the sink has a volume property");
964 /* use the sink to control the volume */
965 chain->volume = chain->sink;
966 g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL);
967 /* if the sink also has a mute property we can use this as well. We'll only
968 * use the mute property if there is a volume property. We can simulate the
969 * mute with the volume otherwise. */
970 if (g_object_class_find_property (G_OBJECT_GET_CLASS (chain->sink), "mute")) {
971 GST_DEBUG_OBJECT (playsink, "the sink has a mute property");
972 chain->mute = chain->sink;
975 /* no volume, we need to add a volume element when we can */
976 GST_DEBUG_OBJECT (playsink, "the sink has no volume property");
981 GST_DEBUG_OBJECT (playsink, "creating audioconvert");
982 chain->conv = gst_element_factory_make ("audioconvert", "aconv");
983 if (chain->conv == NULL) {
984 post_missing_element_message (playsink, "audioconvert");
985 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
986 (_("Missing element '%s' - check your GStreamer installation."),
987 "audioconvert"), ("possibly a liboil version mismatch?"));
989 gst_bin_add (bin, chain->conv);
991 if (!gst_element_link_pads (prev, "src", chain->conv, "sink"))
999 GST_DEBUG_OBJECT (playsink, "creating audioresample");
1000 chain->resample = gst_element_factory_make ("audioresample", "aresample");
1001 if (chain->resample == NULL) {
1002 post_missing_element_message (playsink, "audioresample");
1003 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
1004 (_("Missing element '%s' - check your GStreamer installation."),
1005 "audioresample"), ("possibly a liboil version mismatch?"));
1007 gst_bin_add (bin, chain->resample);
1009 if (!gst_element_link_pads (prev, "src", chain->resample, "sink"))
1012 head = chain->resample;
1014 prev = chain->resample;
1017 if (!have_volume && playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) {
1018 GST_DEBUG_OBJECT (playsink, "creating volume");
1019 chain->volume = gst_element_factory_make ("volume", "volume");
1020 if (chain->volume == NULL) {
1021 post_missing_element_message (playsink, "volume");
1022 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
1023 (_("Missing element '%s' - check your GStreamer installation."),
1024 "volume"), ("possibly a liboil version mismatch?"));
1028 /* volume also has the mute property */
1029 chain->mute = chain->volume;
1031 /* configure with the latest volume and mute */
1032 g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume,
1034 g_object_set (G_OBJECT (chain->mute), "mute", playsink->mute, NULL);
1035 gst_bin_add (bin, chain->volume);
1038 if (!gst_element_link_pads (prev, "src", chain->volume, "sink"))
1041 head = chain->volume;
1043 prev = chain->volume;
1049 /* we only have to link to the previous element if we have something in
1050 * front of the sink */
1051 GST_DEBUG_OBJECT (playsink, "linking to sink");
1052 if (!gst_element_link_pads (prev, "src", chain->sink, NULL))
1056 /* post a warning if we have no way to configure the volume */
1058 GST_ELEMENT_WARNING (playsink, STREAM, NOT_IMPLEMENTED,
1059 (_("No volume control found")), ("No volume control found"));
1062 /* and ghost the sinkpad of the headmost element */
1063 GST_DEBUG_OBJECT (playsink, "ghosting sink pad");
1064 pad = gst_element_get_static_pad (head, "sink");
1065 chain->sinkpad = gst_ghost_pad_new ("sink", pad);
1066 gst_object_unref (pad);
1067 gst_element_add_pad (chain->chain.bin, chain->sinkpad);
1074 post_missing_element_message (playsink, "autoaudiosink");
1075 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
1076 (_("Both autoaudiosink and alsasink elements are missing.")), (NULL));
1077 free_chain ((GstPlayChain *) chain);
1082 GST_ELEMENT_ERROR (playsink, CORE, PAD,
1083 (NULL), ("Failed to configure the audio sink."));
1084 free_chain ((GstPlayChain *) chain);
1090 * +-------------------------------------------------------------------+
1092 * | +----------+ +------------+ +----------+ +-------+ |
1093 * | | visqueue | | audioconv | | audiores | | vis | |
1094 * | +-sink src-sink + samp src-sink src-sink src-+ |
1095 * | | +----------+ +------------+ +----------+ +-------+ | |
1097 * +-------------------------------------------------------------------+
1100 static GstPlayVisChain *
1101 gen_vis_chain (GstPlaySink * playsink)
1103 GstPlayVisChain *chain;
1108 chain = g_new0 (GstPlayVisChain, 1);
1109 chain->chain.playsink = playsink;
1111 GST_DEBUG_OBJECT (playsink, "making vis chain %p", chain);
1113 chain->chain.bin = gst_bin_new ("visbin");
1114 bin = GST_BIN_CAST (chain->chain.bin);
1115 gst_object_ref (bin);
1116 gst_object_sink (bin);
1118 /* we're queuing raw audio here, we can remove this queue when we can disable
1119 * async behaviour in the video sink. */
1120 chain->queue = gst_element_factory_make ("queue", "visqueue");
1121 gst_bin_add (bin, chain->queue);
1123 chain->conv = gst_element_factory_make ("audioconvert", "aconv");
1124 if (chain->conv == NULL)
1125 goto no_audioconvert;
1126 gst_bin_add (bin, chain->conv);
1128 chain->resample = gst_element_factory_make ("audioresample", "aresample");
1129 if (chain->resample == NULL)
1130 goto no_audioresample;
1131 gst_bin_add (bin, chain->resample);
1133 /* this pad will be used for blocking the dataflow and switching the vis
1135 chain->blockpad = gst_element_get_static_pad (chain->resample, "src");
1137 if (playsink->visualisation) {
1138 chain->vis = gst_object_ref (playsink->visualisation);
1140 chain->vis = gst_element_factory_make ("goom", "vis");
1144 gst_bin_add (bin, chain->vis);
1146 res = gst_element_link_pads (chain->queue, "src", chain->conv, "sink");
1147 res &= gst_element_link_pads (chain->conv, "src", chain->resample, "sink");
1148 res &= gst_element_link_pads (chain->resample, "src", chain->vis, "sink");
1152 chain->vissinkpad = gst_element_get_static_pad (chain->vis, "sink");
1153 chain->vissrcpad = gst_element_get_static_pad (chain->vis, "src");
1155 pad = gst_element_get_static_pad (chain->queue, "sink");
1156 chain->sinkpad = gst_ghost_pad_new ("sink", pad);
1157 gst_object_unref (pad);
1158 gst_element_add_pad (chain->chain.bin, chain->sinkpad);
1160 chain->srcpad = gst_ghost_pad_new ("src", chain->vissrcpad);
1161 gst_element_add_pad (chain->chain.bin, chain->srcpad);
1168 post_missing_element_message (playsink, "audioconvert");
1169 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
1170 (_("Missing element '%s' - check your GStreamer installation."),
1171 "audioconvert"), ("possibly a liboil version mismatch?"));
1172 free_chain ((GstPlayChain *) chain);
1177 post_missing_element_message (playsink, "audioresample");
1178 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
1179 (_("Missing element '%s' - check your GStreamer installation."),
1180 "audioresample"), (NULL));
1181 free_chain ((GstPlayChain *) chain);
1186 post_missing_element_message (playsink, "goom");
1187 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
1188 (_("Missing element '%s' - check your GStreamer installation."),
1190 free_chain ((GstPlayChain *) chain);
1195 GST_ELEMENT_ERROR (playsink, CORE, PAD,
1196 (NULL), ("Failed to configure the visualisation element."));
1197 free_chain ((GstPlayChain *) chain);
1202 /* this function is called when all the request pads are requested and when we
1203 * have to construct the final pipeline. Based on the flags we construct the
1204 * final output pipelines.
1207 gst_play_sink_reconfigure (GstPlaySink * playsink)
1210 gboolean need_audio, need_video, need_vis, need_text;
1212 GST_DEBUG_OBJECT (playsink, "reconfiguring");
1214 /* assume we need nothing */
1215 need_audio = need_video = need_vis = need_text = FALSE;
1217 GST_PLAY_SINK_LOCK (playsink);
1218 GST_OBJECT_LOCK (playsink);
1219 /* get flags, there are protected with the object lock */
1220 flags = playsink->flags;
1221 GST_OBJECT_UNLOCK (playsink);
1223 /* figure out which components we need */
1224 if (flags & GST_PLAY_FLAG_TEXT && playsink->text_pad) {
1225 /* we have a text_pad and we need text rendering, in this case we need a
1226 * video_pad to combine the video with the text */
1227 if (!playsink->video_pad)
1228 goto subs_but_no_video;
1230 /* we have subtitles and we are requested to show it, we also need to show
1231 * video in this case. */
1234 } else if (flags & GST_PLAY_FLAG_VIDEO && playsink->video_pad) {
1235 /* we have video and we are requested to show it */
1238 if (playsink->audio_pad) {
1239 if (flags & GST_PLAY_FLAG_AUDIO) {
1242 if (playsink->audio_pad_raw) {
1243 /* only can do vis with raw uncompressed audio */
1244 if (flags & GST_PLAY_FLAG_VIS && !need_video) {
1245 /* also add video when we add visualisation */
1252 /* set up video pipeline */
1254 GST_DEBUG_OBJECT (playsink, "adding video, raw %d",
1255 playsink->video_pad_raw);
1256 if (!playsink->videochain) {
1257 gboolean raw, async;
1259 /* we need a raw sink when we do vis or when we have a raw pad */
1260 raw = need_vis ? TRUE : playsink->video_pad_raw;
1261 /* we try to set the sink async=FALSE when we need vis, this way we can
1262 * avoid a queue in the audio chain. */
1265 playsink->videochain = gen_video_chain (playsink, raw, async);
1267 if (playsink->videochain) {
1268 GST_DEBUG_OBJECT (playsink, "adding video chain");
1269 add_chain (GST_PLAY_CHAIN (playsink->videochain), TRUE);
1270 activate_chain (GST_PLAY_CHAIN (playsink->videochain), TRUE);
1271 /* if we are not part of vis or subtitles, set the ghostpad target */
1272 if (!need_vis && !need_text) {
1273 GST_DEBUG_OBJECT (playsink, "ghosting video sinkpad");
1274 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad),
1275 playsink->videochain->sinkpad);
1279 GST_DEBUG_OBJECT (playsink, "no video needed");
1280 if (playsink->videochain) {
1281 GST_DEBUG_OBJECT (playsink, "removing video chain");
1282 add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
1283 activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
1285 if (playsink->video_pad)
1286 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), NULL);
1290 GST_DEBUG_OBJECT (playsink, "adding text");
1291 if (!playsink->textchain) {
1292 GST_DEBUG_OBJECT (playsink, "creating text chain");
1293 playsink->textchain = gen_text_chain (playsink);
1295 if (playsink->textchain) {
1296 GST_DEBUG_OBJECT (playsink, "adding text chain");
1297 add_chain (GST_PLAY_CHAIN (playsink->textchain), TRUE);
1298 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->text_pad),
1299 playsink->textchain->textsinkpad);
1300 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad),
1301 playsink->textchain->videosinkpad);
1302 gst_pad_link (playsink->textchain->srcpad, playsink->videochain->sinkpad);
1303 activate_chain (GST_PLAY_CHAIN (playsink->textchain), TRUE);
1306 GST_DEBUG_OBJECT (playsink, "no text needed");
1307 /* we have no subtitles/text or we are requested to not show them */
1308 if (playsink->textchain) {
1309 GST_DEBUG_OBJECT (playsink, "removing text chain");
1310 add_chain (GST_PLAY_CHAIN (playsink->textchain), FALSE);
1311 activate_chain (GST_PLAY_CHAIN (playsink->textchain), FALSE);
1313 if (!need_video && playsink->video_pad)
1314 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), NULL);
1315 if (playsink->text_pad)
1316 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->text_pad), NULL);
1320 gboolean create_chain = FALSE;
1321 gboolean raw, queue;
1323 GST_DEBUG_OBJECT (playsink, "adding audio");
1325 /* get a raw sink if we are asked for a raw pad */
1326 raw = playsink->audio_pad_raw;
1327 if (need_vis && playsink->videochain) {
1328 /* If we are dealing with visualisations, we need to add a queue to
1329 * decouple the audio from the video part. We only have to do this when
1330 * the video part is async=true */
1331 queue = ((GstPlayVideoChain *) playsink->videochain)->async;
1332 GST_DEBUG_OBJECT (playsink, "need audio queue for vis: %d", queue);
1334 /* no vis, we can avoid a queue */
1335 GST_DEBUG_OBJECT (playsink, "don't need audio queue");
1339 if (!playsink->audiochain) {
1340 /* create chain if we don't already have one */
1341 create_chain = TRUE;
1343 /* we have a chain, check if it's also raw */
1344 if (playsink->audiochain->chain.raw != raw) {
1345 GST_DEBUG_OBJECT (playsink, "removing current audio chain");
1346 gst_pad_unlink (playsink->audio_tee_asrc,
1347 playsink->audiochain->sinkpad);
1348 add_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
1349 activate_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
1350 create_chain = TRUE;
1355 GST_DEBUG_OBJECT (playsink, "creating new audio chain");
1356 playsink->audiochain = gen_audio_chain (playsink, raw, queue);
1359 if (playsink->audiochain) {
1360 GST_DEBUG_OBJECT (playsink, "adding audio chain");
1361 add_chain (GST_PLAY_CHAIN (playsink->audiochain), TRUE);
1362 gst_pad_link (playsink->audio_tee_asrc, playsink->audiochain->sinkpad);
1363 activate_chain (GST_PLAY_CHAIN (playsink->audiochain), TRUE);
1366 GST_DEBUG_OBJECT (playsink, "no audio needed");
1367 /* we have no audio or we are requested to not play audio */
1368 if (playsink->audiochain) {
1369 GST_DEBUG_OBJECT (playsink, "removing audio chain");
1370 gst_pad_unlink (playsink->audio_tee_asrc, playsink->audiochain->sinkpad);
1371 add_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
1372 activate_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
1379 if (!playsink->vischain)
1380 playsink->vischain = gen_vis_chain (playsink);
1382 GST_DEBUG_OBJECT (playsink, "adding visualisation");
1384 if (playsink->vischain) {
1385 GST_DEBUG_OBJECT (playsink, "setting up vis chain");
1387 gst_element_get_static_pad (GST_ELEMENT_CAST (playsink->vischain->
1389 add_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE);
1390 gst_pad_link (playsink->audio_tee_vissrc, playsink->vischain->sinkpad);
1391 gst_pad_link (srcpad, playsink->videochain->sinkpad);
1392 gst_object_unref (srcpad);
1393 activate_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE);
1396 GST_DEBUG_OBJECT (playsink, "no vis needed");
1397 if (playsink->vischain) {
1398 GST_DEBUG_OBJECT (playsink, "removing vis chain");
1399 add_chain (GST_PLAY_CHAIN (playsink->vischain), FALSE);
1400 activate_chain (GST_PLAY_CHAIN (playsink->vischain), FALSE);
1403 GST_PLAY_SINK_UNLOCK (playsink);
1410 GST_ELEMENT_ERROR (playsink, STREAM, FORMAT,
1411 (_("Can't play a text file without video.")),
1412 ("Have text pad but no video pad"));
1413 GST_PLAY_SINK_UNLOCK (playsink);
1419 * gst_play_sink_set_flags:
1420 * @playsink: a #GstPlaySink
1421 * @flags: #GstPlayFlags
1423 * Configure @flags on @playsink. The flags control the behaviour of @playsink
1424 * when constructing the sink pipelins.
1426 * Returns: TRUE if the flags could be configured.
1429 gst_play_sink_set_flags (GstPlaySink * playsink, GstPlayFlags flags)
1431 g_return_val_if_fail (GST_IS_PLAY_SINK (playsink), FALSE);
1433 GST_OBJECT_LOCK (playsink);
1434 playsink->flags = flags;
1435 GST_OBJECT_UNLOCK (playsink);
1441 * gst_play_sink_get_flags:
1442 * @playsink: a #GstPlaySink
1444 * Get the flags of @playsink. That flags control the behaviour of the sink when
1445 * it constructs the sink pipelines.
1447 * Returns: the currently configured #GstPlayFlags.
1450 gst_play_sink_get_flags (GstPlaySink * playsink)
1454 g_return_val_if_fail (GST_IS_PLAY_SINK (playsink), 0);
1456 GST_OBJECT_LOCK (playsink);
1457 res = playsink->flags;
1458 GST_OBJECT_UNLOCK (playsink);
1464 gst_play_sink_set_font_desc (GstPlaySink * playsink, const gchar * desc)
1466 GstPlayTextChain *chain;
1468 GST_PLAY_SINK_LOCK (playsink);
1469 chain = (GstPlayTextChain *) playsink->textchain;
1470 g_free (playsink->font_desc);
1471 playsink->font_desc = g_strdup (desc);
1472 if (chain && chain->overlay) {
1473 g_object_set (chain->overlay, "font-desc", desc, NULL);
1475 GST_PLAY_SINK_UNLOCK (playsink);
1479 gst_play_sink_get_font_desc (GstPlaySink * playsink)
1481 gchar *result = NULL;
1482 GstPlayTextChain *chain;
1484 GST_PLAY_SINK_LOCK (playsink);
1485 chain = (GstPlayTextChain *) playsink->textchain;
1486 if (chain && chain->overlay) {
1487 g_object_get (chain->overlay, "font-desc", &result, NULL);
1488 playsink->font_desc = g_strdup (result);
1490 result = g_strdup (playsink->font_desc);
1492 GST_PLAY_SINK_UNLOCK (playsink);
1498 * gst_play_sink_get_last_frame:
1499 * @playsink: a #GstPlaySink
1501 * Get the last displayed frame from @playsink. This frame is in the native
1502 * format of the sink element, the caps on the result buffer contain the format
1503 * of the frame data.
1505 * Returns: a #GstBuffer with the frame data or %NULL when no video frame is
1509 gst_play_sink_get_last_frame (GstPlaySink * playsink)
1511 GstBuffer *result = NULL;
1512 GstPlayVideoChain *chain;
1514 GST_PLAY_SINK_LOCK (playsink);
1515 GST_DEBUG_OBJECT (playsink, "taking last frame");
1516 /* get the video chain if we can */
1517 if ((chain = (GstPlayVideoChain *) playsink->videochain)) {
1518 GST_DEBUG_OBJECT (playsink, "found video chain");
1519 /* see if the chain is active */
1520 if (chain->chain.activated && chain->sink) {
1523 GST_DEBUG_OBJECT (playsink, "video chain active and has a sink");
1525 /* find and get the last-buffer property now */
1527 gst_play_sink_find_property (playsink, chain->sink,
1529 GST_DEBUG_OBJECT (playsink, "getting last-buffer property");
1530 g_object_get (elem, "last-buffer", &result, NULL);
1531 gst_object_unref (elem);
1535 GST_PLAY_SINK_UNLOCK (playsink);
1541 * gst_play_sink_request_pad
1542 * @playsink: a #GstPlaySink
1543 * @type: a #GstPlaySinkType
1545 * Create or return a pad of @type.
1547 * Returns: a #GstPad of @type or %NULL when the pad could not be created.
1550 gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
1553 gboolean created = FALSE;
1554 gboolean raw = FALSE;
1556 GST_DEBUG_OBJECT (playsink, "request pad type %d", type);
1558 GST_PLAY_SINK_LOCK (playsink);
1560 case GST_PLAY_SINK_TYPE_AUDIO_RAW:
1562 case GST_PLAY_SINK_TYPE_AUDIO:
1563 if (!playsink->audio_tee) {
1564 GST_LOG_OBJECT (playsink, "creating tee");
1565 /* create tee when needed. This element will feed the audio sink chain
1566 * and the vis chain. */
1567 playsink->audio_tee = gst_element_factory_make ("tee", "audiotee");
1568 playsink->audio_tee_sink =
1569 gst_element_get_static_pad (playsink->audio_tee, "sink");
1570 /* get two request pads */
1571 playsink->audio_tee_vissrc =
1572 gst_element_get_request_pad (playsink->audio_tee, "src%d");
1573 playsink->audio_tee_asrc =
1574 gst_element_get_request_pad (playsink->audio_tee, "src%d");
1575 gst_bin_add (GST_BIN_CAST (playsink), playsink->audio_tee);
1576 gst_element_set_state (playsink->audio_tee, GST_STATE_PAUSED);
1578 if (!playsink->audio_pad) {
1579 GST_LOG_OBJECT (playsink, "ghosting tee sinkpad");
1580 playsink->audio_pad =
1581 gst_ghost_pad_new ("audio_sink", playsink->audio_tee_sink);
1584 playsink->audio_pad_raw = raw;
1585 res = playsink->audio_pad;
1587 case GST_PLAY_SINK_TYPE_VIDEO_RAW:
1589 case GST_PLAY_SINK_TYPE_VIDEO:
1590 if (!playsink->video_pad) {
1591 GST_LOG_OBJECT (playsink, "ghosting videosink");
1592 playsink->video_pad =
1593 gst_ghost_pad_new_no_target ("video_sink", GST_PAD_SINK);
1596 playsink->video_pad_raw = raw;
1597 res = playsink->video_pad;
1599 case GST_PLAY_SINK_TYPE_TEXT:
1600 GST_LOG_OBJECT (playsink, "ghosting text");
1601 if (!playsink->text_pad) {
1602 playsink->text_pad =
1603 gst_ghost_pad_new_no_target ("text_sink", GST_PAD_SINK);
1606 res = playsink->text_pad;
1612 GST_PLAY_SINK_UNLOCK (playsink);
1614 if (created && res) {
1615 gst_pad_set_active (res, TRUE);
1616 gst_element_add_pad (GST_ELEMENT_CAST (playsink), res);
1623 gst_play_sink_release_pad (GstPlaySink * playsink, GstPad * pad)
1625 GstPad **res = NULL;
1627 GST_DEBUG_OBJECT (playsink, "release pad %" GST_PTR_FORMAT, pad);
1629 GST_PLAY_SINK_LOCK (playsink);
1630 if (pad == playsink->video_pad) {
1631 res = &playsink->video_pad;
1632 } else if (pad == playsink->audio_pad) {
1633 res = &playsink->audio_pad;
1634 } else if (pad == playsink->text_pad) {
1635 res = &playsink->text_pad;
1637 GST_PLAY_SINK_UNLOCK (playsink);
1640 GST_DEBUG_OBJECT (playsink, "deactivate pad %" GST_PTR_FORMAT, *res);
1641 gst_pad_set_active (*res, FALSE);
1642 GST_DEBUG_OBJECT (playsink, "remove pad %" GST_PTR_FORMAT, *res);
1643 gst_element_remove_pad (GST_ELEMENT_CAST (playsink), *res);
1648 /* Send an event to our sinks until one of them works; don't then send to the
1649 * remaining sinks (unlike GstBin)
1652 gst_play_sink_send_event_to_sink (GstPlaySink * playsink, GstEvent * event)
1654 gboolean res = TRUE;
1656 if (playsink->videochain) {
1657 gst_event_ref (event);
1658 if ((res = gst_element_send_event (playsink->videochain->chain.bin, event))) {
1659 GST_DEBUG_OBJECT (playsink, "Sent event succesfully to video sink");
1662 GST_DEBUG_OBJECT (playsink, "Event failed when sent to video sink");
1664 if (playsink->audiochain) {
1665 gst_event_ref (event);
1666 if ((res = gst_element_send_event (playsink->audiochain->chain.bin, event))) {
1667 GST_DEBUG_OBJECT (playsink, "Sent event succesfully to audio sink");
1670 GST_DEBUG_OBJECT (playsink, "Event failed when sent to audio sink");
1673 gst_event_unref (event);
1677 /* We only want to send the event to a single sink (overriding GstBin's
1678 * behaviour), but we want to keep GstPipeline's behaviour - wrapping seek
1679 * events appropriately. So, this is a messy duplication of code. */
1681 gst_play_sink_send_event (GstElement * element, GstEvent * event)
1683 gboolean res = FALSE;
1684 GstEventType event_type = GST_EVENT_TYPE (event);
1686 switch (event_type) {
1687 case GST_EVENT_SEEK:
1688 GST_DEBUG_OBJECT (element, "Sending seek event to a sink");
1689 res = gst_play_sink_send_event_to_sink (GST_PLAY_SINK (element), event);
1693 GST_ELEMENT_CLASS (gst_play_sink_parent_class)->send_event (element,
1700 static GstStateChangeReturn
1701 gst_play_sink_change_state (GstElement * element, GstStateChange transition)
1703 GstStateChangeReturn ret;
1704 GstPlaySink *playsink;
1706 playsink = GST_PLAY_SINK (element);
1708 switch (transition) {
1709 case GST_STATE_CHANGE_READY_TO_PAUSED:
1716 GST_ELEMENT_CLASS (gst_play_sink_parent_class)->change_state (element,
1718 if (ret == GST_STATE_CHANGE_FAILURE)
1721 switch (transition) {
1722 case GST_STATE_CHANGE_READY_TO_PAUSED:
1724 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1725 /* FIXME Release audio device when we implement that */
1727 case GST_STATE_CHANGE_PAUSED_TO_READY:
1728 /* remove sinks we added */
1729 if (playsink->videochain) {
1730 activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
1731 add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
1733 if (playsink->audiochain) {
1734 activate_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
1735 add_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);