diff --git a/backends/gstreamer/rb-player-gst-xfade.c b/backends/gstreamer/rb-player-gst-xfade.c
index 723d00a..489c2e8 100644
--- a/backends/gstreamer/rb-player-gst-xfade.c
+++ b/backends/gstreamer/rb-player-gst-xfade.c
@@ -156,6 +156,7 @@
 #include <math.h>
 
 #include <glib/gi18n.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gst/gst.h>
 #include <gst/controller/gstcontroller.h>
 #include <gst/base/gstbasetransform.h>
@@ -326,6 +328,8 @@ typedef struct
 
 	GSList *missing_plugins;
 	gulong  emit_missing_plugins_id;
+
+	GList *tags;
 } RBXFadeStream;
 
 #define RB_TYPE_XFADE_STREAM 	(rb_xfade_stream_get_type ())
@@ -1415,6 +1423,55 @@ schedule_stream_reap (RBPlayerGstXFade *player)
 	g_static_rec_mutex_unlock (&player->priv->stream_list_lock);
 }
 
+/* specific handling for embedded images */
+static void
+process_embedded_image (RBXFadeStream *stream, const GValue *val)
+{
+	GstBuffer *buf;
+	GdkPixbufLoader *loader;
+	GdkPixbuf *pixbuf;
+	GError *error = NULL;
+
+	buf = gst_value_get_buffer (val);
+	if (buf == NULL) {
+		rb_debug ("apparently couldn't get image buffer");
+		return;
+	}
+
+	/* 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;
+	}
+	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;
+	}
+
+	rb_debug ("emitting embedded image: %d x %d / %d",
+		  gdk_pixbuf_get_width (pixbuf),
+		  gdk_pixbuf_get_height (pixbuf),
+		  gdk_pixbuf_get_bits_per_sample (pixbuf));
+
+	_rb_player_emit_image (RB_PLAYER (stream->player),
+			       stream->stream_data,
+			       pixbuf);
+	g_object_unref (pixbuf);
+}
+
 /* emits a tag signal from the player, maybe */
 static void
 process_tag (const GstTagList *list, const gchar *tag, RBXFadeStream *stream)
@@ -1442,7 +1499,10 @@ process_tag (const GstTagList *list, const gchar *tag, RBXFadeStream *stream)
 	else if (!strcmp (tag, GST_TAG_MUSICBRAINZ_TRACKID))
 		field = RB_METADATA_FIELD_MUSICBRAINZ_TRACKID;
 #endif
-	else
+	else if (!strcmp (tag, GST_TAG_IMAGE)) {
+		process_embedded_image (stream, gst_tag_list_get_value_index (list, tag, 0));
+		return;
+	} else
 		return;
 
 	/* of those, all except bitrate are strings */
@@ -1621,8 +1681,12 @@ rb_player_gst_xfade_bus_cb (GstBus *bus, GstMessage *message, RBPlayerGstXFade *
 			GstTagList *tags;
 			gst_message_parse_tag (message, &tags);
 
-			gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, stream);
-			gst_tag_list_free (tags);
+			if (stream->emitted_playing) {
+				gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, stream);
+				gst_tag_list_free (tags);
+			} else {
+				stream->tags = g_list_append (stream->tags, tags);
+			}
 		}
 		break;
 
@@ -1651,8 +1715,23 @@ rb_player_gst_xfade_bus_cb (GstBus *bus, GstMessage *message, RBPlayerGstXFade *
 		if (stream == NULL) {
 			rb_debug ("got application message %s for unknown stream", name);
 		} else if (strcmp (name, STREAM_PLAYING_MESSAGE) == 0) {
+			GList *t;
+
 			rb_debug ("got stream playing message for %s", stream->uri);
 			_rb_player_emit_playing_stream (RB_PLAYER (player), stream->stream_data);
+
+			/* process any buffered tag lists we received while prerolling the stream */
+			for (t = stream->tags; t != NULL; t = t->next) {
+				GstTagList *tags;
+
+				tags = (GstTagList *)t->data;
+				rb_debug ("processing buffered taglist");
+				gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, stream);
+				gst_tag_list_free (tags);
+			}
+			g_list_free (stream->tags);
+			stream->tags = NULL;
+
 		} else if (strcmp (name, FADE_IN_DONE_MESSAGE) == 0) {
 			/* do something? */
 		} else if (strcmp (name, FADE_OUT_DONE_MESSAGE) == 0) {
diff --git a/backends/gstreamer/rb-player-gst.c b/backends/gstreamer/rb-player-gst.c
index f44ec4b..1cc96de 100644
--- a/backends/gstreamer/rb-player-gst.c
+++ b/backends/gstreamer/rb-player-gst.c
@@ -145,6 +145,7 @@ typedef enum
 	TICK,
 	BUFFERING,
 	EVENT,
+	IMAGE,
 } RBPlayerGstSignalType;
 
 typedef struct
@@ -350,11 +351,59 @@ emit_signal_idle (RBPlayerGstSignal *signal)
 }
 
 static void
