From bd6cfe9c1d3c24fe3cf5eec28928189b22f2e6bf Mon Sep 17 00:00:00 2001 From: Rov Juvano Date: Sun, 18 May 2008 22:59:48 -0400 Subject: [PATCH] implement seek to, change rate, gui seek bar --- src/demo-gui.c | 147 +++++++++++++++++++++++++++++++++++++++++------------- src/demo-main.c | 4 +- src/demo-player.c | 141 +++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 231 insertions(+), 61 deletions(-) diff --git a/src/demo-gui.c b/src/demo-gui.c index e1305fb..31e287c 100644 --- a/src/demo-gui.c +++ b/src/demo-gui.c @@ -40,9 +40,14 @@ typedef struct _DemoGuiPrivate DemoPlayer *player; GList *uris; GList *now_playing; - GtkWidget *window; gboolean is_playing; + GtkWidget *window; + GtkEntry *rate_entry; GtkStatusbar *status_bar; + gint position_updater_id; + GtkRange *seek_range; + GtkLabel *amount_played; + GtkLabel *amount_to_play; } DemoGuiPrivate; #define DEMO_GUI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEMO_TYPE_GUI, DemoGuiPrivate)) @@ -89,14 +94,48 @@ demo_gui_seek_bar_format (GtkScale *scale, return g_strdup_printf ("%" PRINTF_TIME_FORMAT, PRINTF_TIME_ARGS ((gint64)value)); } +gboolean update_position (gpointer data) { + DemoGui *gui = DEMO_GUI (data); + DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); + gchar pos_str[16], dur_str[16]; + + gint pos = demo_player_get_position (priv->player); + if (pos > 0) { + g_snprintf (pos_str, 16, "%" PRINTF_TIME_FORMAT, PRINTF_TIME_ARGS (pos)); + gint dur = demo_player_get_duration (priv->player); + if (dur > 0) { + g_snprintf (dur_str, 16, "-%" PRINTF_TIME_FORMAT, PRINTF_TIME_ARGS (dur - pos)); + } else { + dur = pos; + g_sprintf (dur_str, "-??:??:??"); + } + if (dur > 0) + gtk_range_set_range (GTK_RANGE (priv->seek_range), 0, (gdouble)dur); + gtk_range_set_value (GTK_RANGE (priv->seek_range), (gdouble)pos); + } else { + g_sprintf (pos_str, "??:??:??"); + g_sprintf (dur_str, "-??:??:??"); + } + gtk_label_set_text (GTK_LABEL (priv->amount_played), pos_str); + gtk_label_set_text (GTK_LABEL (priv->amount_to_play), dur_str); + + return priv->is_playing; +} + + gboolean demo_gui_seek_bar_change (GtkRange *range, GtkScrollType scroll, gdouble value, gpointer data) { + DemoGui *gui = DEMO_GUI (data); + DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); gint new_second = (gint)value; - g_message ("Seeking to %i second", new_second); + + status_bar_printf (priv->status_bar, "Seeking to %i second", new_second); + demo_player_seek_to (priv->player, new_second); + return FALSE; } @@ -106,17 +145,29 @@ static void demo_gui_do_change_rate (GtkAction *action, gpointer data) { - gdouble scale_amount = g_value_get_double ((GValue *)data); - g_message ("Changing rate by %3.2lf%%", scale_amount); + GValueArray *gvalues = (GValueArray *)data; + DemoGui *gui = g_value_get_object (g_value_array_get_nth (gvalues, 0)); + gdouble scale_amount = g_value_get_double (g_value_array_get_nth (gvalues, 1)); + DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); + + status_bar_printf (priv->status_bar, "Changing rate by %3.2lf", scale_amount); + + demo_player_scale_rate (priv->player, scale_amount); } static void demo_gui_do_rate_entered (GtkWidget *widget, gpointer data) { + DemoGui *gui = DEMO_GUI (data); + DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); double new_rate; + sscanf (gtk_entry_get_text (GTK_ENTRY (widget)), "%lf", &new_rate); - g_message ("Setting rate to %3.2lf", new_rate); + + status_bar_printf (priv->status_bar, "Setting rate to %3.2lf", new_rate); + + demo_player_set_rate (priv->player, new_rate); } static void @@ -127,11 +178,10 @@ demo_gui_do_seek (GtkAction *action, DemoGui *gui = g_value_get_object (g_value_array_get_nth (gvalues, 0)); gint seconds = g_value_get_int (g_value_array_get_nth (gvalues, 1)); - - g_debug ("Seeking %i seconds", seconds); - DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); + status_bar_printf (priv->status_bar, "Seeking %i seconds", seconds); + demo_player_seek_by (priv->player, seconds); } @@ -147,7 +197,8 @@ demo_gui_do_play (GtkAction *action, return; } - g_debug ("Trying to start playing"); + status_bar_printf (priv->status_bar, "Trying to start playing"); + demo_player_play (priv->player); } @@ -163,7 +214,8 @@ demo_gui_do_pause (GtkAction *action, return; } - g_debug ("Trying to pause playing"); + status_bar_printf (priv->status_bar, "Trying to pause playing"); + demo_player_pause (priv->player); } @@ -174,7 +226,8 @@ demo_gui_do_play_pause (GtkAction *action, DemoGui *gui = DEMO_GUI (data); DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); - g_debug ("Trying to toggle playing"); + status_bar_printf (priv->status_bar, "Trying to toggle playing"); + if (priv->is_playing) demo_player_pause (priv->player); else @@ -196,7 +249,13 @@ demo_gui_rate_changed (DemoPlayer *player, gdouble new_rate, gpointer data) { - g_message ("Rate changed to %3.2lf", new_rate); + DemoGui *gui = DEMO_GUI (data); + DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); + status_bar_printf (priv->status_bar, "Rate changed to %3.2lf", new_rate); + + gchar e[6]; + snprintf (e, 6, "%3.2f", new_rate); + gtk_entry_set_text (GTK_ENTRY (priv->rate_entry), e); } static void @@ -205,8 +264,16 @@ demo_gui_playing_started (DemoPlayer *player, { DemoGui *gui = DEMO_GUI (data); DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); + priv->is_playing = TRUE; status_bar_printf (priv->status_bar, "Playing started"); + + if (priv->position_updater_id) { + g_source_remove (priv->position_updater_id); + priv->position_updater_id = 0; + } + update_position (gui); + priv->position_updater_id = g_timeout_add (1000, update_position, gui); } static void @@ -215,7 +282,14 @@ demo_gui_playing_paused (DemoPlayer *player, { DemoGui *gui = DEMO_GUI (data); DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); + priv->is_playing = FALSE; + + if (priv->position_updater_id) + g_source_remove (priv->position_updater_id); + priv->position_updater_id = 0; + update_position (gui); + status_bar_printf (priv->status_bar, "Playing paused"); } @@ -234,13 +308,12 @@ static void demo_gui_set_player_func (DemoGui *gui, DemoPlayer *player) { - g_message ("setting player"); DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); if (priv->player) { - g_signal_handlers_disconnect_by_func(G_OBJECT (priv->player), G_CALLBACK (demo_gui_rate_changed), gui); - g_signal_handlers_disconnect_by_func(G_OBJECT (priv->player), G_CALLBACK (demo_gui_playing_started), gui); - g_signal_handlers_disconnect_by_func(G_OBJECT (priv->player), G_CALLBACK (demo_gui_playing_paused), gui); - g_signal_handlers_disconnect_by_func(G_OBJECT (priv->player), G_CALLBACK (demo_gui_playing_ended), gui); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->player), G_CALLBACK (demo_gui_rate_changed), gui); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->player), G_CALLBACK (demo_gui_playing_started), gui); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->player), G_CALLBACK (demo_gui_playing_paused), gui); + g_signal_handlers_disconnect_by_func (G_OBJECT (priv->player), G_CALLBACK (demo_gui_playing_ended), gui); } priv->player = player; g_signal_connect (G_OBJECT (priv->player), "rate-changed", G_CALLBACK (demo_gui_rate_changed), gui); @@ -256,7 +329,6 @@ static void demo_gui_set_playlist_func (DemoGui *gui, GList *uris) { - g_message ("Setting playlist"); DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); priv->uris = uris; priv->now_playing = priv->uris; @@ -330,11 +402,8 @@ create_action (ActionEntry *p) static void demo_gui_show_func (DemoGui *gui) { - g_message ("showing GUI"); DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); - if (priv->window) { - return; - } + gtk_init (NULL, NULL); GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (demo_gui_do_quit), gui); @@ -469,7 +538,7 @@ demo_gui_show_func (DemoGui *gui) { gtk_entry_set_max_length (GTK_ENTRY (rate_entry), 5); gtk_entry_set_text (GTK_ENTRY (rate_entry), "1.0"); gtk_entry_set_width_chars (GTK_ENTRY (rate_entry), 5); - g_signal_connect (G_OBJECT (rate_entry), "activate", G_CALLBACK (demo_gui_do_rate_entered), NULL); + g_signal_connect (G_OBJECT (rate_entry), "activate", G_CALLBACK (demo_gui_do_rate_entered), gui); GtkWidget *menu = gtk_menu_new (); gtk_menu_set_accel_group (GTK_MENU (menu), accel_group); @@ -513,8 +582,8 @@ demo_gui_show_func (DemoGui *gui) { gtk_box_pack_start (GTK_BOX (seek_bar), amount_played, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (seek_bar), seek_range, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (seek_bar), amount_to_play, FALSE, FALSE, 2); - g_signal_connect (G_OBJECT (seek_range), "format-value", G_CALLBACK (demo_gui_seek_bar_format), NULL); - g_signal_connect (G_OBJECT (seek_range), "change-value", G_CALLBACK (demo_gui_seek_bar_change), NULL); + g_signal_connect (G_OBJECT (seek_range), "format-value", G_CALLBACK (demo_gui_seek_bar_format), gui); + g_signal_connect (G_OBJECT (seek_range), "change-value", G_CALLBACK (demo_gui_seek_bar_change), gui); GtkWidget *status_bar = gtk_statusbar_new (); @@ -527,16 +596,21 @@ demo_gui_show_func (DemoGui *gui) { gtk_box_pack_start (GTK_BOX (toplevel_box), seek_bar, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (toplevel_box), status_bar, FALSE, FALSE, 2); + priv->window = window; + priv->rate_entry = GTK_ENTRY (rate_entry); + priv->status_bar = GTK_STATUSBAR (status_bar); + priv->seek_range = GTK_RANGE (seek_range); + priv->amount_played = GTK_LABEL (amount_played); + priv->amount_to_play = GTK_LABEL (amount_to_play); + gtk_widget_show_all (window); + status_bar_printf (GTK_STATUSBAR (status_bar), "Welcome to the Scaletempo demo."); + gtk_widget_grab_focus (seek_range); GError *error; if (!g_thread_create ((GThreadFunc)gtk_main, NULL, FALSE, &error)) { g_signal_emit (gui, demo_gui_signals[SIGNAL_ERROR], 0, error->message); } - - priv->status_bar = GTK_STATUSBAR (status_bar); - - status_bar_printf (priv->status_bar, "Welcome to the Scaletempo demo."); } @@ -608,11 +682,16 @@ demo_gui_init (GTypeInstance *instance, DemoGui *gui = (DemoGui *)instance; DemoGuiPrivate *priv = DEMO_GUI_GET_PRIVATE (gui); - priv->player = NULL; - priv->uris = NULL; - priv->now_playing = NULL; - priv->window = NULL; - priv->is_playing = FALSE; + priv->player = NULL; + priv->uris = NULL; + priv->now_playing = NULL; + priv->is_playing = FALSE; + priv->window = NULL; + priv->rate_entry = NULL; + priv->position_updater_id = 0; + priv->seek_range = NULL; + priv->amount_played = NULL; + priv->amount_to_play = NULL; } static void diff --git a/src/demo-main.c b/src/demo-main.c index 417d16c..c1e50f2 100644 --- a/src/demo-main.c +++ b/src/demo-main.c @@ -56,7 +56,7 @@ main (int argc, char *argv[]) { NULL, } }; - if (!g_thread_supported()) + if (!g_thread_supported ()) g_thread_init (NULL); GOptionContext *ctx = g_option_context_new ("uri ..."); @@ -92,7 +92,7 @@ main (int argc, char *argv[]) } demo_gui_show (gui); - demo_gui_set_playlist(gui, uri_list); + demo_gui_set_playlist (gui, uri_list); g_main_loop_run (loop); return 0; diff --git a/src/demo-player.c b/src/demo-player.c index d17f8e2..aede157 100644 --- a/src/demo-player.c +++ b/src/demo-player.c @@ -61,6 +61,26 @@ no_pipeline (DemoPlayer *player) return FALSE; } +static gboolean +demo_player_event_listener (GstElement *host, + GstEvent *event, + gpointer data) +{ + DemoPlayer *player = DEMO_PLAYER (data); + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + + if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) { + gdouble new_rate; + gst_event_parse_new_segment_full (event, NULL, &new_rate, NULL, NULL, NULL, NULL, NULL); + if (priv->rate != new_rate) { + priv->rate = new_rate; + g_signal_emit (player, demo_player_signals[SIGNAL_RATE_CHANGE], 0, new_rate); + } + } + + return TRUE; +} + static void demo_player_state_changed_cb (GstBus *bus, GstMessage *message, @@ -139,7 +159,7 @@ demo_player_build_pipeline (DemoPlayer *player) LINK_ELEMENTS (format, resample); LINK_ELEMENTS (resample, asink); - //gst_pad_add_event_probe (gst_element_get_pad (filter, "src"), G_CALLBACK (event_listener), playbin); + gst_pad_add_event_probe (gst_element_get_pad (filter, "src"), G_CALLBACK (demo_player_event_listener), player); GstPad *ghostpad = gst_element_get_pad (filter, "sink"); gst_element_add_pad (audioline, gst_ghost_pad_new ("sink", ghostpad)); @@ -157,13 +177,46 @@ demo_player_build_pipeline (DemoPlayer *player) /* method implementations */ +static void _set_rate (DemoPlayer *player, + gdouble new_rate) +{ + if (new_rate == 0) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Cannot set playback to zero. Pausing instead."); + demo_player_pause (player); + } + + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + + gint64 pos; + GstFormat fmt = GST_FORMAT_TIME; + GstSeekType seek_type = GST_SEEK_TYPE_SET; + if ( !gst_element_query_position (priv->pipeline, &fmt, &pos) ) { + // This should be the default but too many upstream elements seek anyway + pos = GST_CLOCK_TIME_NONE; + seek_type = GST_SEEK_TYPE_NONE; + } + if (!gst_element_seek (priv->pipeline, new_rate, + GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, + seek_type, pos, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Unable to change playback rate"); + } else { + priv->ignore_state_change = TRUE; + } +} + static void demo_player_scale_rate_func (DemoPlayer *player, gdouble scale) { if (no_pipeline (player)) return; - g_print ("Scaling Rate to: %3.2f\n", scale); + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + + if (scale != 1.0) { + g_message ("Scaling Rate by: %3.2f", scale); + _set_rate (player, priv->rate * scale); + } } static void @@ -172,7 +225,12 @@ demo_player_set_rate_func (DemoPlayer *player, { if (no_pipeline (player)) return; - g_print ("Setting Rate to: %3.2f\n", new_rate); + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + + if (priv->rate != new_rate) { + g_message ("Setting Rate to: %3.2f", new_rate); + _set_rate (player, new_rate); + } } static void @@ -232,30 +290,36 @@ demo_player_pause_func (DemoPlayer *player) } static void +_seek_to (DemoPlayer *player, + gint new_second) +{ + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + if (!gst_element_seek (priv->pipeline, priv->rate, + GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, + GST_SEEK_TYPE_SET, new_second * GST_SECOND, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Seek failed"); + return; + } + + priv->ignore_state_change = TRUE; +} + +static void demo_player_seek_by_func (DemoPlayer *player, gint seconds) { if (no_pipeline (player)) return; - DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); - g_debug ("Seeking by: %i", seconds); - gint64 pos; - GstFormat fmt = GST_FORMAT_TIME; - if ( !gst_element_query_position (priv->pipeline, &fmt, &pos) ) { + gint pos = demo_player_get_position (player); + if (pos < 0) { g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Seek-by failed: could not determine position"); return; } - gint64 new_pos = MAX(0, pos + seconds * GST_SECOND); - if (!gst_element_seek (priv->pipeline, priv->rate, - GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, - GST_SEEK_TYPE_SET, new_pos, - GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { - g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Seek failed"); - return; - } - priv->ignore_state_change = TRUE; + + _seek_to (player, MAX (0, pos + seconds)); } static void @@ -264,25 +328,52 @@ demo_player_seek_to_func (DemoPlayer *player, { if (no_pipeline (player)) return; - g_print ("Seeking to: %i\n", second); + g_debug ("Seeking to: %i", second); + + gint new_second; + + if (second < 0) { + gint dur = demo_player_get_duration (player); + if (dur < 0) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Seek-to failed: could not determine duration"); + return; + } + new_second = MAX (0, dur + second); + } else { + new_second = second; + } + + _seek_to (player, new_second); } static gint demo_player_get_position_func (DemoPlayer *player) { - if (no_pipeline (player)) return -1; + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + if (!priv->pipeline) return -1; - g_print ("Returning position\n"); - return -1; + gint64 pos; + GstFormat fmt = GST_FORMAT_TIME; + if ( !gst_element_query_position (priv->pipeline, &fmt, &pos) || pos < 0) { + return -1; + } + + return (gint)(pos / GST_SECOND); } static gint demo_player_get_duration_func (DemoPlayer *player) { - if (no_pipeline (player)) return -1; + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + if (!priv->pipeline) return -1; + + gint64 dur; + GstFormat fmt = GST_FORMAT_TIME; + if ( !gst_element_query_duration (priv->pipeline, &fmt, &dur) || dur < 0) { + return -1; + } - g_print ("Returning duration"); - return -1; + return (gint)(dur / GST_SECOND); } @@ -319,7 +410,7 @@ demo_player_play (DemoPlayer *player) { g_return_if_fail (DEMO_IS_PLAYER (player)); - DEMO_PLAYER_GET_CLASS (player)->play(player); + DEMO_PLAYER_GET_CLASS (player)->play (player); } void -- 2.11.4.GIT