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