+process_embedded_image (RBPlayerGst *player, const GValue *val)
+{
+	GstBuffer *buf;
+	GdkPixbufLoader *loader;
+	GdkPixbuf *pixbuf;
+	GError *error = NULL;
+
+	buf = gst_value_get_buffer (val);
+	if (buf == NULL) {
+		rb_debug ("apparently couldn't get image buffer");
+		return;
+	}
+
+	/* 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;
+	}
+	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;
+	}
+
+	rb_debug ("emitting embedded image: %d x %d / %d",
+		  gdk_pixbuf_get_width (pixbuf),
+		  gdk_pixbuf_get_height (pixbuf),
+		  gdk_pixbuf_get_bits_per_sample (pixbuf));
+
+	_rb_player_emit_image (RB_PLAYER (player),
+			       player->priv->stream_data,
+			       pixbuf);
+	g_object_unref (pixbuf);
+}
+
+static void
 process_tag (const GstTagList *list, const gchar *tag, RBPlayerGst *player)
 {
 	int count;
-	RBMetaDataField field;
 	RBPlayerGstSignal *signal;
+	RBMetaDataField field;
 	const GValue *val;
 	GValue *newval;
 
@@ -362,7 +411,7 @@ process_tag (const GstTagList *list, const gchar *tag, RBPlayerGst *player)
 	if (count < 1)
 		return;
 
-	/* only handle the subset of fields we use for iradio */
+	/* only handle the subset of fields we use for iradio, and embedded images */
 	if (!strcmp (tag, GST_TAG_TITLE))
 		field = RB_METADATA_FIELD_TITLE;
 	else if (!strcmp (tag, GST_TAG_GENRE))
@@ -375,8 +424,13 @@ process_tag (const GstTagList *list, const gchar *tag, RBPlayerGst *player)
 	else if (!strcmp (tag, GST_TAG_MUSICBRAINZ_TRACKID))
 		field = RB_METADATA_FIELD_MUSICBRAINZ_TRACKID;
 #endif
-	else
+	else if (!strcmp (tag, GST_TAG_IMAGE)) {
+		/* can't really pretend this is like the other fields we handle here */
+		process_embedded_image (player, gst_tag_list_get_value_index (list, tag, 0));
 		return;
+	} else {
+		return;
+	}
 
 	/* of those, all except bitrate are strings */
 	newval = g_new0 (GValue, 1);
@@ -403,7 +457,7 @@ process_tag (const GstTagList *list, const gchar *tag, RBPlayerGst *player)
 	}
 
 	signal = g_new0 (RBPlayerGstSignal, 1);
-	signal->object = player;
+	signal->object = g_object_ref (player);
 	signal->info_field = field;
 	signal->info = newval;
 	signal->type = INFO;
@@ -412,7 +466,6 @@ process_tag (const GstTagList *list, const gchar *tag, RBPlayerGst *player)
 				      signal,
 				      destroy_idle_signal);
 
-	g_object_ref (G_OBJECT (player));
 	g_hash_table_insert (player->priv->idle_info_ids, GUINT_TO_POINTER (signal->id), NULL);
 }
 
diff --git a/backends/rb-player.c b/backends/rb-player.c
index 586e41a..276846c 100644
--- a/backends/rb-player.c
+++ b/backends/rb-player.c
@@ -42,6 +42,7 @@ enum {
 	TICK,
 	EVENT,
 	PLAYING_STREAM,
+	IMAGE,
 	LAST_SIGNAL
 };
 
@@ -230,6 +231,26 @@ rb_player_interface_init (RBPlayerIface *iface)
 			      G_TYPE_NONE,
 			      1,
 			      G_TYPE_POINTER);
+	
+	/**
+	 * RBPlayer::image:
+	 * @player: the #RBPlayer
+	 * @stream_data: data associated with the stream
+	 * @iamge: 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
@@ -625,6 +646,21 @@ _rb_player_emit_playing_stream (RBPlayer *player, gpointer stream_data)
 	g_signal_emit (player, signals[PLAYING_STREAM], 0, stream_data);
 }
 
+/**
+ * _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 0db18a6..6ad7e2e 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
@@ -119,6 +120,9 @@ struct _RBPlayerIface
 	void		(*event)		(RBPlayer *player,
 						 gpointer stream_data,
 						 gpointer data);
+	void		(*image)		(RBPlayer *player,
+						 gpointer stream_data,
+						 GdkPixbuf *image);
 };
 
 GType		rb_player_get_type   (void);
@@ -160,6 +164,7 @@ void	_rb_player_emit_error (RBPlayer *player, gpointer stream_data, GError *erro
 void	_rb_player_emit_tick (RBPlayer *player, gpointer stream_data, long elapsed, long duration);
 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_image (RBPlayer *player, gpointer stream_data, GdkPixbuf *image);
 
 G_END_DECLS
 
diff --git a/lib/rb-marshal.list b/lib/rb-marshal.list
index 6d11f45..f862916 100644
--- a/lib/rb-marshal.list
+++ b/lib/rb-marshal.list
@@ -26,6 +26,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 d2d1ab3..ff02602 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,
@@ -1007,6 +1008,11 @@ rb_shell_player_init (RBShellPlayer *player)
 				 G_CALLBACK (missing_plugins_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),
@@ -3521,9 +3551,11 @@ playing_stream_cb (RBPlayer *mmplayer,
 
 	/* only emit playing-song-changed etc. when the entry changes */
 	if (player->priv->playing_entry != entry) {
-		player->priv->emit_playing_id = g_idle_add ((GSourceFunc) new_playing_stream_idle_cb, player);
+		/*player->priv->emit_playing_id = g_idle_add ((GSourceFunc) new_playing_stream_idle_cb, player);*/
+		new_playing_stream_idle_cb (player);
 	} else {
-		player->priv->emit_playing_id = g_idle_add ((GSourceFunc) current_playing_stream_idle_cb, player);
+		/*player->priv->emit_playing_id = g_idle_add ((GSourceFunc) current_playing_stream_idle_cb, player);*/
+		current_playing_stream_idle_cb (player);
 	}
 
 	/* update playing entry */
@@ -3732,6 +3764,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
