GstElement *playbin;
- GstState state;
+ GstState target_state;
+ gboolean buffering;
} PlayerInternal;
static void prepare_xwindow_id_callback(GstBus *bus, GstMessage *message, PlayerInternal *priv)
gint64 pos, len;
char tmp[8];
- if (priv->state != GST_STATE_NULL)
+ if (priv->target_state != GST_STATE_NULL)
{
if (!gst_element_query_position(priv->playbin, &fmt, &pos))
pos = -1;
return TRUE;
}
-static void stop_playback(PlayerInternal *priv)
+static void start_playback(PlayerInternal *priv)
{
- /* This is necessary because some versions of gstreamer have a bug that prevents messages for
- * transitions to GST_STATE_NULL ever being generated/delivered */
+ g_debug("starting playback");
+
+ priv->target_state = GST_STATE_PLAYING;
+ gtk_widget_set_name(GTK_WIDGET(priv->playbutton), "pause-button");
+
+ gst_element_set_state(priv->playbin, priv->target_state);
+
+ update_progress_callback(priv);
+}
+
+static void pause_playback(PlayerInternal *priv)
+{
+ g_debug("pausing playback");
+
+ priv->target_state = GST_STATE_PAUSED;
+ gtk_widget_set_name(GTK_WIDGET(priv->playbutton), "play-button");
+
+ gst_element_set_state(priv->playbin, priv->target_state);
- gst_element_set_state(priv->playbin, GST_STATE_NULL);
+ update_progress_callback(priv);
+}
+
+static void stop_playback(PlayerInternal *priv)
+{
+ g_debug("stopping playback");
- priv->state = GST_STATE_NULL;
+ priv->target_state = GST_STATE_NULL;
gtk_widget_set_name(GTK_WIDGET(priv->playbutton), "play-button");
+ gst_element_set_state(priv->playbin, priv->target_state);
+
+ if (priv->buffering)
+ {
+ priv->buffering = FALSE;
+ gtk_progress_bar_set_text(GTK_PROGRESS_BAR(priv->progressbar), "");
+ }
+
update_progress_callback(priv);
/* Invalidate the video area so it gets repainted with background */
g_debug("pipeline changed state, %d -> %d (want %d)", old, new, pending);
- /* We don't care about intermediate states */
- if (pending != GST_STATE_VOID_PENDING)
- return;
-
- switch (new)
+ if (priv->buffering && new == GST_STATE_PLAYING)
{
- case GST_STATE_PLAYING:
- gtk_widget_set_name(GTK_WIDGET(priv->playbutton), "pause-button");
- break;
-
- case GST_STATE_NULL:
- case GST_STATE_PAUSED:
- gtk_widget_set_name(GTK_WIDGET(priv->playbutton), "play-button");
- break;
-
- /* Any final READY state is a bug, we never intend that */
- case GST_STATE_READY:
- g_return_if_reached();
-
- /* Any unknown state is not a good thing either */
- default:
- g_return_if_reached();
+ priv->buffering = FALSE;
+ gtk_progress_bar_set_text(GTK_PROGRESS_BAR(priv->progressbar), "");
}
-
- priv->state = new;
-
- update_progress_callback(priv);
}
static void error_callback(GstBus *bus, GstMessage *message, PlayerInternal *priv)
gst_message_parse_error(message, &gerror, &debug);
+ stop_playback(priv);
+
if (gerror)
{
gchar *tmp;
g_error_free(gerror);
g_free(debug);
-
- stop_playback(priv);
}
static void eos_callback(GstBus *bus, GstMessage *message, PlayerInternal *priv)
stop_playback(priv);
}
+static void buffering_callback(GstBus *bus, GstMessage *message, PlayerInternal *priv)
+{
+ gint percent;
+
+ if (gst_structure_get_int(message->structure, "buffer-percent", &percent))
+ {
+ char tmp[32];
+
+ gchar *srcname = gst_object_get_name(GST_MESSAGE_SRC(message));
+ g_debug("buffering, %s -> %d%%", srcname, percent);
+ g_free(srcname);
+
+ snprintf(tmp, sizeof(tmp), "Buffering: %d%%", percent);
+
+ priv->buffering = TRUE;
+
+ gtk_progress_bar_set_text(GTK_PROGRESS_BAR(priv->progressbar), tmp);
+ }
+}
+
static gboolean paint_label_background_callback(GtkWidget *widget, GdkEventExpose *event, void *unused)
{
if (GTK_WIDGET_DRAWABLE(widget))
static void playbutton_clicked_callback(GtkButton *button, PlayerInternal *priv)
{
- if (priv->state == GST_STATE_PLAYING)
- gst_element_set_state(priv->playbin, GST_STATE_PAUSED);
+ if (priv->target_state == GST_STATE_PLAYING)
+ pause_playback(priv);
else
- gst_element_set_state(priv->playbin, GST_STATE_PLAYING);
-
- gtk_progress_bar_set_text(GTK_PROGRESS_BAR(priv->progressbar), "");
+ start_playback(priv);
}
static void stopbutton_clicked_callback(GtkButton *button, PlayerInternal *priv)
setup_ui(priv);
- priv->state = GST_STATE_NULL;
+ priv->target_state = GST_STATE_NULL;
priv->playbin = gst_element_factory_make("playbin", "playbin");
g_object_set(G_OBJECT(priv->playbin), "uri", argv[1], NULL);
g_signal_connect(bus, "message::state-changed", G_CALLBACK(state_changed_callback), priv);
g_signal_connect(bus, "message::error", G_CALLBACK(error_callback), priv);
g_signal_connect(bus, "message::eos", G_CALLBACK(eos_callback), priv);
+ g_signal_connect(bus, "message::buffering", G_CALLBACK(buffering_callback), priv);
g_timeout_add(250, (GSourceFunc)update_progress_callback, priv);