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