2 * Copyright (C) 2008 Rov Juvano <rovjuvano@users.sourceforge.net>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include <gst/interfaces/xoverlay.h>
30 #define STATUSBAR_TIMEOUT 2000
32 static GstElement
*pipeline
;
34 static GtkWidget
*_rate_entry
;
35 static GtkWidget
*_image_playing_start
;
36 static GtkWidget
*_image_playing_pause
;
37 static GtkWidget
*_play_pause
;
38 static GtkWidget
*_status_bar
;
39 static GtkWidget
*_pos_label
;
40 static GtkWidget
*_video_window
;
41 static gboolean _stop_updating_position
;
44 /* Callback for status bar */
46 pop_sb_cb (gpointer data
) {
47 gtk_statusbar_remove (GTK_STATUSBAR (_status_bar
), 0, GPOINTER_TO_UINT (data
));
51 gboolean
update_position (gpointer data
) {
53 if (get_position(data
, &pos
)) {
55 snprintf(text
, 32, "%" GST_TIME_FORMAT
, GST_TIME_ARGS (pos
));
56 gtk_label_set_text (GTK_LABEL (_pos_label
), text
);
58 gtk_label_set_text (GTK_LABEL (_pos_label
), "Could not determine position");
60 if (_stop_updating_position
) {
61 _stop_updating_position
= 0;
68 /* Callbacks from key presses */
70 gui_change_rate (gfloat rate
, gboolean abs
)
72 change_rate(pipeline
, rate
, abs
);
76 gui_seek (GstElement
* pipeline
, gint seconds
, gboolean abs
)
79 snprintf(msg
, 32, (abs
?"Seeking to %i":"Seeking %i seconds"), seconds
);
80 guint msg_id
= gtk_statusbar_push (GTK_STATUSBAR (_status_bar
), 0, msg
);
81 g_timeout_add (STATUSBAR_TIMEOUT
, pop_sb_cb
, GUINT_TO_POINTER (msg_id
));
83 seek(pipeline
, seconds
, abs
);
87 gui_stop(GstElement
* pipeline
) {
94 faster_cb (GtkButton
* button
, gpointer data
)
96 gui_change_rate(1.0594630943593, FALSE
);
97 guint msg_id
= gtk_statusbar_push (GTK_STATUSBAR (_status_bar
), 0, "Faster.");
98 g_timeout_add(STATUSBAR_TIMEOUT
, pop_sb_cb
, GUINT_TO_POINTER (msg_id
));
102 slower_cb (GtkButton
* button
, gpointer data
)
104 gui_change_rate(0.943874312681694, FALSE
);
105 guint msg_id
= gtk_statusbar_push (GTK_STATUSBAR (_status_bar
), 0, "S l o w e r.");
106 g_timeout_add (STATUSBAR_TIMEOUT
, pop_sb_cb
, GUINT_TO_POINTER (msg_id
));
110 change_rate_cb (GtkWidget
* widget
, gpointer data
)
113 sscanf (gtk_entry_get_text (GTK_ENTRY (widget
)), "%lf", &rate
);
114 gui_change_rate(rate
, TRUE
);
118 play_pause_cb (GtkButton
* button
, gpointer data
)
120 if (gtk_button_get_image (GTK_BUTTON (button
)) == _image_playing_pause
) {
128 rw_button_cb (GtkButton
* button
, gpointer data
)
130 gui_seek(pipeline
, -30, FALSE
);
134 ff_button_cb (GtkButton
* button
, gpointer data
)
136 gui_seek(pipeline
, 30, FALSE
);
140 /* Callbacks from signals */
142 gui_rate_changed (GstElement
* pipeline
, gdouble new_rate
, gpointer data
) {
144 snprintf(e
, 6, "%3.2f", new_rate
);
145 gtk_entry_set_text (GTK_ENTRY (_rate_entry
), e
);
148 snprintf(msg
, 32, "Rate changed to %3.2f", new_rate
);
149 guint msg_id
= gtk_statusbar_push (GTK_STATUSBAR (_status_bar
), 0, msg
);
150 g_timeout_add (STATUSBAR_TIMEOUT
, pop_sb_cb
, GUINT_TO_POINTER (msg_id
));
154 gui_playing_started (GstElement
* pipeline
) {
155 guint msg_id
= gtk_statusbar_push (GTK_STATUSBAR (_status_bar
), 0, "PLAYING Started");
156 gtk_button_set_image (GTK_BUTTON (_play_pause
), _image_playing_pause
);
157 gtk_button_set_label (GTK_BUTTON (_play_pause
), "_Pause");
158 g_timeout_add (STATUSBAR_TIMEOUT
, pop_sb_cb
, GUINT_TO_POINTER (msg_id
));
159 g_timeout_add(1000, update_position
, pipeline
);
163 gui_playing_paused (GstElement
* pipeline
) {
164 guint msg_id
= gtk_statusbar_push (GTK_STATUSBAR (_status_bar
), 0, "PLAYING Paused");
165 gtk_button_set_image (GTK_BUTTON (_play_pause
), _image_playing_start
);
166 gtk_button_set_label (GTK_BUTTON (_play_pause
), "_Play");
167 g_timeout_add (STATUSBAR_TIMEOUT
, pop_sb_cb
, GUINT_TO_POINTER (msg_id
));
168 _stop_updating_position
= 1;
173 key_press (GtkWidget
*widget
, GdkEventKey
*event
)
175 switch (event
->keyval
) {
180 gui_change_rate(1.059463094352953, FALSE
);
183 gui_change_rate(2.0, FALSE
);
186 gui_change_rate(0.9438743126816935, FALSE
);
189 gui_change_rate(.5, FALSE
);
193 gui_change_rate(1.0, TRUE
);
196 gui_change_rate(-1, TRUE
);
200 gui_seek(pipeline
, -5, FALSE
);
204 gui_seek(pipeline
, 5, FALSE
);
208 gui_seek(pipeline
, -30, FALSE
);
212 gui_seek(pipeline
, 30, FALSE
);
215 gui_seek(pipeline
, 0, TRUE
);
218 play_pause (pipeline
);
224 gui_seek(pipeline
, 0, FALSE
);
226 GstFormat fmt
= GST_FORMAT_TIME
;
227 if ( !gst_element_query_position (pipeline
, &fmt
, &pos
) ) {
228 g_print ("position query failed!\n");
230 g_print ("%" GST_TIME_FORMAT
"\n", GST_TIME_ARGS(pos
));
234 g_print ("char: %s (%i)", event
->string
, event
->keyval
);
235 return GDK_FILTER_CONTINUE
;
238 return GDK_FILTER_REMOVE
;
241 static GtkWidget
*create_arrow_button( GtkArrowType arrow_type
,
242 GtkShadowType shadow_type
)
247 button
= gtk_button_new ();
248 arrow
= gtk_arrow_new (arrow_type
, shadow_type
);
250 gtk_container_add (GTK_CONTAINER (button
), arrow
);
252 gtk_widget_show (button
);
253 gtk_widget_show (arrow
);
258 static GstBusSyncReply
259 create_window (GstBus
* bus
, GstMessage
* message
, GtkWidget
* window
)
261 if (GST_MESSAGE_TYPE (message
) != GST_MESSAGE_ELEMENT
||
262 !gst_structure_has_name (message
->structure
, "prepare-xwindow-id"))
265 gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message
)),
266 GDK_WINDOW_XWINDOW (window
->window
));
267 gst_x_overlay_handle_events (GST_X_OVERLAY (GST_MESSAGE_SRC (message
)), TRUE
);
270 const GstStructure *s = gst_message_get_structure (message);
271 g_print ("\nmessage from \"%s\" (%s): ",
272 GST_STR_NULL (gst_element_get_name (GST_MESSAGE_SRC (message))),
273 gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
275 gchar *sstr = gst_structure_to_string (s);
276 g_print ("%s\n", sstr);
279 g_print ("no message details\n");
287 gui_build(int argc
, char *argv
[], gpointer
**window_ref
) {
288 gtk_init (&argc
, &argv
);
289 GtkWidget
*window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
290 *window_ref
= (gpointer
)window
;
292 GtkWidget
*play_pause_button
= gtk_button_new_with_mnemonic("_Pause");
293 GtkWidget
*play_image
= gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY
, GTK_ICON_SIZE_SMALL_TOOLBAR
);
294 GtkWidget
*pause_image
= gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE
, GTK_ICON_SIZE_SMALL_TOOLBAR
);
295 gtk_button_set_image (GTK_BUTTON (play_pause_button
), pause_image
);
296 GtkRequisition play_size
;
297 gtk_widget_size_request (play_pause_button
, &play_size
);
298 gtk_widget_set_size_request (play_pause_button
, play_size
.width
, -1);
300 GtkWidget
*stop_button
= gtk_button_new_from_stock(GTK_STOCK_MEDIA_STOP
);
301 GtkWidget
*rw_button
= gtk_button_new_from_stock(GTK_STOCK_MEDIA_REWIND
);
302 GtkWidget
*ff_button
= gtk_button_new_from_stock(GTK_STOCK_MEDIA_FORWARD
);
304 GtkWidget
*rate_entry
= gtk_entry_new ();
305 GtkWidget
*rate_label
= gtk_label_new ("Rate:");
306 gtk_entry_set_max_length (GTK_ENTRY (rate_entry
), 5);
307 gtk_entry_set_text (GTK_ENTRY (rate_entry
), "1.0");
308 gtk_entry_set_width_chars (GTK_ENTRY (rate_entry
), 5);
309 GtkWidget
*faster_button
= create_arrow_button (GTK_ARROW_UP
, GTK_SHADOW_OUT
);
310 GtkWidget
*slower_button
= create_arrow_button (GTK_ARROW_DOWN
, GTK_SHADOW_OUT
);
311 GtkWidget
*rate_box
= gtk_hbox_new (FALSE
, 0);
312 gtk_box_pack_start (GTK_BOX (rate_box
), rate_label
, FALSE
, FALSE
, 2);
313 gtk_box_pack_start (GTK_BOX (rate_box
), slower_button
, FALSE
, FALSE
, 2);
314 gtk_box_pack_start (GTK_BOX (rate_box
), rate_entry
, FALSE
, FALSE
, 2);
315 gtk_box_pack_start (GTK_BOX (rate_box
), faster_button
, FALSE
, FALSE
, 2);
317 GtkWidget
*controls_box
= gtk_hbox_new (FALSE
, 0);
318 gtk_box_pack_start (GTK_BOX (controls_box
), rate_box
, FALSE
, FALSE
, 2);
319 gtk_box_pack_start (GTK_BOX (controls_box
), play_pause_button
, FALSE
, FALSE
, 2);
320 gtk_box_pack_start (GTK_BOX (controls_box
), stop_button
, FALSE
, FALSE
, 2);
321 gtk_box_pack_start (GTK_BOX (controls_box
), rw_button
, FALSE
, FALSE
, 2);
322 gtk_box_pack_start (GTK_BOX (controls_box
), ff_button
, FALSE
, FALSE
, 2);
324 GtkWidget
*video_window
= gtk_drawing_area_new ();
325 gtk_drawing_area_size (GTK_DRAWING_AREA (video_window
), 640, 360);
326 g_object_set (G_OBJECT (video_window
), "can-focus", TRUE
, NULL
);
328 GtkWidget
*pos_label
= gtk_label_new ("Position");
329 gtk_misc_set_alignment (GTK_MISC (pos_label
), 1, 0.5);
330 gtk_label_set_width_chars (GTK_LABEL (pos_label
), 20);
331 GtkWidget
*status_bar
= gtk_statusbar_new ();
332 GtkWidget
*status_line
= status_bar
;
333 gtk_box_pack_start (GTK_BOX (status_bar
), pos_label
, FALSE
, FALSE
, 2);
334 gtk_box_reorder_child (GTK_BOX (status_bar
), pos_label
, 0);
336 gtk_window_set_title (GTK_WINDOW (window
), "Scaletempo Demo");
337 GtkWidget
*toplevel_box
= gtk_vbox_new (FALSE
, 0);
338 gtk_container_set_border_width (GTK_CONTAINER (toplevel_box
), 3);
339 gtk_container_add (GTK_CONTAINER (window
), toplevel_box
);
340 gtk_box_pack_start (GTK_BOX (toplevel_box
), controls_box
, FALSE
, FALSE
, 2);
341 gtk_box_pack_start (GTK_BOX (toplevel_box
), video_window
, TRUE
, TRUE
, 2);
342 gtk_box_pack_start (GTK_BOX (toplevel_box
), status_line
, FALSE
, FALSE
, 2);
344 gtk_widget_ref (play_image
);
345 gtk_widget_ref (pause_image
);
346 _rate_entry
= rate_entry
;
347 _play_pause
= play_pause_button
;
348 _image_playing_start
= play_image
;
349 _image_playing_pause
= pause_image
;
350 _video_window
= video_window
;
351 _status_bar
= status_bar
;
352 _pos_label
= pos_label
;
354 g_signal_connect (G_OBJECT (window
), "destroy", gtk_main_quit
, NULL
);
355 g_signal_connect (G_OBJECT (window
), "destroy", G_CALLBACK(gtk_widget_destroyed
), window_ref
);
356 gtk_widget_set_events (video_window
, GDK_KEY_PRESS_MASK
);
357 gtk_signal_connect (GTK_OBJECT (video_window
), "key_press_event", GTK_SIGNAL_FUNC (key_press
), NULL
);
359 g_signal_connect (G_OBJECT(faster_button
), "clicked", G_CALLBACK (faster_cb
), NULL
);
360 g_signal_connect (G_OBJECT(slower_button
), "clicked", G_CALLBACK (slower_cb
), NULL
);
361 g_signal_connect (G_OBJECT(play_pause_button
), "clicked", G_CALLBACK (play_pause_cb
), NULL
);
362 g_signal_connect (G_OBJECT(stop_button
), "clicked", G_CALLBACK (gtk_main_quit
), NULL
);
363 g_signal_connect (G_OBJECT(rw_button
), "clicked", G_CALLBACK (rw_button_cb
), NULL
);
364 g_signal_connect (G_OBJECT(ff_button
), "clicked", G_CALLBACK (ff_button_cb
), NULL
);
365 g_signal_connect (G_OBJECT(rate_entry
), "activate", G_CALLBACK (change_rate_cb
), NULL
);
367 gtk_widget_show_all (window
);
368 gtk_statusbar_push (GTK_STATUSBAR (status_bar
), 0, "Welcome to the jungle.");
369 gtk_widget_grab_focus (video_window
);
373 gui_play_uri (const gchar
*uri
, const gchar
*filter_name
)
375 pipeline
= build_pipeline (uri
, filter_name
);
377 g_print("An error occured building pipeline for: %s\n", uri
);
381 GstBus
*bus
= gst_pipeline_get_bus (GST_PIPELINE (pipeline
));
382 gst_bus_set_sync_handler (bus
, (GstBusSyncHandler
) create_window
, _video_window
);
383 //g_signal_connect (bus, "message::element", G_CALLBACK (create_window), _video_window);
384 gst_object_unref (bus
);
386 set_rate_changed_cb (gui_rate_changed
);
387 set_playing_started_cb (gui_playing_started
);
388 set_playing_paused_cb (gui_playing_paused
);
389 set_stop_cb (gui_stop
);
394 gst_element_set_state (pipeline
, GST_STATE_NULL
);
395 gst_object_unref (pipeline
);