[rhythmbox] process embedded images received during playback
- From: Jonathan Matthew <jmatthew src gnome org>
- To: svn-commits-list gnome org
- Subject: [rhythmbox] process embedded images received during playback
- Date: Wed, 29 Apr 2009 04:30:39 -0400 (EDT)
commit 95d5ed9fb1fe752440c6a60ee950e0fd8e3628a7
Author: Jonathan Matthew <jonathan d14n org>
Date: Sat Apr 18 02:03:59 2009 +1000
process embedded images received during playback
- add a new signal on the RBPlayer interface to make embedded images
available as GdkPixbufs
- move tag processing code to rb-player-gst-helper.c, add code to handle
converting images from GstBuffers to GdkPixbufs
- process GST_TAG_IMAGE and GST_TAG_PREVIEW_IMAGE tags, emitting the new
'image' signal
- emit rb:coverArt extra metadata notification when an image is received
from the player, causing the art display plugin to use the embedded
image.
Fixes half of #345975.
---
backends/gstreamer/rb-player-gst-helper.c | 134 +++++++++++++++++++++++++++++
backends/gstreamer/rb-player-gst-helper.h | 21 ++++-
backends/gstreamer/rb-player-gst-xfade.c | 72 ++++-----------
backends/gstreamer/rb-player-gst.c | 71 ++++-----------
backends/rb-player.c | 36 ++++++++
backends/rb-player.h | 5 +
lib/rb-marshal.list | 1 +
shell/rb-shell-player.c | 29 ++++++
8 files changed, 262 insertions(+), 107 deletions(-)
diff --git a/backends/gstreamer/rb-player-gst-helper.c b/backends/gstreamer/rb-player-gst-helper.c
index f36d441..abdd0ea 100644
--- a/backends/gstreamer/rb-player-gst-helper.c
+++ b/backends/gstreamer/rb-player-gst-helper.c
@@ -125,3 +125,137 @@ rb_player_gst_find_element_with_property (GstElement *element, const char *prope
gst_iterator_free (iter);
return result;
}
+
+/**
+ * rb_gst_process_embedded_image:
+ * @taglist: a #GstTagList containing an image
+ * @tag: the tag name
+ *
+ * Converts embedded image data extracted from a tag list into
+ * a #GdkPixbuf. The returned #GdkPixbuf is owned by the caller.
+ *
+ * Returns: a #GdkPixbuf, or NULL.
+ */
+GdkPixbuf *
+rb_gst_process_embedded_image (const GstTagList *taglist, const char *tag)
+{
+ GstBuffer *buf;
+ GdkPixbufLoader *loader;
+ GdkPixbuf *pixbuf;
+ GError *error = NULL;
+ const GValue *val;
+
+ val = gst_tag_list_get_value_index (taglist, tag, 0);
+ if (val == NULL) {
+ rb_debug ("no value for tag %s in the tag list" , tag);
+ return NULL;
+ }
+
+ buf = gst_value_get_buffer (val);
+ if (buf == NULL) {
+ rb_debug ("apparently couldn't get image buffer");
+ return NULL;
+ }
+
+ /* probably should check media type? text/uri-list won't work too well in a pixbuf loader */
+
+ loader = gdk_pixbuf_loader_new ();
+ rb_debug ("sending %d bytes to pixbuf loader", buf->size);
+ if (gdk_pixbuf_loader_write (loader, buf->data, buf->size, &error) == FALSE) {
+ rb_debug ("pixbuf loader doesn't like the data: %s", error->message);
+ g_error_free (error);
+ g_object_unref (loader);
+ return NULL;
+ }
+
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+ if (pixbuf != NULL) {
+ g_object_ref (pixbuf);
+ }
+
+ gdk_pixbuf_loader_close (loader, NULL);
+ g_object_unref (loader);
+
+ if (pixbuf == NULL) {
+ rb_debug ("pixbuf loader didn't give us a pixbuf");
+ return NULL;
+ }
+
+ rb_debug ("returning embedded image: %d x %d / %d",
+ gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf),
+ gdk_pixbuf_get_bits_per_sample (pixbuf));
+ return pixbuf;
+}
+
+/**
+ * rb_gst_process_tag_string:
+ * @taglist: a #GstTagList containing a string tag
+ * @tag: tag name
+ * @field: returns the #RBMetaDataField corresponding to the tag
+ * @value: returns the tag value
+ *
+ * Processes a tag string, determining the metadata field identifier
+ * corresponding to the tag name, and converting the tag data into the
+ * appropriate value type.
+ *
+ * Return value: %TRUE if the tag was successfully converted.
+ */
+gboolean
+rb_gst_process_tag_string (const GstTagList *taglist,
+ const char *tag,
+ RBMetaDataField *field,
+ GValue *value)
+{
+ const GValue *tagval;
+
+ if (gst_tag_list_get_tag_size (taglist, tag) < 0) {
+ rb_debug ("no values in taglist for tag %s", tag);
+ return FALSE;
+ }
+
+ /* only handle a few fields here */
+ if (!strcmp (tag, GST_TAG_TITLE))
+ *field = RB_METADATA_FIELD_TITLE;
+ else if (!strcmp (tag, GST_TAG_GENRE))
+ *field = RB_METADATA_FIELD_GENRE;
+ else if (!strcmp (tag, GST_TAG_COMMENT))
+ *field = RB_METADATA_FIELD_COMMENT;
+ else if (!strcmp (tag, GST_TAG_BITRATE))
+ *field = RB_METADATA_FIELD_BITRATE;
+#ifdef GST_TAG_MUSICBRAINZ_TRACKID
+ else if (!strcmp (tag, GST_TAG_MUSICBRAINZ_TRACKID))
+ *field = RB_METADATA_FIELD_MUSICBRAINZ_TRACKID;
+#endif
+ else {
+ rb_debug ("tag %s doesn't correspond to a metadata field we're interested in", tag);
+ return FALSE;
+ }
+
+ /* most of the fields we care about are strings */
+ switch (*field) {
+ case RB_METADATA_FIELD_BITRATE:
+ g_value_init (value, G_TYPE_ULONG);
+ break;
+
+ case RB_METADATA_FIELD_TITLE:
+ case RB_METADATA_FIELD_GENRE:
+ case RB_METADATA_FIELD_COMMENT:
+ case RB_METADATA_FIELD_MUSICBRAINZ_TRACKID:
+ default:
+ g_value_init (value, G_TYPE_STRING);
+ break;
+ }
+
+ tagval = gst_tag_list_get_value_index (taglist, tag, 0);
+ if (!g_value_transform (tagval, value)) {
+ rb_debug ("Could not transform tag value type %s into %s",
+ g_type_name (G_VALUE_TYPE (tagval)),
+ g_type_name (G_VALUE_TYPE (value)));
+ g_value_unset (value);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/backends/gstreamer/rb-player-gst-helper.h b/backends/gstreamer/rb-player-gst-helper.h
index 85cb20e..539fa05 100644
--- a/backends/gstreamer/rb-player-gst-helper.h
+++ b/backends/gstreamer/rb-player-gst-helper.h
@@ -29,8 +29,25 @@
#ifndef __RB_PLAYER_GST_HELPER_H
#define __RB_PLAYER_GST_HELPER_H
-GstElement *rb_player_gst_try_audio_sink (const char *plugin_name, const char *name);
+#include <gst/gst.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
-GstElement *rb_player_gst_find_element_with_property (GstElement *element, const char *property);
+#include "rb-metadata.h"
+
+G_BEGIN_DECLS
+
+GstElement * rb_player_gst_try_audio_sink (const char *plugin_name, const char *name);
+
+GstElement * rb_player_gst_find_element_with_property (GstElement *element, const char *property);
+
+GdkPixbuf * rb_gst_process_embedded_image (const GstTagList *taglist,
+ const char *tag);
+
+gboolean rb_gst_process_tag_string (const GstTagList *taglist,
+ const char *tag,
+ RBMetaDataField *field,
+ GValue *value);
+
+G_END_DECLS
#endif /* __RB_PLAYER_GST_HELPER_H */
diff --git a/backends/gstreamer/rb-player-gst-xfade.c b/backends/gstreamer/rb-player-gst-xfade.c
index e0e8806..e6a884f 100644
--- a/backends/gstreamer/rb-player-gst-xfade.c
+++ b/backends/gstreamer/rb-player-gst-xfade.c
@@ -1442,61 +1442,27 @@ schedule_stream_reap (RBPlayerGstXFade *player)
static void
process_tag (const GstTagList *list, const gchar *tag, RBXFadeStream *stream)
{
- int count;
RBMetaDataField field;
- const GValue *val;
- GValue newval = {0,};
-
- count = gst_tag_list_get_tag_size (list, tag);
- if (count < 1)
- return;
-
- rb_debug ("got tag %s for stream %s", tag, stream->uri);
- /* only handle the subset of fields we use for iradio */
- if (!strcmp (tag, GST_TAG_TITLE))
- field = RB_METADATA_FIELD_TITLE;
- else if (!strcmp (tag, GST_TAG_GENRE))
- field = RB_METADATA_FIELD_GENRE;
- else if (!strcmp (tag, GST_TAG_COMMENT))
- field = RB_METADATA_FIELD_COMMENT;
- else if (!strcmp (tag, GST_TAG_BITRATE))
- field = RB_METADATA_FIELD_BITRATE;
-#ifdef GST_TAG_MUSICBRAINZ_TRACKID
- else if (!strcmp (tag, GST_TAG_MUSICBRAINZ_TRACKID))
- field = RB_METADATA_FIELD_MUSICBRAINZ_TRACKID;
-#endif
- else
- return;
-
- /* of those, all except bitrate are strings */
- switch (field) {
- case RB_METADATA_FIELD_BITRATE:
- g_value_init (&newval, G_TYPE_ULONG);
- break;
-
- case RB_METADATA_FIELD_TITLE:
- case RB_METADATA_FIELD_GENRE:
- case RB_METADATA_FIELD_COMMENT:
- case RB_METADATA_FIELD_MUSICBRAINZ_TRACKID:
- default:
- g_value_init (&newval, G_TYPE_STRING);
- break;
+ GValue value = {0,};
+
+ /* process embedded images */
+ if (!strcmp (tag, GST_TAG_IMAGE) || !strcmp (tag, GST_TAG_PREVIEW_IMAGE)) {
+ GdkPixbuf *pixbuf;
+ pixbuf = rb_gst_process_embedded_image (list, tag);
+ if (pixbuf != NULL) {
+ _rb_player_emit_image (RB_PLAYER (stream->player),
+ stream->stream_data,
+ pixbuf);
+ g_object_unref (pixbuf);
+ }
+ } else if (rb_gst_process_tag_string (list, tag, &field, &value)) {
+ rb_debug ("emitting info field %d", field);
+ _rb_player_emit_info (RB_PLAYER (stream->player),
+ stream->stream_data,
+ field,
+ &value);
+ g_value_unset (&value);
}
- val = gst_tag_list_get_value_index (list, tag, 0);
- if (!g_value_transform (val, &newval)) {
- rb_debug ("Could not transform tag value type %s into %s",
- g_type_name (G_VALUE_TYPE (val)),
- g_type_name (G_VALUE_TYPE (&newval)));
- return;
- }
-
- rb_debug ("emitting info field %d for uri %s", field, stream->uri);
- _rb_player_emit_info (RB_PLAYER (stream->player),
- stream->stream_data,
- field,
- &newval);
-
- g_value_unset (&newval);
}
diff --git a/backends/gstreamer/rb-player-gst.c b/backends/gstreamer/rb-player-gst.c
index 3e96f05..d21b5a3 100644
--- a/backends/gstreamer/rb-player-gst.c
+++ b/backends/gstreamer/rb-player-gst.c
@@ -262,60 +262,27 @@ rb_player_gst_gst_free_playbin (RBPlayerGst *player)
static void
process_tag (const GstTagList *list, const gchar *tag, RBPlayerGst *player)
{
- int count;
RBMetaDataField field;
- const GValue *val;
- GValue *newval;
-
- count = gst_tag_list_get_tag_size (list, tag);
- if (count < 1)
- return;
-
- /* only handle the subset of fields we use for iradio */
- if (!strcmp (tag, GST_TAG_TITLE))
- field = RB_METADATA_FIELD_TITLE;
- else if (!strcmp (tag, GST_TAG_GENRE))
- field = RB_METADATA_FIELD_GENRE;
- else if (!strcmp (tag, GST_TAG_COMMENT))
- field = RB_METADATA_FIELD_COMMENT;
- else if (!strcmp (tag, GST_TAG_BITRATE))
- field = RB_METADATA_FIELD_BITRATE;
-#ifdef GST_TAG_MUSICBRAINZ_TRACKID
- else if (!strcmp (tag, GST_TAG_MUSICBRAINZ_TRACKID))
- field = RB_METADATA_FIELD_MUSICBRAINZ_TRACKID;
-#endif
- else
- return;
-
- /* of those, all except bitrate are strings */
- newval = g_new0 (GValue, 1);
- switch (field) {
- case RB_METADATA_FIELD_BITRATE:
- g_value_init (newval, G_TYPE_ULONG);
- break;
-
- case RB_METADATA_FIELD_TITLE:
- case RB_METADATA_FIELD_GENRE:
- case RB_METADATA_FIELD_COMMENT:
- case RB_METADATA_FIELD_MUSICBRAINZ_TRACKID:
- default:
- g_value_init (newval, G_TYPE_STRING);
- break;
- }
- val = gst_tag_list_get_value_index (list, tag, 0);
- if (!g_value_transform (val, newval)) {
- rb_debug ("Could not transform tag value type %s into %s",
- g_type_name (G_VALUE_TYPE (val)),
- g_type_name (G_VALUE_TYPE (newval)));
- g_free (newval);
- return;
+ GValue value = {0,};
+
+ /* process embedded images */
+ if (!strcmp (tag, GST_TAG_IMAGE) || !strcmp (tag, GST_TAG_PREVIEW_IMAGE)) {
+ GdkPixbuf *pixbuf;
+ pixbuf = rb_gst_process_embedded_image (list, tag);
+ if (pixbuf != NULL) {
+ _rb_player_emit_image (RB_PLAYER (player),
+ player->priv->stream_data,
+ pixbuf);
+ g_object_unref (pixbuf);
+ }
+ } else if (rb_gst_process_tag_string (list, tag, &field, &value)) {
+ rb_debug ("emitting info field %d", field);
+ _rb_player_emit_info (RB_PLAYER (player),
+ player->priv->stream_data,
+ field,
+ &value);
+ g_value_unset (&value);
}
-
- _rb_player_emit_info (RB_PLAYER (player),
- player->priv->stream_data,
- field,
- newval);
- g_free (newval);
}
static void
diff --git a/backends/rb-player.c b/backends/rb-player.c
index 2d65f22..960fa11 100644
--- a/backends/rb-player.c
+++ b/backends/rb-player.c
@@ -43,6 +43,7 @@ enum {
EVENT,
PLAYING_STREAM,
VOLUME_CHANGED,
+ IMAGE,
LAST_SIGNAL
};
@@ -249,6 +250,26 @@ rb_player_interface_init (RBPlayerIface *iface)
G_TYPE_NONE,
1,
G_TYPE_FLOAT);
+
+ /**
+ * RBPlayer::image:
+ * @player: the #RBPlayer
+ * @stream_data: data associated with the stream
+ * @image: the image extracted from the stream
+ *
+ * The 'image' signal is emitted to provide access to images extracted
+ * from the stream.
+ */
+ signals[IMAGE] =
+ g_signal_new ("image",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (RBPlayerIface, image),
+ NULL, NULL,
+ rb_marshal_VOID__POINTER_OBJECT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_POINTER, GDK_TYPE_PIXBUF);
}
GType
@@ -658,6 +679,21 @@ _rb_player_emit_volume_changed (RBPlayer *player, float volume)
g_signal_emit (player, signals[VOLUME_CHANGED], 0, volume);
}
+/**
+ * _rb_player_emit_image:
+ * @player: a #RBPlayer implementation
+ * @stream_data: data associated with the stream
+ * @image: an image extracted from the stream
+ *
+ * Emits the 'image' signal to notify listeners of an image that
+ * has been extracted from the stream. To be used by implementations only.
+ */
+void
+_rb_player_emit_image (RBPlayer *player, gpointer stream_data, GdkPixbuf *image)
+{
+ g_signal_emit (player, signals[IMAGE], 0, stream_data, image);
+}
+
GQuark
rb_player_error_quark (void)
{
diff --git a/backends/rb-player.h b/backends/rb-player.h
index 634ddab..e9aa61a 100644
--- a/backends/rb-player.h
+++ b/backends/rb-player.h
@@ -32,6 +32,7 @@
#define __RB_PLAYER_H
#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
#include "rb-metadata.h"
G_BEGIN_DECLS
@@ -121,6 +122,9 @@ struct _RBPlayerIface
gpointer data);
void (*volume_changed) (RBPlayer *player,
float volume);
+ void (*image) (RBPlayer *player,
+ gpointer stream_data,
+ GdkPixbuf *image);
};
GType rb_player_get_type (void);
@@ -163,6 +167,7 @@ void _rb_player_emit_tick (RBPlayer *player, gpointer stream_data, long elapsed,
void _rb_player_emit_event (RBPlayer *player, gpointer stream_data, const char *name, gpointer data);
void _rb_player_emit_playing_stream (RBPlayer *player, gpointer stream_data);
void _rb_player_emit_volume_changed (RBPlayer *player, float volume);
+void _rb_player_emit_image (RBPlayer *player, gpointer stream_data, GdkPixbuf *image);
G_END_DECLS
diff --git a/lib/rb-marshal.list b/lib/rb-marshal.list
index 5a18afb..c2edac6 100644
--- a/lib/rb-marshal.list
+++ b/lib/rb-marshal.list
@@ -27,6 +27,7 @@ VOID:OBJECT,INT,POINTER
VOID:POINTER,INT
VOID:POINTER,INT,POINTER
VOID:POINTER,LONG,LONG
+VOID:POINTER,OBJECT
VOID:POINTER,POINTER
VOID:POINTER,POINTER,POINTER
VOID:POINTER,UINT
diff --git a/shell/rb-shell-player.c b/shell/rb-shell-player.c
index b5609ee..8ed04f2 100644
--- a/shell/rb-shell-player.c
+++ b/shell/rb-shell-player.c
@@ -157,6 +157,7 @@ static void tick_cb (RBPlayer *player, RhythmDBEntry *entry, long elapsed, long
static void error_cb (RBPlayer *player, RhythmDBEntry *entry, const GError *err, gpointer data);
static void missing_plugins_cb (RBPlayer *player, RhythmDBEntry *entry, const char **details, const char **descriptions, RBShellPlayer *sp);
static void playing_stream_cb (RBPlayer *player, RhythmDBEntry *entry, RBShellPlayer *shell_player);
+static void player_image_cb (RBPlayer *player, RhythmDBEntry *entry, GdkPixbuf *image, RBShellPlayer *shell_player);
static void rb_shell_player_error (RBShellPlayer *player, gboolean async, const GError *err);
static void rb_shell_player_set_play_order (RBShellPlayer *player,
@@ -1005,6 +1006,11 @@ rb_shell_player_init (RBShellPlayer *player)
G_CALLBACK (rb_shell_player_volume_changed_cb),
player, 0);
+ g_signal_connect_object (player->priv->mmplayer,
+ "image",
+ G_CALLBACK (player_image_cb),
+ player, 0);
+
{
GVolumeMonitor *monitor = g_volume_monitor_get ();
g_signal_connect (G_OBJECT (monitor),
@@ -3676,6 +3682,29 @@ missing_plugins_cb (RBPlayer *player,
g_closure_sink (retry);
}
+static void
+player_image_cb (RBPlayer *player,
+ RhythmDBEntry *entry,
+ GdkPixbuf *image,
+ RBShellPlayer *shell_player)
+{
+ GValue v = {0,};
+
+ if (image == NULL) {
+ return;
+ }
+
+ g_value_init (&v, GDK_TYPE_PIXBUF);
+ g_value_set_object (&v, image);
+
+ rhythmdb_emit_entry_extra_metadata_notify (shell_player->priv->db,
+ entry,
+ "rb:coverArt",
+ &v);
+ g_value_unset (&v);
+
+}
+
/**
* rb_shell_player_get_playing_path:
* @player: the #RBShellPlayer
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]