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