2 * Copyright (C) 2003 Julien Moutte <julien@moutte.net>
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.
34 struct _GstPlayPrivate {
42 gint get_length_attempt;
48 static guint gst_play_signals[LAST_SIGNAL] = { 0 };
50 static GstPipelineClass *parent_class = NULL;
52 /* ======================================================= */
56 /* ======================================================= */
59 gst_play_pipeline_setup (GstPlay *play)
61 GstElement *work_thread, *video_thread;
62 GstElement *source, *autoplugger, *video_switch;
63 GstElement *video_queue, *video_colorspace, *video_scaler, *video_sink;
64 GstElement *audio_thread, *audio_queue, *audio_volume, *audio_sink;
65 GstElement *audio_tee, *vis_thread, *vis_queue, *vis_element;
66 GstPad *audio_tee_pad1, *audio_tee_pad2, *vis_thread_pad, *audio_sink_pad;
68 g_return_val_if_fail (play != NULL, FALSE);
69 g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
71 work_thread = gst_element_factory_make ("thread", "work_thread");
72 if (!GST_IS_ELEMENT (work_thread))
75 g_hash_table_insert (play->priv->elements, "work_thread", work_thread);
76 gst_bin_add (GST_BIN (play), work_thread);
78 /* Placeholder for the source and autoplugger { fakesrc ! spider } */
79 source = gst_element_factory_make ("fakesrc", "source");
80 if (!GST_IS_ELEMENT (source))
83 g_hash_table_insert (play->priv->elements, "source", source);
85 autoplugger = gst_element_factory_make ("spider", "autoplugger");
86 if (!GST_IS_ELEMENT (autoplugger))
89 g_hash_table_insert (play->priv->elements, "autoplugger", autoplugger);
91 gst_bin_add_many (GST_BIN (work_thread), source, autoplugger, NULL);
92 gst_element_link (source, autoplugger);
94 /* Creating our video output bin
95 { queue ! colorspace ! videoscale ! fakesink } */
96 video_thread = gst_element_factory_make ("thread", "video_thread");
97 if (!GST_IS_ELEMENT (video_thread))
100 g_hash_table_insert (play->priv->elements, "video_thread", video_thread);
101 gst_bin_add (GST_BIN (work_thread), video_thread);
103 /* Buffer queue for our video thread */
104 video_queue = gst_element_factory_make ("queue", "video_queue");
105 if (!GST_IS_ELEMENT (video_queue))
108 g_hash_table_insert (play->priv->elements, "video_queue", video_queue);
110 /* Colorspace conversion */
111 video_colorspace = gst_element_factory_make ("ffcolorspace",
113 if (!GST_IS_ELEMENT (video_colorspace)) {
114 video_colorspace = gst_element_factory_make ("colorspace",
116 if (!GST_IS_ELEMENT (video_colorspace))
120 g_hash_table_insert (play->priv->elements, "video_colorspace",
123 /* Software scaling of video stream */
124 video_scaler = gst_element_factory_make ("videoscale", "video_scaler");
125 if (!GST_IS_ELEMENT (video_scaler))
128 g_hash_table_insert (play->priv->elements, "video_scaler", video_scaler);
130 /* Placeholder for future video sink bin */
131 video_sink = gst_element_factory_make ("fakesink", "video_sink");
132 if (!GST_IS_ELEMENT (video_sink))
135 g_hash_table_insert (play->priv->elements, "video_sink", video_sink);
137 /* Linking, Adding, Ghosting */
138 gst_element_link_many (video_queue, video_colorspace,
139 video_scaler, video_sink, NULL);
140 gst_bin_add_many (GST_BIN (video_thread), video_queue, video_colorspace,
141 video_scaler, video_sink, NULL);
142 gst_element_add_ghost_pad (video_thread,
143 gst_element_get_pad (video_queue, "sink"),
146 video_switch = gst_element_factory_make ("switch",
148 if (!GST_IS_ELEMENT (video_switch))
151 g_hash_table_insert (play->priv->elements, "video_switch", video_switch);
153 /*gst_bin_add (GST_BIN (work_thread), video_switch);*/
155 /* Connecting autoplugger to video switch and video switch to video output
156 gst_element_link (autoplugger, video_switch);
157 gst_element_link (video_switch, video_thread);*/
158 gst_element_link (autoplugger, video_thread);
160 /* Creating our audio output bin
161 { queue ! volume ! tee ! { queue ! goom } ! fakesink } */
162 audio_thread = gst_element_factory_make ("thread", "audio_thread");
163 if (!GST_IS_ELEMENT (audio_thread))
166 g_hash_table_insert (play->priv->elements, "audio_thread", audio_thread);
167 gst_bin_add (GST_BIN (work_thread), audio_thread);
169 /* Buffer queue for our audio thread */
170 audio_queue = gst_element_factory_make ("queue", "audio_queue");
171 if (!GST_IS_ELEMENT (audio_queue))
174 g_hash_table_insert (play->priv->elements, "audio_queue", audio_queue);
177 audio_volume = gst_element_factory_make ("volume", "audio_volume");
178 if (!GST_IS_ELEMENT (audio_volume))
181 g_hash_table_insert (play->priv->elements, "audio_volume", audio_volume);
183 /* Duplicate audio signal to sink and visualization thread */
184 audio_tee = gst_element_factory_make ("tee", "audio_tee");
185 if (!GST_IS_ELEMENT (audio_tee))
188 audio_tee_pad1 = gst_element_get_request_pad (audio_tee, "src%d");
189 audio_tee_pad2 = gst_element_get_request_pad (audio_tee, "src%d");
190 g_hash_table_insert (play->priv->elements, "audio_tee_pad1",
192 g_hash_table_insert (play->priv->elements, "audio_tee_pad2",
194 g_hash_table_insert (play->priv->elements, "audio_tee", audio_tee);
196 /* Placeholder for future audio sink bin */
197 audio_sink = gst_element_factory_make ("fakesink", "audio_sink");
198 if (!GST_IS_ELEMENT (audio_sink))
201 audio_sink_pad = gst_element_get_pad (audio_sink, "sink");
202 g_hash_table_insert (play->priv->elements, "audio_sink_pad",
204 g_hash_table_insert (play->priv->elements, "audio_sink", audio_sink);
206 /* Visualization thread */
207 vis_thread = gst_element_factory_make ("thread", "vis_thread");
208 if (!GST_IS_ELEMENT (vis_thread))
211 g_hash_table_insert (play->priv->elements, "vis_thread", vis_thread);
213 /* Buffer queue for our visualization thread */
214 vis_queue = gst_element_factory_make ("queue", "vis_queue");
215 if (!GST_IS_ELEMENT (vis_queue))
218 g_hash_table_insert (play->priv->elements, "vis_queue", vis_queue);
220 vis_element = gst_element_factory_make ("identity", "vis_element");
221 if (!GST_IS_ELEMENT (vis_element))
224 g_hash_table_insert (play->priv->elements, "vis_element", vis_element);
226 /* Adding, Linking, Ghosting in visualization */
227 gst_bin_add_many (GST_BIN (vis_thread), vis_queue, vis_element, NULL);
228 gst_element_link (vis_queue, vis_element);
229 vis_thread_pad = gst_element_add_ghost_pad (vis_thread,
230 gst_element_get_pad (vis_queue, "sink"),
232 g_hash_table_insert (play->priv->elements, "vis_thread_pad",
236 /* Linking, Adding, Ghosting in audio */
237 gst_element_link_many (audio_queue, audio_volume, audio_tee, NULL);
238 gst_pad_link (audio_tee_pad1, audio_sink_pad);
239 gst_bin_add_many (GST_BIN (audio_thread), audio_queue, audio_volume,
240 audio_tee, vis_thread, audio_sink, NULL);
241 gst_element_add_ghost_pad (audio_thread,
242 gst_element_get_pad (audio_queue, "sink"),
245 /* Connecting audio output to autoplugger */
246 gst_element_link (autoplugger, audio_thread);
252 gst_play_have_video_size (GstElement *element, gint width,
253 gint height, GstPlay *play)
255 g_return_if_fail (play != NULL);
256 g_return_if_fail (GST_IS_PLAY (play));
257 g_signal_emit (G_OBJECT (play), gst_play_signals[HAVE_VIDEO_SIZE],
262 gst_play_tick_callback (GstPlay *play)
264 GstClock *clock = NULL;
266 g_return_val_if_fail (play != NULL, FALSE);
268 if (!GST_IS_PLAY (play)) {
269 play->priv->tick_id = 0;
273 clock = gst_bin_get_clock (GST_BIN (play));
274 play->priv->time_nanos = gst_clock_get_time (clock);
276 g_signal_emit (G_OBJECT (play), gst_play_signals[TIME_TICK],
277 0,play->priv->time_nanos);
279 if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING)
282 play->priv->tick_id = 0;
288 gst_play_get_length_callback (GstPlay *play)
290 GstElement *audio_sink_element, *video_sink_element;
291 GstFormat format = GST_FORMAT_TIME;
295 g_return_val_if_fail (play != NULL, FALSE);
296 g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
298 /* We try to get length from all real sink elements */
299 audio_sink_element = g_hash_table_lookup (play->priv->elements,
300 "audio_sink_element");
301 video_sink_element = g_hash_table_lookup (play->priv->elements,
302 "video_sink_element");
303 if (!GST_IS_ELEMENT (audio_sink_element) &&
304 !GST_IS_ELEMENT (video_sink_element)) {
305 play->priv->length_id = 0;
309 /* Audio first and then Video */
310 if (GST_IS_ELEMENT (audio_sink_element))
311 q = gst_element_query (audio_sink_element, GST_QUERY_TOTAL, &format,
313 if ( (!q) && (GST_IS_ELEMENT (video_sink_element)) )
314 q = gst_element_query (video_sink_element, GST_QUERY_TOTAL, &format,
318 play->priv->length_nanos = value;
319 g_signal_emit (G_OBJECT (play), gst_play_signals[STREAM_LENGTH],
320 0,play->priv->length_nanos);
321 play->priv->length_id = 0;
325 play->priv->get_length_attempt++;
327 /* We try 16 times */
328 if (play->priv->get_length_attempt > 15) {
329 play->priv->length_id = 0;
337 gst_play_state_change (GstElement *element, GstElementState old,
338 GstElementState state)
342 g_return_if_fail (element != NULL);
343 g_return_if_fail (GST_IS_PLAY (element));
345 play = GST_PLAY (element);
347 if (state == GST_STATE_PLAYING) {
348 if (play->priv->tick_id) {
349 g_source_remove (play->priv->tick_id);
350 play->priv->tick_id = 0;
353 play->priv->tick_id = g_timeout_add (200,
354 (GSourceFunc) gst_play_tick_callback,
357 play->priv->get_length_attempt = 0;
359 if (play->priv->length_id) {
360 g_source_remove (play->priv->length_id);
361 play->priv->length_id = 0;
364 play->priv->length_id = g_timeout_add (200,
365 (GSourceFunc) gst_play_get_length_callback,
369 if (GST_ELEMENT_CLASS (parent_class)->state_change)
370 GST_ELEMENT_CLASS (parent_class)->state_change (element, old, state);
373 /* =========================================== */
375 /* Init & Dispose & Class init */
377 /* =========================================== */
380 gst_play_dispose (GObject *object)
384 g_return_if_fail (object != NULL);
385 g_return_if_fail (GST_IS_PLAY (object));
387 play = GST_PLAY (object);
389 if (play->priv->length_id) {
390 g_source_remove (play->priv->length_id);
391 play->priv->length_id = 0;
394 if (play->priv->tick_id) {
395 g_source_remove (play->priv->tick_id);
396 play->priv->tick_id = 0;
399 if (play->priv->location) {
400 g_free (play->priv->location);
401 play->priv->location = NULL;
404 if (play->priv->elements) {
405 g_hash_table_destroy (play->priv->elements);
406 play->priv->elements = NULL;
409 G_OBJECT_CLASS (parent_class)->dispose (object);
413 gst_play_init (GstPlay *play)
415 play->priv = g_new0 (GstPlayPrivate, 1);
416 play->priv->location = NULL;
417 play->priv->length_nanos = 0;
418 play->priv->time_nanos = 0;
419 play->priv->elements = g_hash_table_new (g_str_hash, g_str_equal);
421 if (!gst_play_pipeline_setup (play))
422 g_warning ("libgstplay: failed initializing pipeline");
426 gst_play_class_init (GstPlayClass *klass)
428 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
429 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
431 parent_class = g_type_class_peek_parent (klass);
433 gobject_class->dispose = gst_play_dispose;
435 element_class->state_change = gst_play_state_change;
437 gst_play_signals[TIME_TICK] =
438 g_signal_new ("time_tick", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
439 G_STRUCT_OFFSET (GstPlayClass, time_tick), NULL, NULL,
440 gst_marshal_VOID__INT64, G_TYPE_NONE, 1, G_TYPE_INT64);
441 gst_play_signals[STREAM_LENGTH] =
442 g_signal_new ("stream_length", G_TYPE_FROM_CLASS (klass),
444 G_STRUCT_OFFSET (GstPlayClass, stream_length), NULL, NULL,
445 gst_marshal_VOID__INT64, G_TYPE_NONE, 1, G_TYPE_INT64);
446 gst_play_signals[HAVE_VIDEO_SIZE] =
447 g_signal_new ("have_video_size", G_TYPE_FROM_CLASS (klass),
449 G_STRUCT_OFFSET (GstPlayClass, have_video_size), NULL, NULL,
450 gst_marshal_VOID__INT_INT, G_TYPE_NONE, 2,
451 G_TYPE_INT, G_TYPE_INT);
454 /* ======================================================= */
458 /* ======================================================= */
461 * gst_play_set_location:
463 * @location: a const #char* indicating location to play
465 * Set location of @play to @location.
467 * Returns: TRUE if location was set successfully.
470 gst_play_set_location (GstPlay *play, const char *location)
472 GstElement *work_thread, *source, *autoplugger, *video_thread, *audio_thread;
474 g_return_val_if_fail (play != NULL, FALSE);
475 g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
477 if (play->priv->location)
478 g_free (play->priv->location);
480 play->priv->location = g_strdup (location);
482 if (GST_STATE (GST_ELEMENT (play)) != GST_STATE_READY)
483 gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY);
485 work_thread = g_hash_table_lookup (play->priv->elements, "work_thread");
486 if (!GST_IS_ELEMENT (work_thread))
488 video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
489 if (!GST_IS_ELEMENT (video_thread))
491 audio_thread = g_hash_table_lookup (play->priv->elements, "audio_thread");
492 if (!GST_IS_ELEMENT (audio_thread))
494 source = g_hash_table_lookup (play->priv->elements, "source");
495 if (!GST_IS_ELEMENT (source))
497 autoplugger = g_hash_table_lookup (play->priv->elements, "autoplugger");
498 if (!GST_IS_ELEMENT (autoplugger))
501 /* Spider can autoplugg only once. We remove the actual one and put a new
503 gst_element_unlink (source, autoplugger);
504 gst_element_unlink (autoplugger, video_thread);
505 gst_element_unlink (autoplugger, audio_thread);
506 gst_bin_remove (GST_BIN (work_thread), autoplugger);
508 autoplugger = gst_element_factory_make ("spider", "autoplugger");
509 if (!GST_IS_ELEMENT (autoplugger))
512 gst_bin_add (GST_BIN (work_thread), autoplugger);
513 gst_element_link (source, autoplugger);
514 gst_element_link (autoplugger, video_thread);
515 gst_element_link (autoplugger, audio_thread);
517 g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger);
519 /* FIXME: Why don't we have an interface to do that kind of stuff ? */
520 g_object_set (G_OBJECT (source), "location", play->priv->location, NULL);
522 play->priv->length_nanos = 0LL;
523 play->priv->time_nanos = 0LL;
525 g_signal_emit (G_OBJECT (play), gst_play_signals[STREAM_LENGTH], 0, 0LL);
526 g_signal_emit (G_OBJECT (play), gst_play_signals[TIME_TICK], 0, 0LL);
532 * gst_play_get_location:
535 * Get current location of @play.
537 * Returns: a const #char* pointer to current location.
540 gst_play_get_location (GstPlay *play)
542 g_return_val_if_fail (play != NULL, NULL);
543 g_return_val_if_fail (GST_IS_PLAY (play), NULL);
544 return g_strdup (play->priv->location);
548 * gst_play_seek_to_time:
550 * @time_nanos: a #gint64 indicating a time position.
552 * Performs a seek on @play until @time_nanos.
555 gst_play_seek_to_time (GstPlay * play, gint64 time_nanos)
557 GstElement *audio_sink_element, *video_sink_element;
559 g_return_val_if_fail (play != NULL, FALSE);
560 g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
562 if (time_nanos < 0LL)
565 audio_sink_element = g_hash_table_lookup (play->priv->elements,
566 "audio_sink_element");
567 video_sink_element = g_hash_table_lookup (play->priv->elements,
568 "video_sink_element");
570 if (GST_IS_ELEMENT (audio_sink_element) &&
571 GST_IS_ELEMENT (video_sink_element)) {
574 s = gst_element_seek (audio_sink_element, GST_FORMAT_TIME |
575 GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH,
578 s = gst_element_seek (video_sink_element, GST_FORMAT_TIME |
579 GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH,
584 GstClock *clock = gst_bin_get_clock (GST_BIN (play));
585 play->priv->time_nanos = gst_clock_get_time (clock);
586 g_signal_emit (G_OBJECT (play), gst_play_signals[TIME_TICK],
587 0,play->priv->time_nanos);
595 * gst_play_set_data_src:
597 * @data_src: a #GstElement.
599 * Set @data_src as the source element of @play.
601 * Returns: TRUE if call succeeded.
604 gst_play_set_data_src (GstPlay *play, GstElement *data_src)
606 GstElement *work_thread, *old_data_src, *autoplugger;
608 g_return_val_if_fail (play != NULL, FALSE);
609 g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
611 /* We bring back the pipeline to READY */
612 if (GST_STATE (GST_ELEMENT (play)) != GST_STATE_READY)
613 gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY);
615 /* Getting needed objects */
616 work_thread = g_hash_table_lookup (play->priv->elements, "work_thread");
617 if (!GST_IS_ELEMENT (work_thread))
619 old_data_src = g_hash_table_lookup (play->priv->elements, "source");
620 if (!GST_IS_ELEMENT (old_data_src))
622 autoplugger = g_hash_table_lookup (play->priv->elements, "autoplugger");
623 if (!GST_IS_ELEMENT (autoplugger))
626 /* Unlinking old source from autoplugger, removing it from pipeline, adding
627 the new one and connecting it to autoplugger FIXME: we should put a new
628 autoplugger here as spider can autoplugg only once */
629 gst_element_unlink (old_data_src, autoplugger);
630 gst_bin_remove (GST_BIN (work_thread), old_data_src);
631 gst_bin_add (GST_BIN (work_thread), data_src);
632 gst_element_link (data_src, autoplugger);
634 g_hash_table_replace (play->priv->elements, "source", data_src);
640 * gst_play_set_video_sink:
642 * @video_sink: a #GstElement.
644 * Set @video_sink as the video sink element of @play.
646 * Returns: TRUE if call succeeded.
649 gst_play_set_video_sink (GstPlay *play, GstElement *video_sink)
651 GstElement *video_thread, *old_video_sink, *video_scaler, *video_sink_element;
653 g_return_val_if_fail (play != NULL, FALSE);
654 g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
655 g_return_val_if_fail (video_sink != NULL, FALSE);
656 g_return_val_if_fail (GST_IS_ELEMENT (video_sink), FALSE);
658 /* We bring back the pipeline to READY */
659 if (GST_STATE (GST_ELEMENT (play)) != GST_STATE_READY)
660 gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY);
662 /* Getting needed objects */
663 video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
664 if (!GST_IS_ELEMENT (video_thread))
666 old_video_sink = g_hash_table_lookup (play->priv->elements, "video_sink");
667 if (!GST_IS_ELEMENT (old_video_sink))
669 video_scaler = g_hash_table_lookup (play->priv->elements, "video_scaler");
670 if (!GST_IS_ELEMENT (video_scaler))
673 /* Unlinking old video sink from video scaler, removing it from pipeline,
674 adding the new one and linking it */
675 gst_element_unlink (video_scaler, old_video_sink);
676 gst_bin_remove (GST_BIN (video_thread), old_video_sink);
677 gst_bin_add (GST_BIN (video_thread), video_sink);
678 gst_element_link (video_scaler, video_sink);
680 g_hash_table_replace (play->priv->elements, "video_sink", video_sink);
682 video_sink_element = gst_play_get_sink_element (play, video_sink,
683 GST_PLAY_SINK_TYPE_VIDEO);
684 if (GST_IS_ELEMENT (video_sink_element)) {
685 g_hash_table_replace (play->priv->elements, "video_sink_element",
687 g_signal_connect (G_OBJECT (video_sink_element), "have_video_size",
688 G_CALLBACK (gst_play_have_video_size), play);
691 gst_element_set_state (video_sink, GST_STATE (GST_ELEMENT(play)));
697 * gst_play_set_audio_sink:
699 * @audio_sink: a #GstElement.
701 * Set @audio_sink as the audio sink element of @play.
703 * Returns: TRUE if call succeeded.
706 gst_play_set_audio_sink (GstPlay *play, GstElement *audio_sink)
708 GstElement *old_audio_sink, *audio_thread, *audio_sink_element;
709 GstPad *audio_tee_pad1, *audio_sink_pad, *old_audio_sink_pad;
711 g_return_val_if_fail (play != NULL, FALSE);
712 g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
713 g_return_val_if_fail (audio_sink != NULL, FALSE);
714 g_return_val_if_fail (GST_IS_ELEMENT (audio_sink), FALSE);
716 /* We bring back the pipeline to READY */
717 if (GST_STATE (GST_ELEMENT (play)) != GST_STATE_READY)
718 gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY);
720 /* Getting needed objects */
721 old_audio_sink = g_hash_table_lookup (play->priv->elements, "audio_sink");
722 if (!GST_IS_ELEMENT (old_audio_sink))
724 old_audio_sink_pad = g_hash_table_lookup (play->priv->elements,
726 if (!GST_IS_PAD (old_audio_sink_pad))
728 audio_thread = g_hash_table_lookup (play->priv->elements, "audio_thread");
729 if (!GST_IS_ELEMENT (audio_thread))
731 audio_tee_pad1 = g_hash_table_lookup (play->priv->elements,
733 if (!GST_IS_PAD (audio_tee_pad1))
735 audio_sink_pad = gst_element_get_pad (audio_sink, "sink");
736 if (!GST_IS_PAD (audio_sink_pad))
739 /* Unlinking old audiosink, removing it from pipeline, putting the new one
741 gst_pad_unlink (audio_tee_pad1, old_audio_sink_pad);
742 gst_bin_remove (GST_BIN (audio_thread), old_audio_sink);
743 gst_bin_add (GST_BIN (audio_thread), audio_sink);
744 gst_pad_link (audio_tee_pad1, audio_sink_pad);
746 g_hash_table_replace (play->priv->elements, "audio_sink", audio_sink);
747 g_hash_table_replace (play->priv->elements, "audio_sink_pad",
750 audio_sink_element = gst_play_get_sink_element (play, audio_sink,
751 GST_PLAY_SINK_TYPE_AUDIO);
752 if (GST_IS_ELEMENT (audio_sink_element)) {
753 g_hash_table_replace (play->priv->elements, "audio_sink_element",
757 gst_element_set_state (audio_sink, GST_STATE (GST_ELEMENT(play)));
763 * gst_play_set_visualization:
765 * @element: a #GstElement.
767 * Set @video_sink as the video sink element of @play.
769 * Returns: TRUE if call succeeded.
772 gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
774 GstElement *old_vis_element, *vis_thread, *vis_queue/*, *video_switch*/;
775 gboolean was_playing = FALSE;
777 g_return_val_if_fail (play != NULL, FALSE);
778 g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
779 g_return_val_if_fail (vis_element != NULL, FALSE);
780 g_return_val_if_fail (GST_IS_ELEMENT (vis_element), FALSE);
782 /* We bring back the pipeline to READY */
783 if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
784 gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
788 /* Getting needed objects */
789 vis_thread = g_hash_table_lookup (play->priv->elements, "vis_thread");
790 if (!GST_IS_ELEMENT (vis_thread))
792 old_vis_element = g_hash_table_lookup (play->priv->elements,
794 if (!GST_IS_ELEMENT (old_vis_element))
796 vis_queue = g_hash_table_lookup (play->priv->elements, "vis_queue");
797 if (!GST_IS_ELEMENT (vis_queue))
799 /*video_switch = g_hash_table_lookup (play->priv->elements, "video_switch");
800 if (!GST_IS_ELEMENT (video_switch))
803 /* Unlinking, removing the old element then adding and linking the new one */
804 gst_element_unlink (vis_queue, old_vis_element);
805 /*gst_element_unlink (old_vis_element, video_switch);*/
806 gst_bin_remove (GST_BIN (vis_thread), old_vis_element);
807 gst_bin_add (GST_BIN (vis_thread), vis_element);
808 gst_element_link (vis_queue, vis_element);
809 /*gst_element_link (vis_element, video_switch);*/
812 gst_element_set_state (GST_ELEMENT (play), GST_STATE_PLAYING);
818 * gst_play_connect_visualization:
820 * @connect: a #gboolean indicating wether or not
821 * visualization should be connected.
823 * Connect or disconnect visualization bin in @play.
825 * Returns: TRUE if call succeeded.
828 gst_play_connect_visualization (GstPlay * play, gboolean connect)
830 GstPad *audio_tee_pad2, *vis_thread_pad;
831 gboolean connected = FALSE, was_playing = FALSE;
833 g_return_val_if_fail (play != NULL, FALSE);
834 g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
836 vis_thread_pad = g_hash_table_lookup (play->priv->elements,
838 if (!GST_IS_PAD (vis_thread_pad))
840 audio_tee_pad2 = g_hash_table_lookup (play->priv->elements,
842 if (!GST_IS_PAD (audio_tee_pad2))
845 if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
846 gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
850 if (gst_pad_get_peer (vis_thread_pad) != NULL)
855 if ((connect) && (!connected))
856 gst_pad_link (audio_tee_pad2, vis_thread_pad);
857 else if ((!connect) && (connected))
858 gst_pad_unlink (audio_tee_pad2, vis_thread_pad);
861 gst_element_set_state (GST_ELEMENT (play), GST_STATE_PLAYING);
867 * gst_play_get_sink_element:
869 * @element: a #GstElement.
870 * @sink_type: a #GstPlaySinkType.
872 * Searches recursively for a sink #GstElement with
873 * type @sink_type in @element which is supposed to be a #GstBin.
875 * Returns: the sink #GstElement of @element.
878 gst_play_get_sink_element (GstPlay *play,
879 GstElement *element, GstPlaySinkType sink_type)
881 GList *elements = NULL;
882 const GList *pads = NULL;
883 gboolean has_src, has_correct_type;
885 g_return_val_if_fail (play != NULL, NULL);
886 g_return_val_if_fail (element != NULL, NULL);
887 g_return_val_if_fail (GST_IS_PLAY (play), NULL);
888 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
890 if (!GST_IS_BIN (element)) {
891 /* since its not a bin, we'll presume this
892 * element is a sink element */
896 elements = (GList *) gst_bin_get_list (GST_BIN (element));
898 /* traverse all elements looking for a src pad */
901 element = GST_ELEMENT (elements->data);
905 if (GST_IS_BIN (element)) {
906 element = gst_play_get_sink_element (play, element, sink_type);
907 if (GST_IS_ELEMENT (element))
911 pads = gst_element_get_pad_list (element);
913 has_correct_type = FALSE;
915 /* check for src pad */
916 if (GST_PAD_DIRECTION (GST_PAD (pads->data)) == GST_PAD_SRC) {
921 /* If not a src pad checking caps */
923 caps = gst_pad_get_caps (GST_PAD (pads->data));
925 gboolean has_video_cap = FALSE, has_audio_cap = FALSE;
926 if (g_ascii_strcasecmp (gst_caps_get_mime (caps),
927 "audio/x-raw-int") == 0) {
928 has_audio_cap = TRUE;
931 if ((g_ascii_strcasecmp (gst_caps_get_mime (caps),
932 "video/x-raw-yuv") == 0) ||
933 (g_ascii_strcasecmp (gst_caps_get_mime (caps),
934 "video/x-raw-rgb") == 0)) {
935 has_video_cap = TRUE;
939 case GST_PLAY_SINK_TYPE_AUDIO:
941 has_correct_type = TRUE;
943 case GST_PLAY_SINK_TYPE_VIDEO:
945 has_correct_type = TRUE;
947 case GST_PLAY_SINK_TYPE_ANY:
948 if ((has_video_cap) || (has_audio_cap))
949 has_correct_type = TRUE;
952 has_correct_type = FALSE;
959 pads = g_list_next (pads);
963 if ((!has_src) && (has_correct_type))
967 elements = g_list_next (elements);
970 /* we didn't find a sink element */
978 GstPlay *play = g_object_new (GST_TYPE_PLAY, NULL);
983 /* =========================================== */
985 /* Object typing & Creation */
987 /* =========================================== */
990 gst_play_get_type (void)
992 static GType play_type = 0;
995 static const GTypeInfo play_info = {
996 sizeof (GstPlayClass),
999 (GClassInitFunc) gst_play_class_init,
1004 (GInstanceInitFunc) gst_play_init,
1008 play_type = g_type_register_static (GST_TYPE_PIPELINE, "GstPlay",