3 * seek.c: seeking sample application
5 * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
6 * 2006 Stefan Kost <ensonic@users.sf.net>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
37 #include <gst/interfaces/xoverlay.h>
39 GST_DEBUG_CATEGORY_STATIC (seek_debug);
40 #define GST_CAT_DEFAULT (seek_debug)
44 //#define SOURCE "filesrc"
45 #define SOURCE "gnomevfssrc"
47 #define ASINK "alsasink"
48 //#define ASINK "osssink"
50 #define VSINK "xvimagesink"
51 //#define VSINK "sdlvideosink"
52 //#define VSINK "ximagesink"
53 //#define VSINK "aasink"
54 //#define VSINK "cacasink"
56 #define FILL_INTERVAL 100
57 //#define UPDATE_INTERVAL 500
58 //#define UPDATE_INTERVAL 100
59 #define UPDATE_INTERVAL 10
61 /* number of milliseconds to play for after a seek */
62 #define SCRUB_TIME 100
64 /* timeout for gst_element_get_state() after a seek */
65 #define SEEK_TIMEOUT 40 * GST_MSECOND
67 #define DEFAULT_VIDEO_HEIGHT 300
70 static GList *seekable_pads = NULL;
71 static GList *rate_pads = NULL;
72 static GList *seekable_elements = NULL;
74 static gboolean accurate_seek = FALSE;
75 static gboolean keyframe_seek = FALSE;
76 static gboolean loop_seek = FALSE;
77 static gboolean flush_seek = TRUE;
78 static gboolean scrub = TRUE;
79 static gboolean play_scrub = FALSE;
80 static gboolean skip_seek = FALSE;
81 static gdouble rate = 1.0;
83 static GstElement *pipeline;
84 static gint pipeline_type;
85 static const gchar *pipeline_spec;
86 static gint64 position = -1;
87 static gint64 duration = -1;
88 static GtkAdjustment *adjustment;
89 static GtkWidget *hscale, *statusbar;
90 static guint status_id = 0;
91 static gboolean stats = FALSE;
92 static gboolean elem_seek = FALSE;
93 static gboolean verbose = FALSE;
95 static gboolean is_live = FALSE;
96 static gboolean buffering = FALSE;
97 static GstBufferingMode mode;
98 static gint64 buffering_left;
99 static GstState state = GST_STATE_NULL;
100 static guint update_id = 0;
101 static guint seek_timeout_id = 0;
102 static gulong changed_id;
103 static guint fill_id = 0;
105 static gint n_video = 0, n_audio = 0, n_text = 0;
106 static gboolean need_streams = TRUE;
107 static GtkWidget *video_combo, *audio_combo, *text_combo, *vis_combo;
108 static GtkWidget *vis_checkbox, *video_checkbox, *audio_checkbox;
109 static GtkWidget *text_checkbox, *mute_checkbox, *volume_spinbutton;
110 static GtkWidget *skip_checkbox, *video_window;
112 GList *paths = NULL, *l = NULL;
114 /* we keep an array of the visualisation entries so that we can easily switch
115 * with the combo box index. */
118 GstElementFactory *factory;
121 static GArray *vis_entries;
123 static void clear_streams (GstElement * pipeline);
125 /* pipeline construction */
129 const gchar *padname;
136 gst_element_factory_make_or_warn (gchar * type, gchar * name)
138 GstElement *element = gst_element_factory_make (type, name);
141 g_warning ("Failed to create element %s of type %s", name, type);
148 dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer data)
151 dyn_link *connect = (dyn_link *) data;
153 padname = gst_pad_get_name (newpad);
155 if (connect->padname == NULL || !strcmp (padname, connect->padname)) {
157 gst_bin_add (GST_BIN (pipeline), connect->bin);
158 gst_pad_link (newpad, connect->target);
160 //seekable_pads = g_list_prepend (seekable_pads, newpad);
161 rate_pads = g_list_prepend (rate_pads, newpad);
167 setup_dynamic_link (GstElement * element, const gchar * padname,
168 GstPad * target, GstElement * bin)
172 connect = g_new0 (dyn_link, 1);
173 connect->padname = g_strdup (padname);
174 connect->target = target;
177 g_signal_connect (G_OBJECT (element), "pad-added", G_CALLBACK (dynamic_link),
182 make_mod_pipeline (const gchar * location)
184 GstElement *pipeline;
185 GstElement *src, *decoder, *audiosink;
188 pipeline = gst_pipeline_new ("app");
190 src = gst_element_factory_make_or_warn (SOURCE, "src");
191 decoder = gst_element_factory_make_or_warn ("modplug", "decoder");
192 audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
193 //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
195 g_object_set (G_OBJECT (src), "location", location, NULL);
197 gst_bin_add (GST_BIN (pipeline), src);
198 gst_bin_add (GST_BIN (pipeline), decoder);
199 gst_bin_add (GST_BIN (pipeline), audiosink);
201 gst_element_link (src, decoder);
202 gst_element_link (decoder, audiosink);
204 seekable = gst_element_get_static_pad (decoder, "src");
205 seekable_pads = g_list_prepend (seekable_pads, seekable);
206 rate_pads = g_list_prepend (rate_pads, seekable);
208 g_list_prepend (rate_pads, gst_element_get_static_pad (decoder, "sink"));
214 make_dv_pipeline (const gchar * location)
216 GstElement *pipeline;
217 GstElement *src, *demux, *decoder, *audiosink, *videosink;
218 GstElement *a_queue, *v_queue;
221 pipeline = gst_pipeline_new ("app");
223 src = gst_element_factory_make_or_warn (SOURCE, "src");
224 demux = gst_element_factory_make_or_warn ("dvdemux", "demuxer");
225 v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
226 decoder = gst_element_factory_make_or_warn ("ffdec_dvvideo", "decoder");
227 videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
228 a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
229 audiosink = gst_element_factory_make_or_warn ("alsasink", "a_sink");
231 g_object_set (G_OBJECT (src), "location", location, NULL);
233 gst_bin_add (GST_BIN (pipeline), src);
234 gst_bin_add (GST_BIN (pipeline), demux);
235 gst_bin_add (GST_BIN (pipeline), a_queue);
236 gst_bin_add (GST_BIN (pipeline), audiosink);
237 gst_bin_add (GST_BIN (pipeline), v_queue);
238 gst_bin_add (GST_BIN (pipeline), decoder);
239 gst_bin_add (GST_BIN (pipeline), videosink);
241 gst_element_link (src, demux);
242 gst_element_link (a_queue, audiosink);
243 gst_element_link (v_queue, decoder);
244 gst_element_link (decoder, videosink);
246 setup_dynamic_link (demux, "video", gst_element_get_static_pad (v_queue,
248 setup_dynamic_link (demux, "audio", gst_element_get_static_pad (a_queue,
251 seekable = gst_element_get_static_pad (decoder, "src");
252 seekable_pads = g_list_prepend (seekable_pads, seekable);
253 rate_pads = g_list_prepend (rate_pads, seekable);
259 make_wav_pipeline (const gchar * location)
261 GstElement *pipeline;
262 GstElement *src, *decoder, *audiosink;
264 pipeline = gst_pipeline_new ("app");
266 src = gst_element_factory_make_or_warn (SOURCE, "src");
267 decoder = gst_element_factory_make_or_warn ("wavparse", "decoder");
268 audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
270 g_object_set (G_OBJECT (src), "location", location, NULL);
272 gst_bin_add (GST_BIN (pipeline), src);
273 gst_bin_add (GST_BIN (pipeline), decoder);
274 gst_bin_add (GST_BIN (pipeline), audiosink);
276 gst_element_link (src, decoder);
278 setup_dynamic_link (decoder, "src", gst_element_get_static_pad (audiosink,
281 seekable_elements = g_list_prepend (seekable_elements, audiosink);
283 /* force element seeking on this pipeline */
290 make_flac_pipeline (const gchar * location)
292 GstElement *pipeline;
293 GstElement *src, *decoder, *audiosink;
296 pipeline = gst_pipeline_new ("app");
298 src = gst_element_factory_make_or_warn (SOURCE, "src");
299 decoder = gst_element_factory_make_or_warn ("flacdec", "decoder");
300 audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
301 g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
303 g_object_set (G_OBJECT (src), "location", location, NULL);
305 gst_bin_add (GST_BIN (pipeline), src);
306 gst_bin_add (GST_BIN (pipeline), decoder);
307 gst_bin_add (GST_BIN (pipeline), audiosink);
309 gst_element_link (src, decoder);
310 gst_element_link (decoder, audiosink);
312 seekable = gst_element_get_static_pad (decoder, "src");
313 seekable_pads = g_list_prepend (seekable_pads, seekable);
314 rate_pads = g_list_prepend (rate_pads, seekable);
316 g_list_prepend (rate_pads, gst_element_get_static_pad (decoder, "sink"));
322 make_sid_pipeline (const gchar * location)
324 GstElement *pipeline;
325 GstElement *src, *decoder, *audiosink;
328 pipeline = gst_pipeline_new ("app");
330 src = gst_element_factory_make_or_warn (SOURCE, "src");
331 decoder = gst_element_factory_make_or_warn ("siddec", "decoder");
332 audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
333 //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
335 g_object_set (G_OBJECT (src), "location", location, NULL);
337 gst_bin_add (GST_BIN (pipeline), src);
338 gst_bin_add (GST_BIN (pipeline), decoder);
339 gst_bin_add (GST_BIN (pipeline), audiosink);
341 gst_element_link (src, decoder);
342 gst_element_link (decoder, audiosink);
344 seekable = gst_element_get_static_pad (decoder, "src");
345 seekable_pads = g_list_prepend (seekable_pads, seekable);
346 rate_pads = g_list_prepend (rate_pads, seekable);
348 g_list_prepend (rate_pads, gst_element_get_static_pad (decoder, "sink"));
354 make_parse_pipeline (const gchar * location)
356 GstElement *pipeline;
357 GstElement *src, *parser, *fakesink;
360 pipeline = gst_pipeline_new ("app");
362 src = gst_element_factory_make_or_warn (SOURCE, "src");
363 parser = gst_element_factory_make_or_warn ("mpegparse", "parse");
364 fakesink = gst_element_factory_make_or_warn ("fakesink", "sink");
365 g_object_set (G_OBJECT (fakesink), "silent", TRUE, NULL);
366 g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
368 g_object_set (G_OBJECT (src), "location", location, NULL);
370 gst_bin_add (GST_BIN (pipeline), src);
371 gst_bin_add (GST_BIN (pipeline), parser);
372 gst_bin_add (GST_BIN (pipeline), fakesink);
374 gst_element_link (src, parser);
375 gst_element_link (parser, fakesink);
377 seekable = gst_element_get_static_pad (parser, "src");
378 seekable_pads = g_list_prepend (seekable_pads, seekable);
379 rate_pads = g_list_prepend (rate_pads, seekable);
381 g_list_prepend (rate_pads, gst_element_get_static_pad (parser, "sink"));
387 make_vorbis_pipeline (const gchar * location)
389 GstElement *pipeline, *audio_bin;
390 GstElement *src, *demux, *decoder, *convert, *audiosink;
391 GstPad *pad, *seekable;
393 pipeline = gst_pipeline_new ("app");
395 src = gst_element_factory_make_or_warn (SOURCE, "src");
396 demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
397 decoder = gst_element_factory_make_or_warn ("vorbisdec", "decoder");
398 convert = gst_element_factory_make_or_warn ("audioconvert", "convert");
399 audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
400 g_object_set (G_OBJECT (audiosink), "sync", TRUE, NULL);
402 g_object_set (G_OBJECT (src), "location", location, NULL);
404 audio_bin = gst_bin_new ("a_decoder_bin");
406 gst_bin_add (GST_BIN (pipeline), src);
407 gst_bin_add (GST_BIN (pipeline), demux);
408 gst_bin_add (GST_BIN (audio_bin), decoder);
409 gst_bin_add (GST_BIN (audio_bin), convert);
410 gst_bin_add (GST_BIN (audio_bin), audiosink);
411 gst_bin_add (GST_BIN (pipeline), audio_bin);
413 gst_element_link (src, demux);
414 gst_element_link (decoder, convert);
415 gst_element_link (convert, audiosink);
417 pad = gst_element_get_static_pad (decoder, "sink");
418 gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
419 gst_object_unref (pad);
421 setup_dynamic_link (demux, NULL, gst_element_get_static_pad (audio_bin,
424 seekable = gst_element_get_static_pad (decoder, "src");
425 seekable_pads = g_list_prepend (seekable_pads, seekable);
426 rate_pads = g_list_prepend (rate_pads, seekable);
428 g_list_prepend (rate_pads, gst_element_get_static_pad (decoder, "sink"));
434 make_theora_pipeline (const gchar * location)
436 GstElement *pipeline, *video_bin;
437 GstElement *src, *demux, *decoder, *convert, *videosink;
438 GstPad *pad, *seekable;
440 pipeline = gst_pipeline_new ("app");
442 src = gst_element_factory_make_or_warn (SOURCE, "src");
443 demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
444 decoder = gst_element_factory_make_or_warn ("theoradec", "decoder");
445 convert = gst_element_factory_make_or_warn ("ffmpegcolorspace", "convert");
446 videosink = gst_element_factory_make_or_warn (VSINK, "sink");
448 g_object_set (G_OBJECT (src), "location", location, NULL);
450 video_bin = gst_bin_new ("v_decoder_bin");
452 gst_bin_add (GST_BIN (pipeline), src);
453 gst_bin_add (GST_BIN (pipeline), demux);
454 gst_bin_add (GST_BIN (video_bin), decoder);
455 gst_bin_add (GST_BIN (video_bin), convert);
456 gst_bin_add (GST_BIN (video_bin), videosink);
457 gst_bin_add (GST_BIN (pipeline), video_bin);
459 gst_element_link (src, demux);
460 gst_element_link (decoder, convert);
461 gst_element_link (convert, videosink);
463 pad = gst_element_get_static_pad (decoder, "sink");
464 gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
465 gst_object_unref (pad);
467 setup_dynamic_link (demux, NULL, gst_element_get_static_pad (video_bin,
470 seekable = gst_element_get_static_pad (decoder, "src");
471 seekable_pads = g_list_prepend (seekable_pads, seekable);
472 rate_pads = g_list_prepend (rate_pads, seekable);
474 g_list_prepend (rate_pads, gst_element_get_static_pad (decoder, "sink"));
480 make_vorbis_theora_pipeline (const gchar * location)
482 GstElement *pipeline, *audio_bin, *video_bin;
483 GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
484 GstElement *audiosink, *videosink;
485 GstElement *a_queue, *v_queue, *v_scale;
489 pipeline = gst_pipeline_new ("app");
491 src = gst_element_factory_make_or_warn (SOURCE, "src");
492 g_object_set (G_OBJECT (src), "location", location, NULL);
494 demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
496 gst_bin_add (GST_BIN (pipeline), src);
497 gst_bin_add (GST_BIN (pipeline), demux);
498 gst_element_link (src, demux);
500 audio_bin = gst_bin_new ("a_decoder_bin");
501 a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
502 a_decoder = gst_element_factory_make_or_warn ("vorbisdec", "a_dec");
503 a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
504 audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
506 gst_bin_add (GST_BIN (pipeline), audio_bin);
508 gst_bin_add (GST_BIN (audio_bin), a_queue);
509 gst_bin_add (GST_BIN (audio_bin), a_decoder);
510 gst_bin_add (GST_BIN (audio_bin), a_convert);
511 gst_bin_add (GST_BIN (audio_bin), audiosink);
513 gst_element_link (a_queue, a_decoder);
514 gst_element_link (a_decoder, a_convert);
515 gst_element_link (a_convert, audiosink);
517 pad = gst_element_get_static_pad (a_queue, "sink");
518 gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
519 gst_object_unref (pad);
521 setup_dynamic_link (demux, NULL, gst_element_get_static_pad (audio_bin,
524 video_bin = gst_bin_new ("v_decoder_bin");
525 v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
526 v_decoder = gst_element_factory_make_or_warn ("theoradec", "v_dec");
528 gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
529 v_scale = gst_element_factory_make_or_warn ("videoscale", "v_scale");
530 videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
532 gst_bin_add (GST_BIN (pipeline), video_bin);
534 gst_bin_add (GST_BIN (video_bin), v_queue);
535 gst_bin_add (GST_BIN (video_bin), v_decoder);
536 gst_bin_add (GST_BIN (video_bin), v_convert);
537 gst_bin_add (GST_BIN (video_bin), v_scale);
538 gst_bin_add (GST_BIN (video_bin), videosink);
540 gst_element_link_many (v_queue, v_decoder, v_convert, v_scale, videosink,
543 pad = gst_element_get_static_pad (v_queue, "sink");
544 gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
545 gst_object_unref (pad);
547 setup_dynamic_link (demux, NULL, gst_element_get_static_pad (video_bin,
550 seekable = gst_element_get_static_pad (a_decoder, "src");
551 seekable_pads = g_list_prepend (seekable_pads, seekable);
552 rate_pads = g_list_prepend (rate_pads, seekable);
554 g_list_prepend (rate_pads, gst_element_get_static_pad (a_decoder,
561 make_avi_msmpeg4v3_mp3_pipeline (const gchar * location)
563 GstElement *pipeline, *audio_bin, *video_bin;
564 GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
565 GstElement *audiosink, *videosink;
566 GstElement *a_queue, *v_queue;
567 GstPad *seekable, *pad;
569 pipeline = gst_pipeline_new ("app");
571 src = gst_element_factory_make_or_warn (SOURCE, "src");
572 g_object_set (G_OBJECT (src), "location", location, NULL);
574 demux = gst_element_factory_make_or_warn ("avidemux", "demux");
576 gst_bin_add (GST_BIN (pipeline), src);
577 gst_bin_add (GST_BIN (pipeline), demux);
578 gst_element_link (src, demux);
580 audio_bin = gst_bin_new ("a_decoder_bin");
581 a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
582 a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
583 a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
584 audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
586 gst_bin_add (GST_BIN (audio_bin), a_queue);
587 gst_bin_add (GST_BIN (audio_bin), a_decoder);
588 gst_bin_add (GST_BIN (audio_bin), a_convert);
589 gst_bin_add (GST_BIN (audio_bin), audiosink);
591 gst_element_link (a_queue, a_decoder);
592 gst_element_link (a_decoder, a_convert);
593 gst_element_link (a_convert, audiosink);
595 gst_bin_add (GST_BIN (pipeline), audio_bin);
597 pad = gst_element_get_static_pad (a_queue, "sink");
598 gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
599 gst_object_unref (pad);
601 setup_dynamic_link (demux, NULL, gst_element_get_static_pad (audio_bin,
604 video_bin = gst_bin_new ("v_decoder_bin");
605 v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
606 v_decoder = gst_element_factory_make_or_warn ("ffdec_msmpeg4", "v_dec");
608 gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
609 videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
611 gst_bin_add (GST_BIN (video_bin), v_queue);
612 gst_bin_add (GST_BIN (video_bin), v_decoder);
613 gst_bin_add (GST_BIN (video_bin), v_convert);
614 gst_bin_add (GST_BIN (video_bin), videosink);
616 gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
618 gst_bin_add (GST_BIN (pipeline), video_bin);
620 pad = gst_element_get_static_pad (v_queue, "sink");
621 gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
622 gst_object_unref (pad);
624 setup_dynamic_link (demux, NULL, gst_element_get_static_pad (video_bin,
627 seekable = gst_element_get_static_pad (a_decoder, "src");
628 seekable_pads = g_list_prepend (seekable_pads, seekable);
629 rate_pads = g_list_prepend (rate_pads, seekable);
631 g_list_prepend (rate_pads, gst_element_get_static_pad (a_decoder,
638 make_mp3_pipeline (const gchar * location)
640 GstElement *pipeline;
641 GstElement *src, *decoder, *osssink, *queue;
644 pipeline = gst_pipeline_new ("app");
646 src = gst_element_factory_make_or_warn (SOURCE, "src");
647 decoder = gst_element_factory_make_or_warn ("mad", "dec");
648 queue = gst_element_factory_make_or_warn ("queue", "queue");
649 osssink = gst_element_factory_make_or_warn (ASINK, "sink");
651 seekable_elements = g_list_prepend (seekable_elements, osssink);
653 g_object_set (G_OBJECT (src), "location", location, NULL);
654 //g_object_set (G_OBJECT (osssink), "fragment", 0x00180008, NULL);
656 gst_bin_add (GST_BIN (pipeline), src);
657 gst_bin_add (GST_BIN (pipeline), decoder);
658 gst_bin_add (GST_BIN (pipeline), queue);
659 gst_bin_add (GST_BIN (pipeline), osssink);
661 gst_element_link (src, decoder);
662 gst_element_link (decoder, queue);
663 gst_element_link (queue, osssink);
665 seekable = gst_element_get_static_pad (queue, "src");
666 seekable_pads = g_list_prepend (seekable_pads, seekable);
667 rate_pads = g_list_prepend (rate_pads, seekable);
669 g_list_prepend (rate_pads, gst_element_get_static_pad (decoder, "sink"));
675 make_avi_pipeline (const gchar * location)
677 GstElement *pipeline, *audio_bin, *video_bin;
678 GstElement *src, *demux, *a_decoder, *v_decoder, *audiosink, *videosink;
679 GstElement *a_queue = NULL, *v_queue = NULL;
682 pipeline = gst_pipeline_new ("app");
684 src = gst_element_factory_make_or_warn (SOURCE, "src");
685 g_object_set (G_OBJECT (src), "location", location, NULL);
687 demux = gst_element_factory_make_or_warn ("avidemux", "demux");
688 seekable_elements = g_list_prepend (seekable_elements, demux);
690 gst_bin_add (GST_BIN (pipeline), src);
691 gst_bin_add (GST_BIN (pipeline), demux);
692 gst_element_link (src, demux);
694 audio_bin = gst_bin_new ("a_decoder_bin");
695 a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
696 audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
697 a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
698 gst_element_link (a_decoder, a_queue);
699 gst_element_link (a_queue, audiosink);
700 gst_bin_add (GST_BIN (audio_bin), a_decoder);
701 gst_bin_add (GST_BIN (audio_bin), a_queue);
702 gst_bin_add (GST_BIN (audio_bin), audiosink);
703 gst_element_set_state (audio_bin, GST_STATE_PAUSED);
705 setup_dynamic_link (demux, "audio_00", gst_element_get_static_pad (a_decoder,
708 seekable = gst_element_get_static_pad (a_queue, "src");
709 seekable_pads = g_list_prepend (seekable_pads, seekable);
710 rate_pads = g_list_prepend (rate_pads, seekable);
712 g_list_prepend (rate_pads, gst_element_get_static_pad (a_decoder,
715 video_bin = gst_bin_new ("v_decoder_bin");
716 v_decoder = gst_element_factory_make_or_warn ("ffmpegdecall", "v_dec");
717 videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
718 v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
719 gst_element_link (v_decoder, v_queue);
720 gst_element_link (v_queue, videosink);
721 gst_bin_add (GST_BIN (video_bin), v_decoder);
722 gst_bin_add (GST_BIN (video_bin), v_queue);
723 gst_bin_add (GST_BIN (video_bin), videosink);
725 gst_element_set_state (video_bin, GST_STATE_PAUSED);
727 setup_dynamic_link (demux, "video_00", gst_element_get_static_pad (v_decoder,
730 seekable = gst_element_get_static_pad (v_queue, "src");
731 seekable_pads = g_list_prepend (seekable_pads, seekable);
732 rate_pads = g_list_prepend (rate_pads, seekable);
734 g_list_prepend (rate_pads, gst_element_get_static_pad (v_decoder,
741 make_mpeg_pipeline (const gchar * location)
743 GstElement *pipeline, *audio_bin, *video_bin;
744 GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
745 GstElement *audiosink, *videosink;
746 GstElement *a_queue, *v_queue;
750 pipeline = gst_pipeline_new ("app");
752 src = gst_element_factory_make_or_warn (SOURCE, "src");
753 g_object_set (G_OBJECT (src), "location", location, NULL);
755 //demux = gst_element_factory_make_or_warn ("mpegdemux", "demux");
756 demux = gst_element_factory_make_or_warn ("flupsdemux", "demux");
758 gst_bin_add (GST_BIN (pipeline), src);
759 gst_bin_add (GST_BIN (pipeline), demux);
760 gst_element_link (src, demux);
762 audio_bin = gst_bin_new ("a_decoder_bin");
763 a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
764 a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
765 audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
766 gst_bin_add (GST_BIN (audio_bin), a_decoder);
767 gst_bin_add (GST_BIN (audio_bin), a_queue);
768 gst_bin_add (GST_BIN (audio_bin), audiosink);
770 gst_element_link (a_decoder, a_queue);
771 gst_element_link (a_queue, audiosink);
773 gst_bin_add (GST_BIN (pipeline), audio_bin);
775 pad = gst_element_get_static_pad (a_decoder, "sink");
776 gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
777 gst_object_unref (pad);
779 setup_dynamic_link (demux, "audio_c0", gst_element_get_static_pad (audio_bin,
782 video_bin = gst_bin_new ("v_decoder_bin");
783 v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
784 v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
785 v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
786 videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
788 gst_bin_add (GST_BIN (video_bin), v_decoder);
789 gst_bin_add (GST_BIN (video_bin), v_queue);
790 gst_bin_add (GST_BIN (video_bin), v_filter);
791 gst_bin_add (GST_BIN (video_bin), videosink);
793 gst_element_link (v_decoder, v_queue);
794 gst_element_link (v_queue, v_filter);
795 gst_element_link (v_filter, videosink);
797 gst_bin_add (GST_BIN (pipeline), video_bin);
799 pad = gst_element_get_static_pad (v_decoder, "sink");
800 gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
801 gst_object_unref (pad);
803 setup_dynamic_link (demux, "video_e0", gst_element_get_static_pad (video_bin,
806 seekable = gst_element_get_static_pad (v_filter, "src");
807 seekable_pads = g_list_prepend (seekable_pads, seekable);
808 rate_pads = g_list_prepend (rate_pads, seekable);
810 g_list_prepend (rate_pads, gst_element_get_static_pad (v_decoder,
817 make_mpegnt_pipeline (const gchar * location)
819 GstElement *pipeline, *audio_bin, *video_bin;
820 GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
821 GstElement *audiosink, *videosink;
825 pipeline = gst_pipeline_new ("app");
827 src = gst_element_factory_make_or_warn (SOURCE, "src");
828 g_object_set (G_OBJECT (src), "location", location, NULL);
830 demux = gst_element_factory_make_or_warn ("mpegdemux", "demux");
831 //g_object_set (G_OBJECT (demux), "sync", TRUE, NULL);
833 seekable_elements = g_list_prepend (seekable_elements, demux);
835 gst_bin_add (GST_BIN (pipeline), src);
836 gst_bin_add (GST_BIN (pipeline), demux);
837 gst_element_link (src, demux);
839 audio_bin = gst_bin_new ("a_decoder_bin");
840 a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
841 a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
842 audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
843 //g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
844 g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
845 gst_element_link (a_decoder, a_queue);
846 gst_element_link (a_queue, audiosink);
847 gst_bin_add (GST_BIN (audio_bin), a_decoder);
848 gst_bin_add (GST_BIN (audio_bin), a_queue);
849 gst_bin_add (GST_BIN (audio_bin), audiosink);
851 setup_dynamic_link (demux, "audio_00", gst_element_get_static_pad (a_decoder,
854 seekable = gst_element_get_static_pad (a_queue, "src");
855 seekable_pads = g_list_prepend (seekable_pads, seekable);
856 rate_pads = g_list_prepend (rate_pads, seekable);
858 g_list_prepend (rate_pads, gst_element_get_static_pad (a_decoder,
861 video_bin = gst_bin_new ("v_decoder_bin");
862 v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
863 v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
864 videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
865 gst_element_link_many (v_decoder, v_filter, videosink, NULL);
867 gst_bin_add_many (GST_BIN (video_bin), v_decoder, v_filter, videosink, NULL);
869 setup_dynamic_link (demux, "video_00", gst_element_get_static_pad (v_decoder,
872 seekable = gst_element_get_static_pad (v_decoder, "src");
873 seekable_pads = g_list_prepend (seekable_pads, seekable);
874 rate_pads = g_list_prepend (rate_pads, seekable);
876 g_list_prepend (rate_pads, gst_element_get_static_pad (v_decoder,
883 playerbin_set_uri (GstElement * player, const gchar * location)
887 /* Add "file://" prefix for convenience */
888 if (g_str_has_prefix (location, "/")) {
889 uri = g_strconcat ("file://", location, NULL);
890 g_object_set (G_OBJECT (player), "uri", uri, NULL);
893 g_object_set (G_OBJECT (player), "uri", location, NULL);
898 construct_playerbin (const gchar * name, const gchar * location)
902 player = gst_element_factory_make (name, "player");
905 playerbin_set_uri (player, location);
907 seekable_elements = g_list_prepend (seekable_elements, player);
909 /* force element seeking on this pipeline */
916 make_playerbin_pipeline (const gchar * location)
918 return construct_playerbin ("playbin", location);
922 make_playerbin2_pipeline (const gchar * location)
924 return construct_playerbin ("playbin2", location);
927 #ifndef GST_DISABLE_PARSE
929 make_parselaunch_pipeline (const gchar * description)
931 GstElement *pipeline;
932 GError *error = NULL;
934 pipeline = gst_parse_launch (description, &error);
936 seekable_elements = g_list_prepend (seekable_elements, pipeline);
947 GstElement *(*func) (const gchar * location);
951 static Pipeline pipelines[] = {
952 {"mp3", make_mp3_pipeline},
953 {"avi", make_avi_pipeline},
954 {"mpeg1", make_mpeg_pipeline},
955 {"mpegparse", make_parse_pipeline},
956 {"vorbis", make_vorbis_pipeline},
957 {"theora", make_theora_pipeline},
958 {"ogg/v/t", make_vorbis_theora_pipeline},
959 {"avi/msmpeg4v3/mp3", make_avi_msmpeg4v3_mp3_pipeline},
960 {"sid", make_sid_pipeline},
961 {"flac", make_flac_pipeline},
962 {"wav", make_wav_pipeline},
963 {"mod", make_mod_pipeline},
964 {"dv", make_dv_pipeline},
965 {"mpeg1nothreads", make_mpegnt_pipeline},
966 {"playerbin", make_playerbin_pipeline},
967 #ifndef GST_DISABLE_PARSE
968 {"parse-launch", make_parselaunch_pipeline},
970 {"playerbin2", make_playerbin2_pipeline},
974 #define NUM_TYPES ((sizeof (pipelines) / sizeof (Pipeline)) - 1)
976 /* ui callbacks and helpers */
979 format_value (GtkScale * scale, gdouble value)
985 real = value * duration / 100;
986 seconds = (gint64) real / GST_SECOND;
987 subseconds = (gint64) real / (GST_SECOND / 100);
989 return g_strdup_printf ("%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ":%02"
990 G_GINT64_FORMAT, seconds / 60, seconds % 60, subseconds % 100);
996 const GstFormat format;
1000 static seek_format seek_formats[] = {
1001 {"tim", GST_FORMAT_TIME},
1002 {"byt", GST_FORMAT_BYTES},
1003 {"buf", GST_FORMAT_BUFFERS},
1004 {"def", GST_FORMAT_DEFAULT},
1008 G_GNUC_UNUSED static void
1011 GList *walk = rate_pads;
1014 GstPad *pad = GST_PAD (walk->data);
1017 g_print ("rate/sec %8.8s: ", GST_PAD_NAME (pad));
1018 while (seek_formats[i].name) {
1022 format = seek_formats[i].format;
1024 if (gst_pad_query_convert (pad, GST_FORMAT_TIME, GST_SECOND, &format,
1026 g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
1028 g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
1033 g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
1035 walk = g_list_next (walk);
1039 G_GNUC_UNUSED static void
1040 query_positions_elems (void)
1042 GList *walk = seekable_elements;
1045 GstElement *element = GST_ELEMENT (walk->data);
1048 g_print ("positions %8.8s: ", GST_ELEMENT_NAME (element));
1049 while (seek_formats[i].name) {
1050 gint64 position, total;
1053 format = seek_formats[i].format;
1055 if (gst_element_query_position (element, &format, &position) &&
1056 gst_element_query_duration (element, &format, &total)) {
1057 g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ",
1058 seek_formats[i].name, position, total);
1060 g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*",
1065 g_print (" %s\n", GST_ELEMENT_NAME (element));
1067 walk = g_list_next (walk);
1071 G_GNUC_UNUSED static void
1072 query_positions_pads (void)
1074 GList *walk = seekable_pads;
1077 GstPad *pad = GST_PAD (walk->data);
1080 g_print ("positions %8.8s: ", GST_PAD_NAME (pad));
1081 while (seek_formats[i].name) {
1083 gint64 position, total;
1085 format = seek_formats[i].format;
1087 if (gst_pad_query_position (pad, &format, &position) &&
1088 gst_pad_query_duration (pad, &format, &total)) {
1089 g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ",
1090 seek_formats[i].name, position, total);
1092 g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*",
1098 g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
1100 walk = g_list_next (walk);
1104 static gboolean start_seek (GtkWidget * widget, GdkEventButton * event,
1105 gpointer user_data);
1106 static gboolean stop_seek (GtkWidget * widget, GdkEventButton * event,
1107 gpointer user_data);
1108 static void seek_cb (GtkWidget * widget);
1111 set_scale (gdouble value)
1113 g_signal_handlers_block_by_func (hscale, (void *) start_seek,
1115 g_signal_handlers_block_by_func (hscale, (void *) stop_seek,
1117 g_signal_handlers_block_by_func (hscale, (void *) seek_cb, (void *) pipeline);
1118 gtk_adjustment_set_value (adjustment, value);
1119 g_signal_handlers_unblock_by_func (hscale, (void *) start_seek,
1121 g_signal_handlers_unblock_by_func (hscale, (void *) stop_seek,
1123 g_signal_handlers_unblock_by_func (hscale, (void *) seek_cb,
1125 gtk_widget_queue_draw (hscale);
1129 update_fill (gpointer data)
1132 if (seekable_elements) {
1133 GstElement *element = GST_ELEMENT (seekable_elements->data);
1136 query = gst_query_new_buffering (GST_FORMAT_PERCENT);
1137 if (gst_element_query (element, query)) {
1144 gst_query_parse_buffering_percent (query, &busy, &percent);
1146 if (buffering && !busy) {
1147 /* if we were buffering but not anymore, start playing */
1148 if (state == GST_STATE_PLAYING && !is_live) {
1149 fprintf (stderr, "setting pipeline to PLAYING ...\n");
1150 gst_element_set_state (pipeline, GST_STATE_PLAYING);
1151 gtk_statusbar_pop (GTK_STATUSBAR (statusbar), status_id);
1152 gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id,
1155 state = GST_STATE_PAUSED;
1159 gst_query_parse_buffering_range (query, &format, &start, &stop, NULL);
1161 GST_DEBUG ("start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT,
1165 fill = 100.0 * stop / GST_FORMAT_PERCENT_MAX;
1169 gtk_range_set_fill_level (GTK_RANGE (hscale), fill);
1171 gst_query_unref (query);
1178 update_scale (gpointer data)
1180 GstFormat format = GST_FORMAT_TIME;
1186 if (seekable_elements) {
1187 GstElement *element = GST_ELEMENT (seekable_elements->data);
1189 gst_element_query_position (element, &format, &position);
1190 gst_element_query_duration (element, &format, &duration);
1193 if (seekable_pads) {
1194 GstPad *pad = GST_PAD (seekable_pads->data);
1196 gst_pad_query_position (pad, &format, &position);
1197 gst_pad_query_duration (pad, &format, &duration);
1203 query_positions_elems ();
1205 query_positions_pads ();
1209 if (position >= duration)
1210 duration = position;
1213 set_scale (position * 100.0 / duration);
1219 static void do_seek (GtkWidget * widget);
1220 static void connect_bus_signals (GstElement * pipeline);
1221 static void set_update_scale (gboolean active);
1222 static void set_update_fill (gboolean active);
1225 end_scrub (GtkWidget * widget)
1227 GST_DEBUG ("end scrub, PAUSE");
1228 gst_element_set_state (pipeline, GST_STATE_PAUSED);
1229 seek_timeout_id = 0;
1235 send_event (GstEvent * event)
1237 gboolean res = FALSE;
1240 GList *walk = seekable_pads;
1243 GstPad *seekable = GST_PAD (walk->data);
1245 GST_DEBUG ("send event on pad %s:%s", GST_DEBUG_PAD_NAME (seekable));
1247 gst_event_ref (event);
1248 res = gst_pad_send_event (seekable, event);
1250 walk = g_list_next (walk);
1253 GList *walk = seekable_elements;
1256 GstElement *seekable = GST_ELEMENT (walk->data);
1258 GST_DEBUG ("send event on element %s", GST_ELEMENT_NAME (seekable));
1260 gst_event_ref (event);
1261 res = gst_element_send_event (seekable, event);
1263 walk = g_list_next (walk);
1266 gst_event_unref (event);
1271 do_seek (GtkWidget * widget)
1274 gboolean res = FALSE;
1278 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
1282 flags |= GST_SEEK_FLAG_FLUSH;
1284 flags |= GST_SEEK_FLAG_ACCURATE;
1286 flags |= GST_SEEK_FLAG_KEY_UNIT;
1288 flags |= GST_SEEK_FLAG_SEGMENT;
1290 flags |= GST_SEEK_FLAG_SKIP;
1293 s_event = gst_event_new_seek (rate,
1294 GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, real, GST_SEEK_TYPE_SET,
1295 GST_CLOCK_TIME_NONE);
1296 GST_DEBUG ("seek with rate %lf to %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT,
1297 rate, GST_TIME_ARGS (real), GST_TIME_ARGS (duration));
1299 s_event = gst_event_new_seek (rate,
1300 GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
1301 GST_SEEK_TYPE_SET, real);
1302 GST_DEBUG ("seek with rate %lf to %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT,
1303 rate, GST_TIME_ARGS (0), GST_TIME_ARGS (real));
1306 res = send_event (s_event);
1310 gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, SEEK_TIMEOUT);
1312 set_update_scale (TRUE);
1315 g_print ("seek failed\n");
1316 set_update_scale (TRUE);
1321 seek_cb (GtkWidget * widget)
1323 /* If the timer hasn't expired yet, then the pipeline is running */
1324 if (play_scrub && seek_timeout_id != 0) {
1325 GST_DEBUG ("do scrub seek, PAUSED");
1326 gst_element_set_state (pipeline, GST_STATE_PAUSED);
1329 GST_DEBUG ("do seek");
1333 GST_DEBUG ("do scrub seek, PLAYING");
1334 gst_element_set_state (pipeline, GST_STATE_PLAYING);
1336 if (seek_timeout_id == 0) {
1338 g_timeout_add (SCRUB_TIME, (GSourceFunc) end_scrub, widget);
1344 set_update_fill (gboolean active)
1346 GST_DEBUG ("fill scale is %d", active);
1351 g_timeout_add (FILL_INTERVAL, (GtkFunction) update_fill, pipeline);
1355 g_source_remove (fill_id);
1362 set_update_scale (gboolean active)
1365 GST_DEBUG ("update scale is %d", active);
1368 if (update_id == 0) {
1370 g_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
1374 g_source_remove (update_id);
1381 start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
1383 if (event->type != GDK_BUTTON_PRESS)
1386 set_update_scale (FALSE);
1388 if (state == GST_STATE_PLAYING && flush_seek && scrub) {
1389 GST_DEBUG ("start scrub seek, PAUSE");
1390 gst_element_set_state (pipeline, GST_STATE_PAUSED);
1393 if (changed_id == 0 && flush_seek && scrub) {
1394 changed_id = gtk_signal_connect (GTK_OBJECT (hscale),
1395 "value_changed", G_CALLBACK (seek_cb), pipeline);
1402 stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
1405 g_signal_handler_disconnect (GTK_OBJECT (hscale), changed_id);
1409 if (!flush_seek || !scrub) {
1410 GST_DEBUG ("do final seek");
1414 if (seek_timeout_id != 0) {
1415 g_source_remove (seek_timeout_id);
1416 seek_timeout_id = 0;
1417 /* Still scrubbing, so the pipeline is playing, see if we need PAUSED
1419 if (state == GST_STATE_PAUSED) {
1420 GST_DEBUG ("stop scrub seek, PAUSED");
1421 gst_element_set_state (pipeline, GST_STATE_PAUSED);
1424 if (state == GST_STATE_PLAYING) {
1425 GST_DEBUG ("stop scrub seek, PLAYING");
1426 gst_element_set_state (pipeline, GST_STATE_PLAYING);
1434 play_cb (GtkButton * button, gpointer data)
1436 GstStateChangeReturn ret;
1438 if (state != GST_STATE_PLAYING) {
1439 g_print ("PLAY pipeline\n");
1440 gtk_statusbar_pop (GTK_STATUSBAR (statusbar), status_id);
1442 ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
1444 case GST_STATE_CHANGE_FAILURE:
1446 case GST_STATE_CHANGE_NO_PREROLL:
1452 state = GST_STATE_PLAYING;
1453 gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Playing");
1459 g_print ("PLAY failed\n");
1460 gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Play failed");
1465 pause_cb (GtkButton * button, gpointer data)
1467 if (state != GST_STATE_PAUSED) {
1468 GstStateChangeReturn ret;
1470 gtk_statusbar_pop (GTK_STATUSBAR (statusbar), status_id);
1471 g_print ("PAUSE pipeline\n");
1472 ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
1474 case GST_STATE_CHANGE_FAILURE:
1476 case GST_STATE_CHANGE_NO_PREROLL:
1483 state = GST_STATE_PAUSED;
1484 gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Paused");
1490 g_print ("PAUSE failed\n");
1491 gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Pause failed");
1496 stop_cb (GtkButton * button, gpointer data)
1498 if (state != GST_STATE_READY) {
1499 GstStateChangeReturn ret;
1501 g_print ("READY pipeline\n");
1502 gtk_statusbar_pop (GTK_STATUSBAR (statusbar), status_id);
1504 ret = gst_element_set_state (pipeline, GST_STATE_READY);
1505 if (ret == GST_STATE_CHANGE_FAILURE)
1508 state = GST_STATE_READY;
1509 gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Stopped");
1513 set_update_scale (FALSE);
1515 set_update_fill (FALSE);
1517 if (pipeline_type == 16)
1518 clear_streams (pipeline);
1521 /* if one uses parse_launch, play, stop and play again it fails as all the
1522 * pads after the demuxer can't be reconnected
1524 if (!strcmp (pipelines[pipeline_type].name, "parse-launch")) {
1525 gst_element_set_state (pipeline, GST_STATE_NULL);
1526 gst_object_unref (pipeline);
1528 g_list_free (seekable_elements);
1529 seekable_elements = NULL;
1530 g_list_free (seekable_pads);
1531 seekable_pads = NULL;
1532 g_list_free (rate_pads);
1535 pipeline = pipelines[pipeline_type].func (pipeline_spec);
1536 g_assert (pipeline);
1537 gst_element_set_state (pipeline, GST_STATE_READY);
1538 connect_bus_signals (pipeline);
1546 g_print ("STOP failed\n");
1547 gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Stop failed");
1552 accurate_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1554 accurate_seek = gtk_toggle_button_get_active (button);
1558 key_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1560 keyframe_seek = gtk_toggle_button_get_active (button);
1564 loop_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1566 loop_seek = gtk_toggle_button_get_active (button);
1567 if (state == GST_STATE_PLAYING) {
1573 flush_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1575 flush_seek = gtk_toggle_button_get_active (button);
1579 scrub_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1581 scrub = gtk_toggle_button_get_active (button);
1585 play_scrub_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1587 play_scrub = gtk_toggle_button_get_active (button);
1591 skip_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1593 skip_seek = gtk_toggle_button_get_active (button);
1594 if (state == GST_STATE_PLAYING) {
1600 rate_spinbutton_changed_cb (GtkSpinButton * button, GstPipeline * pipeline)
1602 gboolean res = FALSE;
1606 rate = gtk_spin_button_get_value (button);
1610 flags |= GST_SEEK_FLAG_FLUSH;
1612 flags |= GST_SEEK_FLAG_SEGMENT;
1614 flags |= GST_SEEK_FLAG_ACCURATE;
1616 flags |= GST_SEEK_FLAG_KEY_UNIT;
1618 flags |= GST_SEEK_FLAG_SKIP;
1621 s_event = gst_event_new_seek (rate,
1622 GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, position,
1623 GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE);
1625 s_event = gst_event_new_seek (rate,
1626 GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
1627 GST_SEEK_TYPE_SET, position);
1630 GST_DEBUG ("rate changed to %lf", rate);
1632 res = send_event (s_event);
1636 gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, SEEK_TIMEOUT);
1639 g_print ("seek failed\n");
1643 update_flag (GstPipeline * pipeline, gint num, gboolean state)
1647 g_object_get (pipeline, "flags", &flags, NULL);
1649 flags |= (1 << num);
1651 flags &= ~(1 << num);
1652 g_object_set (pipeline, "flags", flags, NULL);
1656 vis_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1660 state = gtk_toggle_button_get_active (button);
1661 update_flag (pipeline, 3, state);
1662 gtk_widget_set_sensitive (vis_combo, state);
1666 audio_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1670 state = gtk_toggle_button_get_active (button);
1671 update_flag (pipeline, 1, state);
1672 gtk_widget_set_sensitive (audio_combo, state);
1676 video_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1680 state = gtk_toggle_button_get_active (button);
1681 update_flag (pipeline, 0, state);
1682 gtk_widget_set_sensitive (video_combo, state);
1686 text_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1690 state = gtk_toggle_button_get_active (button);
1691 update_flag (pipeline, 2, state);
1692 gtk_widget_set_sensitive (text_combo, state);
1696 mute_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1700 mute = gtk_toggle_button_get_active (button);
1701 g_object_set (pipeline, "mute", mute, NULL);
1705 clear_streams (GstElement * pipeline)
1709 /* remove previous info */
1710 for (i = 0; i < n_video; i++)
1711 gtk_combo_box_remove_text (GTK_COMBO_BOX (video_combo), 0);
1712 for (i = 0; i < n_audio; i++)
1713 gtk_combo_box_remove_text (GTK_COMBO_BOX (audio_combo), 0);
1714 for (i = 0; i < n_text; i++)
1715 gtk_combo_box_remove_text (GTK_COMBO_BOX (text_combo), 0);
1717 n_audio = n_video = n_text = 0;
1718 gtk_widget_set_sensitive (video_combo, FALSE);
1719 gtk_widget_set_sensitive (audio_combo, FALSE);
1720 gtk_widget_set_sensitive (text_combo, FALSE);
1722 need_streams = TRUE;
1726 update_streams (GstPipeline * pipeline)
1730 if (pipeline_type == 16 && need_streams) {
1736 /* remove previous info */
1737 clear_streams (GST_ELEMENT_CAST (pipeline));
1739 /* here we get and update the different streams detected by playbin2 */
1740 g_object_get (pipeline, "n-video", &n_video, NULL);
1741 g_object_get (pipeline, "n-audio", &n_audio, NULL);
1742 g_object_get (pipeline, "n-text", &n_text, NULL);
1744 g_print ("video %d, audio %d, text %d\n", n_video, n_audio, n_text);
1747 for (i = 0; i < n_video; i++) {
1748 g_signal_emit_by_name (pipeline, "get-video-tags", i, &tags);
1749 /* find good name for the label */
1750 name = g_strdup_printf ("video %d", i + 1);
1751 gtk_combo_box_append_text (GTK_COMBO_BOX (video_combo), name);
1754 state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (video_checkbox));
1755 gtk_widget_set_sensitive (video_combo, state && n_video > 0);
1756 gtk_combo_box_set_active (GTK_COMBO_BOX (video_combo), active_idx);
1759 for (i = 0; i < n_audio; i++) {
1760 g_signal_emit_by_name (pipeline, "get-audio-tags", i, &tags);
1761 /* find good name for the label */
1762 name = g_strdup_printf ("audio %d", i + 1);
1763 gtk_combo_box_append_text (GTK_COMBO_BOX (audio_combo), name);
1766 state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (audio_checkbox));
1767 gtk_widget_set_sensitive (audio_combo, state && n_audio > 0);
1768 gtk_combo_box_set_active (GTK_COMBO_BOX (audio_combo), active_idx);
1771 for (i = 0; i < n_text; i++) {
1772 g_signal_emit_by_name (pipeline, "get-text-tags", i, &tags);
1775 const GValue *value;
1777 /* get the language code if we can */
1778 value = gst_tag_list_get_value_index (tags, GST_TAG_LANGUAGE_CODE, 0);
1779 if (value && G_VALUE_HOLDS_STRING (value)) {
1780 name = g_strdup_printf ("text %s", g_value_get_string (value));
1783 /* find good name for the label if we didn't use a tag */
1785 name = g_strdup_printf ("text %d", i + 1);
1787 gtk_combo_box_append_text (GTK_COMBO_BOX (text_combo), name);
1790 state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (text_checkbox));
1791 gtk_widget_set_sensitive (text_combo, state && n_text > 0);
1792 gtk_combo_box_set_active (GTK_COMBO_BOX (text_combo), active_idx);
1794 need_streams = FALSE;
1799 video_combo_cb (GtkComboBox * combo, GstPipeline * pipeline)
1803 active = gtk_combo_box_get_active (combo);
1805 g_print ("setting current video track %d\n", active);
1806 g_object_set (pipeline, "current-video", active, NULL);
1810 audio_combo_cb (GtkComboBox * combo, GstPipeline * pipeline)
1814 active = gtk_combo_box_get_active (combo);
1816 g_print ("setting current audio track %d\n", active);
1817 g_object_set (pipeline, "current-audio", active, NULL);
1821 text_combo_cb (GtkComboBox * combo, GstPipeline * pipeline)
1825 active = gtk_combo_box_get_active (combo);
1827 g_print ("setting current text track %d\n", active);
1828 g_object_set (pipeline, "current-text", active, NULL);
1832 filter_features (GstPluginFeature * feature, gpointer data)
1834 GstElementFactory *f;
1836 if (!GST_IS_ELEMENT_FACTORY (feature))
1838 f = GST_ELEMENT_FACTORY (feature);
1839 if (!g_strrstr (gst_element_factory_get_klass (f), "Visualization"))
1846 init_visualization_features (void)
1850 vis_entries = g_array_new (FALSE, FALSE, sizeof (VisEntry));
1852 list = gst_registry_feature_filter (gst_registry_get_default (),
1853 filter_features, FALSE, NULL);
1855 for (walk = list; walk; walk = g_list_next (walk)) {
1859 entry.factory = GST_ELEMENT_FACTORY (walk->data);
1860 name = gst_element_factory_get_longname (entry.factory);
1862 g_array_append_val (vis_entries, entry);
1863 gtk_combo_box_append_text (GTK_COMBO_BOX (vis_combo), name);
1865 gtk_combo_box_set_active (GTK_COMBO_BOX (vis_combo), 0);
1869 vis_combo_cb (GtkComboBox * combo, GstPipeline * pipeline)
1873 GstElement *element;
1875 /* get the selected index and get the factory for this index */
1876 index = gtk_combo_box_get_active (GTK_COMBO_BOX (vis_combo));
1877 if (vis_entries->len > 0) {
1878 entry = &g_array_index (vis_entries, VisEntry, index);
1880 /* create an instance of the element from the factory */
1881 element = gst_element_factory_create (entry->factory, NULL);
1885 /* set vis plugin for playbin2 */
1886 g_object_set (pipeline, "vis-plugin", element, NULL);
1891 volume_spinbutton_changed_cb (GtkSpinButton * button, GstPipeline * pipeline)
1895 volume = gtk_spin_button_get_value (button);
1897 g_object_set (pipeline, "volume", volume, NULL);
1901 shot_cb (GtkButton * button, gpointer data)
1906 /* convert to our desired format (RGB24) */
1907 caps = gst_caps_new_simple ("video/x-raw-rgb",
1908 "bpp", G_TYPE_INT, 24, "depth", G_TYPE_INT, 24,
1909 /* Note: we don't ask for a specific width/height here, so that
1910 * videoscale can adjust dimensions from a non-1/1 pixel aspect
1911 * ratio to a 1/1 pixel-aspect-ratio */
1912 "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
1913 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
1914 "red_mask", G_TYPE_INT, 0xff0000,
1915 "green_mask", G_TYPE_INT, 0x00ff00,
1916 "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
1918 /* convert the latest frame to the requested format */
1919 g_signal_emit_by_name (pipeline, "convert-frame", caps, &buffer);
1920 gst_caps_unref (caps);
1928 GError *error = NULL;
1930 /* get the snapshot buffer format now. We set the caps on the appsink so
1931 * that it can only be an rgb buffer. The only thing we have not specified
1932 * on the caps is the height, which is dependant on the pixel-aspect-ratio
1933 * of the source material */
1934 caps = GST_BUFFER_CAPS (buffer);
1936 g_warning ("could not get snapshot format\n");
1939 s = gst_caps_get_structure (caps, 0);
1941 /* we need to get the final caps on the buffer to get the size */
1942 res = gst_structure_get_int (s, "width", &width);
1943 res |= gst_structure_get_int (s, "height", &height);
1945 g_warning ("could not get snapshot dimension\n");
1949 /* create pixmap from buffer and save, gstreamer video buffers have a stride
1950 * that is rounded up to the nearest multiple of 4 */
1951 pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buffer),
1952 GDK_COLORSPACE_RGB, FALSE, 8, width, height,
1953 GST_ROUND_UP_4 (width * 3), NULL, NULL);
1955 /* save the pixbuf */
1956 gdk_pixbuf_save (pixbuf, "snapshot.png", "png", &error, NULL);
1959 gst_buffer_unref (buffer);
1964 message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
1966 const GstStructure *s;
1968 s = gst_message_get_structure (message);
1969 g_print ("message from \"%s\" (%s): ",
1970 GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))),
1971 gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
1975 sstr = gst_structure_to_string (s);
1976 g_print ("%s\n", sstr);
1979 g_print ("no message details\n");
1984 msg_async_done (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
1986 GST_DEBUG ("async done");
1987 /* when we get ASYNC_DONE we can query position, duration and other
1989 update_scale (pipeline);
1991 /* update the available streams */
1992 update_streams (pipeline);
1996 msg_state_changed (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
1998 const GstStructure *s;
2000 s = gst_message_get_structure (message);
2002 /* We only care about state changed on the pipeline */
2003 if (s && GST_MESSAGE_SRC (message) == GST_OBJECT_CAST (pipeline)) {
2004 GstState old, new, pending;
2006 gst_message_parse_state_changed (message, &old, &new, &pending);
2008 /* When state of the pipeline changes to paused or playing we start updating scale */
2009 if (new == GST_STATE_PLAYING) {
2010 set_update_scale (TRUE);
2012 set_update_scale (FALSE);
2018 msg_segment_done (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
2025 GST_DEBUG ("position is %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
2026 gst_message_parse_segment_done (message, &format, &position);
2027 GST_DEBUG ("end of segment at %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
2030 /* in the segment-done callback we never flush as this would not make sense
2031 * for seamless playback. */
2033 flags |= GST_SEEK_FLAG_SEGMENT;
2035 flags |= GST_SEEK_FLAG_SKIP;
2037 s_event = gst_event_new_seek (rate,
2038 GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
2039 GST_SEEK_TYPE_SET, duration);
2041 GST_DEBUG ("restart loop with rate %lf to 0 / %" GST_TIME_FORMAT,
2042 rate, GST_TIME_ARGS (duration));
2044 res = send_event (s_event);
2046 g_print ("segment seek failed\n");
2049 /* in stream buffering mode we PAUSE the pipeline until we receive a 100%
2052 do_stream_buffering (gint percent)
2056 gtk_statusbar_pop (GTK_STATUSBAR (statusbar), status_id);
2057 bufstr = g_strdup_printf ("Buffering...%d", percent);
2058 gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, bufstr);
2061 if (percent == 100) {
2062 /* a 100% message means buffering is done */
2064 /* if the desired state is playing, go back */
2065 if (state == GST_STATE_PLAYING) {
2066 /* no state management needed for live pipelines */
2068 fprintf (stderr, "Done buffering, setting pipeline to PLAYING ...\n");
2069 gst_element_set_state (pipeline, GST_STATE_PLAYING);
2071 gtk_statusbar_pop (GTK_STATUSBAR (statusbar), status_id);
2072 gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Playing");
2075 /* buffering busy */
2076 if (buffering == FALSE && state == GST_STATE_PLAYING) {
2077 /* we were not buffering but PLAYING, PAUSE the pipeline. */
2079 fprintf (stderr, "Buffering, setting pipeline to PAUSED ...\n");
2080 gst_element_set_state (pipeline, GST_STATE_PAUSED);
2088 do_download_buffering (gint percent)
2090 if (!buffering && percent < 100) {
2095 bufstr = g_strdup_printf ("Downloading...");
2096 gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, bufstr);
2099 /* once we get a buffering message, we'll do the fill update */
2100 set_update_fill (TRUE);
2102 if (state == GST_STATE_PLAYING && !is_live) {
2103 fprintf (stderr, "Downloading, setting pipeline to PAUSED ...\n");
2104 gst_element_set_state (pipeline, GST_STATE_PAUSED);
2110 msg_buffering (GstBus * bus, GstMessage * message, GstPipeline * data)
2114 gst_message_parse_buffering (message, &percent);
2116 /* get more stats */
2117 gst_message_parse_buffering_stats (message, &mode, NULL, NULL,
2121 case GST_BUFFERING_DOWNLOAD:
2122 do_download_buffering (percent);
2124 case GST_BUFFERING_LIVE:
2125 case GST_BUFFERING_TIMESHIFT:
2126 case GST_BUFFERING_STREAM:
2127 do_stream_buffering (percent);
2134 static guint embed_xid = 0;
2136 static GstBusSyncReply
2137 bus_sync_handler (GstBus * bus, GstMessage * message, GstPipeline * data)
2139 if ((GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT) &&
2140 gst_structure_has_name (message->structure, "prepare-xwindow-id")) {
2141 GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (message));
2143 g_print ("got prepare-xwindow-id\n");
2145 embed_xid = GDK_WINDOW_XID (GDK_WINDOW (video_window->window));
2148 if (g_object_class_find_property (G_OBJECT_GET_CLASS (element),
2149 "force-aspect-ratio")) {
2150 g_object_set (element, "force-aspect-ratio", TRUE, NULL);
2153 gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)),
2156 return GST_BUS_PASS;
2161 msg_eos (GstBus * bus, GstMessage * message, GstPipeline * data)
2163 message_received (bus, message, data);
2165 /* Set new uri for playerbins and continue playback */
2166 if (l && (pipeline_type == 14 || pipeline_type == 16)) {
2167 stop_cb (NULL, NULL);
2168 l = g_list_next (l);
2170 playerbin_set_uri (GST_ELEMENT (data), l->data);
2171 play_cb (NULL, NULL);
2177 connect_bus_signals (GstElement * pipeline)
2179 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
2182 /* handle prepare-xwindow-id element message synchronously */
2183 gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler,
2187 gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
2189 g_signal_connect (bus, "message::state-changed",
2190 (GCallback) msg_state_changed, pipeline);
2191 g_signal_connect (bus, "message::segment-done", (GCallback) msg_segment_done,
2193 g_signal_connect (bus, "message::async-done", (GCallback) msg_async_done,
2196 g_signal_connect (bus, "message::new-clock", (GCallback) message_received,
2198 g_signal_connect (bus, "message::error", (GCallback) message_received,
2200 g_signal_connect (bus, "message::warning", (GCallback) message_received,
2202 g_signal_connect (bus, "message::eos", (GCallback) msg_eos, pipeline);
2203 g_signal_connect (bus, "message::tag", (GCallback) message_received,
2205 g_signal_connect (bus, "message::element", (GCallback) message_received,
2207 g_signal_connect (bus, "message::segment-done", (GCallback) message_received,
2209 g_signal_connect (bus, "message::buffering", (GCallback) msg_buffering,
2212 gst_object_unref (bus);
2215 /* Return GList of paths described in location string */
2217 handle_wildcards (const gchar * location)
2220 gchar *path = g_path_get_dirname (location);
2221 gchar *pattern = g_path_get_basename (location);
2222 GPatternSpec *pspec = g_pattern_spec_new (pattern);
2223 GDir *dir = g_dir_open (path, 0, NULL);
2226 g_print ("matching %s from %s\n", pattern, path);
2229 g_print ("opening directory %s failed\n", path);
2233 while ((name = g_dir_read_name (dir)) != NULL) {
2234 if (g_pattern_match_string (pspec, name)) {
2235 res = g_list_append (res, g_strjoin ("/", path, name, NULL));
2236 g_print (" found clip %s\n", name);
2242 g_pattern_spec_free (pspec);
2250 delete_event_cb (void)
2252 stop_cb (NULL, NULL);
2257 print_usage (int argc, char **argv)
2261 g_print ("usage: %s <type> <filename>\n", argv[0]);
2262 g_print (" possible types:\n");
2264 for (i = 0; i < NUM_TYPES; i++) {
2265 g_print (" %d = %s\n", i, pipelines[i].name);
2270 main (int argc, char **argv)
2272 GtkWidget *window, *hbox, *vbox, *panel, *boxes, *flagtable, *boxes2;
2273 GtkWidget *play_button, *pause_button, *stop_button, *shot_button;
2274 GtkWidget *accurate_checkbox, *key_checkbox, *loop_checkbox, *flush_checkbox;
2275 GtkWidget *scrub_checkbox, *play_scrub_checkbox, *rate_spinbutton;
2276 GtkWidget *rate_label;
2278 GOptionEntry options[] = {
2279 {"stats", 's', 0, G_OPTION_ARG_NONE, &stats,
2280 "Show pad stats", NULL},
2281 {"elem", 'e', 0, G_OPTION_ARG_NONE, &elem_seek,
2282 "Seek on elements instead of pads", NULL},
2283 {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
2284 "Verbose properties", NULL},
2287 GOptionContext *ctx;
2290 if (!g_thread_supported ())
2291 g_thread_init (NULL);
2293 ctx = g_option_context_new ("- test seeking in gsteamer");
2294 g_option_context_add_main_entries (ctx, options, NULL);
2295 g_option_context_add_group (ctx, gst_init_get_option_group ());
2296 g_option_context_add_group (ctx, gtk_get_option_group (TRUE));
2298 if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
2299 g_print ("Error initializing: %s\n", err->message);
2303 GST_DEBUG_CATEGORY_INIT (seek_debug, "seek", 0, "seek example");
2306 print_usage (argc, argv);
2310 pipeline_type = atoi (argv[1]);
2312 if (pipeline_type < 0 || pipeline_type >= NUM_TYPES) {
2313 print_usage (argc, argv);
2317 pipeline_spec = argv[2];
2319 if (g_strrstr (pipeline_spec, "*") != NULL ||
2320 g_strrstr (pipeline_spec, "?") != NULL) {
2321 paths = handle_wildcards (pipeline_spec);
2323 paths = g_list_prepend (paths, g_strdup (pipeline_spec));
2327 g_print ("opening %s failed\n", pipeline_spec);
2333 pipeline = pipelines[pipeline_type].func ((gchar *) l->data);
2334 g_assert (pipeline);
2336 /* initialize gui elements ... */
2337 tips = gtk_tooltips_new ();
2338 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2339 video_window = gtk_drawing_area_new ();
2340 gtk_widget_set_double_buffered (video_window, FALSE);
2341 statusbar = gtk_statusbar_new ();
2342 status_id = gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), "seek");
2343 gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Stopped");
2344 hbox = gtk_hbox_new (FALSE, 0);
2345 vbox = gtk_vbox_new (FALSE, 0);
2346 flagtable = gtk_table_new (4, 2, FALSE);
2347 gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
2349 /* media controls */
2350 play_button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PLAY);
2351 pause_button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PAUSE);
2352 stop_button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_STOP);
2355 accurate_checkbox = gtk_check_button_new_with_label ("Accurate Seek");
2356 key_checkbox = gtk_check_button_new_with_label ("Key-unit Seek");
2357 loop_checkbox = gtk_check_button_new_with_label ("Loop");
2358 flush_checkbox = gtk_check_button_new_with_label ("Flush");
2359 scrub_checkbox = gtk_check_button_new_with_label ("Scrub");
2360 play_scrub_checkbox = gtk_check_button_new_with_label ("Play Scrub");
2361 skip_checkbox = gtk_check_button_new_with_label ("Play Skip");
2362 rate_spinbutton = gtk_spin_button_new_with_range (-100, 100, 0.1);
2363 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (rate_spinbutton), 3);
2364 rate_label = gtk_label_new ("Rate");
2366 gtk_tooltips_set_tip (tips, accurate_checkbox,
2367 "accurate position is requested, this might be considerably slower for some formats",
2369 gtk_tooltips_set_tip (tips, key_checkbox,
2370 "seek to the nearest keyframe. This might be faster but less accurate",
2372 gtk_tooltips_set_tip (tips, loop_checkbox, "loop playback", NULL);
2373 gtk_tooltips_set_tip (tips, flush_checkbox, "flush pipeline after seeking",
2375 gtk_tooltips_set_tip (tips, rate_spinbutton, "define the playback rate, "
2376 "negative value trigger reverse playback", NULL);
2377 gtk_tooltips_set_tip (tips, scrub_checkbox, "show images while seeking",
2379 gtk_tooltips_set_tip (tips, play_scrub_checkbox, "play video while seeking",
2381 gtk_tooltips_set_tip (tips, skip_checkbox,
2382 "Skip frames while playing at high frame rates", NULL);
2384 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (flush_checkbox), TRUE);
2385 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scrub_checkbox), TRUE);
2387 gtk_spin_button_set_value (GTK_SPIN_BUTTON (rate_spinbutton), rate);
2391 GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
2392 hscale = gtk_hscale_new (adjustment);
2393 gtk_scale_set_digits (GTK_SCALE (hscale), 2);
2394 #if GTK_CHECK_VERSION(2,12,0)
2395 gtk_range_set_show_fill_level (GTK_RANGE (hscale), TRUE);
2396 gtk_range_set_fill_level (GTK_RANGE (hscale), 100.0);
2398 gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
2400 gtk_signal_connect (GTK_OBJECT (hscale),
2401 "button_press_event", G_CALLBACK (start_seek), pipeline);
2402 gtk_signal_connect (GTK_OBJECT (hscale),
2403 "button_release_event", G_CALLBACK (stop_seek), pipeline);
2404 gtk_signal_connect (GTK_OBJECT (hscale),
2405 "format_value", G_CALLBACK (format_value), pipeline);
2407 if (pipeline_type == 16) {
2408 /* the playbin2 panel controls for the video/audio/subtitle tracks */
2409 panel = gtk_hbox_new (FALSE, 0);
2410 video_combo = gtk_combo_box_new_text ();
2411 audio_combo = gtk_combo_box_new_text ();
2412 text_combo = gtk_combo_box_new_text ();
2413 gtk_widget_set_sensitive (video_combo, FALSE);
2414 gtk_widget_set_sensitive (audio_combo, FALSE);
2415 gtk_widget_set_sensitive (text_combo, FALSE);
2416 gtk_box_pack_start (GTK_BOX (panel), video_combo, TRUE, TRUE, 2);
2417 gtk_box_pack_start (GTK_BOX (panel), audio_combo, TRUE, TRUE, 2);
2418 gtk_box_pack_start (GTK_BOX (panel), text_combo, TRUE, TRUE, 2);
2419 g_signal_connect (G_OBJECT (video_combo), "changed",
2420 G_CALLBACK (video_combo_cb), pipeline);
2421 g_signal_connect (G_OBJECT (audio_combo), "changed",
2422 G_CALLBACK (audio_combo_cb), pipeline);
2423 g_signal_connect (G_OBJECT (text_combo), "changed",
2424 G_CALLBACK (text_combo_cb), pipeline);
2425 /* playbin2 panel for flag checkboxes and volume/mute */
2426 boxes = gtk_hbox_new (FALSE, 0);
2427 vis_checkbox = gtk_check_button_new_with_label ("Vis");
2428 video_checkbox = gtk_check_button_new_with_label ("Video");
2429 audio_checkbox = gtk_check_button_new_with_label ("Audio");
2430 text_checkbox = gtk_check_button_new_with_label ("Text");
2431 mute_checkbox = gtk_check_button_new_with_label ("Mute");
2432 volume_spinbutton = gtk_spin_button_new_with_range (0, 10.0, 0.1);
2433 gtk_spin_button_set_value (GTK_SPIN_BUTTON (volume_spinbutton), 1.0);
2434 gtk_box_pack_start (GTK_BOX (boxes), video_checkbox, TRUE, TRUE, 2);
2435 gtk_box_pack_start (GTK_BOX (boxes), audio_checkbox, TRUE, TRUE, 2);
2436 gtk_box_pack_start (GTK_BOX (boxes), text_checkbox, TRUE, TRUE, 2);
2437 gtk_box_pack_start (GTK_BOX (boxes), vis_checkbox, TRUE, TRUE, 2);
2438 gtk_box_pack_start (GTK_BOX (boxes), mute_checkbox, TRUE, TRUE, 2);
2439 gtk_box_pack_start (GTK_BOX (boxes), volume_spinbutton, TRUE, TRUE, 2);
2440 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (vis_checkbox), FALSE);
2441 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (audio_checkbox), TRUE);
2442 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (video_checkbox), TRUE);
2443 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_checkbox), TRUE);
2444 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mute_checkbox), FALSE);
2445 g_signal_connect (G_OBJECT (vis_checkbox), "toggled",
2446 G_CALLBACK (vis_toggle_cb), pipeline);
2447 g_signal_connect (G_OBJECT (audio_checkbox), "toggled",
2448 G_CALLBACK (audio_toggle_cb), pipeline);
2449 g_signal_connect (G_OBJECT (video_checkbox), "toggled",
2450 G_CALLBACK (video_toggle_cb), pipeline);
2451 g_signal_connect (G_OBJECT (text_checkbox), "toggled",
2452 G_CALLBACK (text_toggle_cb), pipeline);
2453 g_signal_connect (G_OBJECT (mute_checkbox), "toggled",
2454 G_CALLBACK (mute_toggle_cb), pipeline);
2455 g_signal_connect (G_OBJECT (volume_spinbutton), "value_changed",
2456 G_CALLBACK (volume_spinbutton_changed_cb), pipeline);
2457 /* playbin2 panel for snapshot */
2458 boxes2 = gtk_hbox_new (FALSE, 0);
2459 shot_button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
2460 gtk_tooltips_set_tip (tips, shot_button,
2461 "save a screenshot .png in the current directory", NULL);
2462 g_signal_connect (G_OBJECT (shot_button), "clicked", G_CALLBACK (shot_cb),
2464 vis_combo = gtk_combo_box_new_text ();
2465 g_signal_connect (G_OBJECT (vis_combo), "changed",
2466 G_CALLBACK (vis_combo_cb), pipeline);
2467 gtk_widget_set_sensitive (vis_combo, FALSE);
2468 gtk_box_pack_start (GTK_BOX (boxes2), shot_button, TRUE, TRUE, 2);
2469 gtk_box_pack_start (GTK_BOX (boxes2), vis_combo, TRUE, TRUE, 2);
2471 /* fill the vis combo box and the array of factories */
2472 init_visualization_features ();
2474 panel = boxes = boxes2 = NULL;
2477 /* do the packing stuff ... */
2478 gtk_window_set_default_size (GTK_WINDOW (window), 250, 96);
2479 /* FIXME: can we avoid this for audio only? */
2480 gtk_widget_set_size_request (GTK_WIDGET (video_window), -1,
2481 DEFAULT_VIDEO_HEIGHT);
2482 gtk_container_add (GTK_CONTAINER (window), vbox);
2483 gtk_box_pack_start (GTK_BOX (vbox), video_window, TRUE, TRUE, 2);
2484 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2);
2485 gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
2486 gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
2487 gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
2488 gtk_box_pack_start (GTK_BOX (hbox), flagtable, FALSE, FALSE, 2);
2489 gtk_table_attach_defaults (GTK_TABLE (flagtable), accurate_checkbox, 0, 1, 0,
2491 gtk_table_attach_defaults (GTK_TABLE (flagtable), flush_checkbox, 1, 2, 0, 1);
2492 gtk_table_attach_defaults (GTK_TABLE (flagtable), loop_checkbox, 2, 3, 0, 1);
2493 gtk_table_attach_defaults (GTK_TABLE (flagtable), key_checkbox, 0, 1, 1, 2);
2494 gtk_table_attach_defaults (GTK_TABLE (flagtable), scrub_checkbox, 1, 2, 1, 2);
2495 gtk_table_attach_defaults (GTK_TABLE (flagtable), play_scrub_checkbox, 2, 3,
2497 gtk_table_attach_defaults (GTK_TABLE (flagtable), skip_checkbox, 3, 4, 0, 1);
2498 gtk_table_attach_defaults (GTK_TABLE (flagtable), rate_label, 4, 5, 0, 1);
2499 gtk_table_attach_defaults (GTK_TABLE (flagtable), rate_spinbutton, 4, 5, 1,
2501 if (panel && boxes && boxes2) {
2502 gtk_box_pack_start (GTK_BOX (vbox), panel, FALSE, FALSE, 2);
2503 gtk_box_pack_start (GTK_BOX (vbox), boxes, FALSE, FALSE, 2);
2504 gtk_box_pack_start (GTK_BOX (vbox), boxes2, FALSE, FALSE, 2);
2506 gtk_box_pack_start (GTK_BOX (vbox), hscale, FALSE, FALSE, 2);
2507 gtk_box_pack_start (GTK_BOX (vbox), statusbar, FALSE, FALSE, 2);
2509 /* connect things ... */
2510 g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
2512 g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb),
2514 g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb),
2516 g_signal_connect (G_OBJECT (accurate_checkbox), "toggled",
2517 G_CALLBACK (accurate_toggle_cb), pipeline);
2518 g_signal_connect (G_OBJECT (key_checkbox), "toggled",
2519 G_CALLBACK (key_toggle_cb), pipeline);
2520 g_signal_connect (G_OBJECT (loop_checkbox), "toggled",
2521 G_CALLBACK (loop_toggle_cb), pipeline);
2522 g_signal_connect (G_OBJECT (flush_checkbox), "toggled",
2523 G_CALLBACK (flush_toggle_cb), pipeline);
2524 g_signal_connect (G_OBJECT (scrub_checkbox), "toggled",
2525 G_CALLBACK (scrub_toggle_cb), pipeline);
2526 g_signal_connect (G_OBJECT (play_scrub_checkbox), "toggled",
2527 G_CALLBACK (play_scrub_toggle_cb), pipeline);
2528 g_signal_connect (G_OBJECT (skip_checkbox), "toggled",
2529 G_CALLBACK (skip_toggle_cb), pipeline);
2530 g_signal_connect (G_OBJECT (rate_spinbutton), "value_changed",
2531 G_CALLBACK (rate_spinbutton_changed_cb), pipeline);
2533 g_signal_connect (G_OBJECT (window), "delete-event", delete_event_cb, NULL);
2536 gtk_widget_show_all (window);
2539 g_signal_connect (pipeline, "deep_notify",
2540 G_CALLBACK (gst_object_default_deep_notify), NULL);
2543 connect_bus_signals (pipeline);
2546 g_print ("NULL pipeline\n");
2547 gst_element_set_state (pipeline, GST_STATE_NULL);
2549 g_print ("free pipeline\n");
2550 gst_object_unref (pipeline);
2552 g_list_foreach (paths, (GFunc) g_free, NULL);
2553 g_list_free (paths);