| From d64c7edb66f4a64ff49c4306cf77fd269b7079ab Mon Sep 17 00:00:00 2001 |
| From: Jussi Kukkonen <jussi.kukkonen@intel.com> |
| Date: Mon, 16 Mar 2015 13:45:30 +0200 |
| Subject: [PATCH] Add error signal emission for missing plugins |
| |
| Add a missing plugins error signal to gst-player. Note that this error |
| does not necessarily mean the playback has completely failed, but in |
| practice the user experience will be bad (think, e.g. of a mp4 file |
| where H.264 codec is missing: AAC playback still works...). |
| |
| Use the signal in gtk-play to show a infobar if plugins are missing. |
| |
| Submitted upstream at https://github.com/sdroege/gst-player/pull/11 |
| |
| Upstream-Status: Submitted |
| Signed-off-by: Jussi Kukkonen <jussi.kukkonen@intel.com> |
| --- |
| configure.ac | 2 +- |
| gtk/gtk-play.c | 54 +++++++++++++++++++++++++++++++++++++++++++++- |
| lib/gst/player/gstplayer.c | 22 +++++++++++++++++++ |
| lib/gst/player/gstplayer.h | 3 ++- |
| 4 files changed, 78 insertions(+), 3 deletions(-) |
| |
| diff --git a/configure.ac b/configure.ac |
| index 90ab74c..6cdb4eb 100644 |
| --- a/configure.ac |
| +++ b/configure.ac |
| @@ -53,7 +53,7 @@ AC_SUBST(LT_AGE) |
| PKG_PROG_PKG_CONFIG |
| |
| PKG_CHECK_MODULES(GLIB, [glib-2.0 gobject-2.0]) |
| -PKG_CHECK_MODULES(GSTREAMER, [gstreamer-1.0 >= 1.4 gstreamer-video-1.0 >= 1.4]) |
| +PKG_CHECK_MODULES(GSTREAMER, [gstreamer-1.0 >= 1.4 gstreamer-video-1.0 >= 1.4 gstreamer-pbutils-1.0]) |
| |
| GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`" |
| AC_SUBST(GLIB_PREFIX) |
| diff --git a/gtk/gtk-play.c b/gtk/gtk-play.c |
| index b92773b..e2b605a 100644 |
| --- a/gtk/gtk-play.c |
| +++ b/gtk/gtk-play.c |
| @@ -30,6 +30,8 @@ typedef struct |
| GtkWidget *prev_button, *next_button; |
| GtkWidget *seekbar; |
| GtkWidget *video_area; |
| + GtkWidget *info_label; |
| + GtkWidget *info_bar; |
| GtkWidget *volume_button; |
| gulong seekbar_value_changed_signal_id; |
| gboolean playing; |
| @@ -141,6 +143,13 @@ play_pause_clicked_cb (GtkButton * button, GtkPlay * play) |
| } |
| |
| static void |
| +clear_missing_plugins (GtkPlay * play) |
| +{ |
| + gtk_label_set_text (GTK_LABEL (play->info_label), ""); |
| + gtk_widget_hide (play->info_bar); |
| +} |
| + |
| +static void |
| skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) |
| { |
| GList *prev; |
| @@ -155,6 +164,7 @@ skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) |
| |
| gtk_widget_set_sensitive (play->next_button, TRUE); |
| gst_player_set_uri (play->player, prev->data); |
| + clear_missing_plugins (play); |
| gst_player_play (play->player); |
| set_title (play, prev->data); |
| gtk_widget_set_sensitive (play->prev_button, g_list_previous (prev) != NULL); |
| @@ -175,6 +185,7 @@ skip_next_clicked_cb (GtkButton * button, GtkPlay * play) |
| |
| gtk_widget_set_sensitive (play->prev_button, TRUE); |
| gst_player_set_uri (play->player, next->data); |
| + clear_missing_plugins (play); |
| gst_player_play (play->player); |
| set_title (play, next->data); |
| gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); |
| @@ -193,10 +204,16 @@ volume_changed_cb (GtkScaleButton * button, gdouble value, GtkPlay * play) |
| gst_player_set_volume (play->player, value); |
| } |
| |
| +void |
| +info_bar_response_cb (GtkInfoBar * bar, gint response, GtkPlay * play) |
| +{ |
| + gtk_widget_hide (GTK_WIDGET (bar)); |
| +} |
| + |
| static void |
| create_ui (GtkPlay * play) |
| { |
| - GtkWidget *controls, *main_hbox, *main_vbox; |
| + GtkWidget *controls, *main_hbox, *main_vbox, *info_bar, *content_area; |
| |
| play->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
| g_signal_connect (G_OBJECT (play->window), "delete-event", |
| @@ -208,6 +225,20 @@ create_ui (GtkPlay * play) |
| g_signal_connect (play->video_area, "realize", |
| G_CALLBACK (video_area_realize_cb), play); |
| |
| + play->info_bar = gtk_info_bar_new (); |
| + gtk_info_bar_set_message_type (GTK_INFO_BAR (play->info_bar), |
| + GTK_MESSAGE_WARNING); |
| + //gtk_info_bar_set_show_close_button (GTK_INFO_BAR (play->info_bar), |
| + // TRUE); |
| + gtk_widget_set_no_show_all (play->info_bar, TRUE); |
| + g_signal_connect (play->info_bar, "response", |
| + G_CALLBACK (info_bar_response_cb), play); |
| + |
| + content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (play->info_bar)); |
| + play->info_label = gtk_label_new (""); |
| + gtk_container_add (GTK_CONTAINER (content_area), play->info_label); |
| + gtk_widget_show (play->info_label); |
| + |
| /* Unified play/pause button */ |
| play->play_pause_button = |
| gtk_button_new_from_icon_name ("media-playback-pause", |
| @@ -258,6 +289,7 @@ create_ui (GtkPlay * play) |
| |
| main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); |
| gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 0); |
| + gtk_box_pack_start (GTK_BOX (main_vbox), play->info_bar, FALSE, FALSE, 0); |
| gtk_box_pack_start (GTK_BOX (main_vbox), controls, FALSE, FALSE, 0); |
| gtk_container_add (GTK_CONTAINER (play->window), main_vbox); |
| |
| @@ -322,6 +354,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) |
| gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); |
| |
| gst_player_set_uri (play->player, next->data); |
| + clear_missing_plugins (play); |
| gst_player_play (play->player); |
| set_title (play, next->data); |
| } else { |
| @@ -330,6 +363,24 @@ eos_cb (GstPlayer * unused, GtkPlay * play) |
| } |
| } |
| |
| +static void |
| +error_cb (GstPlayer * player, GError * err, GtkPlay * play) |
| +{ |
| + char *message; |
| + |
| + if (g_error_matches (err, gst_player_error_quark (), |
| + GST_PLAYER_ERROR_MISSING_PLUGIN)) { |
| + // add message to end of any existing message: there may be |
| + // multiple missing plugins. |
| + message = g_strdup_printf ("%s%s. ", |
| + gtk_label_get_text (GTK_LABEL (play->info_label)), err->message); |
| + gtk_label_set_text (GTK_LABEL (play->info_label), message); |
| + g_free (message); |
| + |
| + gtk_widget_show (play->info_bar); |
| + } |
| +} |
| + |
| int |
| main (gint argc, gchar ** argv) |
| { |
| @@ -422,6 +473,7 @@ main (gint argc, gchar ** argv) |
| g_signal_connect (play.player, "video-dimensions-changed", |
| G_CALLBACK (video_dimensions_changed_cb), &play); |
| g_signal_connect (play.player, "end-of-stream", G_CALLBACK (eos_cb), &play); |
| + g_signal_connect (play.player, "error", G_CALLBACK (error_cb), &play); |
| |
| /* We have file(s) that need playing. */ |
| set_title (&play, g_list_first (play.uris)->data); |
| diff --git a/lib/gst/player/gstplayer.c b/lib/gst/player/gstplayer.c |
| index bd682d9..78e7ba1 100644 |
| --- a/lib/gst/player/gstplayer.c |
| +++ b/lib/gst/player/gstplayer.c |
| @@ -47,6 +47,7 @@ |
| |
| #include <gst/gst.h> |
| #include <gst/video/video.h> |
| +#include <gst/pbutils/missing-plugins.h> |
| |
| GST_DEBUG_CATEGORY_STATIC (gst_player_debug); |
| #define GST_CAT_DEFAULT gst_player_debug |
| @@ -238,6 +239,7 @@ gst_player_class_init (GstPlayerClass * klass) |
| g_signal_new ("video-dimensions-changed", G_TYPE_FROM_CLASS (klass), |
| G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, |
| NULL, NULL, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); |
| + |
| } |
| |
| static void |
| @@ -619,6 +621,21 @@ error_cb (GstBus * bus, GstMessage * msg, gpointer user_data) |
| g_mutex_unlock (&self->priv->lock); |
| } |
| |
| +static void |
| +element_cb (GstBus * bus, GstMessage * msg, gpointer user_data) |
| +{ |
| + GstPlayer *self = GST_PLAYER (user_data); |
| + |
| + if (gst_is_missing_plugin_message (msg)) { |
| + gchar *desc; |
| + |
| + desc = gst_missing_plugin_message_get_description (msg); |
| + emit_error (self, g_error_new (GST_PLAYER_ERROR, |
| + GST_PLAYER_ERROR_MISSING_PLUGIN, "Missing plugin '%s'", desc)); |
| + g_free (desc); |
| + } |
| +} |
| + |
| static gboolean |
| eos_dispatch (gpointer user_data) |
| { |
| @@ -1059,6 +1076,8 @@ gst_player_main (gpointer data) |
| NULL, NULL); |
| g_source_attach (bus_source, self->priv->context); |
| |
| + g_signal_connect (G_OBJECT (bus), "message::element", |
| + G_CALLBACK (element_cb), self); |
| g_signal_connect (G_OBJECT (bus), "message::error", G_CALLBACK (error_cb), |
| self); |
| g_signal_connect (G_OBJECT (bus), "message::eos", G_CALLBACK (eos_cb), self); |
| @@ -1560,6 +1579,7 @@ gst_player_error_get_type (void) |
| static gsize id = 0; |
| static const GEnumValue values[] = { |
| {C_ENUM (GST_PLAYER_ERROR_FAILED), "GST_PLAYER_ERROR_FAILED", "failed"}, |
| + {C_ENUM (GST_PLAYER_ERROR_MISSING_PLUGIN), "GST_PLAYER_ERROR_MISSING_PLUGIN", "missing-plugin"}, |
| {0, NULL, NULL} |
| }; |
| |
| @@ -1577,6 +1597,8 @@ gst_player_error_get_name (GstPlayerError error) |
| switch (error) { |
| case GST_PLAYER_ERROR_FAILED: |
| return "failed"; |
| + case GST_PLAYER_ERROR_MISSING_PLUGIN: |
| + return "missing-plugin"; |
| } |
| |
| g_assert_not_reached (); |
| diff --git a/lib/gst/player/gstplayer.h b/lib/gst/player/gstplayer.h |
| index c438513..35fb5bb 100644 |
| --- a/lib/gst/player/gstplayer.h |
| +++ b/lib/gst/player/gstplayer.h |
| @@ -44,7 +44,8 @@ GType gst_player_error_get_type (void); |
| #define GST_TYPE_PLAYER_ERROR (gst_player_error_get_type ()) |
| |
| typedef enum { |
| - GST_PLAYER_ERROR_FAILED = 0 |
| + GST_PLAYER_ERROR_FAILED = 0, |
| + GST_PLAYER_ERROR_MISSING_PLUGIN |
| } GstPlayerError; |
| |
| const gchar *gst_player_error_get_name (GstPlayerError error); |
| -- |
| 2.1.4 |
| |