2ad1ca7f8b96e80361ff851610c343da58535d4e
[platform/upstream/gst-plugins-good.git] / examples / seeking / seek.c
1 #include <stdlib.h>
2 #include <glib.h>
3 #include <gtk/gtk.h>
4 #include <gst/gst.h>
5 #include <string.h>
6
7 static GList *seekable_pads = NULL;
8 static GList *rate_pads = NULL;
9 static GList *seekable_elements = NULL;
10
11 static GstElement *pipeline;
12 static guint64 duration;
13 static GtkAdjustment *adjustment;
14 static gboolean stats = FALSE;
15
16 static guint update_id;
17
18 //#define SOURCE "gnomevfssrc"
19 #define SOURCE "filesrc"
20
21 #define UPDATE_INTERVAL 500
22
23 #define THREAD
24 #define PAD_SEEK
25
26 typedef struct
27 {
28   const gchar   *padname;
29   GstPad        *target;
30   GstElement    *bin;
31 } dyn_link;
32
33 static GstElement *
34 gst_element_factory_make_or_warn (gchar *type, gchar *name)
35 {
36   GstElement *element = gst_element_factory_make (type, name);
37
38   if (!element) {
39     g_warning ("Failed to create element %s of type %s",
40                name, type);
41   }
42
43   return element;
44 }
45
46 static void
47 dynamic_link (GstPadTemplate *templ, GstPad *newpad, gpointer data)
48 {
49   dyn_link *connect = (dyn_link *) data;
50
51   if (!strcmp (gst_pad_get_name (newpad), connect->padname)) {
52     gst_element_set_state (pipeline, GST_STATE_PAUSED);
53     gst_bin_add (GST_BIN (pipeline), connect->bin);
54     gst_pad_link (newpad, connect->target);
55     gst_element_set_state (pipeline, GST_STATE_PLAYING);
56
57     seekable_pads = g_list_prepend (seekable_pads, newpad);
58     rate_pads = g_list_prepend (rate_pads, newpad);
59   }
60 }
61
62 static void
63 setup_dynamic_link (GstElement *element, const gchar *padname, GstPad *target, GstElement *bin)
64 {
65   dyn_link *connect;
66
67   connect = g_new0 (dyn_link, 1);
68   connect->padname      = g_strdup (padname);
69   connect->target       = target;
70   connect->bin          = bin;
71
72   g_signal_connect (G_OBJECT (element), "new_pad", G_CALLBACK (dynamic_link), connect);
73 }
74
75 static GstElement*
76 make_mod_pipeline (const gchar *location) 
77 {
78   GstElement *pipeline;
79   GstElement *src, *decoder, *audiosink;
80   GstPad *seekable;
81   
82   pipeline = gst_pipeline_new ("app");
83
84   src = gst_element_factory_make_or_warn (SOURCE, "src");
85   decoder = gst_element_factory_make_or_warn ("modplug", "decoder");
86   audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
87   //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
88
89   g_object_set (G_OBJECT (src), "location", location, NULL);
90
91   gst_bin_add (GST_BIN (pipeline), src);
92   gst_bin_add (GST_BIN (pipeline), decoder);
93   gst_bin_add (GST_BIN (pipeline), audiosink);
94
95   gst_element_link (src, decoder);
96   gst_element_link (decoder, audiosink);
97
98   seekable = gst_element_get_pad (decoder, "src");
99   seekable_pads = g_list_prepend (seekable_pads, seekable);
100   rate_pads = g_list_prepend (rate_pads, seekable);
101   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
102
103   return pipeline;
104 }
105
106 static GstElement*
107 make_dv_pipeline (const gchar *location) 
108 {
109   GstElement *pipeline;
110   GstElement *src, *decoder, *audiosink, *videosink;
111   GstPad *seekable;
112   
113   pipeline = gst_pipeline_new ("app");
114
115   src = gst_element_factory_make_or_warn (SOURCE, "src");
116   decoder = gst_element_factory_make_or_warn ("dvdec", "decoder");
117   videosink = gst_element_factory_make_or_warn ("xvideosink", "v_sink");
118   audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
119   //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
120
121   g_object_set (G_OBJECT (src), "location", location, NULL);
122
123   gst_bin_add (GST_BIN (pipeline), src);
124   gst_bin_add (GST_BIN (pipeline), decoder);
125   gst_bin_add (GST_BIN (pipeline), audiosink);
126   gst_bin_add (GST_BIN (pipeline), videosink);
127
128   gst_element_link (src, decoder);
129   gst_element_link (decoder, audiosink);
130   gst_element_link (decoder, videosink);
131
132   seekable = gst_element_get_pad (decoder, "video");
133   seekable_pads = g_list_prepend (seekable_pads, seekable);
134   rate_pads = g_list_prepend (rate_pads, seekable);
135   seekable = gst_element_get_pad (decoder, "audio");
136   seekable_pads = g_list_prepend (seekable_pads, seekable);
137   rate_pads = g_list_prepend (rate_pads, seekable);
138   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
139
140   return pipeline;
141 }
142
143 static GstElement*
144 make_wav_pipeline (const gchar *location) 
145 {
146   GstElement *pipeline;
147   GstElement *src, *decoder, *audiosink;
148   GstPad *seekable;
149   
150   pipeline = gst_pipeline_new ("app");
151
152   src = gst_element_factory_make_or_warn (SOURCE, "src");
153   decoder = gst_element_factory_make_or_warn ("wavparse", "decoder");
154   audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
155   //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
156
157   g_object_set (G_OBJECT (src), "location", location, NULL);
158
159   gst_bin_add (GST_BIN (pipeline), src);
160   gst_bin_add (GST_BIN (pipeline), decoder);
161   gst_bin_add (GST_BIN (pipeline), audiosink);
162
163   gst_element_link (src, decoder);
164   gst_element_link (decoder, audiosink);
165
166   seekable = gst_element_get_pad (decoder, "src");
167   seekable_pads = g_list_prepend (seekable_pads, seekable);
168   rate_pads = g_list_prepend (rate_pads, seekable);
169   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
170
171   return pipeline;
172 }
173
174 static GstElement*
175 make_flac_pipeline (const gchar *location) 
176 {
177   GstElement *pipeline;
178   GstElement *src, *decoder, *audiosink;
179   GstPad *seekable;
180   
181   pipeline = gst_pipeline_new ("app");
182
183   src = gst_element_factory_make_or_warn (SOURCE, "src");
184   decoder = gst_element_factory_make_or_warn ("flacdec", "decoder");
185   audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
186   g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
187
188   g_object_set (G_OBJECT (src), "location", location, NULL);
189
190   gst_bin_add (GST_BIN (pipeline), src);
191   gst_bin_add (GST_BIN (pipeline), decoder);
192   gst_bin_add (GST_BIN (pipeline), audiosink);
193
194   gst_element_link (src, decoder);
195   gst_element_link (decoder, audiosink);
196
197   seekable = gst_element_get_pad (decoder, "src");
198   seekable_pads = g_list_prepend (seekable_pads, seekable);
199   rate_pads = g_list_prepend (rate_pads, seekable);
200   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
201
202   return pipeline;
203 }
204
205 static GstElement*
206 make_sid_pipeline (const gchar *location) 
207 {
208   GstElement *pipeline;
209   GstElement *src, *decoder, *audiosink;
210   GstPad *seekable;
211   
212   pipeline = gst_pipeline_new ("app");
213
214   src = gst_element_factory_make_or_warn (SOURCE, "src");
215   decoder = gst_element_factory_make_or_warn ("siddec", "decoder");
216   audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
217   //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
218
219   g_object_set (G_OBJECT (src), "location", location, NULL);
220
221   gst_bin_add (GST_BIN (pipeline), src);
222   gst_bin_add (GST_BIN (pipeline), decoder);
223   gst_bin_add (GST_BIN (pipeline), audiosink);
224
225   gst_element_link (src, decoder);
226   gst_element_link (decoder, audiosink);
227
228   seekable = gst_element_get_pad (decoder, "src");
229   seekable_pads = g_list_prepend (seekable_pads, seekable);
230   rate_pads = g_list_prepend (rate_pads, seekable);
231   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
232
233   return pipeline;
234 }
235
236 static GstElement*
237 make_parse_pipeline (const gchar *location) 
238 {
239   GstElement *pipeline;
240   GstElement *src, *parser, *fakesink;
241   GstPad *seekable;
242   
243   pipeline = gst_pipeline_new ("app");
244
245   src = gst_element_factory_make_or_warn (SOURCE, "src");
246   parser = gst_element_factory_make_or_warn ("mpegparse", "parse");
247   fakesink = gst_element_factory_make_or_warn ("fakesink", "sink");
248   g_object_set (G_OBJECT (fakesink), "silent", TRUE, NULL);
249   g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
250
251   g_object_set (G_OBJECT (src), "location", location, NULL);
252
253   gst_bin_add (GST_BIN (pipeline), src);
254   gst_bin_add (GST_BIN (pipeline), parser);
255   gst_bin_add (GST_BIN (pipeline), fakesink);
256
257   gst_element_link (src, parser);
258   gst_element_link (parser, fakesink);
259
260   seekable = gst_element_get_pad (parser, "src");
261   seekable_pads = g_list_prepend (seekable_pads, seekable);
262   rate_pads = g_list_prepend (rate_pads, seekable);
263   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (parser, "sink"));
264
265   return pipeline;
266 }
267
268 static GstElement*
269 make_vorbis_pipeline (const gchar *location) 
270 {
271   GstElement *pipeline;
272   GstElement *src, *decoder, *audiosink;
273   GstPad *seekable;
274   
275   pipeline = gst_pipeline_new ("app");
276
277   src = gst_element_factory_make_or_warn (SOURCE, "src");
278   decoder = gst_element_factory_make_or_warn ("vorbisfile", "decoder");
279   audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
280   g_object_set (G_OBJECT (audiosink), "sync", TRUE, NULL);
281
282   g_object_set (G_OBJECT (src), "location", location, NULL);
283
284   gst_bin_add (GST_BIN (pipeline), src);
285   gst_bin_add (GST_BIN (pipeline), decoder);
286   gst_bin_add (GST_BIN (pipeline), audiosink);
287
288   gst_element_link (src, decoder);
289   gst_element_link (decoder, audiosink);
290
291   seekable = gst_element_get_pad (decoder, "src");
292   seekable_pads = g_list_prepend (seekable_pads, seekable);
293   rate_pads = g_list_prepend (rate_pads, seekable);
294   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
295
296   return pipeline;
297 }
298
299 static GstElement*
300 make_mp3_pipeline (const gchar *location) 
301 {
302   GstElement *pipeline;
303   GstElement *src, *decoder, *osssink, *queue, *audio_thread;
304   GstPad *seekable;
305   
306   pipeline = gst_pipeline_new ("app");
307
308   src = gst_element_factory_make_or_warn (SOURCE, "src");
309   decoder = gst_element_factory_make_or_warn ("mad", "dec");
310   queue = gst_element_factory_make_or_warn ("queue", "queue");
311   osssink = gst_element_factory_make_or_warn ("osssink", "sink");
312
313   audio_thread = gst_thread_new ("a_decoder_thread");
314
315   seekable_elements = g_list_prepend (seekable_elements, osssink);
316
317   g_object_set (G_OBJECT (src), "location", location, NULL);
318   g_object_set (G_OBJECT (osssink), "fragment", 0x00180008, NULL);
319
320   gst_bin_add (GST_BIN (pipeline), src);
321   gst_bin_add (GST_BIN (pipeline), decoder);
322   gst_bin_add (GST_BIN (audio_thread), queue);
323   gst_bin_add (GST_BIN (audio_thread), osssink);
324   gst_bin_add (GST_BIN (pipeline), audio_thread);
325
326   gst_element_link (src, decoder);
327   gst_element_link (decoder, queue);
328   gst_element_link (queue, osssink);
329
330   seekable = gst_element_get_pad (queue, "src");
331   seekable_pads = g_list_prepend (seekable_pads, seekable);
332   rate_pads = g_list_prepend (rate_pads, seekable);
333   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
334
335   return pipeline;
336 }
337
338 static GstElement*
339 make_avi_pipeline (const gchar *location) 
340 {
341   GstElement *pipeline, *audio_bin, *video_bin;
342   GstElement *src, *demux, *a_decoder, *v_decoder, *audiosink, *videosink;
343   GstElement *a_queue = NULL, *audio_thread = NULL, *v_queue = NULL, *video_thread = NULL;
344   GstPad *seekable;
345   
346   pipeline = gst_pipeline_new ("app");
347
348   src = gst_element_factory_make_or_warn (SOURCE, "src");
349   g_object_set (G_OBJECT (src), "location", location, NULL);
350
351   demux = gst_element_factory_make_or_warn ("avidemux", "demux");
352   seekable_elements = g_list_prepend (seekable_elements, demux);
353
354   gst_bin_add (GST_BIN (pipeline), src);
355   gst_bin_add (GST_BIN (pipeline), demux);
356   gst_element_link (src, demux);
357
358   audio_bin = gst_bin_new ("a_decoder_bin");
359   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
360   audio_thread = gst_thread_new ("a_decoder_thread");
361   audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
362   //g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
363   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
364   gst_element_link (a_decoder, a_queue);
365   gst_element_link (a_queue, audiosink);
366   gst_bin_add (GST_BIN (audio_bin), a_decoder);
367   gst_bin_add (GST_BIN (audio_bin), audio_thread);
368   gst_bin_add (GST_BIN (audio_thread), a_queue);
369   gst_bin_add (GST_BIN (audio_thread), audiosink);
370   gst_element_set_state (audio_bin, GST_STATE_PAUSED);
371
372   setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder, "sink"), audio_bin);
373
374   seekable = gst_element_get_pad (a_queue, "src");
375   seekable_pads = g_list_prepend (seekable_pads, seekable);
376   rate_pads = g_list_prepend (rate_pads, seekable);
377   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
378
379   video_bin = gst_bin_new ("v_decoder_bin");
380   //v_decoder = gst_element_factory_make_or_warn ("identity", "v_dec");
381   //v_decoder = gst_element_factory_make_or_warn ("windec", "v_dec");
382   v_decoder = gst_element_factory_make_or_warn ("ffmpegdecall", "v_dec");
383   video_thread = gst_thread_new ("v_decoder_thread");
384   videosink = gst_element_factory_make_or_warn ("xvideosink", "v_sink");
385   //videosink = gst_element_factory_make_or_warn ("fakesink", "v_sink");
386   //g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL);
387   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
388   //g_object_set (G_OBJECT (v_queue), "max_level", 10, NULL);
389   gst_element_link (v_decoder, v_queue);
390   gst_element_link (v_queue, videosink);
391   gst_bin_add (GST_BIN (video_bin), v_decoder);
392   gst_bin_add (GST_BIN (video_bin), video_thread);
393   gst_bin_add (GST_BIN (video_thread), v_queue);
394   gst_bin_add (GST_BIN (video_thread), videosink);
395
396   gst_element_set_state (video_bin, GST_STATE_PAUSED);
397
398   setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder, "sink"), video_bin);
399
400   seekable = gst_element_get_pad (v_queue, "src");
401   seekable_pads = g_list_prepend (seekable_pads, seekable);
402   rate_pads = g_list_prepend (rate_pads, seekable);
403   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (v_decoder, "sink"));
404
405   return pipeline;
406 }
407
408 static GstElement*
409 make_mpeg_pipeline (const gchar *location) 
410 {
411   GstElement *pipeline, *audio_bin, *video_bin;
412   GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
413   GstElement *audiosink, *videosink;
414   GstElement *a_queue, *audio_thread, *v_queue, *video_thread;
415   GstPad *seekable;
416   
417   pipeline = gst_pipeline_new ("app");
418
419   src = gst_element_factory_make_or_warn (SOURCE, "src");
420   g_object_set (G_OBJECT (src), "location", location, NULL);
421
422   demux = gst_element_factory_make_or_warn ("mpegdemux", "demux");
423   g_object_set (G_OBJECT (demux), "sync", FALSE, NULL);
424
425   seekable_elements = g_list_prepend (seekable_elements, demux);
426
427   gst_bin_add (GST_BIN (pipeline), src);
428   gst_bin_add (GST_BIN (pipeline), demux);
429   gst_element_link (src, demux);
430
431   audio_bin = gst_bin_new ("a_decoder_bin");
432   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
433   audio_thread = gst_thread_new ("a_decoder_thread");
434   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
435   audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
436   g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
437   gst_element_link (a_decoder, a_queue);
438   gst_element_link (a_queue, audiosink);
439   gst_bin_add (GST_BIN (audio_bin), a_decoder);
440   gst_bin_add (GST_BIN (audio_bin), audio_thread);
441   gst_bin_add (GST_BIN (audio_thread), a_queue);
442   gst_bin_add (GST_BIN (audio_thread), audiosink);
443
444   setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder, "sink"), audio_bin);
445
446   seekable = gst_element_get_pad (a_queue, "src");
447   seekable_pads = g_list_prepend (seekable_pads, seekable);
448   rate_pads = g_list_prepend (rate_pads, seekable);
449   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
450
451   video_bin = gst_bin_new ("v_decoder_bin");
452   v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
453   video_thread = gst_thread_new ("v_decoder_thread");
454   //g_object_set (G_OBJECT (video_thread), "priority", 2, NULL);
455   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
456   v_filter = gst_element_factory_make_or_warn ("colorspace", "v_filter");
457   videosink = gst_element_factory_make_or_warn ("xvideosink", "v_sink");
458   gst_element_link_many (v_decoder, v_queue, v_filter, NULL);
459   
460   gst_element_link (v_filter, videosink);
461   gst_bin_add_many (GST_BIN (video_bin), v_decoder, video_thread, NULL);
462   gst_bin_add_many (GST_BIN (video_thread), v_queue, v_filter, videosink, NULL);
463
464   setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder, "sink"), video_bin);
465
466   seekable = gst_element_get_pad (v_queue, "src");
467   seekable_pads = g_list_prepend (seekable_pads, seekable);
468   rate_pads = g_list_prepend (rate_pads, seekable);
469   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (v_decoder, "sink"));
470
471   return pipeline;
472 }
473
474 static GstElement*
475 make_mpegnt_pipeline (const gchar *location) 
476 {
477   GstElement *pipeline, *audio_bin, *video_bin;
478   GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
479   GstElement *audiosink, *videosink;
480   GstElement *a_queue, *audio_thread;
481   GstPad *seekable;
482   
483   pipeline = gst_pipeline_new ("app");
484
485   src = gst_element_factory_make_or_warn (SOURCE, "src");
486   g_object_set (G_OBJECT (src), "location", location, NULL);
487
488   demux = gst_element_factory_make_or_warn ("mpegdemux", "demux");
489   //g_object_set (G_OBJECT (demux), "sync", TRUE, NULL);
490
491   seekable_elements = g_list_prepend (seekable_elements, demux);
492
493   gst_bin_add (GST_BIN (pipeline), src);
494   gst_bin_add (GST_BIN (pipeline), demux);
495   gst_element_link (src, demux);
496
497   audio_bin = gst_bin_new ("a_decoder_bin");
498   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
499   audio_thread = gst_thread_new ("a_decoder_thread");
500   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
501   audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
502   //g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
503   g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
504   gst_element_link (a_decoder, a_queue);
505   gst_element_link (a_queue, audiosink);
506   gst_bin_add (GST_BIN (audio_bin), a_decoder);
507   gst_bin_add (GST_BIN (audio_bin), audio_thread);
508   gst_bin_add (GST_BIN (audio_thread), a_queue);
509   gst_bin_add (GST_BIN (audio_thread), audiosink);
510
511   setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder, "sink"), audio_bin);
512
513   seekable = gst_element_get_pad (a_queue, "src");
514   seekable_pads = g_list_prepend (seekable_pads, seekable);
515   rate_pads = g_list_prepend (rate_pads, seekable);
516   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
517
518   video_bin = gst_bin_new ("v_decoder_bin");
519   v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
520   v_filter = gst_element_factory_make_or_warn ("colorspace", "v_filter");
521   videosink = gst_element_factory_make_or_warn ("xvideosink", "v_sink");
522   gst_element_link_many (v_decoder, v_filter, videosink, NULL);
523   
524   gst_bin_add_many (GST_BIN (video_bin), v_decoder, v_filter, videosink, NULL);
525
526   setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder, "sink"), video_bin);
527
528   seekable = gst_element_get_pad (v_decoder, "src");
529   seekable_pads = g_list_prepend (seekable_pads, seekable);
530   rate_pads = g_list_prepend (rate_pads, seekable);
531   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (v_decoder, "sink"));
532
533   return pipeline;
534 }
535
536 static GstElement*
537 make_playerbin_pipeline (const gchar *location) 
538 {
539   return NULL;
540 }
541
542 static gchar*
543 format_value (GtkScale *scale,
544               gdouble   value)
545 {
546   gint64 real;
547   gint64 seconds;
548   gint64 subseconds;
549
550   real = value * duration / 100;
551   seconds = (gint64) real / GST_SECOND;
552   subseconds = (gint64) real / (GST_SECOND / 100);
553
554   return g_strdup_printf ("%02lld:%02lld:%02lld",
555                           seconds/60, 
556                           seconds%60, 
557                           subseconds%100);
558 }
559
560 typedef struct
561 {
562   const gchar *name;
563   const GstFormat format;
564 } seek_format;
565
566 static seek_format seek_formats[] = 
567 {
568   { "tim",  GST_FORMAT_TIME    },
569   { "byt",  GST_FORMAT_BYTES   },
570   { "buf",  GST_FORMAT_BUFFERS },
571   { "def",  GST_FORMAT_DEFAULT },
572   { NULL, 0 }, 
573 };
574
575 G_GNUC_UNUSED static void
576 query_rates (void)
577 {
578   GList *walk = rate_pads;
579
580   while (walk) {
581     GstPad *pad = GST_PAD (walk->data);
582     gint i = 0;
583
584     g_print ("rate/sec  %8.8s: ", GST_PAD_NAME (pad));
585     while (seek_formats[i].name) {
586       gint64 value;
587       GstFormat format;
588
589       format = seek_formats[i].format;
590
591       if (gst_pad_convert (pad, GST_FORMAT_TIME, GST_SECOND, 
592                            &format, &value)) 
593       {
594         g_print ("%s %13lld | ", seek_formats[i].name, value);
595       }
596       else {
597         g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
598       }
599
600       i++;
601     }
602     g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
603
604     walk = g_list_next (walk);
605   }
606 }
607
608 G_GNUC_UNUSED static void
609 query_durations ()
610 {
611   GList *walk = seekable_pads;
612
613   while (walk) {
614     GstPad *pad = GST_PAD (walk->data);
615     gint i = 0;
616
617     g_print ("durations %8.8s: ", GST_PAD_NAME (pad));
618     while (seek_formats[i].name) {
619       gboolean res;
620       gint64 value;
621       GstFormat format;
622
623       format = seek_formats[i].format;
624       res = gst_pad_query (pad, GST_QUERY_TOTAL, &format, &value);
625       if (res) {
626         g_print ("%s %13lld | ", seek_formats[i].name, value);
627       }
628       else {
629         g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
630       }
631       i++;
632     }
633     g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
634   
635     walk = g_list_next (walk);
636   }
637 }
638
639 G_GNUC_UNUSED static void
640 query_positions ()
641 {
642   GList *walk = seekable_pads;
643
644   while (walk) {
645     GstPad *pad = GST_PAD (walk->data);
646     gint i = 0;
647
648     g_print ("positions %8.8s: ", GST_PAD_NAME (pad));
649     while (seek_formats[i].name) {
650       gboolean res;
651       gint64 value;
652       GstFormat format;
653
654       format = seek_formats[i].format;
655       res = gst_pad_query (pad, GST_QUERY_POSITION, &format, &value);
656       if (res) {
657         g_print ("%s %13lld | ", seek_formats[i].name, value);
658       }
659       else {
660         g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
661       }
662       i++;
663     }
664     g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
665
666     walk = g_list_next (walk);
667   }
668 }
669
670 static gboolean
671 update_scale (gpointer data) 
672 {
673   GstClock *clock;
674   guint64 position;
675   GstFormat format = GST_FORMAT_TIME;
676
677   duration = 0;
678   clock = gst_bin_get_clock (GST_BIN (pipeline));
679
680   if (seekable_pads) {
681     GstPad *pad = GST_PAD (seekable_pads->data);
682     gst_pad_query (pad, GST_QUERY_TOTAL, &format, &duration);
683   }
684   position = gst_clock_get_time (clock);
685
686   if (stats) {
687     g_print ("clock:                  %13llu  (%s)\n", position, gst_object_get_name (GST_OBJECT (clock)));
688     query_durations ();
689     query_positions ();
690     query_rates ();
691   }
692
693   if (duration > 0) {
694     gtk_adjustment_set_value (adjustment, position * 100.0 / duration);
695   }
696
697   return TRUE;
698 }
699
700 static gboolean
701 iterate (gpointer data)
702 {
703   gboolean res;
704
705   res = gst_bin_iterate (GST_BIN (data));
706   if (!res) {
707     gtk_timeout_remove (update_id);
708     g_print ("stopping iterations\n");
709   }
710   return res;
711 }
712
713 static gboolean
714 start_seek (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
715 {
716   gst_element_set_state (pipeline, GST_STATE_PAUSED);
717   gtk_timeout_remove (update_id);
718
719   return FALSE;
720 }
721
722 static gboolean
723 stop_seek (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
724 {
725   gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
726   gboolean res;
727   GstEvent *s_event;
728 #ifdef PAD_SEEK
729   GList *walk = seekable_pads;
730
731   while (walk) {
732     GstPad *seekable = GST_PAD (walk->data);
733
734     g_print ("seek to %lld on pad %s:%s\n", real, GST_DEBUG_PAD_NAME (seekable));
735     s_event = gst_event_new_seek (GST_FORMAT_TIME |
736                                   GST_SEEK_METHOD_SET |
737                                   GST_SEEK_FLAG_FLUSH, real);
738
739     res = gst_pad_send_event (seekable, s_event);
740
741     walk = g_list_next (walk);
742   }
743 #else
744   GList *walk = seekable_elements;
745
746   while (walk) {
747     GstElement *seekable = GST_ELEMENT (walk->data);
748
749     g_print ("seek to %lld on element %s\n", real, gst_element_get_name (seekable));
750     s_event = gst_event_new_seek (GST_FORMAT_TIME |
751                                   GST_SEEK_METHOD_SET |
752                                   GST_SEEK_FLAG_FLUSH, real);
753
754     res = gst_element_send_event (seekable, s_event);
755
756     walk = g_list_next (walk);
757   }
758 #endif
759
760   gst_element_set_state (pipeline, GST_STATE_PLAYING);
761   gtk_idle_add ((GtkFunction) iterate, pipeline);
762   update_id = gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
763
764   return FALSE;
765 }
766
767 static void
768 play_cb (GtkButton * button, gpointer data)
769 {
770   if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
771     gst_element_set_state (pipeline, GST_STATE_PLAYING);
772     gtk_idle_add ((GtkFunction) iterate, pipeline);
773     update_id = gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
774   }
775 }
776
777 static void
778 pause_cb (GtkButton * button, gpointer data)
779 {
780   if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
781     gst_element_set_state (pipeline, GST_STATE_PAUSED);
782     gtk_timeout_remove (update_id);
783   }
784 }
785
786 static void
787 stop_cb (GtkButton * button, gpointer data)
788 {
789   if (gst_element_get_state (pipeline) != GST_STATE_READY) {
790     gst_element_set_state (pipeline, GST_STATE_READY);
791     gtk_timeout_remove (update_id);
792   }
793 }
794
795 typedef struct
796 {
797   gchar *name;
798   GstElement* (*func) (const gchar *location);
799 } Pipeline;
800
801 static Pipeline pipelines[] = {
802   { "mp3",              make_mp3_pipeline       },
803   { "avi",              make_avi_pipeline       },
804   { "mpeg1",            make_mpeg_pipeline      },
805   { "mpegparse",        make_parse_pipeline     },
806   { "vorbis",           make_vorbis_pipeline    }, 
807   { "sid",              make_sid_pipeline       },
808   { "flac",             make_flac_pipeline      },
809   { "wav",              make_wav_pipeline       },
810   { "mod",              make_mod_pipeline       },
811   { "dv",               make_dv_pipeline        },
812   { "mpeg1nothreads",   make_mpegnt_pipeline    },
813   { "playerbin",        make_playerbin_pipeline },
814   { NULL, NULL},
815 };
816
817 #define NUM_TYPES       ((sizeof (pipelines) / sizeof (Pipeline)) - 1)
818
819 static void
820 print_usage (int argc, char **argv)
821 {
822   gint i;
823
824   g_print ("usage: %s <type> <filename>\n", argv[0]);
825   g_print ("   possible types:\n");
826
827   for (i = 0; i < NUM_TYPES; i++) {
828     g_print ("     %d = %s\n", i, pipelines[i].name);
829   }
830 }
831
832 int
833 main (int argc, char **argv)
834 {
835   GtkWidget *window, *hbox, *vbox, 
836             *play_button, *pause_button, *stop_button, 
837             *hscale;
838   struct poptOption options[] = {
839     { "stats",  's',  POPT_ARG_NONE|POPT_ARGFLAG_STRIP,   &stats,   0,
840            "Show pad stats", NULL },
841     POPT_TABLEEND
842   };
843   gint type;
844                 
845   gst_init_with_popt_table (&argc, &argv, options);
846   gtk_init (&argc, &argv);
847
848   if (argc != 3) {
849     print_usage (argc, argv);
850     exit (-1);
851   }
852
853   type = atoi (argv[1]);
854
855   if (type < 0 || type >= NUM_TYPES) {
856     print_usage (argc, argv);
857     exit (-1);
858   }
859
860   pipeline = pipelines[type].func (argv[2]);
861   g_assert (pipeline);
862
863   /* initialize gui elements ... */
864   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
865   hbox = gtk_hbox_new (FALSE, 0);
866   vbox = gtk_vbox_new (FALSE, 0);
867   play_button = gtk_button_new_with_label ("play");
868   pause_button = gtk_button_new_with_label ("pause");
869   stop_button = gtk_button_new_with_label ("stop");
870
871   adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
872   hscale = gtk_hscale_new (adjustment);
873   gtk_scale_set_digits (GTK_SCALE (hscale), 2);
874   gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
875
876   gtk_signal_connect(GTK_OBJECT(hscale),
877                              "button_press_event", G_CALLBACK (start_seek), pipeline);
878   gtk_signal_connect(GTK_OBJECT(hscale),
879                              "button_release_event", G_CALLBACK (stop_seek), pipeline);
880   gtk_signal_connect(GTK_OBJECT(hscale),
881                              "format_value", G_CALLBACK (format_value), pipeline);
882
883   /* do the packing stuff ... */
884   gtk_window_set_default_size (GTK_WINDOW (window), 96, 96);
885   gtk_container_add (GTK_CONTAINER (window), vbox);
886   gtk_container_add (GTK_CONTAINER (vbox), hbox);
887   gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
888   gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
889   gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
890   gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
891
892   /* connect things ... */
893   g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb), pipeline);
894   g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb), pipeline);
895   g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb), pipeline);
896   g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL);
897
898   /* show the gui. */
899   gtk_widget_show_all (window);
900
901   g_signal_connect (pipeline, "deep_notify", G_CALLBACK (gst_element_default_deep_notify), NULL);
902   g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error), NULL);
903
904   gtk_main ();
905
906   gst_element_set_state (pipeline, GST_STATE_NULL);
907
908   //gst_object_unref (GST_OBJECT (pipeline));
909
910   //g_mem_chunk_info();
911
912   return 0;
913 }