a21aac166acf07b0b4be875e8e1e39cbc077c63f
[platform/upstream/gst-plugins-good.git] / examples / seeking / spider_seek.c
1 #include <stdlib.h>
2 #include <glib.h>
3 #include <gtk/gtk.h>
4 #include <gst/gst.h>
5 #include <string.h>
6
7 static GList *rate_pads = NULL;
8 static GList *seekable_elements = NULL;
9
10 static GstElement *pipeline;
11 static GtkAdjustment *adjustment;
12 static gboolean stats = FALSE;
13 static guint64 duration;
14
15 static guint update_id;
16
17 //#define SOURCE "gnomevfssrc"
18 #define SOURCE "filesrc"
19
20 #define UPDATE_INTERVAL 500
21
22 static GstElement*
23 make_spider_pipeline (const gchar *location, gboolean thread) 
24 {
25   GstElement *pipeline;
26   GstElement *src, *decoder, *audiosink, *videosink, *a_thread, *v_thread, *a_queue, *v_queue;
27   
28   if (thread) {
29     pipeline = gst_thread_new ("app");
30   }
31   else {
32     pipeline = gst_pipeline_new ("app");
33   }
34   
35
36   src = gst_element_factory_make (SOURCE, "src");
37   decoder = gst_element_factory_make ("spider", "decoder");
38   a_thread = gst_thread_new ("a_thread");
39   a_queue = gst_element_factory_make ("queue", "a_queue");
40   audiosink = gst_element_factory_make ("osssink", "a_sink");
41   //g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
42
43   v_thread = gst_thread_new ("v_thread");
44   v_queue = gst_element_factory_make ("queue", "v_queue");
45   videosink = gst_element_factory_make ("xvideosink", "v_sink");
46   //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
47
48   g_object_set (G_OBJECT (src), "location", location, NULL);
49
50   gst_bin_add (GST_BIN (pipeline), src);
51   gst_bin_add (GST_BIN (pipeline), decoder);
52   gst_bin_add (GST_BIN (a_thread), a_queue);
53   gst_bin_add (GST_BIN (a_thread), audiosink);
54   gst_bin_add (GST_BIN (v_thread), v_queue);
55   gst_bin_add (GST_BIN (v_thread), videosink);
56   gst_bin_add (GST_BIN (pipeline), a_thread);
57   gst_bin_add (GST_BIN (pipeline), v_thread);
58
59   gst_element_link (src, decoder);
60   gst_element_link (v_queue, videosink);
61   gst_element_link (decoder, v_queue);
62   gst_element_link (a_queue, audiosink);
63   gst_element_link (decoder, a_queue);
64
65   seekable_elements = g_list_prepend (seekable_elements, videosink);
66   seekable_elements = g_list_prepend (seekable_elements, audiosink);
67   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (audiosink, "sink"));
68   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (videosink, "sink"));
69
70   return pipeline;
71 }
72
73 static gchar*
74 format_value (GtkScale *scale,
75               gdouble   value)
76 {
77   gint64 real;
78   gint64 seconds;
79   gint64 subseconds;
80
81   real = value * duration / 100;
82   seconds = (gint64) real / GST_SECOND;
83   subseconds = (gint64) real / (GST_SECOND / 100);
84
85   return g_strdup_printf ("%02lld:%02lld:%02lld",
86                           seconds/60, 
87                           seconds%60, 
88                           subseconds%100);
89 }
90
91 typedef struct
92 {
93   const gchar *name;
94   const GstFormat format;
95 } seek_format;
96
97 static seek_format seek_formats[] = 
98 {
99   { "tim",  GST_FORMAT_TIME    },
100   { "byt",  GST_FORMAT_BYTES   },
101   { "buf",  GST_FORMAT_BUFFERS },
102   { "def",  GST_FORMAT_DEFAULT },
103   { NULL, 0 }, 
104 };
105
106 G_GNUC_UNUSED static void
107 query_rates (void)
108 {
109   GList *walk = rate_pads;
110
111   while (walk) {
112     GstPad *pad = GST_PAD (walk->data);
113     gint i = 0;
114
115     g_print ("rate/sec  %8.8s: ", GST_PAD_NAME (pad));
116     while (seek_formats[i].name) {
117       gint64 value;
118       GstFormat format;
119
120       format = seek_formats[i].format;
121
122       if (gst_pad_convert (pad, GST_FORMAT_TIME, GST_SECOND, 
123                            &format, &value)) 
124       {
125         g_print ("%s %13lld | ", seek_formats[i].name, value);
126       }
127       else {
128         g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
129       }
130
131       i++;
132     }
133     g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
134
135     walk = g_list_next (walk);
136   }
137 }
138
139 G_GNUC_UNUSED static void
140 query_durations ()
141 {
142   GList *walk = seekable_elements;
143
144   while (walk) {
145     GstElement *element = GST_ELEMENT (walk->data);
146     gint i = 0;
147
148     g_print ("durations %8.8s: ", GST_ELEMENT_NAME (element));
149     while (seek_formats[i].name) {
150       gboolean res;
151       gint64 value;
152       GstFormat format;
153
154       format = seek_formats[i].format;
155       res = gst_element_query (element, GST_QUERY_TOTAL, &format, &value);
156       if (res) {
157         g_print ("%s %13lld | ", seek_formats[i].name, value);
158       }
159       else {
160         g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
161       }
162       i++;
163     }
164     g_print (" %s\n", GST_ELEMENT_NAME (element));
165     walk = g_list_next (walk);
166   }
167 }
168
169 G_GNUC_UNUSED static void
170 query_positions ()
171 {
172   GList *walk = seekable_elements;
173
174   while (walk) {
175     GstElement *element = GST_ELEMENT (walk->data);
176     gint i = 0;
177
178     g_print ("positions %8.8s: ", GST_ELEMENT_NAME (element));
179     while (seek_formats[i].name) {
180       gboolean res;
181       gint64 value;
182       GstFormat format;
183
184       format = seek_formats[i].format;
185       res = gst_element_query (element, GST_QUERY_POSITION, &format, &value);
186       if (res) {
187         g_print ("%s %13lld | ", seek_formats[i].name, value);
188       }
189       else {
190         g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
191       }
192       i++;
193     }
194     g_print (" %s\n", GST_ELEMENT_NAME (element));
195     walk = g_list_next (walk);
196   }
197 }
198
199 static gboolean
200 update_scale (gpointer data) 
201 {
202   GstClock *clock;
203   guint64 position;
204   GstFormat format = GST_FORMAT_TIME;
205
206   duration = 0;
207   clock = gst_bin_get_clock (GST_BIN (pipeline));
208
209   if (seekable_elements) {
210     GstElement *element = GST_ELEMENT (seekable_elements->data);
211     gst_element_query (element, GST_QUERY_TOTAL, &format, &duration);
212   }
213   position = gst_clock_get_time (clock);
214
215   if (stats) {
216     g_print ("clock:                  %13llu  (%s)\n", position, gst_object_get_name (GST_OBJECT (clock)));
217     query_durations ();
218     query_positions ();
219     query_rates ();
220   }
221   if (duration > 0) {
222     gtk_adjustment_set_value (adjustment, position * 100.0 / duration);
223   }
224
225   return TRUE;
226 }
227
228 static gboolean
229 iterate (gpointer data)
230 {
231   gboolean res = TRUE;
232
233   res = gst_bin_iterate (GST_BIN (data));
234   if (!res) {
235     gtk_timeout_remove (update_id);
236     g_print ("stopping iterations\n");
237   }
238   return res;
239 }
240
241 static gboolean
242 start_seek (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
243 {
244   gst_element_set_state (pipeline, GST_STATE_PAUSED);
245   gtk_timeout_remove (update_id);
246
247   return FALSE;
248 }
249
250 static gboolean
251 stop_seek (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
252 {
253   gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
254   gboolean res;
255   GstEvent *s_event;
256   GList *walk = seekable_elements;
257
258   while (walk) {
259     GstElement *seekable = GST_ELEMENT (walk->data);
260
261     g_print ("seek to %lld on element %s\n", real, GST_ELEMENT_NAME (seekable));
262     s_event = gst_event_new_seek (GST_FORMAT_TIME |
263                                   GST_SEEK_METHOD_SET |
264                                   GST_SEEK_FLAG_FLUSH, real);
265
266     res = gst_element_send_event (seekable, s_event);
267
268     walk = g_list_next (walk);
269   }
270
271   gst_element_set_state (pipeline, GST_STATE_PLAYING);
272   if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
273     gtk_idle_add ((GtkFunction) iterate, pipeline);
274   update_id = gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
275
276   return FALSE;
277 }
278
279 static void
280 play_cb (GtkButton * button, gpointer data)
281 {
282   if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
283     gst_element_set_state (pipeline, GST_STATE_PLAYING);
284     if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
285       gtk_idle_add ((GtkFunction) iterate, pipeline);
286     update_id = gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
287   }
288 }
289
290 static void
291 pause_cb (GtkButton * button, gpointer data)
292 {
293   if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
294     gst_element_set_state (pipeline, GST_STATE_PAUSED);
295     gtk_timeout_remove (update_id);
296   }
297 }
298
299 static void
300 stop_cb (GtkButton * button, gpointer data)
301 {
302   if (gst_element_get_state (pipeline) != GST_STATE_READY) {
303     gst_element_set_state (pipeline, GST_STATE_READY);
304     gtk_timeout_remove (update_id);
305   }
306 }
307
308 int
309 main (int argc, char **argv)
310 {
311   GtkWidget *window, *hbox, *vbox, 
312             *play_button, *pause_button, *stop_button, 
313             *hscale;
314   gboolean threaded = FALSE;
315   struct poptOption options[] = {
316     {"threaded",  't',  POPT_ARG_NONE|POPT_ARGFLAG_STRIP,   &threaded,   0,
317          "Run the pipeline in a toplevel thread", NULL},
318     {"stats",  's',  POPT_ARG_NONE|POPT_ARGFLAG_STRIP,   &stats,   0,
319          "Show element stats", NULL},
320      POPT_TABLEEND
321     };
322
323   gst_init_with_popt_table (&argc, &argv, options);
324   gtk_init (&argc, &argv);
325
326   if (argc != 2) {
327     g_print ("usage: %s <filename>\n", argv[0]);
328     exit (-1);
329   }
330
331   pipeline = make_spider_pipeline (argv[1], threaded);
332
333   /* initialize gui elements ... */
334   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
335   hbox = gtk_hbox_new (FALSE, 0);
336   vbox = gtk_vbox_new (FALSE, 0);
337   play_button = gtk_button_new_with_label ("play");
338   pause_button = gtk_button_new_with_label ("pause");
339   stop_button = gtk_button_new_with_label ("stop");
340
341   adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
342   hscale = gtk_hscale_new (adjustment);
343   gtk_scale_set_digits (GTK_SCALE (hscale), 2);
344   gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
345
346   gtk_signal_connect(GTK_OBJECT(hscale),
347                              "button_press_event", G_CALLBACK (start_seek), pipeline);
348   gtk_signal_connect(GTK_OBJECT(hscale),
349                              "button_release_event", G_CALLBACK (stop_seek), pipeline);
350   gtk_signal_connect(GTK_OBJECT(hscale),
351                              "format_value", G_CALLBACK (format_value), pipeline);
352
353   /* do the packing stuff ... */
354   gtk_window_set_default_size (GTK_WINDOW (window), 96, 96);
355   gtk_container_add (GTK_CONTAINER (window), vbox);
356   gtk_container_add (GTK_CONTAINER (vbox), hbox);
357   gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
358   gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
359   gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
360   gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
361
362   /* connect things ... */
363   g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb), pipeline);
364   g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb), pipeline);
365   g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb), pipeline);
366   g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL);
367
368   /* show the gui. */
369   gtk_widget_show_all (window);
370
371   gtk_main ();
372
373   return 0;
374 }