Update for _get_state() API change.
[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     gst_pipeline_set_new_stream_time (GST_PIPELINE (pipeline), 0);
1022     gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL,
1023         100 * GST_MSECOND);
1024   } else
1025     g_print ("seek failed\n");
1026 }
1027
1028 static void
1029 seek_cb (GtkWidget * widget)
1030 {
1031 #ifdef SCRUB
1032   /* If the timer hasn't expired yet, then the pipeline is running */
1033   if (seek_timeout_id != 0) {
1034     gst_element_set_state (pipeline, GST_STATE_PAUSED);
1035   }
1036 #endif
1037
1038   do_seek (widget);
1039
1040 #ifdef SCRUB
1041   gst_element_set_state (pipeline, GST_STATE_PLAYING);
1042
1043   if (seek_timeout_id == 0) {
1044     seek_timeout_id =
1045         g_timeout_add (SCRUB_TIME, (GSourceFunc) end_scrub, widget);
1046   }
1047 #endif
1048 }
1049
1050 static void
1051 set_update_scale (gboolean active)
1052 {
1053   if (active) {
1054     if (update_id == 0) {
1055       update_id =
1056           g_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
1057     }
1058   } else {
1059     if (update_id) {
1060       g_source_remove (update_id);
1061       update_id = 0;
1062     }
1063   }
1064 }
1065
1066 static gboolean
1067 start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
1068 {
1069   if (state == GST_STATE_PLAYING)
1070     gst_element_set_state (pipeline, GST_STATE_PAUSED);
1071
1072   set_update_scale (FALSE);
1073
1074   if (changed_id == 0) {
1075     changed_id = gtk_signal_connect (GTK_OBJECT (hscale),
1076         "value_changed", G_CALLBACK (seek_cb), pipeline);
1077   }
1078
1079   return FALSE;
1080 }
1081
1082 static gboolean
1083 stop_seek (GtkWidget * widget, gpointer user_data)
1084 {
1085   g_signal_handler_disconnect (GTK_OBJECT (hscale), changed_id);
1086   changed_id = 0;
1087   if (seek_timeout_id != 0) {
1088     g_source_remove (seek_timeout_id);
1089     seek_timeout_id = 0;
1090     /* Still scrubbing, so the pipeline is already playing */
1091   } else {
1092     if (state == GST_STATE_PLAYING)
1093       gst_element_set_state (pipeline, GST_STATE_PLAYING);
1094   }
1095
1096   set_update_scale (TRUE);
1097
1098   return FALSE;
1099 }
1100
1101 static void
1102 play_cb (GtkButton * button, gpointer data)
1103 {
1104   GstStateChangeReturn ret;
1105
1106   if (state != GST_STATE_PLAYING) {
1107     g_print ("PLAY pipeline\n");
1108     ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
1109     if (ret == GST_STATE_CHANGE_FAILURE)
1110       goto failed;
1111
1112     set_update_scale (TRUE);
1113     state = GST_STATE_PLAYING;
1114   }
1115   return;
1116
1117 failed:
1118   {
1119     g_print ("PLAY failed\n");
1120   }
1121 }
1122
1123 static void
1124 pause_cb (GtkButton * button, gpointer data)
1125 {
1126   GstStateChangeReturn ret;
1127
1128   if (state != GST_STATE_PAUSED) {
1129     g_print ("PAUSE pipeline\n");
1130     ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
1131     if (ret == GST_STATE_CHANGE_FAILURE)
1132       goto failed;
1133
1134     set_update_scale (FALSE);
1135     state = GST_STATE_PAUSED;
1136   }
1137   return;
1138
1139 failed:
1140   {
1141     g_print ("PAUSE failed\n");
1142   }
1143 }
1144
1145 static void
1146 stop_cb (GtkButton * button, gpointer data)
1147 {
1148   GstStateChangeReturn ret;
1149
1150   if (state != GST_STATE_READY) {
1151     g_print ("READY pipeline\n");
1152     ret = gst_element_set_state (pipeline, GST_STATE_READY);
1153     if (ret == GST_STATE_CHANGE_FAILURE)
1154       goto failed;
1155
1156     gtk_adjustment_set_value (adjustment, 0.0);
1157     set_update_scale (FALSE);
1158
1159     state = GST_STATE_READY;
1160   }
1161   return;
1162
1163 failed:
1164   {
1165     g_print ("READY failed\n");
1166   }
1167 }
1168
1169 static void
1170 message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
1171 {
1172   const GstStructure *s;
1173
1174   s = gst_message_get_structure (message);
1175   g_print ("message from \"%s\" (%s): ",
1176       GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))),
1177       gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
1178   if (s) {
1179     gchar *sstr;
1180
1181     sstr = gst_structure_to_string (s);
1182     g_print ("%s\n", sstr);
1183     g_free (sstr);
1184   } else {
1185     g_print ("no message details\n");
1186   }
1187 }
1188
1189
1190 typedef struct
1191 {
1192   gchar *name;
1193   GstElement *(*func) (const gchar * location);
1194 }
1195 Pipeline;
1196
1197 static Pipeline pipelines[] = {
1198   {"mp3", make_mp3_pipeline},
1199   {"avi", make_avi_pipeline},
1200   {"mpeg1", make_mpeg_pipeline},
1201   {"mpegparse", make_parse_pipeline},
1202   {"vorbis", make_vorbis_pipeline},
1203   {"theora", make_theora_pipeline},
1204   {"ogg/v/t", make_vorbis_theora_pipeline},
1205   {"avi/msmpeg4v3/mp3", make_avi_msmpeg4v3_mp3_pipeline},
1206   {"sid", make_sid_pipeline},
1207   {"flac", make_flac_pipeline},
1208   {"wav", make_wav_pipeline},
1209   {"mod", make_mod_pipeline},
1210   {"dv", make_dv_pipeline},
1211   {"mpeg1nothreads", make_mpegnt_pipeline},
1212   {"playerbin", make_playerbin_pipeline},
1213   {NULL, NULL},
1214 };
1215
1216 #define NUM_TYPES       ((sizeof (pipelines) / sizeof (Pipeline)) - 1)
1217
1218 static void
1219 print_usage (int argc, char **argv)
1220 {
1221   gint i;
1222
1223   g_print ("usage: %s <type> <filename>\n", argv[0]);
1224   g_print ("   possible types:\n");
1225
1226   for (i = 0; i < NUM_TYPES; i++) {
1227     g_print ("     %d = %s\n", i, pipelines[i].name);
1228   }
1229 }
1230
1231 int
1232 main (int argc, char **argv)
1233 {
1234   GtkWidget *window, *hbox, *vbox, *play_button, *pause_button, *stop_button;
1235   GOptionEntry options[] = {
1236     {"stats", 's', 0, G_OPTION_ARG_NONE, &stats,
1237         "Show pad stats", NULL},
1238     {"elem", 'e', 0, G_OPTION_ARG_NONE, &elem_seek,
1239         "Seek on elements instead of pads", NULL},
1240     {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
1241         "Verbose properties", NULL},
1242     {NULL}
1243   };
1244   gint type;
1245   GOptionContext *ctx;
1246   GError *err = NULL;
1247
1248   ctx = g_option_context_new ("seek");
1249   g_option_context_add_main_entries (ctx, options, NULL);
1250   g_option_context_add_group (ctx, gst_init_get_option_group ());
1251
1252   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
1253     g_print ("Error initializing: %s\n", err->message);
1254     exit (1);
1255   }
1256
1257   GST_DEBUG_CATEGORY_INIT (seek_debug, "seek", 0, "seek example");
1258
1259   gtk_init (&argc, &argv);
1260
1261   if (argc != 3) {
1262     print_usage (argc, argv);
1263     exit (-1);
1264   }
1265
1266   type = atoi (argv[1]);
1267
1268   if (type < 0 || type >= NUM_TYPES) {
1269     print_usage (argc, argv);
1270     exit (-1);
1271   }
1272
1273   pipeline = pipelines[type].func (argv[2]);
1274   g_assert (pipeline);
1275
1276   /* initialize gui elements ... */
1277   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1278   hbox = gtk_hbox_new (FALSE, 0);
1279   vbox = gtk_vbox_new (FALSE, 0);
1280   play_button = gtk_button_new_with_label ("play");
1281   pause_button = gtk_button_new_with_label ("pause");
1282   stop_button = gtk_button_new_with_label ("stop");
1283
1284   adjustment =
1285       GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
1286   hscale = gtk_hscale_new (adjustment);
1287   gtk_scale_set_digits (GTK_SCALE (hscale), 2);
1288   gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
1289
1290   gtk_signal_connect (GTK_OBJECT (hscale),
1291       "button_press_event", G_CALLBACK (start_seek), pipeline);
1292   gtk_signal_connect (GTK_OBJECT (hscale),
1293       "button_release_event", G_CALLBACK (stop_seek), pipeline);
1294   gtk_signal_connect (GTK_OBJECT (hscale),
1295       "format_value", G_CALLBACK (format_value), pipeline);
1296
1297   /* do the packing stuff ... */
1298   gtk_window_set_default_size (GTK_WINDOW (window), 250, 96);
1299   gtk_container_add (GTK_CONTAINER (window), vbox);
1300   gtk_container_add (GTK_CONTAINER (vbox), hbox);
1301   gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
1302   gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
1303   gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
1304   gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
1305
1306   /* connect things ... */
1307   g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
1308       pipeline);
1309   g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb),
1310       pipeline);
1311   g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb),
1312       pipeline);
1313   g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL);
1314
1315   /* show the gui. */
1316   gtk_widget_show_all (window);
1317
1318   if (verbose) {
1319     g_signal_connect (pipeline, "deep_notify",
1320         G_CALLBACK (gst_object_default_deep_notify), NULL);
1321   }
1322   {
1323     GstBus *bus;
1324
1325     bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
1326     gst_bus_add_signal_watch (bus);
1327
1328 //    g_signal_connect (bus, "message::state-changed", (GCallback) message_received, pipeline);
1329     g_signal_connect (bus, "message::new-clock", (GCallback) message_received,
1330         pipeline);
1331     g_signal_connect (bus, "message::error", (GCallback) message_received,
1332         pipeline);
1333     g_signal_connect (bus, "message::warning", (GCallback) message_received,
1334         pipeline);
1335     g_signal_connect (bus, "message::eos", (GCallback) message_received,
1336         pipeline);
1337   }
1338   gtk_main ();
1339
1340   g_print ("NULL pipeline\n");
1341   gst_element_set_state (pipeline, GST_STATE_NULL);
1342
1343   g_print ("free pipeline\n");
1344   gst_object_unref (pipeline);
1345
1346   return 0;
1347 }