Better state handling and buffering indicator.
authorIlpo Ruotsalainen <ilpo.ruotsalainen@movial.fi>
Thu, 2 Oct 2008 06:42:16 +0000 (09:42 +0300)
committerIlpo Ruotsalainen <ilpo.ruotsalainen@movial.fi>
Thu, 2 Oct 2008 06:42:16 +0000 (09:42 +0300)
isatis-player/player.c

index acf1ff9..37bab9b 100644 (file)
@@ -20,7 +20,8 @@ typedef struct _PlayerInternal
 
        GstElement *playbin;
 
-       GstState state;
+       GstState target_state;
+       gboolean buffering;
 } PlayerInternal;
 
 static void prepare_xwindow_id_callback(GstBus *bus, GstMessage *message, PlayerInternal *priv)
@@ -41,7 +42,7 @@ static gboolean update_progress_callback(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;
@@ -87,16 +88,45 @@ static gboolean update_progress_callback(PlayerInternal *priv)
        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 */
@@ -115,33 +145,11 @@ static void state_changed_callback(GstBus *bus, GstMessage *message, PlayerInter
 
        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)
@@ -151,6 +159,8 @@ static void error_callback(GstBus *bus, GstMessage *message, PlayerInternal *pri
 
        gst_message_parse_error(message, &gerror, &debug);
 
+       stop_playback(priv);
+
        if (gerror)
        {
                gchar *tmp;
@@ -166,8 +176,6 @@ static void error_callback(GstBus *bus, GstMessage *message, PlayerInternal *pri
 
        g_error_free(gerror);
        g_free(debug);
-
-       stop_playback(priv);
 }
 
 static void eos_callback(GstBus *bus, GstMessage *message, PlayerInternal *priv)
@@ -177,6 +185,26 @@ 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))
@@ -191,12 +219,10 @@ static gboolean paint_label_background_callback(GtkWidget *widget, GdkEventExpos
 
 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)
@@ -319,7 +345,7 @@ int main(int argc, char **argv)
 
        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);
@@ -332,6 +358,7 @@ int main(int argc, char **argv)
        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);