963c591e9e2b3e47b1c05925503e4e0172d3c514
[platform/upstream/gstreamer.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 GST_DEBUG_CATEGORY (seek_debug);
8 #define GST_CAT_DEFAULT (seek_debug)
9
10 static GList *seekable_pads = NULL;
11 static GList *rate_pads = NULL;
12 static GList *seekable_elements = NULL;
13
14 static GstElement *pipeline;
15 static gint64 position;
16 static gint64 duration;
17 static GtkAdjustment *adjustment;
18 static GtkWidget *hscale;
19 static gboolean stats = FALSE;
20 static gboolean elem_seek = FALSE;
21 static gboolean verbose = FALSE;
22
23 static GstState state;
24 static guint update_id = 0;
25 static guint seek_timeout_id = 0;
26 static gulong changed_id;
27
28 //#define SOURCE "filesrc"
29 #define SOURCE "gnomevfssrc"
30 #define ASINK "alsasink"
31 //#define ASINK "osssink"
32 #define VSINK "xvimagesink"
33 //#define VSINK "ximagesink"
34 //#define VSINK "aasink"
35 //#define VSINK "cacasink"
36
37 #define UPDATE_INTERVAL 500
38
39 /* number of milliseconds to play for after a seek */
40 //#define SCRUB_TIME 250
41 //#define SCRUB
42
43 #define THREAD
44 #define PAD_SEEK
45
46 typedef struct
47 {
48   const gchar *padname;
49   GstPad *target;
50   GstElement *bin;
51 }
52 dyn_link;
53
54 static GstElement *
55 gst_element_factory_make_or_warn (gchar * type, gchar * name)
56 {
57   GstElement *element = gst_element_factory_make (type, name);
58
59   if (!element) {
60     g_warning ("Failed to create element %s of type %s", name, type);
61   }
62
63   return element;
64 }
65
66 static void
67 dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer data)
68 {
69   dyn_link *connect = (dyn_link *) data;
70
71   if (connect->padname == NULL ||
72       !strcmp (gst_pad_get_name (newpad), connect->padname)) {
73     if (connect->bin)
74       gst_bin_add (GST_BIN (pipeline), connect->bin);
75     gst_pad_link (newpad, connect->target);
76
77     //seekable_pads = g_list_prepend (seekable_pads, newpad);
78     rate_pads = g_list_prepend (rate_pads, newpad);
79   }
80 }
81
82 static void
83 setup_dynamic_link (GstElement * element, const gchar * padname,
84     GstPad * target, GstElement * bin)
85 {
86   dyn_link *connect;
87
88   connect = g_new0 (dyn_link, 1);
89   connect->padname = g_strdup (padname);
90   connect->target = target;
91   connect->bin = bin;
92
93   g_signal_connect (G_OBJECT (element), "pad-added", G_CALLBACK (dynamic_link),
94       connect);
95 }
96
97 static GstElement *
98 make_mod_pipeline (const gchar * location)
99 {
100   GstElement *pipeline;
101   GstElement *src, *decoder, *audiosink;
102   GstPad *seekable;
103
104   pipeline = gst_pipeline_new ("app");
105
106   src = gst_element_factory_make_or_warn (SOURCE, "src");
107   decoder = gst_element_factory_make_or_warn ("modplug", "decoder");
108   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
109   //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
110
111   g_object_set (G_OBJECT (src), "location", location, NULL);
112
113   gst_bin_add (GST_BIN (pipeline), src);
114   gst_bin_add (GST_BIN (pipeline), decoder);
115   gst_bin_add (GST_BIN (pipeline), audiosink);
116
117   gst_element_link (src, decoder);
118   gst_element_link (decoder, audiosink);
119
120   seekable = gst_element_get_pad (decoder, "src");
121   seekable_pads = g_list_prepend (seekable_pads, seekable);
122   rate_pads = g_list_prepend (rate_pads, seekable);
123   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
124
125   return pipeline;
126 }
127
128 static GstElement *
129 make_dv_pipeline (const gchar * location)
130 {
131   GstElement *pipeline;
132   GstElement *src, *demux, *decoder, *audiosink, *videosink;
133   GstElement *a_queue, *v_queue;
134   GstPad *seekable;
135
136   pipeline = gst_pipeline_new ("app");
137
138   src = gst_element_factory_make_or_warn (SOURCE, "src");
139   demux = gst_element_factory_make_or_warn ("dvdemux", "demuxer");
140   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
141   decoder = gst_element_factory_make_or_warn ("ffdec_dvvideo", "decoder");
142   videosink = gst_element_factory_make_or_warn ("xvimagesink", "v_sink");
143   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
144   audiosink = gst_element_factory_make_or_warn ("alsasink", "a_sink");
145
146   g_object_set (G_OBJECT (src), "location", location, NULL);
147
148   gst_bin_add (GST_BIN (pipeline), src);
149   gst_bin_add (GST_BIN (pipeline), demux);
150   gst_bin_add (GST_BIN (pipeline), a_queue);
151   gst_bin_add (GST_BIN (pipeline), audiosink);
152   gst_bin_add (GST_BIN (pipeline), v_queue);
153   gst_bin_add (GST_BIN (pipeline), decoder);
154   gst_bin_add (GST_BIN (pipeline), videosink);
155
156   gst_element_link (src, demux);
157   gst_element_link (a_queue, audiosink);
158   gst_element_link (v_queue, decoder);
159   gst_element_link (decoder, videosink);
160
161   setup_dynamic_link (demux, "video", gst_element_get_pad (v_queue, "sink"),
162       NULL);
163   setup_dynamic_link (demux, "audio", gst_element_get_pad (a_queue, "sink"),
164       NULL);
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
170   return pipeline;
171 }
172
173 static GstElement *
174 make_wav_pipeline (const gchar * location)
175 {
176   GstElement *pipeline;
177   GstElement *src, *decoder, *audiosink;
178
179   pipeline = gst_pipeline_new ("app");
180
181   src = gst_element_factory_make_or_warn (SOURCE, "src");
182   decoder = gst_element_factory_make_or_warn ("wavparse", "decoder");
183   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
184
185   g_object_set (G_OBJECT (src), "location", location, NULL);
186
187   gst_bin_add (GST_BIN (pipeline), src);
188   gst_bin_add (GST_BIN (pipeline), decoder);
189   gst_bin_add (GST_BIN (pipeline), audiosink);
190
191   gst_element_link (src, decoder);
192
193   setup_dynamic_link (decoder, "src", gst_element_get_pad (audiosink, "sink"),
194       NULL);
195
196   seekable_elements = g_list_prepend (seekable_elements, audiosink);
197
198   /* force element seeking on this pipeline */
199   elem_seek = TRUE;
200
201   return pipeline;
202 }
203
204 static GstElement *
205 make_flac_pipeline (const gchar * location)
206 {
207   GstElement *pipeline;
208   GstElement *src, *decoder, *audiosink;
209   GstPad *seekable;
210
211   pipeline = gst_pipeline_new ("app");
212
213   src = gst_element_factory_make_or_warn (SOURCE, "src");
214   decoder = gst_element_factory_make_or_warn ("flacdec", "decoder");
215   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
216   g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
217
218   g_object_set (G_OBJECT (src), "location", location, NULL);
219
220   gst_bin_add (GST_BIN (pipeline), src);
221   gst_bin_add (GST_BIN (pipeline), decoder);
222   gst_bin_add (GST_BIN (pipeline), audiosink);
223
224   gst_element_link (src, decoder);
225   gst_element_link (decoder, audiosink);
226
227   seekable = gst_element_get_pad (decoder, "src");
228   seekable_pads = g_list_prepend (seekable_pads, seekable);
229   rate_pads = g_list_prepend (rate_pads, seekable);
230   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
231
232   return pipeline;
233 }
234
235 static GstElement *
236 make_sid_pipeline (const gchar * location)
237 {
238   GstElement *pipeline;
239   GstElement *src, *decoder, *audiosink;
240   GstPad *seekable;
241
242   pipeline = gst_pipeline_new ("app");
243
244   src = gst_element_factory_make_or_warn (SOURCE, "src");
245   decoder = gst_element_factory_make_or_warn ("siddec", "decoder");
246   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
247   //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
248
249   g_object_set (G_OBJECT (src), "location", location, NULL);
250
251   gst_bin_add (GST_BIN (pipeline), src);
252   gst_bin_add (GST_BIN (pipeline), decoder);
253   gst_bin_add (GST_BIN (pipeline), audiosink);
254
255   gst_element_link (src, decoder);
256   gst_element_link (decoder, audiosink);
257
258   seekable = gst_element_get_pad (decoder, "src");
259   seekable_pads = g_list_prepend (seekable_pads, seekable);
260   rate_pads = g_list_prepend (rate_pads, seekable);
261   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
262
263   return pipeline;
264 }
265
266 static GstElement *
267 make_parse_pipeline (const gchar * location)
268 {
269   GstElement *pipeline;
270   GstElement *src, *parser, *fakesink;
271   GstPad *seekable;
272
273   pipeline = gst_pipeline_new ("app");
274
275   src = gst_element_factory_make_or_warn (SOURCE, "src");
276   parser = gst_element_factory_make_or_warn ("mpegparse", "parse");
277   fakesink = gst_element_factory_make_or_warn ("fakesink", "sink");
278   g_object_set (G_OBJECT (fakesink), "silent", TRUE, NULL);
279   g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
280
281   g_object_set (G_OBJECT (src), "location", location, NULL);
282
283   gst_bin_add (GST_BIN (pipeline), src);
284   gst_bin_add (GST_BIN (pipeline), parser);
285   gst_bin_add (GST_BIN (pipeline), fakesink);
286
287   gst_element_link (src, parser);
288   gst_element_link (parser, fakesink);
289
290   seekable = gst_element_get_pad (parser, "src");
291   seekable_pads = g_list_prepend (seekable_pads, seekable);
292   rate_pads = g_list_prepend (rate_pads, seekable);
293   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (parser, "sink"));
294
295   return pipeline;
296 }
297
298 static GstElement *
299 make_vorbis_pipeline (const gchar * location)
300 {
301   GstElement *pipeline, *audio_bin;
302   GstElement *src, *demux, *decoder, *convert, *audiosink;
303   GstPad *pad, *seekable;
304
305   pipeline = gst_pipeline_new ("app");
306
307   src = gst_element_factory_make_or_warn (SOURCE, "src");
308   demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
309   decoder = gst_element_factory_make_or_warn ("vorbisdec", "decoder");
310   convert = gst_element_factory_make_or_warn ("audioconvert", "convert");
311   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
312   g_object_set (G_OBJECT (audiosink), "sync", TRUE, NULL);
313
314   g_object_set (G_OBJECT (src), "location", location, NULL);
315
316   audio_bin = gst_bin_new ("a_decoder_bin");
317
318   gst_bin_add (GST_BIN (pipeline), src);
319   gst_bin_add (GST_BIN (pipeline), demux);
320   gst_bin_add (GST_BIN (audio_bin), decoder);
321   gst_bin_add (GST_BIN (audio_bin), convert);
322   gst_bin_add (GST_BIN (audio_bin), audiosink);
323   gst_bin_add (GST_BIN (pipeline), audio_bin);
324
325   gst_element_link (src, demux);
326   gst_element_link (decoder, convert);
327   gst_element_link (convert, audiosink);
328
329   pad = gst_element_get_pad (decoder, "sink");
330   gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
331   gst_object_unref (pad);
332
333   setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
334       NULL);
335
336   seekable = gst_element_get_pad (decoder, "src");
337   seekable_pads = g_list_prepend (seekable_pads, seekable);
338   rate_pads = g_list_prepend (rate_pads, seekable);
339   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
340
341   return pipeline;
342 }
343
344 static GstElement *
345 make_theora_pipeline (const gchar * location)
346 {
347   GstElement *pipeline, *video_bin;
348   GstElement *src, *demux, *decoder, *convert, *videosink;
349   GstPad *pad, *seekable;
350
351   pipeline = gst_pipeline_new ("app");
352
353   src = gst_element_factory_make_or_warn (SOURCE, "src");
354   demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
355   decoder = gst_element_factory_make_or_warn ("theoradec", "decoder");
356   convert = gst_element_factory_make_or_warn ("ffmpegcolorspace", "convert");
357   videosink = gst_element_factory_make_or_warn (VSINK, "sink");
358
359   g_object_set (G_OBJECT (src), "location", location, NULL);
360
361   video_bin = gst_bin_new ("v_decoder_bin");
362
363   gst_bin_add (GST_BIN (pipeline), src);
364   gst_bin_add (GST_BIN (pipeline), demux);
365   gst_bin_add (GST_BIN (video_bin), decoder);
366   gst_bin_add (GST_BIN (video_bin), convert);
367   gst_bin_add (GST_BIN (video_bin), videosink);
368   gst_bin_add (GST_BIN (pipeline), video_bin);
369
370   gst_element_link (src, demux);
371   gst_element_link (decoder, convert);
372   gst_element_link (convert, videosink);
373
374   pad = gst_element_get_pad (decoder, "sink");
375   gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
376   gst_object_unref (pad);
377
378   setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
379       NULL);
380
381   seekable = gst_element_get_pad (decoder, "src");
382   seekable_pads = g_list_prepend (seekable_pads, seekable);
383   rate_pads = g_list_prepend (rate_pads, seekable);
384   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
385
386   return pipeline;
387 }
388
389 static GstElement *
390 make_vorbis_theora_pipeline (const gchar * location)
391 {
392   GstElement *pipeline, *audio_bin, *video_bin;
393   GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
394   GstElement *audiosink, *videosink;
395   GstElement *a_queue, *v_queue;
396   GstPad *seekable;
397   GstPad *pad;
398
399   pipeline = gst_pipeline_new ("app");
400
401   src = gst_element_factory_make_or_warn (SOURCE, "src");
402   g_object_set (G_OBJECT (src), "location", location, NULL);
403
404   demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
405
406   gst_bin_add (GST_BIN (pipeline), src);
407   gst_bin_add (GST_BIN (pipeline), demux);
408   gst_element_link (src, demux);
409
410   audio_bin = gst_bin_new ("a_decoder_bin");
411   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
412   a_decoder = gst_element_factory_make_or_warn ("vorbisdec", "a_dec");
413   a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
414   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
415
416   gst_bin_add (GST_BIN (pipeline), audio_bin);
417
418   gst_bin_add (GST_BIN (audio_bin), a_queue);
419   gst_bin_add (GST_BIN (audio_bin), a_decoder);
420   gst_bin_add (GST_BIN (audio_bin), a_convert);
421   gst_bin_add (GST_BIN (audio_bin), audiosink);
422
423   gst_element_link (a_queue, a_decoder);
424   gst_element_link (a_decoder, a_convert);
425   gst_element_link (a_convert, audiosink);
426
427   pad = gst_element_get_pad (a_queue, "sink");
428   gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
429   gst_object_unref (pad);
430
431   setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
432       NULL);
433
434   video_bin = gst_bin_new ("v_decoder_bin");
435   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
436   v_decoder = gst_element_factory_make_or_warn ("theoradec", "v_dec");
437   v_convert =
438       gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
439   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
440
441   gst_bin_add (GST_BIN (pipeline), video_bin);
442
443   gst_bin_add (GST_BIN (video_bin), v_queue);
444   gst_bin_add (GST_BIN (video_bin), v_decoder);
445   gst_bin_add (GST_BIN (video_bin), v_convert);
446   gst_bin_add (GST_BIN (video_bin), videosink);
447
448   gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
449
450   pad = gst_element_get_pad (v_queue, "sink");
451   gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
452   gst_object_unref (pad);
453
454   setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
455       NULL);
456
457   seekable = gst_element_get_pad (a_decoder, "src");
458   seekable_pads = g_list_prepend (seekable_pads, seekable);
459   rate_pads = g_list_prepend (rate_pads, seekable);
460   rate_pads =
461       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
462
463   return pipeline;
464 }
465
466 static GstElement *
467 make_avi_msmpeg4v3_mp3_pipeline (const gchar * location)
468 {
469   GstElement *pipeline, *audio_bin, *video_bin;
470   GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
471   GstElement *audiosink, *videosink;
472   GstElement *a_queue, *v_queue;
473   GstPad *seekable, *pad;
474
475   pipeline = gst_pipeline_new ("app");
476
477   src = gst_element_factory_make_or_warn (SOURCE, "src");
478   g_object_set (G_OBJECT (src), "location", location, NULL);
479
480   demux = gst_element_factory_make_or_warn ("avidemux", "demux");
481
482   gst_bin_add (GST_BIN (pipeline), src);
483   gst_bin_add (GST_BIN (pipeline), demux);
484   gst_element_link (src, demux);
485
486   audio_bin = gst_bin_new ("a_decoder_bin");
487   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
488   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
489   a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
490   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
491
492   gst_bin_add (GST_BIN (audio_bin), a_queue);
493   gst_bin_add (GST_BIN (audio_bin), a_decoder);
494   gst_bin_add (GST_BIN (audio_bin), a_convert);
495   gst_bin_add (GST_BIN (audio_bin), audiosink);
496
497   gst_element_link (a_queue, a_decoder);
498   gst_element_link (a_decoder, a_convert);
499   gst_element_link (a_convert, audiosink);
500
501   gst_bin_add (GST_BIN (pipeline), audio_bin);
502
503   pad = gst_element_get_pad (a_queue, "sink");
504   gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
505   gst_object_unref (pad);
506
507   setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
508       NULL);
509
510   video_bin = gst_bin_new ("v_decoder_bin");
511   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
512   v_decoder = gst_element_factory_make_or_warn ("ffdec_msmpeg4", "v_dec");
513   v_convert =
514       gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
515   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
516
517   gst_bin_add (GST_BIN (video_bin), v_queue);
518   gst_bin_add (GST_BIN (video_bin), v_decoder);
519   gst_bin_add (GST_BIN (video_bin), v_convert);
520   gst_bin_add (GST_BIN (video_bin), videosink);
521
522   gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
523
524   gst_bin_add (GST_BIN (pipeline), video_bin);
525
526   pad = gst_element_get_pad (v_queue, "sink");
527   gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
528   gst_object_unref (pad);
529
530   setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
531       NULL);
532
533   seekable = gst_element_get_pad (a_decoder, "src");
534   seekable_pads = g_list_prepend (seekable_pads, seekable);
535   rate_pads = g_list_prepend (rate_pads, seekable);
536   rate_pads =
537       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
538
539   return pipeline;
540 }
541
542 static GstElement *
543 make_mp3_pipeline (const gchar * location)
544 {
545   GstElement *pipeline;
546   GstElement *src, *decoder, *osssink, *queue;
547   GstPad *seekable;
548
549   pipeline = gst_pipeline_new ("app");
550
551   src = gst_element_factory_make_or_warn (SOURCE, "src");
552   decoder = gst_element_factory_make_or_warn ("mad", "dec");
553   queue = gst_element_factory_make_or_warn ("queue", "queue");
554   osssink = gst_element_factory_make_or_warn (ASINK, "sink");
555
556   seekable_elements = g_list_prepend (seekable_elements, osssink);
557
558   g_object_set (G_OBJECT (src), "location", location, NULL);
559   //g_object_set (G_OBJECT (osssink), "fragment", 0x00180008, NULL);
560
561   gst_bin_add (GST_BIN (pipeline), src);
562   gst_bin_add (GST_BIN (pipeline), decoder);
563   gst_bin_add (GST_BIN (pipeline), queue);
564   gst_bin_add (GST_BIN (pipeline), osssink);
565
566   gst_element_link (src, decoder);
567   gst_element_link (decoder, queue);
568   gst_element_link (queue, osssink);
569
570   seekable = gst_element_get_pad (queue, "src");
571   seekable_pads = g_list_prepend (seekable_pads, seekable);
572   rate_pads = g_list_prepend (rate_pads, seekable);
573   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
574
575   return pipeline;
576 }
577
578 static GstElement *
579 make_avi_pipeline (const gchar * location)
580 {
581   GstElement *pipeline, *audio_bin, *video_bin;
582   GstElement *src, *demux, *a_decoder, *v_decoder, *audiosink, *videosink;
583   GstElement *a_queue = NULL, *v_queue = NULL;
584   GstPad *seekable;
585
586   pipeline = gst_pipeline_new ("app");
587
588   src = gst_element_factory_make_or_warn (SOURCE, "src");
589   g_object_set (G_OBJECT (src), "location", location, NULL);
590
591   demux = gst_element_factory_make_or_warn ("avidemux", "demux");
592   seekable_elements = g_list_prepend (seekable_elements, demux);
593
594   gst_bin_add (GST_BIN (pipeline), src);
595   gst_bin_add (GST_BIN (pipeline), demux);
596   gst_element_link (src, demux);
597
598   audio_bin = gst_bin_new ("a_decoder_bin");
599   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
600   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
601   //g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
602   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
603   gst_element_link (a_decoder, a_queue);
604   gst_element_link (a_queue, audiosink);
605   gst_bin_add (GST_BIN (audio_bin), a_decoder);
606   gst_bin_add (GST_BIN (audio_bin), a_queue);
607   gst_bin_add (GST_BIN (audio_bin), audiosink);
608   gst_element_set_state (audio_bin, GST_STATE_PAUSED);
609
610   setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
611           "sink"), audio_bin);
612
613   seekable = gst_element_get_pad (a_queue, "src");
614   seekable_pads = g_list_prepend (seekable_pads, seekable);
615   rate_pads = g_list_prepend (rate_pads, seekable);
616   rate_pads =
617       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
618
619   video_bin = gst_bin_new ("v_decoder_bin");
620   //v_decoder = gst_element_factory_make_or_warn ("identity", "v_dec");
621   //v_decoder = gst_element_factory_make_or_warn ("windec", "v_dec");
622   v_decoder = gst_element_factory_make_or_warn ("ffmpegdecall", "v_dec");
623   videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
624   //videosink = gst_element_factory_make_or_warn ("fakesink", "v_sink");
625   //g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL);
626   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
627   //g_object_set (G_OBJECT (v_queue), "max_level", 10, NULL);
628   gst_element_link (v_decoder, v_queue);
629   gst_element_link (v_queue, videosink);
630   gst_bin_add (GST_BIN (video_bin), v_decoder);
631   gst_bin_add (GST_BIN (video_bin), v_queue);
632   gst_bin_add (GST_BIN (video_bin), videosink);
633
634   gst_element_set_state (video_bin, GST_STATE_PAUSED);
635
636   setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder,
637           "sink"), video_bin);
638
639   seekable = gst_element_get_pad (v_queue, "src");
640   seekable_pads = g_list_prepend (seekable_pads, seekable);
641   rate_pads = g_list_prepend (rate_pads, seekable);
642   rate_pads =
643       g_list_prepend (rate_pads, gst_element_get_pad (v_decoder, "sink"));
644
645   return pipeline;
646 }
647
648 static GstElement *
649 make_mpeg_pipeline (const gchar * location)
650 {
651   GstElement *pipeline, *audio_bin, *video_bin;
652   GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
653   GstElement *audiosink, *videosink;
654   GstElement *a_queue, *v_queue;
655   GstPad *seekable;
656
657   pipeline = gst_pipeline_new ("app");
658
659   src = gst_element_factory_make_or_warn (SOURCE, "src");
660   g_object_set (G_OBJECT (src), "location", location, NULL);
661
662   demux = gst_element_factory_make_or_warn ("mpegdemux", "demux");
663   g_object_set (G_OBJECT (demux), "sync", FALSE, NULL);
664
665   seekable_elements = g_list_prepend (seekable_elements, demux);
666
667   gst_bin_add (GST_BIN (pipeline), src);
668   gst_bin_add (GST_BIN (pipeline), demux);
669   gst_element_link (src, demux);
670
671   audio_bin = gst_bin_new ("a_decoder_bin");
672   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
673   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
674   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
675   //g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
676   gst_element_link (a_decoder, a_queue);
677   gst_element_link (a_queue, audiosink);
678   gst_bin_add (GST_BIN (audio_bin), a_decoder);
679   gst_bin_add (GST_BIN (audio_bin), a_queue);
680   gst_bin_add (GST_BIN (audio_bin), audiosink);
681
682   setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
683           "sink"), audio_bin);
684
685   seekable = gst_element_get_pad (a_queue, "src");
686   seekable_pads = g_list_prepend (seekable_pads, seekable);
687   rate_pads = g_list_prepend (rate_pads, seekable);
688   rate_pads =
689       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
690
691   video_bin = gst_bin_new ("v_decoder_bin");
692   v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
693   //g_object_set (G_OBJECT (video_thread), "priority", 2, NULL);
694   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
695   v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
696   videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
697   gst_element_link_many (v_decoder, v_queue, v_filter, NULL);
698
699   gst_element_link (v_filter, videosink);
700   gst_bin_add_many (GST_BIN (video_bin), v_decoder, NULL);
701   gst_bin_add_many (GST_BIN (video_bin), v_queue, v_filter, videosink, NULL);
702
703   setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder,
704           "sink"), video_bin);
705
706   seekable = gst_element_get_pad (v_queue, "src");
707   seekable_pads = g_list_prepend (seekable_pads, seekable);
708   rate_pads = g_list_prepend (rate_pads, seekable);
709   rate_pads =
710       g_list_prepend (rate_pads, gst_element_get_pad (v_decoder, "sink"));
711
712   return pipeline;
713 }
714
715 static GstElement *
716 make_mpegnt_pipeline (const gchar * location)
717 {
718   GstElement *pipeline, *audio_bin, *video_bin;
719   GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
720   GstElement *audiosink, *videosink;
721   GstElement *a_queue;
722   GstPad *seekable;
723
724   pipeline = gst_pipeline_new ("app");
725
726   src = gst_element_factory_make_or_warn (SOURCE, "src");
727   g_object_set (G_OBJECT (src), "location", location, NULL);
728
729   demux = gst_element_factory_make_or_warn ("mpegdemux", "demux");
730   //g_object_set (G_OBJECT (demux), "sync", TRUE, NULL);
731
732   seekable_elements = g_list_prepend (seekable_elements, demux);
733
734   gst_bin_add (GST_BIN (pipeline), src);
735   gst_bin_add (GST_BIN (pipeline), demux);
736   gst_element_link (src, demux);
737
738   audio_bin = gst_bin_new ("a_decoder_bin");
739   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
740   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
741   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
742   //g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
743   g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
744   gst_element_link (a_decoder, a_queue);
745   gst_element_link (a_queue, audiosink);
746   gst_bin_add (GST_BIN (audio_bin), a_decoder);
747   gst_bin_add (GST_BIN (audio_bin), a_queue);
748   gst_bin_add (GST_BIN (audio_bin), audiosink);
749
750   setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
751           "sink"), audio_bin);
752
753   seekable = gst_element_get_pad (a_queue, "src");
754   seekable_pads = g_list_prepend (seekable_pads, seekable);
755   rate_pads = g_list_prepend (rate_pads, seekable);
756   rate_pads =
757       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
758
759   video_bin = gst_bin_new ("v_decoder_bin");
760   v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
761   v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
762   videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
763   gst_element_link_many (v_decoder, v_filter, videosink, NULL);
764
765   gst_bin_add_many (GST_BIN (video_bin), v_decoder, v_filter, videosink, NULL);
766
767   setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder,
768           "sink"), video_bin);
769
770   seekable = gst_element_get_pad (v_decoder, "src");
771   seekable_pads = g_list_prepend (seekable_pads, seekable);
772   rate_pads = g_list_prepend (rate_pads, seekable);
773   rate_pads =
774       g_list_prepend (rate_pads, gst_element_get_pad (v_decoder, "sink"));
775
776   return pipeline;
777 }
778
779 static GstElement *
780 make_playerbin_pipeline (const gchar * location)
781 {
782   GstElement *player;
783
784   player = gst_element_factory_make ("playbin", "player");
785   g_assert (player);
786
787   g_object_set (G_OBJECT (player), "uri", location, NULL);
788
789   seekable_elements = g_list_prepend (seekable_elements, player);
790
791   /* force element seeking on this pipeline */
792   elem_seek = TRUE;
793
794   return player;
795 }
796
797 static gchar *
798 format_value (GtkScale * scale, gdouble value)
799 {
800   gint64 real;
801   gint64 seconds;
802   gint64 subseconds;
803
804   real = value * duration / 100;
805   seconds = (gint64) real / GST_SECOND;
806   subseconds = (gint64) real / (GST_SECOND / 100);
807
808   return g_strdup_printf ("%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ":%02"
809       G_GINT64_FORMAT, seconds / 60, seconds % 60, subseconds % 100);
810 }
811
812 typedef struct
813 {
814   const gchar *name;
815   const GstFormat format;
816 }
817 seek_format;
818
819 static seek_format seek_formats[] = {
820   {"tim", GST_FORMAT_TIME},
821   {"byt", GST_FORMAT_BYTES},
822   {"buf", GST_FORMAT_BUFFERS},
823   {"def", GST_FORMAT_DEFAULT},
824   {NULL, 0},
825 };
826
827 G_GNUC_UNUSED static void
828 query_rates (void)
829 {
830   GList *walk = rate_pads;
831
832   while (walk) {
833     GstPad *pad = GST_PAD (walk->data);
834     gint i = 0;
835
836     g_print ("rate/sec  %8.8s: ", GST_PAD_NAME (pad));
837     while (seek_formats[i].name) {
838       gint64 value;
839       GstFormat format;
840
841       format = seek_formats[i].format;
842
843       if (gst_pad_query_convert (pad, GST_FORMAT_TIME, GST_SECOND, &format,
844               &value)) {
845         g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
846       } else {
847         g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
848       }
849
850       i++;
851     }
852     g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
853
854     walk = g_list_next (walk);
855   }
856 }
857
858 G_GNUC_UNUSED static void
859 query_positions_elems ()
860 {
861   GList *walk = seekable_elements;
862
863   while (walk) {
864     GstElement *element = GST_ELEMENT (walk->data);
865     gint i = 0;
866
867     g_print ("positions %8.8s: ", GST_ELEMENT_NAME (element));
868     while (seek_formats[i].name) {
869       gint64 position, total;
870       GstFormat format;
871
872       format = seek_formats[i].format;
873
874       if (gst_element_query_position (element, &format, &position, &total)) {
875         g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ",
876             seek_formats[i].name, position, total);
877       } else {
878         g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*",
879             "*NA*");
880       }
881       i++;
882     }
883     g_print (" %s\n", GST_ELEMENT_NAME (element));
884
885     walk = g_list_next (walk);
886   }
887 }
888
889 G_GNUC_UNUSED static void
890 query_positions_pads ()
891 {
892   GList *walk = seekable_pads;
893
894   while (walk) {
895     GstPad *pad = GST_PAD (walk->data);
896     gint i = 0;
897
898     g_print ("positions %8.8s: ", GST_PAD_NAME (pad));
899     while (seek_formats[i].name) {
900       GstFormat format;
901       gint64 position, total;
902
903       format = seek_formats[i].format;
904
905       if (gst_pad_query_position (pad, &format, &position, &total)) {
906         g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ",
907             seek_formats[i].name, position, total);
908       } else {
909         g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*",
910             "*NA*");
911       }
912
913       i++;
914     }
915     g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
916
917     walk = g_list_next (walk);
918   }
919 }
920
921 static gboolean
922 update_scale (gpointer data)
923 {
924   GstFormat format;
925
926   position = 0;
927   duration = 0;
928
929   format = GST_FORMAT_TIME;
930
931   if (elem_seek) {
932     if (seekable_elements) {
933       GstElement *element = GST_ELEMENT (seekable_elements->data);
934
935       gst_element_query_position (element, &format, &position, &duration);
936     }
937   } else {
938     if (seekable_pads) {
939       GstPad *pad = GST_PAD (seekable_pads->data);
940
941       gst_pad_query_position (pad, &format, &position, &duration);
942     }
943   }
944
945   if (stats) {
946     if (elem_seek) {
947       query_positions_elems ();
948     } else {
949       query_positions_pads ();
950     }
951     query_rates ();
952   }
953   if (position >= duration)
954     duration = position;
955
956   if (duration > 0) {
957     gtk_adjustment_set_value (adjustment, position * 100.0 / duration);
958     gtk_widget_queue_draw (hscale);
959   }
960
961   return TRUE;
962 }
963
964 static void do_seek (GtkWidget * widget);
965
966 #ifdef SCRUB
967 static gboolean
968 end_scrub (GtkWidget * widget)
969 {
970   gst_element_set_state (pipeline, GST_STATE_PAUSED);
971   seek_timeout_id = 0;
972
973   return FALSE;
974 }
975 #endif
976
977 static void
978 do_seek (GtkWidget * widget)
979 {
980   gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
981   gboolean res = FALSE;
982   GstEvent *s_event;
983
984   if (!elem_seek) {
985     GList *walk = seekable_pads;
986
987     while (walk) {
988       GstPad *seekable = GST_PAD (walk->data);
989
990       GST_DEBUG ("seek to %" GST_TIME_FORMAT " on pad %s:%s",
991           GST_TIME_ARGS (real), GST_DEBUG_PAD_NAME (seekable));
992
993       s_event = gst_event_new_seek (1.0,
994           GST_FORMAT_TIME,
995           GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, real, GST_SEEK_TYPE_NONE, 0);
996
997       res = gst_pad_send_event (seekable, s_event);
998
999       walk = g_list_next (walk);
1000     }
1001   } else {
1002     GList *walk = seekable_elements;
1003
1004     while (walk) {
1005       GstElement *seekable = GST_ELEMENT (walk->data);
1006
1007       GST_DEBUG ("seek to %" GST_TIME_FORMAT " on element %s",
1008           GST_TIME_ARGS (real), GST_ELEMENT_NAME (seekable));
1009
1010       s_event = gst_event_new_seek (1.0,
1011           GST_FORMAT_TIME,
1012           GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, real, GST_SEEK_TYPE_NONE, 0);
1013
1014       res = gst_element_send_event (seekable, s_event);
1015
1016       walk = g_list_next (walk);
1017     }
1018   }
1019
1020   if (res) {
1021     GTimeVal tv;
1022
1023     gst_pipeline_set_new_stream_time (GST_PIPELINE (pipeline), 0);
1024     GST_TIME_TO_TIMEVAL (100 * GST_MSECOND, tv);
1025     gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, &tv);
1026   } else
1027     g_print ("seek failed\n");
1028 }
1029
1030 static void
1031 seek_cb (GtkWidget * widget)
1032 {
1033 #ifdef SCRUB
1034   /* If the timer hasn't expired yet, then the pipeline is running */
1035   if (seek_timeout_id != 0) {
1036     gst_element_set_state (pipeline, GST_STATE_PAUSED);
1037   }
1038 #endif
1039
1040   do_seek (widget);
1041
1042 #ifdef SCRUB
1043   gst_element_set_state (pipeline, GST_STATE_PLAYING);
1044
1045   if (seek_timeout_id == 0) {
1046     seek_timeout_id =
1047         g_timeout_add (SCRUB_TIME, (GSourceFunc) end_scrub, widget);
1048   }
1049 #endif
1050 }
1051
1052 static void
1053 set_update_scale (gboolean active)
1054 {
1055   if (active) {
1056     if (update_id == 0) {
1057       update_id =
1058           g_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
1059     }
1060   } else {
1061     if (update_id) {
1062       g_source_remove (update_id);
1063       update_id = 0;
1064     }
1065   }
1066 }
1067
1068 static gboolean
1069 start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
1070 {
1071   if (state == GST_STATE_PLAYING)
1072     gst_element_set_state (pipeline, GST_STATE_PAUSED);
1073
1074   set_update_scale (FALSE);
1075
1076   if (changed_id == 0) {
1077     changed_id = gtk_signal_connect (GTK_OBJECT (hscale),
1078         "value_changed", G_CALLBACK (seek_cb), pipeline);
1079   }
1080
1081   return FALSE;
1082 }
1083
1084 static gboolean
1085 stop_seek (GtkWidget * widget, gpointer user_data)
1086 {
1087   g_signal_handler_disconnect (GTK_OBJECT (hscale), changed_id);
1088   changed_id = 0;
1089   if (seek_timeout_id != 0) {
1090     g_source_remove (seek_timeout_id);
1091     seek_timeout_id = 0;
1092     /* Still scrubbing, so the pipeline is already playing */
1093   } else {
1094     if (state == GST_STATE_PLAYING)
1095       gst_element_set_state (pipeline, GST_STATE_PLAYING);
1096   }
1097
1098   set_update_scale (TRUE);
1099
1100   return FALSE;
1101 }
1102
1103 static void
1104 play_cb (GtkButton * button, gpointer data)
1105 {
1106   GstStateChangeReturn ret;
1107
1108   if (state != GST_STATE_PLAYING) {
1109     g_print ("PLAY pipeline\n");
1110     ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
1111     if (ret == GST_STATE_CHANGE_FAILURE)
1112       goto failed;
1113
1114     set_update_scale (TRUE);
1115     state = GST_STATE_PLAYING;
1116   }
1117   return;
1118
1119 failed:
1120   {
1121     g_print ("PLAY failed\n");
1122   }
1123 }
1124
1125 static void
1126 pause_cb (GtkButton * button, gpointer data)
1127 {
1128   GstStateChangeReturn ret;
1129
1130   if (state != GST_STATE_PAUSED) {
1131     g_print ("PAUSE pipeline\n");
1132     ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
1133     if (ret == GST_STATE_CHANGE_FAILURE)
1134       goto failed;
1135
1136     set_update_scale (FALSE);
1137     state = GST_STATE_PAUSED;
1138   }
1139   return;
1140
1141 failed:
1142   {
1143     g_print ("PAUSE failed\n");
1144   }
1145 }
1146
1147 static void
1148 stop_cb (GtkButton * button, gpointer data)
1149 {
1150   GstStateChangeReturn ret;
1151
1152   if (state != GST_STATE_READY) {
1153     g_print ("READY pipeline\n");
1154     ret = gst_element_set_state (pipeline, GST_STATE_READY);
1155     if (ret == GST_STATE_CHANGE_FAILURE)
1156       goto failed;
1157
1158     gtk_adjustment_set_value (adjustment, 0.0);
1159     set_update_scale (FALSE);
1160
1161     state = GST_STATE_READY;
1162   }
1163   return;
1164
1165 failed:
1166   {
1167     g_print ("READY failed\n");
1168   }
1169 }
1170
1171 static void
1172 message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
1173 {
1174   const GstStructure *s;
1175
1176   s = gst_message_get_structure (message);
1177   g_print ("message from \"%s\" (%s): ",
1178       GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))),
1179       gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
1180   if (s) {
1181     gchar *sstr;
1182
1183     sstr = gst_structure_to_string (s);
1184     g_print ("%s\n", sstr);
1185     g_free (sstr);
1186   } else {
1187     g_print ("no message details\n");
1188   }
1189 }
1190
1191
1192 typedef struct
1193 {
1194   gchar *name;
1195   GstElement *(*func) (const gchar * location);
1196 }
1197 Pipeline;
1198
1199 static Pipeline pipelines[] = {
1200   {"mp3", make_mp3_pipeline},
1201   {"avi", make_avi_pipeline},
1202   {"mpeg1", make_mpeg_pipeline},
1203   {"mpegparse", make_parse_pipeline},
1204   {"vorbis", make_vorbis_pipeline},
1205   {"theora", make_theora_pipeline},
1206   {"ogg/v/t", make_vorbis_theora_pipeline},
1207   {"avi/msmpeg4v3/mp3", make_avi_msmpeg4v3_mp3_pipeline},
1208   {"sid", make_sid_pipeline},
1209   {"flac", make_flac_pipeline},
1210   {"wav", make_wav_pipeline},
1211   {"mod", make_mod_pipeline},
1212   {"dv", make_dv_pipeline},
1213   {"mpeg1nothreads", make_mpegnt_pipeline},
1214   {"playerbin", make_playerbin_pipeline},
1215   {NULL, NULL},
1216 };
1217
1218 #define NUM_TYPES       ((sizeof (pipelines) / sizeof (Pipeline)) - 1)
1219
1220 static void
1221 print_usage (int argc, char **argv)
1222 {
1223   gint i;
1224
1225   g_print ("usage: %s <type> <filename>\n", argv[0]);
1226   g_print ("   possible types:\n");
1227
1228   for (i = 0; i < NUM_TYPES; i++) {
1229     g_print ("     %d = %s\n", i, pipelines[i].name);
1230   }
1231 }
1232
1233 int
1234 main (int argc, char **argv)
1235 {
1236   GtkWidget *window, *hbox, *vbox, *play_button, *pause_button, *stop_button;
1237   GOptionEntry options[] = {
1238     {"stats", 's', 0, G_OPTION_ARG_NONE, &stats,
1239         "Show pad stats", NULL},
1240     {"elem", 'e', 0, G_OPTION_ARG_NONE, &elem_seek,
1241         "Seek on elements instead of pads", NULL},
1242     {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
1243         "Verbose properties", NULL},
1244     {NULL}
1245   };
1246   gint type;
1247   GOptionContext *ctx;
1248   GError *err = NULL;
1249
1250   ctx = g_option_context_new ("seek");
1251   g_option_context_add_main_entries (ctx, options, NULL);
1252   g_option_context_add_group (ctx, gst_init_get_option_group ());
1253
1254   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
1255     g_print ("Error initializing: %s\n", err->message);
1256     exit (1);
1257   }
1258
1259   GST_DEBUG_CATEGORY_INIT (seek_debug, "seek", 0, "seek example");
1260
1261   gtk_init (&argc, &argv);
1262
1263   if (argc != 3) {
1264     print_usage (argc, argv);
1265     exit (-1);
1266   }
1267
1268   type = atoi (argv[1]);
1269
1270   if (type < 0 || type >= NUM_TYPES) {
1271     print_usage (argc, argv);
1272     exit (-1);
1273   }
1274
1275   pipeline = pipelines[type].func (argv[2]);
1276   g_assert (pipeline);
1277
1278   /* initialize gui elements ... */
1279   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1280   hbox = gtk_hbox_new (FALSE, 0);
1281   vbox = gtk_vbox_new (FALSE, 0);
1282   play_button = gtk_button_new_with_label ("play");
1283   pause_button = gtk_button_new_with_label ("pause");
1284   stop_button = gtk_button_new_with_label ("stop");
1285
1286   adjustment =
1287       GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
1288   hscale = gtk_hscale_new (adjustment);
1289   gtk_scale_set_digits (GTK_SCALE (hscale), 2);
1290   gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
1291
1292   gtk_signal_connect (GTK_OBJECT (hscale),
1293       "button_press_event", G_CALLBACK (start_seek), pipeline);
1294   gtk_signal_connect (GTK_OBJECT (hscale),
1295       "button_release_event", G_CALLBACK (stop_seek), pipeline);
1296   gtk_signal_connect (GTK_OBJECT (hscale),
1297       "format_value", G_CALLBACK (format_value), pipeline);
1298
1299   /* do the packing stuff ... */
1300   gtk_window_set_default_size (GTK_WINDOW (window), 250, 96);
1301   gtk_container_add (GTK_CONTAINER (window), vbox);
1302   gtk_container_add (GTK_CONTAINER (vbox), hbox);
1303   gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
1304   gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
1305   gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
1306   gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
1307
1308   /* connect things ... */
1309   g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
1310       pipeline);
1311   g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb),
1312       pipeline);
1313   g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb),
1314       pipeline);
1315   g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL);
1316
1317   /* show the gui. */
1318   gtk_widget_show_all (window);
1319
1320   if (verbose) {
1321     g_signal_connect (pipeline, "deep_notify",
1322         G_CALLBACK (gst_object_default_deep_notify), NULL);
1323   }
1324   {
1325     GstBus *bus;
1326
1327     bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
1328     gst_bus_add_signal_watch (bus);
1329
1330 //    g_signal_connect (bus, "message::state-changed", (GCallback) message_received, pipeline);
1331     g_signal_connect (bus, "message::new-clock", (GCallback) message_received,
1332         pipeline);
1333     g_signal_connect (bus, "message::error", (GCallback) message_received,
1334         pipeline);
1335     g_signal_connect (bus, "message::warning", (GCallback) message_received,
1336         pipeline);
1337     g_signal_connect (bus, "message::eos", (GCallback) message_received,
1338         pipeline);
1339   }
1340   gtk_main ();
1341
1342   g_print ("NULL pipeline\n");
1343   gst_element_set_state (pipeline, GST_STATE_NULL);
1344
1345   g_print ("free pipeline\n");
1346   gst_object_unref (pipeline);
1347
1348   return 0;
1349 }