gst/playback/gstplaybin2.c: Get the object data correct so that we can remove our...
[platform/upstream/gstreamer.git] / tests / examples / seek / seek.c
1 /* GStreamer
2  *
3  * seek.c: seeking sample application
4  *
5  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
6  *               2006 Stefan Kost <ensonic@users.sf.net>
7  *
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.
12  *
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.
17  *
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.
22  */
23 /* FIXME: remove #if 0 code
24  *
25  */
26 #include <stdlib.h>
27 #include <glib.h>
28 #include <gtk/gtk.h>
29 #include <gst/gst.h>
30 #include <string.h>
31
32 GST_DEBUG_CATEGORY_STATIC (seek_debug);
33 #define GST_CAT_DEFAULT (seek_debug)
34
35 /* configuration */
36
37 //#define SOURCE "filesrc"
38 #define SOURCE "gnomevfssrc"
39
40 #define ASINK "alsasink"
41 //#define ASINK "osssink"
42
43 #define VSINK "xvimagesink"
44 //#define VSINK "sdlvideosink"
45 //#define VSINK "ximagesink"
46 //#define VSINK "aasink"
47 //#define VSINK "cacasink"
48
49 //#define UPDATE_INTERVAL 500
50 //#define UPDATE_INTERVAL 100
51 #define UPDATE_INTERVAL 10
52
53 /* number of milliseconds to play for after a seek */
54 #define SCRUB_TIME 100
55
56 /* timeout for gst_element_get_state() after a seek */
57 #define SEEK_TIMEOUT 40 * GST_MSECOND
58
59
60 static GList *seekable_pads = NULL;
61 static GList *rate_pads = NULL;
62 static GList *seekable_elements = NULL;
63
64 static gboolean accurate_seek = FALSE;
65 static gboolean keyframe_seek = FALSE;
66 static gboolean loop_seek = FALSE;
67 static gboolean flush_seek = TRUE;
68 static gboolean scrub = TRUE;
69 static gboolean play_scrub = FALSE;
70 static gdouble rate = 1.0;
71
72 static GstElement *pipeline;
73 static gint pipeline_type;
74 static const gchar *pipeline_spec;
75 static gint64 position = -1;
76 static gint64 duration = -1;
77 static GtkAdjustment *adjustment;
78 static GtkWidget *hscale;
79 static gboolean stats = FALSE;
80 static gboolean elem_seek = FALSE;
81 static gboolean verbose = FALSE;
82
83 static GstState state = GST_STATE_NULL;
84 static guint update_id = 0;
85 static guint seek_timeout_id = 0;
86 static gulong changed_id;
87
88 static gint n_video = 0, n_audio = 0, n_text = 0;
89 static gboolean need_streams = TRUE;
90 static GtkWidget *video_combo, *audio_combo, *text_combo;
91 static GtkWidget *vis_checkbox, *video_checkbox, *audio_checkbox;
92 static GtkWidget *text_checkbox, *mute_checkbox, *volume_spinbutton;
93
94 static void clear_streams (GstElement * pipeline);
95
96 /* pipeline construction */
97
98 typedef struct
99 {
100   const gchar *padname;
101   GstPad *target;
102   GstElement *bin;
103 }
104 dyn_link;
105
106 static GstElement *
107 gst_element_factory_make_or_warn (gchar * type, gchar * name)
108 {
109   GstElement *element = gst_element_factory_make (type, name);
110
111   if (!element) {
112     g_warning ("Failed to create element %s of type %s", name, type);
113   }
114
115   return element;
116 }
117
118 static void
119 dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer data)
120 {
121   gchar *padname;
122   dyn_link *connect = (dyn_link *) data;
123
124   padname = gst_pad_get_name (newpad);
125
126   if (connect->padname == NULL || !strcmp (padname, connect->padname)) {
127     if (connect->bin)
128       gst_bin_add (GST_BIN (pipeline), connect->bin);
129     gst_pad_link (newpad, connect->target);
130
131     //seekable_pads = g_list_prepend (seekable_pads, newpad);
132     rate_pads = g_list_prepend (rate_pads, newpad);
133   }
134   g_free (padname);
135 }
136
137 static void
138 setup_dynamic_link (GstElement * element, const gchar * padname,
139     GstPad * target, GstElement * bin)
140 {
141   dyn_link *connect;
142
143   connect = g_new0 (dyn_link, 1);
144   connect->padname = g_strdup (padname);
145   connect->target = target;
146   connect->bin = bin;
147
148   g_signal_connect (G_OBJECT (element), "pad-added", G_CALLBACK (dynamic_link),
149       connect);
150 }
151
152 static GstElement *
153 make_mod_pipeline (const gchar * location)
154 {
155   GstElement *pipeline;
156   GstElement *src, *decoder, *audiosink;
157   GstPad *seekable;
158
159   pipeline = gst_pipeline_new ("app");
160
161   src = gst_element_factory_make_or_warn (SOURCE, "src");
162   decoder = gst_element_factory_make_or_warn ("modplug", "decoder");
163   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
164   //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
165
166   g_object_set (G_OBJECT (src), "location", location, NULL);
167
168   gst_bin_add (GST_BIN (pipeline), src);
169   gst_bin_add (GST_BIN (pipeline), decoder);
170   gst_bin_add (GST_BIN (pipeline), audiosink);
171
172   gst_element_link (src, decoder);
173   gst_element_link (decoder, audiosink);
174
175   seekable = gst_element_get_pad (decoder, "src");
176   seekable_pads = g_list_prepend (seekable_pads, seekable);
177   rate_pads = g_list_prepend (rate_pads, seekable);
178   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
179
180   return pipeline;
181 }
182
183 static GstElement *
184 make_dv_pipeline (const gchar * location)
185 {
186   GstElement *pipeline;
187   GstElement *src, *demux, *decoder, *audiosink, *videosink;
188   GstElement *a_queue, *v_queue;
189   GstPad *seekable;
190
191   pipeline = gst_pipeline_new ("app");
192
193   src = gst_element_factory_make_or_warn (SOURCE, "src");
194   demux = gst_element_factory_make_or_warn ("dvdemux", "demuxer");
195   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
196   decoder = gst_element_factory_make_or_warn ("ffdec_dvvideo", "decoder");
197   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
198   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
199   audiosink = gst_element_factory_make_or_warn ("alsasink", "a_sink");
200
201   g_object_set (G_OBJECT (src), "location", location, NULL);
202
203   gst_bin_add (GST_BIN (pipeline), src);
204   gst_bin_add (GST_BIN (pipeline), demux);
205   gst_bin_add (GST_BIN (pipeline), a_queue);
206   gst_bin_add (GST_BIN (pipeline), audiosink);
207   gst_bin_add (GST_BIN (pipeline), v_queue);
208   gst_bin_add (GST_BIN (pipeline), decoder);
209   gst_bin_add (GST_BIN (pipeline), videosink);
210
211   gst_element_link (src, demux);
212   gst_element_link (a_queue, audiosink);
213   gst_element_link (v_queue, decoder);
214   gst_element_link (decoder, videosink);
215
216   setup_dynamic_link (demux, "video", gst_element_get_pad (v_queue, "sink"),
217       NULL);
218   setup_dynamic_link (demux, "audio", gst_element_get_pad (a_queue, "sink"),
219       NULL);
220
221   seekable = gst_element_get_pad (decoder, "src");
222   seekable_pads = g_list_prepend (seekable_pads, seekable);
223   rate_pads = g_list_prepend (rate_pads, seekable);
224
225   return pipeline;
226 }
227
228 static GstElement *
229 make_wav_pipeline (const gchar * location)
230 {
231   GstElement *pipeline;
232   GstElement *src, *decoder, *audiosink;
233
234   pipeline = gst_pipeline_new ("app");
235
236   src = gst_element_factory_make_or_warn (SOURCE, "src");
237   decoder = gst_element_factory_make_or_warn ("wavparse", "decoder");
238   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
239
240   g_object_set (G_OBJECT (src), "location", location, NULL);
241
242   gst_bin_add (GST_BIN (pipeline), src);
243   gst_bin_add (GST_BIN (pipeline), decoder);
244   gst_bin_add (GST_BIN (pipeline), audiosink);
245
246   gst_element_link (src, decoder);
247
248   setup_dynamic_link (decoder, "src", gst_element_get_pad (audiosink, "sink"),
249       NULL);
250
251   seekable_elements = g_list_prepend (seekable_elements, audiosink);
252
253   /* force element seeking on this pipeline */
254   elem_seek = TRUE;
255
256   return pipeline;
257 }
258
259 static GstElement *
260 make_flac_pipeline (const gchar * location)
261 {
262   GstElement *pipeline;
263   GstElement *src, *decoder, *audiosink;
264   GstPad *seekable;
265
266   pipeline = gst_pipeline_new ("app");
267
268   src = gst_element_factory_make_or_warn (SOURCE, "src");
269   decoder = gst_element_factory_make_or_warn ("flacdec", "decoder");
270   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
271   g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
272
273   g_object_set (G_OBJECT (src), "location", location, NULL);
274
275   gst_bin_add (GST_BIN (pipeline), src);
276   gst_bin_add (GST_BIN (pipeline), decoder);
277   gst_bin_add (GST_BIN (pipeline), audiosink);
278
279   gst_element_link (src, decoder);
280   gst_element_link (decoder, audiosink);
281
282   seekable = gst_element_get_pad (decoder, "src");
283   seekable_pads = g_list_prepend (seekable_pads, seekable);
284   rate_pads = g_list_prepend (rate_pads, seekable);
285   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
286
287   return pipeline;
288 }
289
290 static GstElement *
291 make_sid_pipeline (const gchar * location)
292 {
293   GstElement *pipeline;
294   GstElement *src, *decoder, *audiosink;
295   GstPad *seekable;
296
297   pipeline = gst_pipeline_new ("app");
298
299   src = gst_element_factory_make_or_warn (SOURCE, "src");
300   decoder = gst_element_factory_make_or_warn ("siddec", "decoder");
301   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
302   //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
303
304   g_object_set (G_OBJECT (src), "location", location, NULL);
305
306   gst_bin_add (GST_BIN (pipeline), src);
307   gst_bin_add (GST_BIN (pipeline), decoder);
308   gst_bin_add (GST_BIN (pipeline), audiosink);
309
310   gst_element_link (src, decoder);
311   gst_element_link (decoder, audiosink);
312
313   seekable = gst_element_get_pad (decoder, "src");
314   seekable_pads = g_list_prepend (seekable_pads, seekable);
315   rate_pads = g_list_prepend (rate_pads, seekable);
316   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
317
318   return pipeline;
319 }
320
321 static GstElement *
322 make_parse_pipeline (const gchar * location)
323 {
324   GstElement *pipeline;
325   GstElement *src, *parser, *fakesink;
326   GstPad *seekable;
327
328   pipeline = gst_pipeline_new ("app");
329
330   src = gst_element_factory_make_or_warn (SOURCE, "src");
331   parser = gst_element_factory_make_or_warn ("mpegparse", "parse");
332   fakesink = gst_element_factory_make_or_warn ("fakesink", "sink");
333   g_object_set (G_OBJECT (fakesink), "silent", TRUE, NULL);
334   g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
335
336   g_object_set (G_OBJECT (src), "location", location, NULL);
337
338   gst_bin_add (GST_BIN (pipeline), src);
339   gst_bin_add (GST_BIN (pipeline), parser);
340   gst_bin_add (GST_BIN (pipeline), fakesink);
341
342   gst_element_link (src, parser);
343   gst_element_link (parser, fakesink);
344
345   seekable = gst_element_get_pad (parser, "src");
346   seekable_pads = g_list_prepend (seekable_pads, seekable);
347   rate_pads = g_list_prepend (rate_pads, seekable);
348   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (parser, "sink"));
349
350   return pipeline;
351 }
352
353 static GstElement *
354 make_vorbis_pipeline (const gchar * location)
355 {
356   GstElement *pipeline, *audio_bin;
357   GstElement *src, *demux, *decoder, *convert, *audiosink;
358   GstPad *pad, *seekable;
359
360   pipeline = gst_pipeline_new ("app");
361
362   src = gst_element_factory_make_or_warn (SOURCE, "src");
363   demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
364   decoder = gst_element_factory_make_or_warn ("vorbisdec", "decoder");
365   convert = gst_element_factory_make_or_warn ("audioconvert", "convert");
366   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
367   g_object_set (G_OBJECT (audiosink), "sync", TRUE, NULL);
368
369   g_object_set (G_OBJECT (src), "location", location, NULL);
370
371   audio_bin = gst_bin_new ("a_decoder_bin");
372
373   gst_bin_add (GST_BIN (pipeline), src);
374   gst_bin_add (GST_BIN (pipeline), demux);
375   gst_bin_add (GST_BIN (audio_bin), decoder);
376   gst_bin_add (GST_BIN (audio_bin), convert);
377   gst_bin_add (GST_BIN (audio_bin), audiosink);
378   gst_bin_add (GST_BIN (pipeline), audio_bin);
379
380   gst_element_link (src, demux);
381   gst_element_link (decoder, convert);
382   gst_element_link (convert, audiosink);
383
384   pad = gst_element_get_pad (decoder, "sink");
385   gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
386   gst_object_unref (pad);
387
388   setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
389       NULL);
390
391   seekable = gst_element_get_pad (decoder, "src");
392   seekable_pads = g_list_prepend (seekable_pads, seekable);
393   rate_pads = g_list_prepend (rate_pads, seekable);
394   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
395
396   return pipeline;
397 }
398
399 static GstElement *
400 make_theora_pipeline (const gchar * location)
401 {
402   GstElement *pipeline, *video_bin;
403   GstElement *src, *demux, *decoder, *convert, *videosink;
404   GstPad *pad, *seekable;
405
406   pipeline = gst_pipeline_new ("app");
407
408   src = gst_element_factory_make_or_warn (SOURCE, "src");
409   demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
410   decoder = gst_element_factory_make_or_warn ("theoradec", "decoder");
411   convert = gst_element_factory_make_or_warn ("ffmpegcolorspace", "convert");
412   videosink = gst_element_factory_make_or_warn (VSINK, "sink");
413
414   g_object_set (G_OBJECT (src), "location", location, NULL);
415
416   video_bin = gst_bin_new ("v_decoder_bin");
417
418   gst_bin_add (GST_BIN (pipeline), src);
419   gst_bin_add (GST_BIN (pipeline), demux);
420   gst_bin_add (GST_BIN (video_bin), decoder);
421   gst_bin_add (GST_BIN (video_bin), convert);
422   gst_bin_add (GST_BIN (video_bin), videosink);
423   gst_bin_add (GST_BIN (pipeline), video_bin);
424
425   gst_element_link (src, demux);
426   gst_element_link (decoder, convert);
427   gst_element_link (convert, videosink);
428
429   pad = gst_element_get_pad (decoder, "sink");
430   gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
431   gst_object_unref (pad);
432
433   setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
434       NULL);
435
436   seekable = gst_element_get_pad (decoder, "src");
437   seekable_pads = g_list_prepend (seekable_pads, seekable);
438   rate_pads = g_list_prepend (rate_pads, seekable);
439   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
440
441   return pipeline;
442 }
443
444 static GstElement *
445 make_vorbis_theora_pipeline (const gchar * location)
446 {
447   GstElement *pipeline, *audio_bin, *video_bin;
448   GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
449   GstElement *audiosink, *videosink;
450   GstElement *a_queue, *v_queue, *v_scale;
451   GstPad *seekable;
452   GstPad *pad;
453
454   pipeline = gst_pipeline_new ("app");
455
456   src = gst_element_factory_make_or_warn (SOURCE, "src");
457   g_object_set (G_OBJECT (src), "location", location, NULL);
458
459   demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
460
461   gst_bin_add (GST_BIN (pipeline), src);
462   gst_bin_add (GST_BIN (pipeline), demux);
463   gst_element_link (src, demux);
464
465   audio_bin = gst_bin_new ("a_decoder_bin");
466   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
467   a_decoder = gst_element_factory_make_or_warn ("vorbisdec", "a_dec");
468   a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
469   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
470
471   gst_bin_add (GST_BIN (pipeline), audio_bin);
472
473   gst_bin_add (GST_BIN (audio_bin), a_queue);
474   gst_bin_add (GST_BIN (audio_bin), a_decoder);
475   gst_bin_add (GST_BIN (audio_bin), a_convert);
476   gst_bin_add (GST_BIN (audio_bin), audiosink);
477
478   gst_element_link (a_queue, a_decoder);
479   gst_element_link (a_decoder, a_convert);
480   gst_element_link (a_convert, audiosink);
481
482   pad = gst_element_get_pad (a_queue, "sink");
483   gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
484   gst_object_unref (pad);
485
486   setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
487       NULL);
488
489   video_bin = gst_bin_new ("v_decoder_bin");
490   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
491   v_decoder = gst_element_factory_make_or_warn ("theoradec", "v_dec");
492   v_convert =
493       gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
494   v_scale = gst_element_factory_make_or_warn ("videoscale", "v_scale");
495   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
496
497   gst_bin_add (GST_BIN (pipeline), video_bin);
498
499   gst_bin_add (GST_BIN (video_bin), v_queue);
500   gst_bin_add (GST_BIN (video_bin), v_decoder);
501   gst_bin_add (GST_BIN (video_bin), v_convert);
502   gst_bin_add (GST_BIN (video_bin), v_scale);
503   gst_bin_add (GST_BIN (video_bin), videosink);
504
505   gst_element_link_many (v_queue, v_decoder, v_convert, v_scale, videosink,
506       NULL);
507
508   pad = gst_element_get_pad (v_queue, "sink");
509   gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
510   gst_object_unref (pad);
511
512   setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
513       NULL);
514
515   seekable = gst_element_get_pad (a_decoder, "src");
516   seekable_pads = g_list_prepend (seekable_pads, seekable);
517   rate_pads = g_list_prepend (rate_pads, seekable);
518   rate_pads =
519       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
520
521   return pipeline;
522 }
523
524 static GstElement *
525 make_avi_msmpeg4v3_mp3_pipeline (const gchar * location)
526 {
527   GstElement *pipeline, *audio_bin, *video_bin;
528   GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
529   GstElement *audiosink, *videosink;
530   GstElement *a_queue, *v_queue;
531   GstPad *seekable, *pad;
532
533   pipeline = gst_pipeline_new ("app");
534
535   src = gst_element_factory_make_or_warn (SOURCE, "src");
536   g_object_set (G_OBJECT (src), "location", location, NULL);
537
538   demux = gst_element_factory_make_or_warn ("avidemux", "demux");
539
540   gst_bin_add (GST_BIN (pipeline), src);
541   gst_bin_add (GST_BIN (pipeline), demux);
542   gst_element_link (src, demux);
543
544   audio_bin = gst_bin_new ("a_decoder_bin");
545   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
546   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
547   a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
548   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
549
550   gst_bin_add (GST_BIN (audio_bin), a_queue);
551   gst_bin_add (GST_BIN (audio_bin), a_decoder);
552   gst_bin_add (GST_BIN (audio_bin), a_convert);
553   gst_bin_add (GST_BIN (audio_bin), audiosink);
554
555   gst_element_link (a_queue, a_decoder);
556   gst_element_link (a_decoder, a_convert);
557   gst_element_link (a_convert, audiosink);
558
559   gst_bin_add (GST_BIN (pipeline), audio_bin);
560
561   pad = gst_element_get_pad (a_queue, "sink");
562   gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
563   gst_object_unref (pad);
564
565   setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
566       NULL);
567
568   video_bin = gst_bin_new ("v_decoder_bin");
569   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
570   v_decoder = gst_element_factory_make_or_warn ("ffdec_msmpeg4", "v_dec");
571   v_convert =
572       gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
573   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
574
575   gst_bin_add (GST_BIN (video_bin), v_queue);
576   gst_bin_add (GST_BIN (video_bin), v_decoder);
577   gst_bin_add (GST_BIN (video_bin), v_convert);
578   gst_bin_add (GST_BIN (video_bin), videosink);
579
580   gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
581
582   gst_bin_add (GST_BIN (pipeline), video_bin);
583
584   pad = gst_element_get_pad (v_queue, "sink");
585   gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
586   gst_object_unref (pad);
587
588   setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
589       NULL);
590
591   seekable = gst_element_get_pad (a_decoder, "src");
592   seekable_pads = g_list_prepend (seekable_pads, seekable);
593   rate_pads = g_list_prepend (rate_pads, seekable);
594   rate_pads =
595       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
596
597   return pipeline;
598 }
599
600 static GstElement *
601 make_mp3_pipeline (const gchar * location)
602 {
603   GstElement *pipeline;
604   GstElement *src, *decoder, *osssink, *queue;
605   GstPad *seekable;
606
607   pipeline = gst_pipeline_new ("app");
608
609   src = gst_element_factory_make_or_warn (SOURCE, "src");
610   decoder = gst_element_factory_make_or_warn ("mad", "dec");
611   queue = gst_element_factory_make_or_warn ("queue", "queue");
612   osssink = gst_element_factory_make_or_warn (ASINK, "sink");
613
614   seekable_elements = g_list_prepend (seekable_elements, osssink);
615
616   g_object_set (G_OBJECT (src), "location", location, NULL);
617   //g_object_set (G_OBJECT (osssink), "fragment", 0x00180008, NULL);
618
619   gst_bin_add (GST_BIN (pipeline), src);
620   gst_bin_add (GST_BIN (pipeline), decoder);
621   gst_bin_add (GST_BIN (pipeline), queue);
622   gst_bin_add (GST_BIN (pipeline), osssink);
623
624   gst_element_link (src, decoder);
625   gst_element_link (decoder, queue);
626   gst_element_link (queue, osssink);
627
628   seekable = gst_element_get_pad (queue, "src");
629   seekable_pads = g_list_prepend (seekable_pads, seekable);
630   rate_pads = g_list_prepend (rate_pads, seekable);
631   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
632
633   return pipeline;
634 }
635
636 static GstElement *
637 make_avi_pipeline (const gchar * location)
638 {
639   GstElement *pipeline, *audio_bin, *video_bin;
640   GstElement *src, *demux, *a_decoder, *v_decoder, *audiosink, *videosink;
641   GstElement *a_queue = NULL, *v_queue = NULL;
642   GstPad *seekable;
643
644   pipeline = gst_pipeline_new ("app");
645
646   src = gst_element_factory_make_or_warn (SOURCE, "src");
647   g_object_set (G_OBJECT (src), "location", location, NULL);
648
649   demux = gst_element_factory_make_or_warn ("avidemux", "demux");
650   seekable_elements = g_list_prepend (seekable_elements, demux);
651
652   gst_bin_add (GST_BIN (pipeline), src);
653   gst_bin_add (GST_BIN (pipeline), demux);
654   gst_element_link (src, demux);
655
656   audio_bin = gst_bin_new ("a_decoder_bin");
657   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
658   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
659   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
660   gst_element_link (a_decoder, a_queue);
661   gst_element_link (a_queue, audiosink);
662   gst_bin_add (GST_BIN (audio_bin), a_decoder);
663   gst_bin_add (GST_BIN (audio_bin), a_queue);
664   gst_bin_add (GST_BIN (audio_bin), audiosink);
665   gst_element_set_state (audio_bin, GST_STATE_PAUSED);
666
667   setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
668           "sink"), audio_bin);
669
670   seekable = gst_element_get_pad (a_queue, "src");
671   seekable_pads = g_list_prepend (seekable_pads, seekable);
672   rate_pads = g_list_prepend (rate_pads, seekable);
673   rate_pads =
674       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
675
676   video_bin = gst_bin_new ("v_decoder_bin");
677   v_decoder = gst_element_factory_make_or_warn ("ffmpegdecall", "v_dec");
678   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
679   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
680   gst_element_link (v_decoder, v_queue);
681   gst_element_link (v_queue, videosink);
682   gst_bin_add (GST_BIN (video_bin), v_decoder);
683   gst_bin_add (GST_BIN (video_bin), v_queue);
684   gst_bin_add (GST_BIN (video_bin), videosink);
685
686   gst_element_set_state (video_bin, GST_STATE_PAUSED);
687
688   setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder,
689           "sink"), video_bin);
690
691   seekable = gst_element_get_pad (v_queue, "src");
692   seekable_pads = g_list_prepend (seekable_pads, seekable);
693   rate_pads = g_list_prepend (rate_pads, seekable);
694   rate_pads =
695       g_list_prepend (rate_pads, gst_element_get_pad (v_decoder, "sink"));
696
697   return pipeline;
698 }
699
700 static GstElement *
701 make_mpeg_pipeline (const gchar * location)
702 {
703   GstElement *pipeline, *audio_bin, *video_bin;
704   GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
705   GstElement *audiosink, *videosink;
706   GstElement *a_queue, *v_queue;
707   GstPad *seekable;
708   GstPad *pad;
709
710   pipeline = gst_pipeline_new ("app");
711
712   src = gst_element_factory_make_or_warn (SOURCE, "src");
713   g_object_set (G_OBJECT (src), "location", location, NULL);
714
715   //demux = gst_element_factory_make_or_warn ("mpegdemux", "demux");
716   demux = gst_element_factory_make_or_warn ("flupsdemux", "demux");
717
718   gst_bin_add (GST_BIN (pipeline), src);
719   gst_bin_add (GST_BIN (pipeline), demux);
720   gst_element_link (src, demux);
721
722   audio_bin = gst_bin_new ("a_decoder_bin");
723   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
724   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
725   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
726   gst_bin_add (GST_BIN (audio_bin), a_decoder);
727   gst_bin_add (GST_BIN (audio_bin), a_queue);
728   gst_bin_add (GST_BIN (audio_bin), audiosink);
729
730   gst_element_link (a_decoder, a_queue);
731   gst_element_link (a_queue, audiosink);
732
733   gst_bin_add (GST_BIN (pipeline), audio_bin);
734
735   pad = gst_element_get_pad (a_decoder, "sink");
736   gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
737   gst_object_unref (pad);
738
739   setup_dynamic_link (demux, "audio_c0", gst_element_get_pad (audio_bin,
740           "sink"), NULL);
741
742   video_bin = gst_bin_new ("v_decoder_bin");
743   v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
744   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
745   v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
746   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
747
748   gst_bin_add (GST_BIN (video_bin), v_decoder);
749   gst_bin_add (GST_BIN (video_bin), v_queue);
750   gst_bin_add (GST_BIN (video_bin), v_filter);
751   gst_bin_add (GST_BIN (video_bin), videosink);
752
753   gst_element_link (v_decoder, v_queue);
754   gst_element_link (v_queue, v_filter);
755   gst_element_link (v_filter, videosink);
756
757   gst_bin_add (GST_BIN (pipeline), video_bin);
758
759   pad = gst_element_get_pad (v_decoder, "sink");
760   gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
761   gst_object_unref (pad);
762
763   setup_dynamic_link (demux, "video_e0", gst_element_get_pad (video_bin,
764           "sink"), NULL);
765
766   seekable = gst_element_get_pad (v_filter, "src");
767   seekable_pads = g_list_prepend (seekable_pads, seekable);
768   rate_pads = g_list_prepend (rate_pads, seekable);
769   rate_pads =
770       g_list_prepend (rate_pads, gst_element_get_pad (v_decoder, "sink"));
771
772   return pipeline;
773 }
774
775 static GstElement *
776 make_mpegnt_pipeline (const gchar * location)
777 {
778   GstElement *pipeline, *audio_bin, *video_bin;
779   GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
780   GstElement *audiosink, *videosink;
781   GstElement *a_queue;
782   GstPad *seekable;
783
784   pipeline = gst_pipeline_new ("app");
785
786   src = gst_element_factory_make_or_warn (SOURCE, "src");
787   g_object_set (G_OBJECT (src), "location", location, NULL);
788
789   demux = gst_element_factory_make_or_warn ("mpegdemux", "demux");
790   //g_object_set (G_OBJECT (demux), "sync", TRUE, NULL);
791
792   seekable_elements = g_list_prepend (seekable_elements, demux);
793
794   gst_bin_add (GST_BIN (pipeline), src);
795   gst_bin_add (GST_BIN (pipeline), demux);
796   gst_element_link (src, demux);
797
798   audio_bin = gst_bin_new ("a_decoder_bin");
799   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
800   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
801   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
802   //g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
803   g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
804   gst_element_link (a_decoder, a_queue);
805   gst_element_link (a_queue, audiosink);
806   gst_bin_add (GST_BIN (audio_bin), a_decoder);
807   gst_bin_add (GST_BIN (audio_bin), a_queue);
808   gst_bin_add (GST_BIN (audio_bin), audiosink);
809
810   setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
811           "sink"), audio_bin);
812
813   seekable = gst_element_get_pad (a_queue, "src");
814   seekable_pads = g_list_prepend (seekable_pads, seekable);
815   rate_pads = g_list_prepend (rate_pads, seekable);
816   rate_pads =
817       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
818
819   video_bin = gst_bin_new ("v_decoder_bin");
820   v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
821   v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
822   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
823   gst_element_link_many (v_decoder, v_filter, videosink, NULL);
824
825   gst_bin_add_many (GST_BIN (video_bin), v_decoder, v_filter, videosink, NULL);
826
827   setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder,
828           "sink"), video_bin);
829
830   seekable = gst_element_get_pad (v_decoder, "src");
831   seekable_pads = g_list_prepend (seekable_pads, seekable);
832   rate_pads = g_list_prepend (rate_pads, seekable);
833   rate_pads =
834       g_list_prepend (rate_pads, gst_element_get_pad (v_decoder, "sink"));
835
836   return pipeline;
837 }
838
839 static GstElement *
840 make_playerbin_pipeline (const gchar * location)
841 {
842   GstElement *player;
843
844   player = gst_element_factory_make ("playbin", "player");
845   g_assert (player);
846
847   g_object_set (G_OBJECT (player), "uri", location, NULL);
848
849   seekable_elements = g_list_prepend (seekable_elements, player);
850
851   /* force element seeking on this pipeline */
852   elem_seek = TRUE;
853
854   return player;
855 }
856
857 static GstElement *
858 make_playerbin2_pipeline (const gchar * location)
859 {
860   GstElement *player;
861
862   player = gst_element_factory_make ("playbin2", "player");
863   g_assert (player);
864
865   g_object_set (G_OBJECT (player), "uri", location, NULL);
866
867   seekable_elements = g_list_prepend (seekable_elements, player);
868
869   /* force element seeking on this pipeline */
870   elem_seek = TRUE;
871
872   return player;
873 }
874
875 #ifndef GST_DISABLE_PARSE
876 static GstElement *
877 make_parselaunch_pipeline (const gchar * description)
878 {
879   GstElement *pipeline;
880   GError *error;
881
882   pipeline = gst_parse_launch (description, &error);
883
884   seekable_elements = g_list_prepend (seekable_elements, pipeline);
885
886   elem_seek = TRUE;
887
888   return pipeline;
889 }
890 #endif
891
892 typedef struct
893 {
894   gchar *name;
895   GstElement *(*func) (const gchar * location);
896 }
897 Pipeline;
898
899 static Pipeline pipelines[] = {
900   {"mp3", make_mp3_pipeline},
901   {"avi", make_avi_pipeline},
902   {"mpeg1", make_mpeg_pipeline},
903   {"mpegparse", make_parse_pipeline},
904   {"vorbis", make_vorbis_pipeline},
905   {"theora", make_theora_pipeline},
906   {"ogg/v/t", make_vorbis_theora_pipeline},
907   {"avi/msmpeg4v3/mp3", make_avi_msmpeg4v3_mp3_pipeline},
908   {"sid", make_sid_pipeline},
909   {"flac", make_flac_pipeline},
910   {"wav", make_wav_pipeline},
911   {"mod", make_mod_pipeline},
912   {"dv", make_dv_pipeline},
913   {"mpeg1nothreads", make_mpegnt_pipeline},
914   {"playerbin", make_playerbin_pipeline},
915 #ifndef GST_DISABLE_PARSE
916   {"parse-launch", make_parselaunch_pipeline},
917 #endif
918   {"playerbin2", make_playerbin2_pipeline},
919   {NULL, NULL},
920 };
921
922 #define NUM_TYPES       ((sizeof (pipelines) / sizeof (Pipeline)) - 1)
923
924 /* ui callbacks and helpers */
925
926 static gchar *
927 format_value (GtkScale * scale, gdouble value)
928 {
929   gint64 real;
930   gint64 seconds;
931   gint64 subseconds;
932
933   real = value * duration / 100;
934   seconds = (gint64) real / GST_SECOND;
935   subseconds = (gint64) real / (GST_SECOND / 100);
936
937   return g_strdup_printf ("%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ":%02"
938       G_GINT64_FORMAT, seconds / 60, seconds % 60, subseconds % 100);
939 }
940
941 typedef struct
942 {
943   const gchar *name;
944   const GstFormat format;
945 }
946 seek_format;
947
948 static seek_format seek_formats[] = {
949   {"tim", GST_FORMAT_TIME},
950   {"byt", GST_FORMAT_BYTES},
951   {"buf", GST_FORMAT_BUFFERS},
952   {"def", GST_FORMAT_DEFAULT},
953   {NULL, 0},
954 };
955
956 G_GNUC_UNUSED static void
957 query_rates (void)
958 {
959   GList *walk = rate_pads;
960
961   while (walk) {
962     GstPad *pad = GST_PAD (walk->data);
963     gint i = 0;
964
965     g_print ("rate/sec  %8.8s: ", GST_PAD_NAME (pad));
966     while (seek_formats[i].name) {
967       gint64 value;
968       GstFormat format;
969
970       format = seek_formats[i].format;
971
972       if (gst_pad_query_convert (pad, GST_FORMAT_TIME, GST_SECOND, &format,
973               &value)) {
974         g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
975       } else {
976         g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
977       }
978
979       i++;
980     }
981     g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
982
983     walk = g_list_next (walk);
984   }
985 }
986
987 G_GNUC_UNUSED static void
988 query_positions_elems ()
989 {
990   GList *walk = seekable_elements;
991
992   while (walk) {
993     GstElement *element = GST_ELEMENT (walk->data);
994     gint i = 0;
995
996     g_print ("positions %8.8s: ", GST_ELEMENT_NAME (element));
997     while (seek_formats[i].name) {
998       gint64 position, total;
999       GstFormat format;
1000
1001       format = seek_formats[i].format;
1002
1003       if (gst_element_query_position (element, &format, &position) &&
1004           gst_element_query_duration (element, &format, &total)) {
1005         g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ",
1006             seek_formats[i].name, position, total);
1007       } else {
1008         g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*",
1009             "*NA*");
1010       }
1011       i++;
1012     }
1013     g_print (" %s\n", GST_ELEMENT_NAME (element));
1014
1015     walk = g_list_next (walk);
1016   }
1017 }
1018
1019 G_GNUC_UNUSED static void
1020 query_positions_pads ()
1021 {
1022   GList *walk = seekable_pads;
1023
1024   while (walk) {
1025     GstPad *pad = GST_PAD (walk->data);
1026     gint i = 0;
1027
1028     g_print ("positions %8.8s: ", GST_PAD_NAME (pad));
1029     while (seek_formats[i].name) {
1030       GstFormat format;
1031       gint64 position, total;
1032
1033       format = seek_formats[i].format;
1034
1035       if (gst_pad_query_position (pad, &format, &position) &&
1036           gst_pad_query_duration (pad, &format, &total)) {
1037         g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ",
1038             seek_formats[i].name, position, total);
1039       } else {
1040         g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*",
1041             "*NA*");
1042       }
1043
1044       i++;
1045     }
1046     g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
1047
1048     walk = g_list_next (walk);
1049   }
1050 }
1051
1052 static gboolean start_seek (GtkWidget * widget, GdkEventButton * event,
1053     gpointer user_data);
1054 static gboolean stop_seek (GtkWidget * widget, GdkEventButton * event,
1055     gpointer user_data);
1056 static void seek_cb (GtkWidget * widget);
1057
1058 static void
1059 set_scale (gdouble value)
1060 {
1061   g_signal_handlers_block_by_func (hscale, (void *) start_seek,
1062       (void *) pipeline);
1063   g_signal_handlers_block_by_func (hscale, (void *) stop_seek,
1064       (void *) pipeline);
1065   g_signal_handlers_block_by_func (hscale, (void *) seek_cb, (void *) pipeline);
1066   gtk_adjustment_set_value (adjustment, value);
1067   g_signal_handlers_unblock_by_func (hscale, (void *) start_seek,
1068       (void *) pipeline);
1069   g_signal_handlers_unblock_by_func (hscale, (void *) stop_seek,
1070       (void *) pipeline);
1071   g_signal_handlers_unblock_by_func (hscale, (void *) seek_cb,
1072       (void *) pipeline);
1073   gtk_widget_queue_draw (hscale);
1074 }
1075
1076 static gboolean
1077 update_scale (gpointer data)
1078 {
1079   GstFormat format = GST_FORMAT_TIME;
1080
1081   //position = 0;
1082   //duration = 0;
1083
1084   if (elem_seek) {
1085     if (seekable_elements) {
1086       GstElement *element = GST_ELEMENT (seekable_elements->data);
1087
1088       gst_element_query_position (element, &format, &position);
1089       gst_element_query_duration (element, &format, &duration);
1090     }
1091   } else {
1092     if (seekable_pads) {
1093       GstPad *pad = GST_PAD (seekable_pads->data);
1094
1095       gst_pad_query_position (pad, &format, &position);
1096       gst_pad_query_duration (pad, &format, &duration);
1097     }
1098   }
1099
1100   if (stats) {
1101     if (elem_seek) {
1102       query_positions_elems ();
1103     } else {
1104       query_positions_pads ();
1105     }
1106     query_rates ();
1107   }
1108   if (position >= duration)
1109     duration = position;
1110
1111   if (duration > 0) {
1112     set_scale (position * 100.0 / duration);
1113   }
1114
1115   return TRUE;
1116 }
1117
1118 static void do_seek (GtkWidget * widget);
1119 static void connect_bus_signals (GstElement * pipeline);
1120 static void set_update_scale (gboolean active);
1121
1122 static gboolean
1123 end_scrub (GtkWidget * widget)
1124 {
1125   GST_DEBUG ("end scrub, PAUSE");
1126   gst_element_set_state (pipeline, GST_STATE_PAUSED);
1127   seek_timeout_id = 0;
1128
1129   return FALSE;
1130 }
1131
1132 static gboolean
1133 send_event (GstEvent * event)
1134 {
1135   gboolean res = FALSE;
1136
1137   if (!elem_seek) {
1138     GList *walk = seekable_pads;
1139
1140     while (walk) {
1141       GstPad *seekable = GST_PAD (walk->data);
1142
1143       GST_DEBUG ("send event on pad %s:%s", GST_DEBUG_PAD_NAME (seekable));
1144
1145       gst_event_ref (event);
1146       res = gst_pad_send_event (seekable, event);
1147
1148       walk = g_list_next (walk);
1149     }
1150   } else {
1151     GList *walk = seekable_elements;
1152
1153     while (walk) {
1154       GstElement *seekable = GST_ELEMENT (walk->data);
1155
1156       GST_DEBUG ("send event on element %s", GST_ELEMENT_NAME (seekable));
1157
1158       gst_event_ref (event);
1159       res = gst_element_send_event (seekable, event);
1160
1161       walk = g_list_next (walk);
1162     }
1163   }
1164   gst_event_unref (event);
1165   return res;
1166 }
1167
1168 static void
1169 do_seek (GtkWidget * widget)
1170 {
1171   gint64 real;
1172   gboolean res = FALSE;
1173   GstEvent *s_event;
1174   GstSeekFlags flags;
1175
1176   real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
1177
1178   flags = 0;
1179   if (flush_seek)
1180     flags |= GST_SEEK_FLAG_FLUSH;
1181   if (accurate_seek)
1182     flags |= GST_SEEK_FLAG_ACCURATE;
1183   if (keyframe_seek)
1184     flags |= GST_SEEK_FLAG_KEY_UNIT;
1185   if (loop_seek)
1186     flags |= GST_SEEK_FLAG_SEGMENT;
1187
1188   if (rate >= 0) {
1189     s_event = gst_event_new_seek (rate,
1190         GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, real, GST_SEEK_TYPE_SET, -1);
1191     GST_DEBUG ("seek with rate %lf to %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT,
1192         rate, GST_TIME_ARGS (real), GST_TIME_ARGS (duration));
1193   } else {
1194     s_event = gst_event_new_seek (rate,
1195         GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
1196         GST_SEEK_TYPE_SET, real);
1197     GST_DEBUG ("seek with rate %lf to %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT,
1198         rate, GST_TIME_ARGS (0), GST_TIME_ARGS (real));
1199   }
1200
1201   res = send_event (s_event);
1202
1203   if (res) {
1204     if (flush_seek) {
1205       gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, SEEK_TIMEOUT);
1206     } else {
1207       set_update_scale (TRUE);
1208     }
1209   } else {
1210     g_print ("seek failed\n");
1211     set_update_scale (TRUE);
1212   }
1213 }
1214
1215 static void
1216 seek_cb (GtkWidget * widget)
1217 {
1218   /* If the timer hasn't expired yet, then the pipeline is running */
1219   if (play_scrub && seek_timeout_id != 0) {
1220     GST_DEBUG ("do scrub seek, PAUSED");
1221     gst_element_set_state (pipeline, GST_STATE_PAUSED);
1222   }
1223
1224   GST_DEBUG ("do seek");
1225   do_seek (widget);
1226
1227   if (play_scrub) {
1228     GST_DEBUG ("do scrub seek, PLAYING");
1229     gst_element_set_state (pipeline, GST_STATE_PLAYING);
1230
1231     if (seek_timeout_id == 0) {
1232       seek_timeout_id =
1233           g_timeout_add (SCRUB_TIME, (GSourceFunc) end_scrub, widget);
1234     }
1235   }
1236 }
1237
1238 static void
1239 set_update_scale (gboolean active)
1240 {
1241
1242   GST_DEBUG ("update scale is %d", active);
1243
1244   if (active) {
1245     if (update_id == 0) {
1246       update_id =
1247           g_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
1248     }
1249   } else {
1250     if (update_id) {
1251       g_source_remove (update_id);
1252       update_id = 0;
1253     }
1254   }
1255 }
1256
1257 static gboolean
1258 start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
1259 {
1260   if (event->type != GDK_BUTTON_PRESS)
1261     return FALSE;
1262
1263   set_update_scale (FALSE);
1264
1265   if (state == GST_STATE_PLAYING && flush_seek && scrub) {
1266     GST_DEBUG ("start scrub seek, PAUSE");
1267     gst_element_set_state (pipeline, GST_STATE_PAUSED);
1268   }
1269
1270   if (changed_id == 0 && flush_seek && scrub) {
1271     changed_id = gtk_signal_connect (GTK_OBJECT (hscale),
1272         "value_changed", G_CALLBACK (seek_cb), pipeline);
1273   }
1274
1275   return FALSE;
1276 }
1277
1278 static gboolean
1279 stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
1280 {
1281   if (changed_id) {
1282     g_signal_handler_disconnect (GTK_OBJECT (hscale), changed_id);
1283     changed_id = 0;
1284   }
1285
1286   if (!flush_seek || !scrub) {
1287     GST_DEBUG ("do final seek");
1288     do_seek (widget);
1289   }
1290
1291   if (seek_timeout_id != 0) {
1292     g_source_remove (seek_timeout_id);
1293     seek_timeout_id = 0;
1294     /* Still scrubbing, so the pipeline is playing, see if we need PAUSED
1295      * instead. */
1296     if (state == GST_STATE_PAUSED) {
1297       GST_DEBUG ("stop scrub seek, PAUSED");
1298       gst_element_set_state (pipeline, GST_STATE_PAUSED);
1299     }
1300   } else {
1301     if (state == GST_STATE_PLAYING) {
1302       GST_DEBUG ("stop scrub seek, PLAYING");
1303       gst_element_set_state (pipeline, GST_STATE_PLAYING);
1304     }
1305   }
1306
1307   return FALSE;
1308 }
1309
1310 static void
1311 play_cb (GtkButton * button, gpointer data)
1312 {
1313   GstStateChangeReturn ret;
1314
1315   if (state != GST_STATE_PLAYING) {
1316     g_print ("PLAY pipeline\n");
1317     ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
1318     if (ret == GST_STATE_CHANGE_FAILURE)
1319       goto failed;
1320     //do_seek(hscale);
1321
1322     state = GST_STATE_PLAYING;
1323   }
1324   return;
1325
1326 failed:
1327   {
1328     g_print ("PLAY failed\n");
1329   }
1330 }
1331
1332 static void
1333 pause_cb (GtkButton * button, gpointer data)
1334 {
1335   if (state != GST_STATE_PAUSED) {
1336     GstStateChangeReturn ret;
1337
1338     g_print ("PAUSE pipeline\n");
1339     ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
1340     if (ret == GST_STATE_CHANGE_FAILURE)
1341       goto failed;
1342
1343     state = GST_STATE_PAUSED;
1344   }
1345   return;
1346
1347 failed:
1348   {
1349     g_print ("PAUSE failed\n");
1350   }
1351 }
1352
1353 static void
1354 stop_cb (GtkButton * button, gpointer data)
1355 {
1356   if (state != GST_STATE_READY) {
1357     GstStateChangeReturn ret;
1358
1359     g_print ("READY pipeline\n");
1360     ret = gst_element_set_state (pipeline, GST_STATE_READY);
1361     if (ret == GST_STATE_CHANGE_FAILURE)
1362       goto failed;
1363
1364     state = GST_STATE_READY;
1365
1366     set_update_scale (FALSE);
1367     set_scale (0.0);
1368
1369     if (pipeline_type == 16)
1370       clear_streams (pipeline);
1371
1372     /* if one uses parse_launch, play, stop and play again it fails as all the
1373      * pads after the demuxer can't be reconnected
1374      */
1375     if (!strcmp (pipelines[pipeline_type].name, "parse-launch")) {
1376       gst_element_set_state (pipeline, GST_STATE_NULL);
1377       gst_object_unref (pipeline);
1378
1379       pipeline = pipelines[pipeline_type].func (pipeline_spec);
1380       g_assert (pipeline);
1381       gst_element_set_state (pipeline, GST_STATE_READY);
1382       connect_bus_signals (pipeline);
1383     }
1384   }
1385   return;
1386
1387 failed:
1388   {
1389     g_print ("STOP failed\n");
1390   }
1391 }
1392
1393 static void
1394 accurate_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1395 {
1396   accurate_seek = gtk_toggle_button_get_active (button);
1397 }
1398
1399 static void
1400 key_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1401 {
1402   keyframe_seek = gtk_toggle_button_get_active (button);
1403 }
1404
1405 static void
1406 loop_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1407 {
1408   loop_seek = gtk_toggle_button_get_active (button);
1409   if (state == GST_STATE_PLAYING) {
1410     do_seek (hscale);
1411   }
1412 }
1413
1414 static void
1415 flush_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1416 {
1417   flush_seek = gtk_toggle_button_get_active (button);
1418 }
1419
1420 static void
1421 scrub_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1422 {
1423   scrub = gtk_toggle_button_get_active (button);
1424 }
1425
1426 static void
1427 play_scrub_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1428 {
1429   play_scrub = gtk_toggle_button_get_active (button);
1430 }
1431
1432 static void
1433 rate_spinbutton_changed_cb (GtkSpinButton * button, GstPipeline * pipeline)
1434 {
1435   gboolean res = FALSE;
1436   GstEvent *s_event;
1437   GstSeekFlags flags;
1438
1439   rate = gtk_spin_button_get_value (button);
1440
1441   flags = 0;
1442   if (flush_seek)
1443     flags |= GST_SEEK_FLAG_FLUSH;
1444   if (loop_seek)
1445     flags |= GST_SEEK_FLAG_SEGMENT;
1446   if (accurate_seek)
1447     flags |= GST_SEEK_FLAG_ACCURATE;
1448   if (keyframe_seek)
1449     flags |= GST_SEEK_FLAG_KEY_UNIT;
1450
1451   if (rate >= 0) {
1452     s_event = gst_event_new_seek (rate,
1453         GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, position,
1454         GST_SEEK_TYPE_SET, -1);
1455   } else {
1456     s_event = gst_event_new_seek (rate,
1457         GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
1458         GST_SEEK_TYPE_SET, position);
1459   }
1460
1461   GST_DEBUG ("rate changed to %lf", rate);
1462
1463   res = send_event (s_event);
1464
1465   if (res) {
1466     if (flush_seek) {
1467       gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, SEEK_TIMEOUT);
1468     }
1469   } else
1470     g_print ("seek failed\n");
1471 }
1472
1473 static void
1474 update_flag (GstPipeline * pipeline, gint num, gboolean state)
1475 {
1476   gint flags;
1477
1478   g_object_get (pipeline, "flags", &flags, NULL);
1479   if (state)
1480     flags |= (1 << num);
1481   else
1482     flags &= ~(1 << num);
1483   g_object_set (pipeline, "flags", flags, NULL);
1484 }
1485
1486 static void
1487 vis_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1488 {
1489   update_flag (pipeline, 3, gtk_toggle_button_get_active (button));
1490 }
1491
1492 static void
1493 audio_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1494 {
1495   update_flag (pipeline, 1, gtk_toggle_button_get_active (button));
1496 }
1497
1498 static void
1499 video_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1500 {
1501   update_flag (pipeline, 0, gtk_toggle_button_get_active (button));
1502 }
1503
1504 static void
1505 text_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1506 {
1507   update_flag (pipeline, 2, gtk_toggle_button_get_active (button));
1508 }
1509
1510 static void
1511 mute_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
1512 {
1513   gboolean mute;
1514
1515   mute = gtk_toggle_button_get_active (button);
1516   g_object_set (pipeline, "mute", mute, NULL);
1517 }
1518
1519 static void
1520 clear_streams (GstElement * pipeline)
1521 {
1522   gint i;
1523
1524   /* remove previous info */
1525   for (i = 0; i < n_video; i++)
1526     gtk_combo_box_remove_text (GTK_COMBO_BOX (video_combo), 0);
1527   for (i = 0; i < n_audio; i++)
1528     gtk_combo_box_remove_text (GTK_COMBO_BOX (audio_combo), 0);
1529   for (i = 0; i < n_text; i++)
1530     gtk_combo_box_remove_text (GTK_COMBO_BOX (text_combo), 0);
1531
1532   n_audio = n_video = n_text = 0;
1533   gtk_widget_set_sensitive (video_combo, FALSE);
1534   gtk_widget_set_sensitive (audio_combo, FALSE);
1535   gtk_widget_set_sensitive (text_combo, FALSE);
1536
1537   need_streams = TRUE;
1538 }
1539
1540 static void
1541 update_streams (GstPipeline * pipeline)
1542 {
1543   gint i;
1544
1545   if (pipeline_type == 16 && need_streams) {
1546     GstTagList *tags;
1547     gchar *name;
1548     gint active_idx;
1549
1550     /* remove previous info */
1551     clear_streams (GST_ELEMENT_CAST (pipeline));
1552
1553     /* here we get and update the different streams detected by playbin2 */
1554     g_object_get (pipeline, "n-video", &n_video, NULL);
1555     g_object_get (pipeline, "n-audio", &n_audio, NULL);
1556     g_object_get (pipeline, "n-text", &n_text, NULL);
1557
1558     g_print ("video %d, audio %d, text %d\n", n_video, n_audio, n_text);
1559
1560     active_idx = 0;
1561     for (i = 0; i < n_video; i++) {
1562       g_signal_emit_by_name (pipeline, "get-video-tags", i, &tags);
1563       /* find good name for the label */
1564       name = g_strdup_printf ("video %d", i + 1);
1565       gtk_combo_box_append_text (GTK_COMBO_BOX (video_combo), name);
1566       g_free (name);
1567     }
1568     gtk_widget_set_sensitive (video_combo, n_video > 0);
1569     gtk_combo_box_set_active (GTK_COMBO_BOX (video_combo), active_idx);
1570
1571     active_idx = 0;
1572     for (i = 0; i < n_audio; i++) {
1573       g_signal_emit_by_name (pipeline, "get-audio-tags", i, &tags);
1574       /* find good name for the label */
1575       name = g_strdup_printf ("audio %d", i + 1);
1576       gtk_combo_box_append_text (GTK_COMBO_BOX (audio_combo), name);
1577       g_free (name);
1578     }
1579     gtk_widget_set_sensitive (audio_combo, n_audio > 0);
1580     gtk_combo_box_set_active (GTK_COMBO_BOX (audio_combo), active_idx);
1581
1582     active_idx = 0;
1583     for (i = 0; i < n_text; i++) {
1584       g_signal_emit_by_name (pipeline, "get-text-tags", i, &tags);
1585       /* find good name for the label */
1586       name = g_strdup_printf ("text %d", i + 1);
1587       gtk_combo_box_append_text (GTK_COMBO_BOX (text_combo), name);
1588       g_free (name);
1589     }
1590     gtk_widget_set_sensitive (text_combo, n_text > 0);
1591     gtk_combo_box_set_active (GTK_COMBO_BOX (text_combo), active_idx);
1592
1593     need_streams = FALSE;
1594   }
1595 }
1596
1597 static void
1598 video_combo_cb (GtkComboBox * combo, GstPipeline * pipeline)
1599 {
1600   g_object_set (pipeline, "current-video", gtk_combo_box_get_active (combo),
1601       NULL);
1602 }
1603
1604 static void
1605 audio_combo_cb (GtkComboBox * combo, GstPipeline * pipeline)
1606 {
1607   g_object_set (pipeline, "current-audio", gtk_combo_box_get_active (combo),
1608       NULL);
1609 }
1610
1611 static void
1612 text_combo_cb (GtkComboBox * combo, GstPipeline * pipeline)
1613 {
1614   g_object_set (pipeline, "current-text", gtk_combo_box_get_active (combo),
1615       NULL);
1616 }
1617
1618 static void
1619 volume_spinbutton_changed_cb (GtkSpinButton * button, GstPipeline * pipeline)
1620 {
1621   gdouble volume;
1622
1623   volume = gtk_spin_button_get_value (button);
1624
1625   g_object_set (pipeline, "volume", volume, NULL);
1626 }
1627
1628 static void
1629 message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
1630 {
1631   const GstStructure *s;
1632
1633   s = gst_message_get_structure (message);
1634   g_print ("message from \"%s\" (%s): ",
1635       GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))),
1636       gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
1637   if (s) {
1638     gchar *sstr;
1639
1640     sstr = gst_structure_to_string (s);
1641     g_print ("%s\n", sstr);
1642     g_free (sstr);
1643   } else {
1644     g_print ("no message details\n");
1645   }
1646 }
1647
1648 static void
1649 msg_async_done (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
1650 {
1651   GST_DEBUG ("async done");
1652   /* when we get ASYNC_DONE we can query position, duration and other
1653    * properties */
1654   update_scale (pipeline);
1655
1656   /* update the available streams */
1657   update_streams (pipeline);
1658 }
1659
1660 static void
1661 msg_state_changed (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
1662 {
1663   const GstStructure *s;
1664
1665   s = gst_message_get_structure (message);
1666
1667   /* We only care about state changed on the pipeline */
1668   if (s && GST_MESSAGE_SRC (message) == GST_OBJECT_CAST (pipeline)) {
1669     GstState old, new, pending;
1670
1671     gst_message_parse_state_changed (message, &old, &new, &pending);
1672
1673     /* When state of the pipeline changes to paused or playing we start updating scale */
1674     if (new == GST_STATE_PLAYING) {
1675       set_update_scale (TRUE);
1676     } else {
1677       set_update_scale (FALSE);
1678     }
1679   }
1680 }
1681
1682 static void
1683 msg_segment_done (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
1684 {
1685   GstEvent *s_event;
1686   GstSeekFlags flags;
1687   gboolean res;
1688   GstFormat format;
1689
1690   GST_DEBUG ("position is %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
1691   gst_message_parse_segment_done (message, &format, &position);
1692   GST_DEBUG ("end of segment at %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
1693
1694   flags = 0;
1695   /* in the segment-done callback we never flush as this would not make sense
1696    * for seamless playback. */
1697   if (loop_seek)
1698     flags = GST_SEEK_FLAG_SEGMENT;
1699
1700   s_event = gst_event_new_seek (rate,
1701       GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
1702       GST_SEEK_TYPE_SET, duration);
1703
1704   GST_DEBUG ("restart loop with rate %lf to 0 / %" GST_TIME_FORMAT,
1705       rate, GST_TIME_ARGS (duration));
1706
1707   res = send_event (s_event);
1708   if (!res)
1709     g_print ("segment seek failed\n");
1710 }
1711
1712 static void
1713 connect_bus_signals (GstElement * pipeline)
1714 {
1715   GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
1716
1717   gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
1718
1719   g_signal_connect (bus, "message::state-changed",
1720       (GCallback) msg_state_changed, pipeline);
1721   g_signal_connect (bus, "message::segment-done", (GCallback) msg_segment_done,
1722       pipeline);
1723   g_signal_connect (bus, "message::async-done", (GCallback) msg_async_done,
1724       pipeline);
1725
1726   g_signal_connect (bus, "message::new-clock", (GCallback) message_received,
1727       pipeline);
1728   g_signal_connect (bus, "message::error", (GCallback) message_received,
1729       pipeline);
1730   g_signal_connect (bus, "message::warning", (GCallback) message_received,
1731       pipeline);
1732   g_signal_connect (bus, "message::eos", (GCallback) message_received,
1733       pipeline);
1734   g_signal_connect (bus, "message::tag", (GCallback) message_received,
1735       pipeline);
1736   g_signal_connect (bus, "message::element", (GCallback) message_received,
1737       pipeline);
1738   g_signal_connect (bus, "message::segment-done", (GCallback) message_received,
1739       pipeline);
1740
1741   gst_object_unref (bus);
1742 }
1743
1744 static void
1745 print_usage (int argc, char **argv)
1746 {
1747   gint i;
1748
1749   g_print ("usage: %s <type> <filename>\n", argv[0]);
1750   g_print ("   possible types:\n");
1751
1752   for (i = 0; i < NUM_TYPES; i++) {
1753     g_print ("     %d = %s\n", i, pipelines[i].name);
1754   }
1755 }
1756
1757 int
1758 main (int argc, char **argv)
1759 {
1760   GtkWidget *window, *hbox, *vbox, *panel, *boxes, *flagtable;
1761   GtkWidget *play_button, *pause_button, *stop_button;
1762   GtkWidget *accurate_checkbox, *key_checkbox, *loop_checkbox, *flush_checkbox;
1763   GtkWidget *scrub_checkbox, *play_scrub_checkbox, *rate_spinbutton;
1764   GtkWidget *rate_label;
1765   GtkTooltips *tips;
1766   GOptionEntry options[] = {
1767     {"stats", 's', 0, G_OPTION_ARG_NONE, &stats,
1768         "Show pad stats", NULL},
1769     {"elem", 'e', 0, G_OPTION_ARG_NONE, &elem_seek,
1770         "Seek on elements instead of pads", NULL},
1771     {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
1772         "Verbose properties", NULL},
1773     {NULL}
1774   };
1775   GOptionContext *ctx;
1776   GError *err = NULL;
1777
1778   if (!g_thread_supported ())
1779     g_thread_init (NULL);
1780
1781   ctx = g_option_context_new ("- test seeking in gsteamer");
1782   g_option_context_add_main_entries (ctx, options, NULL);
1783   g_option_context_add_group (ctx, gst_init_get_option_group ());
1784
1785   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
1786     g_print ("Error initializing: %s\n", err->message);
1787     exit (1);
1788   }
1789
1790   GST_DEBUG_CATEGORY_INIT (seek_debug, "seek", 0, "seek example");
1791
1792   gtk_init (&argc, &argv);
1793
1794   if (argc != 3) {
1795     print_usage (argc, argv);
1796     exit (-1);
1797   }
1798
1799   pipeline_type = atoi (argv[1]);
1800
1801   if (pipeline_type < 0 || pipeline_type >= NUM_TYPES) {
1802     print_usage (argc, argv);
1803     exit (-1);
1804   }
1805
1806   pipeline_spec = argv[2];
1807
1808   pipeline = pipelines[pipeline_type].func (pipeline_spec);
1809   g_assert (pipeline);
1810
1811   /* initialize gui elements ... */
1812   tips = gtk_tooltips_new ();
1813   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1814   hbox = gtk_hbox_new (FALSE, 0);
1815   vbox = gtk_vbox_new (FALSE, 0);
1816   flagtable = gtk_table_new (4, 2, FALSE);
1817   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
1818
1819   /* media controls */
1820   play_button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PLAY);
1821   pause_button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PAUSE);
1822   stop_button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_STOP);
1823
1824   /* seek flags */
1825   accurate_checkbox = gtk_check_button_new_with_label ("Accurate Seek");
1826   key_checkbox = gtk_check_button_new_with_label ("Key-unit Seek");
1827   loop_checkbox = gtk_check_button_new_with_label ("Loop");
1828   flush_checkbox = gtk_check_button_new_with_label ("Flush");
1829   scrub_checkbox = gtk_check_button_new_with_label ("Scrub");
1830   play_scrub_checkbox = gtk_check_button_new_with_label ("Play Scrub");
1831   rate_spinbutton = gtk_spin_button_new_with_range (-100, 100, 0.1);
1832   gtk_spin_button_set_digits (GTK_SPIN_BUTTON (rate_spinbutton), 3);
1833   rate_label = gtk_label_new ("Rate");
1834
1835   gtk_tooltips_set_tip (tips, accurate_checkbox,
1836       "accurate position is requested, this might be considerably slower for some formats",
1837       NULL);
1838   gtk_tooltips_set_tip (tips, key_checkbox,
1839       "seek to the nearest keyframe. This might be faster but less accurate",
1840       NULL);
1841   gtk_tooltips_set_tip (tips, loop_checkbox, "loop playback", NULL);
1842   gtk_tooltips_set_tip (tips, flush_checkbox, "flush pipeline after seeking",
1843       NULL);
1844   gtk_tooltips_set_tip (tips, rate_spinbutton, "define the playback rate, "
1845       "negative value trigger reverse playback", NULL);
1846   gtk_tooltips_set_tip (tips, scrub_checkbox, "show images while seeking",
1847       NULL);
1848   gtk_tooltips_set_tip (tips, play_scrub_checkbox, "play video while seeking",
1849       NULL);
1850
1851   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (flush_checkbox), TRUE);
1852   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scrub_checkbox), TRUE);
1853
1854   gtk_spin_button_set_value (GTK_SPIN_BUTTON (rate_spinbutton), rate);
1855
1856   /* seek bar */
1857   adjustment =
1858       GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
1859   hscale = gtk_hscale_new (adjustment);
1860   gtk_scale_set_digits (GTK_SCALE (hscale), 2);
1861 #if GTK_CHECK_VERSION(2,12,0)
1862   gtk_range_set_show_fill_level (GTK_RANGE (hscale), TRUE);
1863   gtk_range_set_fill_level (GTK_RANGE (hscale), 100.0);
1864 #endif
1865   gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
1866
1867   gtk_signal_connect (GTK_OBJECT (hscale),
1868       "button_press_event", G_CALLBACK (start_seek), pipeline);
1869   gtk_signal_connect (GTK_OBJECT (hscale),
1870       "button_release_event", G_CALLBACK (stop_seek), pipeline);
1871   gtk_signal_connect (GTK_OBJECT (hscale),
1872       "format_value", G_CALLBACK (format_value), pipeline);
1873
1874   if (pipeline_type == 16) {
1875     /* the playbin2 panel controls for the video/audio/subtitle tracks */
1876     panel = gtk_hbox_new (FALSE, 0);
1877     boxes = gtk_hbox_new (FALSE, 0);
1878     video_combo = gtk_combo_box_new_text ();
1879     audio_combo = gtk_combo_box_new_text ();
1880     text_combo = gtk_combo_box_new_text ();
1881     gtk_widget_set_sensitive (video_combo, FALSE);
1882     gtk_widget_set_sensitive (audio_combo, FALSE);
1883     gtk_widget_set_sensitive (text_combo, FALSE);
1884     gtk_box_pack_start (GTK_BOX (panel), video_combo, TRUE, TRUE, 2);
1885     gtk_box_pack_start (GTK_BOX (panel), audio_combo, TRUE, TRUE, 2);
1886     gtk_box_pack_start (GTK_BOX (panel), text_combo, TRUE, TRUE, 2);
1887     g_signal_connect (G_OBJECT (video_combo), "changed",
1888         G_CALLBACK (video_combo_cb), pipeline);
1889     g_signal_connect (G_OBJECT (audio_combo), "changed",
1890         G_CALLBACK (audio_combo_cb), pipeline);
1891     g_signal_connect (G_OBJECT (text_combo), "changed",
1892         G_CALLBACK (text_combo_cb), pipeline);
1893     vis_checkbox = gtk_check_button_new_with_label ("Vis");
1894     video_checkbox = gtk_check_button_new_with_label ("Video");
1895     audio_checkbox = gtk_check_button_new_with_label ("Audio");
1896     text_checkbox = gtk_check_button_new_with_label ("Text");
1897     mute_checkbox = gtk_check_button_new_with_label ("Mute");
1898     volume_spinbutton = gtk_spin_button_new_with_range (0, 5.0, 0.1);
1899     gtk_spin_button_set_value (GTK_SPIN_BUTTON (volume_spinbutton), 1.0);
1900     gtk_box_pack_start (GTK_BOX (boxes), vis_checkbox, TRUE, TRUE, 2);
1901     gtk_box_pack_start (GTK_BOX (boxes), audio_checkbox, TRUE, TRUE, 2);
1902     gtk_box_pack_start (GTK_BOX (boxes), video_checkbox, TRUE, TRUE, 2);
1903     gtk_box_pack_start (GTK_BOX (boxes), text_checkbox, TRUE, TRUE, 2);
1904     gtk_box_pack_start (GTK_BOX (boxes), mute_checkbox, TRUE, TRUE, 2);
1905     gtk_box_pack_start (GTK_BOX (boxes), volume_spinbutton, TRUE, TRUE, 2);
1906     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (vis_checkbox), FALSE);
1907     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (audio_checkbox), TRUE);
1908     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (video_checkbox), TRUE);
1909     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_checkbox), TRUE);
1910     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mute_checkbox), FALSE);
1911     g_signal_connect (G_OBJECT (vis_checkbox), "toggled",
1912         G_CALLBACK (vis_toggle_cb), pipeline);
1913     g_signal_connect (G_OBJECT (audio_checkbox), "toggled",
1914         G_CALLBACK (audio_toggle_cb), pipeline);
1915     g_signal_connect (G_OBJECT (video_checkbox), "toggled",
1916         G_CALLBACK (video_toggle_cb), pipeline);
1917     g_signal_connect (G_OBJECT (text_checkbox), "toggled",
1918         G_CALLBACK (text_toggle_cb), pipeline);
1919     g_signal_connect (G_OBJECT (mute_checkbox), "toggled",
1920         G_CALLBACK (mute_toggle_cb), pipeline);
1921     g_signal_connect (G_OBJECT (volume_spinbutton), "value_changed",
1922         G_CALLBACK (volume_spinbutton_changed_cb), pipeline);
1923   } else {
1924     panel = boxes = NULL;
1925   }
1926
1927   /* do the packing stuff ... */
1928   gtk_window_set_default_size (GTK_WINDOW (window), 250, 96);
1929   gtk_container_add (GTK_CONTAINER (window), vbox);
1930   gtk_container_add (GTK_CONTAINER (vbox), hbox);
1931   gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
1932   gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
1933   gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
1934   gtk_box_pack_start (GTK_BOX (hbox), flagtable, FALSE, FALSE, 2);
1935   gtk_table_attach_defaults (GTK_TABLE (flagtable), accurate_checkbox, 0, 1, 0,
1936       1);
1937   gtk_table_attach_defaults (GTK_TABLE (flagtable), flush_checkbox, 1, 2, 0, 1);
1938   gtk_table_attach_defaults (GTK_TABLE (flagtable), loop_checkbox, 2, 3, 0, 1);
1939   gtk_table_attach_defaults (GTK_TABLE (flagtable), key_checkbox, 0, 1, 1, 2);
1940   gtk_table_attach_defaults (GTK_TABLE (flagtable), scrub_checkbox, 1, 2, 1, 2);
1941   gtk_table_attach_defaults (GTK_TABLE (flagtable), play_scrub_checkbox, 2, 3,
1942       1, 2);
1943   gtk_table_attach_defaults (GTK_TABLE (flagtable), rate_label, 3, 4, 0, 1);
1944   gtk_table_attach_defaults (GTK_TABLE (flagtable), rate_spinbutton, 3, 4, 1,
1945       2);
1946   if (panel && boxes) {
1947     gtk_box_pack_start (GTK_BOX (vbox), panel, TRUE, TRUE, 2);
1948     gtk_box_pack_start (GTK_BOX (vbox), boxes, TRUE, TRUE, 2);
1949   }
1950   gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
1951
1952   /* connect things ... */
1953   g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
1954       pipeline);
1955   g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb),
1956       pipeline);
1957   g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb),
1958       pipeline);
1959   g_signal_connect (G_OBJECT (accurate_checkbox), "toggled",
1960       G_CALLBACK (accurate_toggle_cb), pipeline);
1961   g_signal_connect (G_OBJECT (key_checkbox), "toggled",
1962       G_CALLBACK (key_toggle_cb), pipeline);
1963   g_signal_connect (G_OBJECT (loop_checkbox), "toggled",
1964       G_CALLBACK (loop_toggle_cb), pipeline);
1965   g_signal_connect (G_OBJECT (flush_checkbox), "toggled",
1966       G_CALLBACK (flush_toggle_cb), pipeline);
1967   g_signal_connect (G_OBJECT (scrub_checkbox), "toggled",
1968       G_CALLBACK (scrub_toggle_cb), pipeline);
1969   g_signal_connect (G_OBJECT (play_scrub_checkbox), "toggled",
1970       G_CALLBACK (play_scrub_toggle_cb), pipeline);
1971   g_signal_connect (G_OBJECT (rate_spinbutton), "value_changed",
1972       G_CALLBACK (rate_spinbutton_changed_cb), pipeline);
1973
1974   g_signal_connect (G_OBJECT (window), "delete-event", gtk_main_quit, NULL);
1975
1976   /* show the gui. */
1977   gtk_widget_show_all (window);
1978
1979   if (verbose) {
1980     g_signal_connect (pipeline, "deep_notify",
1981         G_CALLBACK (gst_object_default_deep_notify), NULL);
1982   }
1983
1984   connect_bus_signals (pipeline);
1985   gtk_main ();
1986
1987   g_print ("NULL pipeline\n");
1988   gst_element_set_state (pipeline, GST_STATE_NULL);
1989
1990   g_print ("free pipeline\n");
1991   gst_object_unref (pipeline);
1992
1993   return 0;
1994 }