summaryrefslogtreecommitdiffstats
path: root/meta/recipes-multimedia
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-multimedia')
-rw-r--r--meta/recipes-multimedia/gstreamer/gst-player/0001-gtk-play-Disable-visualizations.patch59
-rw-r--r--meta/recipes-multimedia/gstreamer/gst-player/Add-error-signal-emission-for-missing-plugins.patch252
-rw-r--r--meta/recipes-multimedia/gstreamer/gst-player/Fix-pause-play.patch107
-rw-r--r--meta/recipes-multimedia/gstreamer/gst-player/filechooser.patch54
-rw-r--r--meta/recipes-multimedia/gstreamer/gst-player_git.bb4
5 files changed, 0 insertions, 476 deletions
diff --git a/meta/recipes-multimedia/gstreamer/gst-player/0001-gtk-play-Disable-visualizations.patch b/meta/recipes-multimedia/gstreamer/gst-player/0001-gtk-play-Disable-visualizations.patch
deleted file mode 100644
index ea88120074..0000000000
--- a/meta/recipes-multimedia/gstreamer/gst-player/0001-gtk-play-Disable-visualizations.patch
+++ /dev/null
@@ -1,59 +0,0 @@
1From 6cf42c468e93b0aaa171961e059bc3e2fb915889 Mon Sep 17 00:00:00 2001
2From: Jussi Kukkonen <jussi.kukkonen@intel.com>
3Date: Fri, 28 Apr 2017 14:35:19 +0300
4Subject: [PATCH] gtk-play: Disable visualizations
5
6This is a workaround for [YOCTO #11410] (audio playback is broken in
7mediaplayer if vaapi is used). It disables visualizations and makes
8sure we clear the window (otherwise nothing does that and result is
9very ugly).
10
11This patch should be removed when 11410 is fixed.
12
13Upstream-Status: Inappropriate [bug workaround]
14Signed-off-by: Jussi Kukkonen <jussi.kukkonen@intel.com>
15---
16 gtk/gtk-play.c | 13 ++++++++++++-
17 1 file changed, 12 insertions(+), 1 deletion(-)
18
19diff --git a/gtk/gtk-play.c b/gtk/gtk-play.c
20index 8ae0fea..63b9bb0 100644
21--- a/gtk/gtk-play.c
22+++ b/gtk/gtk-play.c
23@@ -1401,6 +1401,15 @@ get_child_position (GtkOverlay * overlay, GtkWidget * widget,
24 return TRUE;
25 }
26
27+/* Hack to make sure something gets drawn if visualizations are disabled */
28+static gboolean
29+draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data)
30+{
31+ cairo_set_source_rgb (cr, 0, 0, 0);
32+ cairo_paint (cr);
33+ return FALSE;
34+}
35+
36 static void
37 create_ui (GtkPlay * play)
38 {
39@@ -1431,6 +1440,8 @@ create_ui (GtkPlay * play)
40 play->video_area = gtk_drawing_area_new ();
41 g_signal_connect (play->video_area, "realize",
42 G_CALLBACK (video_area_realize_cb), play);
43+ g_signal_connect (play->video_area, "draw",
44+ G_CALLBACK (draw_cb), NULL);
45 }
46 gtk_widget_set_events (play->video_area, GDK_EXPOSURE_MASK
47 | GDK_LEAVE_NOTIFY_MASK
48@@ -1753,7 +1764,7 @@ gtk_play_constructor (GType type, guint n_construct_params,
49
50 /* enable visualization (by default playbin uses goom) */
51 /* if visualization is enabled then use the first element */
52- gst_player_set_visualization_enabled (self->player, TRUE);
53+ gst_player_set_visualization_enabled (self->player, FALSE);
54
55 g_signal_connect (G_OBJECT (self), "show", G_CALLBACK (show_cb), NULL);
56
57--
582.1.4
59
diff --git a/meta/recipes-multimedia/gstreamer/gst-player/Add-error-signal-emission-for-missing-plugins.patch b/meta/recipes-multimedia/gstreamer/gst-player/Add-error-signal-emission-for-missing-plugins.patch
deleted file mode 100644
index 712d46daa0..0000000000
--- a/meta/recipes-multimedia/gstreamer/gst-player/Add-error-signal-emission-for-missing-plugins.patch
+++ /dev/null
@@ -1,252 +0,0 @@
1From d64c7edb66f4a64ff49c4306cf77fd269b7079ab Mon Sep 17 00:00:00 2001
2From: Jussi Kukkonen <jussi.kukkonen@intel.com>
3Date: Mon, 16 Mar 2015 13:45:30 +0200
4Subject: [PATCH] Add error signal emission for missing plugins
5
6Add a missing plugins error signal to gst-player. Note that this error
7does not necessarily mean the playback has completely failed, but in
8practice the user experience will be bad (think, e.g. of a mp4 file
9where H.264 codec is missing: AAC playback still works...).
10
11Use the signal in gtk-play to show a infobar if plugins are missing.
12
13Submitted upstream at https://github.com/sdroege/gst-player/pull/11
14
15Upstream-Status: Submitted
16Signed-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
24diff --git a/configure.ac b/configure.ac
25index 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)
37diff --git a/gtk/gtk-play.c b/gtk/gtk-play.c
38index 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);
168diff --git a/lib/gst/player/gstplayer.c b/lib/gst/player/gstplayer.c
169index 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 ();
236diff --git a/lib/gst/player/gstplayer.h b/lib/gst/player/gstplayer.h
237index 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--
2512.1.4
252
diff --git a/meta/recipes-multimedia/gstreamer/gst-player/Fix-pause-play.patch b/meta/recipes-multimedia/gstreamer/gst-player/Fix-pause-play.patch
deleted file mode 100644
index 783c42ad70..0000000000
--- a/meta/recipes-multimedia/gstreamer/gst-player/Fix-pause-play.patch
+++ /dev/null
@@ -1,107 +0,0 @@
1Fix pause/play
2
3The current player state is now notified via the state-changed signal,
4and in the GTK UI it was only used to keep track of the desired state.
5
6This is a backport of upstream commit 738479c7a0.
7
8Upstream-Status: Backport
9Signed-off-by: Jussi Kukkonen <jussi.kukkonen@intel.com>
10
11---
12 gtk/gtk-play.c | 8 ++++++--
13 lib/gst/player/gstplayer.c | 12 ------------
14 lib/gst/player/gstplayer.h | 2 --
15 3 files changed, 6 insertions(+), 16 deletions(-)
16
17diff --git a/gtk/gtk-play.c b/gtk/gtk-play.c
18index 6e7a098..e2b605a 100644
19--- a/gtk/gtk-play.c
20+++ b/gtk/gtk-play.c
21@@ -34,6 +34,7 @@ typedef struct
22 GtkWidget *info_bar;
23 GtkWidget *volume_button;
24 gulong seekbar_value_changed_signal_id;
25+ gboolean playing;
26 } GtkPlay;
27
28 /* Compat stubs */
29@@ -118,12 +119,13 @@ play_pause_clicked_cb (GtkButton * button, GtkPlay * play)
30 {
31 GtkWidget *image;
32
33- if (gst_player_is_playing (play->player)) {
34+ if (play->playing) {
35 gst_player_pause (play->player);
36 image =
37 gtk_image_new_from_icon_name ("media-playback-start",
38 GTK_ICON_SIZE_BUTTON);
39 gtk_button_set_image (GTK_BUTTON (play->play_pause_button), image);
40+ play->playing = FALSE;
41 } else {
42 gchar *title;
43
44@@ -136,6 +138,7 @@ play_pause_clicked_cb (GtkButton * button, GtkPlay * play)
45 title = gst_player_get_uri (play->player);
46 set_title (play, title);
47 g_free (title);
48+ play->playing = TRUE;
49 }
50 }
51
52@@ -335,7 +338,7 @@ video_dimensions_changed_cb (GstPlayer * unused, gint width, gint height,
53 static void
54 eos_cb (GstPlayer * unused, GtkPlay * play)
55 {
56- if (gst_player_is_playing (play->player)) {
57+ if (play->playing) {
58 GList *next = NULL;
59 gchar *uri;
60
61@@ -452,6 +455,7 @@ main (gint argc, gchar ** argv)
62 }
63
64 play.player = gst_player_new ();
65+ play.playing = TRUE;
66
67 g_object_set (play.player, "dispatch-to-main-context", TRUE, NULL);
68
69diff --git a/lib/gst/player/gstplayer.c b/lib/gst/player/gstplayer.c
70index 069b284..78e7ba1 100644
71--- a/lib/gst/player/gstplayer.c
72+++ b/lib/gst/player/gstplayer.c
73@@ -1422,18 +1422,6 @@ gst_player_set_uri (GstPlayer * self, const gchar * val)
74 g_object_set (self, "uri", val, NULL);
75 }
76
77-gboolean
78-gst_player_is_playing (GstPlayer * self)
79-{
80- gboolean val;
81-
82- g_return_val_if_fail (GST_IS_PLAYER (self), FALSE);
83-
84- g_object_get (self, "is-playing", &val, NULL);
85-
86- return val;
87-}
88-
89 GstClockTime
90 gst_player_get_position (GstPlayer * self)
91 {
92diff --git a/lib/gst/player/gstplayer.h b/lib/gst/player/gstplayer.h
93index 6933dd7..35fb5bb 100644
94--- a/lib/gst/player/gstplayer.h
95+++ b/lib/gst/player/gstplayer.h
96@@ -93,8 +93,6 @@ gchar * gst_player_get_uri (GstPlayer * player);
97 void gst_player_set_uri (GstPlayer * player,
98 const gchar * uri);
99
100-gboolean gst_player_is_playing (GstPlayer * player);
101-
102 GstClockTime gst_player_get_position (GstPlayer * player);
103 GstClockTime gst_player_get_duration (GstPlayer * player);
104
105--
1062.1.4
107
diff --git a/meta/recipes-multimedia/gstreamer/gst-player/filechooser.patch b/meta/recipes-multimedia/gstreamer/gst-player/filechooser.patch
deleted file mode 100644
index 7bf1b034b3..0000000000
--- a/meta/recipes-multimedia/gstreamer/gst-player/filechooser.patch
+++ /dev/null
@@ -1,54 +0,0 @@
1Upstream-Status: Submitted
2Signed-off-by: Ross Burton <ross.burton@intel.com>
3
4From 43d4b19ab611d844156e26c4840cc54ddb73ae03 Mon Sep 17 00:00:00 2001
5From: Ross Burton <ross.burton@intel.com>
6Date: Thu, 26 Feb 2015 17:17:05 +0000
7Subject: [PATCH] gtk-play: show a file chooser if no URIs were passed
8
9---
10 gtk/gtk-play.c | 28 ++++++++++++++++++++++++++--
11 1 file changed, 26 insertions(+), 2 deletions(-)
12
13diff --git a/gtk/gtk-play.c b/gtk/gtk-play.c
14index f015077..9766a72 100644
15--- a/gtk/gtk-play.c
16+++ b/gtk/gtk-play.c
17@@ -319,8 +319,32 @@ main (gint argc, gchar ** argv)
18 // FIXME: Add support for playlists and stuff
19 /* Parse the list of the file names we have to play. */
20 if (!file_names) {
21- g_print ("Usage: %s FILE(s)|URI(s)\n", APP_NAME);
22- return 1;
23+ GtkWidget *chooser;
24+ int res;
25+
26+ chooser = gtk_file_chooser_dialog_new ("Select files to play", NULL,
27+ GTK_FILE_CHOOSER_ACTION_OPEN,
28+ "_Cancel", GTK_RESPONSE_CANCEL,
29+ "_Open", GTK_RESPONSE_ACCEPT,
30+ NULL);
31+ g_object_set (chooser,
32+ "local-only", FALSE,
33+ "select-multiple", TRUE,
34+ NULL);
35+
36+ res = gtk_dialog_run (GTK_DIALOG (chooser));
37+ if (res == GTK_RESPONSE_ACCEPT) {
38+ GSList *l;
39+
40+ l = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser));
41+ while (l) {
42+ play.uris = g_list_append (play.uris, l->data);
43+ l = g_slist_delete_link (l, l);
44+ }
45+ } else {
46+ return 0;
47+ }
48+ gtk_widget_destroy (chooser);
49 } else {
50 guint i;
51
52--
531.7.10.4
54
diff --git a/meta/recipes-multimedia/gstreamer/gst-player_git.bb b/meta/recipes-multimedia/gstreamer/gst-player_git.bb
index f3580570b4..4fe8fdef4a 100644
--- a/meta/recipes-multimedia/gstreamer/gst-player_git.bb
+++ b/meta/recipes-multimedia/gstreamer/gst-player_git.bb
@@ -5,10 +5,6 @@ LIC_FILES_CHKSUM = "file://gtk/gtk-play.c;beginline=1;endline=20;md5=f8c72dae3d3
5DEPENDS = "glib-2.0 gstreamer1.0 gstreamer1.0-plugins-base gstreamer1.0-plugins-bad gtk+3 glib-2.0-native" 5DEPENDS = "glib-2.0 gstreamer1.0 gstreamer1.0-plugins-base gstreamer1.0-plugins-bad gtk+3 glib-2.0-native"
6 6
7SRC_URI = "git://github.com/sdroege/gst-player.git \ 7SRC_URI = "git://github.com/sdroege/gst-player.git \
8 file://filechooser.patch;apply=0 \
9 file://Fix-pause-play.patch;apply=0 \
10 file://Add-error-signal-emission-for-missing-plugins.patch;apply=0 \
11 file://0001-gtk-play-Disable-visualizations.patch \
12 file://gst-player.desktop" 8 file://gst-player.desktop"
13 9
14SRCREV = "ee3c226c82767a089743e4e06058743e67f73cdb" 10SRCREV = "ee3c226c82767a089743e4e06058743e67f73cdb"