6ce5547157524fa3a0b3f7588a3619d9fd4b8e7b
[platform/upstream/gst-plugins-good.git] / examples / seeking / cdplayer.c
1 #include <stdlib.h>
2 #include <glib.h>
3 #include <gtk/gtk.h>
4 #include <gst/gst.h>
5 #include <string.h>
6
7 static GList *seekable_elements = NULL;
8
9 static GstElement *pipeline;
10 static GtkAdjustment *adjustment;
11 static gboolean stats = FALSE;
12 static guint64 duration;
13
14 static guint update_id;
15
16 #define UPDATE_INTERVAL 500
17
18 static GstElement*
19 make_cdaudio_pipeline (void) 
20 {
21   GstElement *cdaudio;
22   
23   cdaudio = gst_element_factory_make ("cdaudio", "cdaudio");
24   g_assert (cdaudio != NULL);
25
26   seekable_elements = g_list_prepend (seekable_elements, cdaudio);
27
28   return cdaudio;
29 }
30
31 static gchar*
32 format_value (GtkScale *scale,
33               gdouble   value)
34 {
35   gint64 real;
36   gint64 seconds;
37   gint64 subseconds;
38
39   real = value * duration / 100;
40   seconds = (gint64) real / GST_SECOND;
41   subseconds = (gint64) real / (GST_SECOND / 100);
42
43   return g_strdup_printf ("%02lld:%02lld:%02lld",
44                           seconds/60, 
45                           seconds%60, 
46                           subseconds%100);
47 }
48
49 typedef struct
50 {
51   const gchar *name;
52   const GstFormat format;
53 } seek_format;
54
55 static seek_format seek_formats[] = 
56 {
57   { "tim",  GST_FORMAT_TIME    },
58   { "byt",  GST_FORMAT_BYTES   },
59   { "buf",  GST_FORMAT_BUFFERS },
60   { "def",  GST_FORMAT_DEFAULT },
61   { NULL, 0 }, 
62 };
63
64
65 G_GNUC_UNUSED static void
66 query_durations ()
67 {
68   GList *walk = seekable_elements;
69
70   while (walk) {
71     GstElement *element = GST_ELEMENT (walk->data);
72     gint i = 0;
73
74     g_print ("durations %8.8s: ", GST_ELEMENT_NAME (element));
75     while (seek_formats[i].name) {
76       gboolean res;
77       gint64 value;
78       GstFormat format;
79
80       format = seek_formats[i].format;
81       res = gst_element_query (element, GST_QUERY_TOTAL, &format, &value);
82       if (res) {
83         g_print ("%s %13lld | ", seek_formats[i].name, value);
84       }
85       else {
86         g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
87       }
88       i++;
89     }
90     g_print (" %s\n", GST_ELEMENT_NAME (element));
91     walk = g_list_next (walk);
92   }
93 }
94
95 G_GNUC_UNUSED static void
96 query_positions ()
97 {
98   GList *walk = seekable_elements;
99
100   while (walk) {
101     GstElement *element = GST_ELEMENT (walk->data);
102     gint i = 0;
103
104     g_print ("positions %8.8s: ", GST_ELEMENT_NAME (element));
105     while (seek_formats[i].name) {
106       gboolean res;
107       gint64 value;
108       GstFormat format;
109
110       format = seek_formats[i].format;
111       res = gst_element_query (element, GST_QUERY_POSITION, &format, &value);
112       if (res) {
113         g_print ("%s %13lld | ", seek_formats[i].name, value);
114       }
115       else {
116         g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
117       }
118       i++;
119     }
120     g_print (" %s\n", GST_ELEMENT_NAME (element));
121     walk = g_list_next (walk);
122   }
123 }
124
125 static gboolean
126 update_scale (gpointer data) 
127 {
128   GstClock *clock;
129   guint64 position = 0;
130   GstFormat format = GST_FORMAT_TIME;
131
132   duration = 0;
133   clock = gst_bin_get_clock (GST_BIN (pipeline));
134
135   if (seekable_elements) {
136     GstElement *element = GST_ELEMENT (seekable_elements->data);
137     gst_element_query (element, GST_QUERY_TOTAL, &format, &duration);
138   }
139   if (clock)
140     position = gst_clock_get_time (clock);
141
142   if (stats) {
143     if (clock)
144       g_print ("clock:                  %13llu  (%s)\n", position, gst_object_get_name (GST_OBJECT (clock)));
145     query_durations ();
146     query_positions ();
147   }
148   if (duration > 0) {
149     gtk_adjustment_set_value (adjustment, position * 100.0 / duration);
150   }
151
152   return TRUE;
153 }
154
155 static gboolean
156 iterate (gpointer data)
157 {
158   gboolean res = TRUE;
159
160   g_print ("iterate\n");
161   res = gst_bin_iterate (GST_BIN (data));
162   if (!res) {
163     gtk_timeout_remove (update_id);
164     g_print ("stopping iterations\n");
165   }
166   return res;
167 }
168
169 static gboolean
170 start_seek (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
171 {
172   gst_element_set_state (pipeline, GST_STATE_PAUSED);
173   gtk_timeout_remove (update_id);
174
175   return FALSE;
176 }
177
178 static gboolean
179 stop_seek (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
180 {
181   gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
182   gboolean res;
183   GstEvent *s_event;
184   GList *walk = seekable_elements;
185
186   while (walk) {
187     GstElement *seekable = GST_ELEMENT (walk->data);
188
189     g_print ("seek to %lld on element %s\n", real, GST_ELEMENT_NAME (seekable));
190     s_event = gst_event_new_seek (GST_FORMAT_TIME |
191                                   GST_SEEK_METHOD_SET |
192                                   GST_SEEK_FLAG_FLUSH, real);
193
194     res = gst_element_send_event (seekable, s_event);
195
196     walk = g_list_next (walk);
197   }
198
199   gst_element_set_state (pipeline, GST_STATE_PLAYING);
200   if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
201     gtk_idle_add ((GtkFunction) iterate, pipeline);
202   update_id = gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
203
204   return FALSE;
205 }
206
207 static void
208 play_cb (GtkButton * button, gpointer data)
209 {
210   if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
211     gst_element_set_state (pipeline, GST_STATE_PLAYING);
212     if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
213       gtk_idle_add ((GtkFunction) iterate, pipeline);
214     update_id = gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
215   }
216 }
217
218 static void
219 pause_cb (GtkButton * button, gpointer data)
220 {
221   if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
222     gst_element_set_state (pipeline, GST_STATE_PAUSED);
223     gtk_timeout_remove (update_id);
224   }
225 }
226
227 static void
228 stop_cb (GtkButton * button, gpointer data)
229 {
230   if (gst_element_get_state (pipeline) != GST_STATE_READY) {
231     gst_element_set_state (pipeline, GST_STATE_READY);
232     gtk_timeout_remove (update_id);
233   }
234 }
235
236 int
237 main (int argc, char **argv)
238 {
239   GtkWidget *window, *hbox, *vbox, 
240             *play_button, *pause_button, *stop_button, 
241             *hscale;
242   struct poptOption options[] = {
243     {"stats",  's',  POPT_ARG_NONE|POPT_ARGFLAG_STRIP,   &stats,   0,
244          "Show element stats", NULL},
245      POPT_TABLEEND
246     };
247
248   gst_init_with_popt_table (&argc, &argv, options);
249   gtk_init (&argc, &argv);
250
251   pipeline = make_cdaudio_pipeline ();
252
253   g_signal_connect (pipeline, "deep_notify", G_CALLBACK (gst_element_default_deep_notify), NULL);
254   g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error), NULL);
255
256   /* initialize gui elements ... */
257   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
258   hbox = gtk_hbox_new (FALSE, 0);
259   vbox = gtk_vbox_new (FALSE, 0);
260   play_button = gtk_button_new_with_label ("play");
261   pause_button = gtk_button_new_with_label ("pause");
262   stop_button = gtk_button_new_with_label ("stop");
263
264   adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
265   hscale = gtk_hscale_new (adjustment);
266   gtk_scale_set_digits (GTK_SCALE (hscale), 2);
267   gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
268
269   gtk_signal_connect(GTK_OBJECT(hscale),
270                              "button_press_event", G_CALLBACK (start_seek), pipeline);
271   gtk_signal_connect(GTK_OBJECT(hscale),
272                              "button_release_event", G_CALLBACK (stop_seek), pipeline);
273   gtk_signal_connect(GTK_OBJECT(hscale),
274                              "format_value", G_CALLBACK (format_value), pipeline);
275
276   /* do the packing stuff ... */
277   gtk_window_set_default_size (GTK_WINDOW (window), 96, 96);
278   gtk_container_add (GTK_CONTAINER (window), vbox);
279   gtk_container_add (GTK_CONTAINER (vbox), hbox);
280   gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
281   gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
282   gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
283   gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
284
285   /* connect things ... */
286   g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb), pipeline);
287   g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb), pipeline);
288   g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb), pipeline);
289   g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL);
290
291   /* show the gui. */
292   gtk_widget_show_all (window);
293
294   gtk_main ();
295
296   gst_element_set_state (pipeline, GST_STATE_NULL);
297
298   return 0;
299 }