Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 1 | From d64c7edb66f4a64ff49c4306cf77fd269b7079ab Mon Sep 17 00:00:00 2001 |
| 2 | From: Jussi Kukkonen <jussi.kukkonen@intel.com> |
| 3 | Date: Mon, 16 Mar 2015 13:45:30 +0200 |
| 4 | Subject: [PATCH] Add error signal emission for missing plugins |
| 5 | |
| 6 | Add a missing plugins error signal to gst-player. Note that this error |
| 7 | does not necessarily mean the playback has completely failed, but in |
| 8 | practice the user experience will be bad (think, e.g. of a mp4 file |
| 9 | where H.264 codec is missing: AAC playback still works...). |
| 10 | |
| 11 | Use the signal in gtk-play to show a infobar if plugins are missing. |
| 12 | |
| 13 | Submitted upstream at https://github.com/sdroege/gst-player/pull/11 |
| 14 | |
| 15 | Upstream-Status: Submitted |
| 16 | Signed-off-by: Jussi Kukkonen <jussi.kukkonen@intel.com> |
| 17 | --- |
| 18 | configure.ac | 2 +- |
| 19 | gtk/gtk-play.c | 54 +++++++++++++++++++++++++++++++++++++++++++++- |
| 20 | lib/gst/player/gstplayer.c | 22 +++++++++++++++++++ |
| 21 | lib/gst/player/gstplayer.h | 3 ++- |
| 22 | 4 files changed, 78 insertions(+), 3 deletions(-) |
| 23 | |
| 24 | diff --git a/configure.ac b/configure.ac |
| 25 | index 90ab74c..6cdb4eb 100644 |
| 26 | --- a/configure.ac |
| 27 | +++ b/configure.ac |
| 28 | @@ -53,7 +53,7 @@ AC_SUBST(LT_AGE) |
| 29 | PKG_PROG_PKG_CONFIG |
| 30 | |
| 31 | PKG_CHECK_MODULES(GLIB, [glib-2.0 gobject-2.0]) |
| 32 | -PKG_CHECK_MODULES(GSTREAMER, [gstreamer-1.0 >= 1.4 gstreamer-video-1.0 >= 1.4]) |
| 33 | +PKG_CHECK_MODULES(GSTREAMER, [gstreamer-1.0 >= 1.4 gstreamer-video-1.0 >= 1.4 gstreamer-pbutils-1.0]) |
| 34 | |
| 35 | GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`" |
| 36 | AC_SUBST(GLIB_PREFIX) |
| 37 | diff --git a/gtk/gtk-play.c b/gtk/gtk-play.c |
| 38 | index b92773b..e2b605a 100644 |
| 39 | --- a/gtk/gtk-play.c |
| 40 | +++ b/gtk/gtk-play.c |
| 41 | @@ -30,6 +30,8 @@ typedef struct |
| 42 | GtkWidget *prev_button, *next_button; |
| 43 | GtkWidget *seekbar; |
| 44 | GtkWidget *video_area; |
| 45 | + GtkWidget *info_label; |
| 46 | + GtkWidget *info_bar; |
| 47 | GtkWidget *volume_button; |
| 48 | gulong seekbar_value_changed_signal_id; |
| 49 | gboolean playing; |
| 50 | @@ -141,6 +143,13 @@ play_pause_clicked_cb (GtkButton * button, GtkPlay * play) |
| 51 | } |
| 52 | |
| 53 | static void |
| 54 | +clear_missing_plugins (GtkPlay * play) |
| 55 | +{ |
| 56 | + gtk_label_set_text (GTK_LABEL (play->info_label), ""); |
| 57 | + gtk_widget_hide (play->info_bar); |
| 58 | +} |
| 59 | + |
| 60 | +static void |
| 61 | skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) |
| 62 | { |
| 63 | GList *prev; |
| 64 | @@ -155,6 +164,7 @@ skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) |
| 65 | |
| 66 | gtk_widget_set_sensitive (play->next_button, TRUE); |
| 67 | gst_player_set_uri (play->player, prev->data); |
| 68 | + clear_missing_plugins (play); |
| 69 | gst_player_play (play->player); |
| 70 | set_title (play, prev->data); |
| 71 | gtk_widget_set_sensitive (play->prev_button, g_list_previous (prev) != NULL); |
| 72 | @@ -175,6 +185,7 @@ skip_next_clicked_cb (GtkButton * button, GtkPlay * play) |
| 73 | |
| 74 | gtk_widget_set_sensitive (play->prev_button, TRUE); |
| 75 | gst_player_set_uri (play->player, next->data); |
| 76 | + clear_missing_plugins (play); |
| 77 | gst_player_play (play->player); |
| 78 | set_title (play, next->data); |
| 79 | gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); |
| 80 | @@ -193,10 +204,16 @@ volume_changed_cb (GtkScaleButton * button, gdouble value, GtkPlay * play) |
| 81 | gst_player_set_volume (play->player, value); |
| 82 | } |
| 83 | |
| 84 | +void |
| 85 | +info_bar_response_cb (GtkInfoBar * bar, gint response, GtkPlay * play) |
| 86 | +{ |
| 87 | + gtk_widget_hide (GTK_WIDGET (bar)); |
| 88 | +} |
| 89 | + |
| 90 | static void |
| 91 | create_ui (GtkPlay * play) |
| 92 | { |
| 93 | - GtkWidget *controls, *main_hbox, *main_vbox; |
| 94 | + GtkWidget *controls, *main_hbox, *main_vbox, *info_bar, *content_area; |
| 95 | |
| 96 | play->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
| 97 | g_signal_connect (G_OBJECT (play->window), "delete-event", |
| 98 | @@ -208,6 +225,20 @@ create_ui (GtkPlay * play) |
| 99 | g_signal_connect (play->video_area, "realize", |
| 100 | G_CALLBACK (video_area_realize_cb), play); |
| 101 | |
| 102 | + play->info_bar = gtk_info_bar_new (); |
| 103 | + gtk_info_bar_set_message_type (GTK_INFO_BAR (play->info_bar), |
| 104 | + GTK_MESSAGE_WARNING); |
| 105 | + //gtk_info_bar_set_show_close_button (GTK_INFO_BAR (play->info_bar), |
| 106 | + // TRUE); |
| 107 | + gtk_widget_set_no_show_all (play->info_bar, TRUE); |
| 108 | + g_signal_connect (play->info_bar, "response", |
| 109 | + G_CALLBACK (info_bar_response_cb), play); |
| 110 | + |
| 111 | + content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (play->info_bar)); |
| 112 | + play->info_label = gtk_label_new (""); |
| 113 | + gtk_container_add (GTK_CONTAINER (content_area), play->info_label); |
| 114 | + gtk_widget_show (play->info_label); |
| 115 | + |
| 116 | /* Unified play/pause button */ |
| 117 | play->play_pause_button = |
| 118 | gtk_button_new_from_icon_name ("media-playback-pause", |
| 119 | @@ -258,6 +289,7 @@ create_ui (GtkPlay * play) |
| 120 | |
| 121 | main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); |
| 122 | gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 0); |
| 123 | + gtk_box_pack_start (GTK_BOX (main_vbox), play->info_bar, FALSE, FALSE, 0); |
| 124 | gtk_box_pack_start (GTK_BOX (main_vbox), controls, FALSE, FALSE, 0); |
| 125 | gtk_container_add (GTK_CONTAINER (play->window), main_vbox); |
| 126 | |
| 127 | @@ -322,6 +354,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) |
| 128 | gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); |
| 129 | |
| 130 | gst_player_set_uri (play->player, next->data); |
| 131 | + clear_missing_plugins (play); |
| 132 | gst_player_play (play->player); |
| 133 | set_title (play, next->data); |
| 134 | } else { |
| 135 | @@ -330,6 +363,24 @@ eos_cb (GstPlayer * unused, GtkPlay * play) |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | +static void |
| 140 | +error_cb (GstPlayer * player, GError * err, GtkPlay * play) |
| 141 | +{ |
| 142 | + char *message; |
| 143 | + |
| 144 | + if (g_error_matches (err, gst_player_error_quark (), |
| 145 | + GST_PLAYER_ERROR_MISSING_PLUGIN)) { |
| 146 | + // add message to end of any existing message: there may be |
| 147 | + // multiple missing plugins. |
| 148 | + message = g_strdup_printf ("%s%s. ", |
| 149 | + gtk_label_get_text (GTK_LABEL (play->info_label)), err->message); |
| 150 | + gtk_label_set_text (GTK_LABEL (play->info_label), message); |
| 151 | + g_free (message); |
| 152 | + |
| 153 | + gtk_widget_show (play->info_bar); |
| 154 | + } |
| 155 | +} |
| 156 | + |
| 157 | int |
| 158 | main (gint argc, gchar ** argv) |
| 159 | { |
| 160 | @@ -422,6 +473,7 @@ main (gint argc, gchar ** argv) |
| 161 | g_signal_connect (play.player, "video-dimensions-changed", |
| 162 | G_CALLBACK (video_dimensions_changed_cb), &play); |
| 163 | g_signal_connect (play.player, "end-of-stream", G_CALLBACK (eos_cb), &play); |
| 164 | + g_signal_connect (play.player, "error", G_CALLBACK (error_cb), &play); |
| 165 | |
| 166 | /* We have file(s) that need playing. */ |
| 167 | set_title (&play, g_list_first (play.uris)->data); |
| 168 | diff --git a/lib/gst/player/gstplayer.c b/lib/gst/player/gstplayer.c |
| 169 | index bd682d9..78e7ba1 100644 |
| 170 | --- a/lib/gst/player/gstplayer.c |
| 171 | +++ b/lib/gst/player/gstplayer.c |
| 172 | @@ -47,6 +47,7 @@ |
| 173 | |
| 174 | #include <gst/gst.h> |
| 175 | #include <gst/video/video.h> |
| 176 | +#include <gst/pbutils/missing-plugins.h> |
| 177 | |
| 178 | GST_DEBUG_CATEGORY_STATIC (gst_player_debug); |
| 179 | #define GST_CAT_DEFAULT gst_player_debug |
| 180 | @@ -238,6 +239,7 @@ gst_player_class_init (GstPlayerClass * klass) |
| 181 | g_signal_new ("video-dimensions-changed", G_TYPE_FROM_CLASS (klass), |
| 182 | G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, |
| 183 | NULL, NULL, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); |
| 184 | + |
| 185 | } |
| 186 | |
| 187 | static void |
| 188 | @@ -619,6 +621,21 @@ error_cb (GstBus * bus, GstMessage * msg, gpointer user_data) |
| 189 | g_mutex_unlock (&self->priv->lock); |
| 190 | } |
| 191 | |
| 192 | +static void |
| 193 | +element_cb (GstBus * bus, GstMessage * msg, gpointer user_data) |
| 194 | +{ |
| 195 | + GstPlayer *self = GST_PLAYER (user_data); |
| 196 | + |
| 197 | + if (gst_is_missing_plugin_message (msg)) { |
| 198 | + gchar *desc; |
| 199 | + |
| 200 | + desc = gst_missing_plugin_message_get_description (msg); |
| 201 | + emit_error (self, g_error_new (GST_PLAYER_ERROR, |
| 202 | + GST_PLAYER_ERROR_MISSING_PLUGIN, "Missing plugin '%s'", desc)); |
| 203 | + g_free (desc); |
| 204 | + } |
| 205 | +} |
| 206 | + |
| 207 | static gboolean |
| 208 | eos_dispatch (gpointer user_data) |
| 209 | { |
| 210 | @@ -1059,6 +1076,8 @@ gst_player_main (gpointer data) |
| 211 | NULL, NULL); |
| 212 | g_source_attach (bus_source, self->priv->context); |
| 213 | |
| 214 | + g_signal_connect (G_OBJECT (bus), "message::element", |
| 215 | + G_CALLBACK (element_cb), self); |
| 216 | g_signal_connect (G_OBJECT (bus), "message::error", G_CALLBACK (error_cb), |
| 217 | self); |
| 218 | g_signal_connect (G_OBJECT (bus), "message::eos", G_CALLBACK (eos_cb), self); |
| 219 | @@ -1560,6 +1579,7 @@ gst_player_error_get_type (void) |
| 220 | static gsize id = 0; |
| 221 | static const GEnumValue values[] = { |
| 222 | {C_ENUM (GST_PLAYER_ERROR_FAILED), "GST_PLAYER_ERROR_FAILED", "failed"}, |
| 223 | + {C_ENUM (GST_PLAYER_ERROR_MISSING_PLUGIN), "GST_PLAYER_ERROR_MISSING_PLUGIN", "missing-plugin"}, |
| 224 | {0, NULL, NULL} |
| 225 | }; |
| 226 | |
| 227 | @@ -1577,6 +1597,8 @@ gst_player_error_get_name (GstPlayerError error) |
| 228 | switch (error) { |
| 229 | case GST_PLAYER_ERROR_FAILED: |
| 230 | return "failed"; |
| 231 | + case GST_PLAYER_ERROR_MISSING_PLUGIN: |
| 232 | + return "missing-plugin"; |
| 233 | } |
| 234 | |
| 235 | g_assert_not_reached (); |
| 236 | diff --git a/lib/gst/player/gstplayer.h b/lib/gst/player/gstplayer.h |
| 237 | index c438513..35fb5bb 100644 |
| 238 | --- a/lib/gst/player/gstplayer.h |
| 239 | +++ b/lib/gst/player/gstplayer.h |
| 240 | @@ -44,7 +44,8 @@ GType gst_player_error_get_type (void); |
| 241 | #define GST_TYPE_PLAYER_ERROR (gst_player_error_get_type ()) |
| 242 | |
| 243 | typedef enum { |
| 244 | - GST_PLAYER_ERROR_FAILED = 0 |
| 245 | + GST_PLAYER_ERROR_FAILED = 0, |
| 246 | + GST_PLAYER_ERROR_MISSING_PLUGIN |
| 247 | } GstPlayerError; |
| 248 | |
| 249 | const gchar *gst_player_error_get_name (GstPlayerError error); |
| 250 | -- |
| 251 | 2.1.4 |
| 252 | |