--- a/gst_plugins_base/gst-libs/gst/tag/gstvorbistag.c Wed Mar 31 22:03:18 2010 +0300
+++ b/gst_plugins_base/gst-libs/gst/tag/gstvorbistag.c Tue Aug 31 15:30:33 2010 +0300
@@ -62,7 +62,7 @@
{GST_TAG_COPYRIGHT, "COPYRIGHT"},
{GST_TAG_LICENSE, "LICENSE"},
{GST_TAG_LICENSE_URI, "LICENSE"},
- {GST_TAG_LOCATION, "LOCATION"},
+ {GST_TAG_GEO_LOCATION_NAME, "LOCATION"},
{GST_TAG_ORGANIZATION, "ORGANIZATION"},
{GST_TAG_DESCRIPTION, "DESCRIPTION"},
{GST_TAG_GENRE, "GENRE"},
@@ -90,7 +90,10 @@
{GST_TAG_LANGUAGE_CODE, "LANGUAGE"},
{GST_TAG_CDDA_MUSICBRAINZ_DISCID, "MUSICBRAINZ_DISCID"},
{GST_TAG_CDDA_CDDB_DISCID, "DISCID"},
- /* some incidence that this makes sense:
+ /* For the apparent de-facto standard for coverart in vorbis comments, see:
+ * http://www.hydrogenaudio.org/forums/lofiversion/index.php/t48386.html */
+ {GST_TAG_PREVIEW_IMAGE, "COVERART"},
+ /* some evidence that "BPM" is used elsewhere:
* http://mail.kde.org/pipermail/amarok/2006-May/000090.html
*/
{GST_TAG_BEATS_PER_MINUTE, "BPM"},
@@ -317,6 +320,62 @@
}
}
+static void
+gst_vorbis_tag_add_coverart (GstTagList * tags, gchar * img_data_base64,
+ gint base64_len)
+{
+ GstBuffer *img;
+ gsize img_len;
+ guchar *out;
+ guint save = 0;
+ gint state = 0;
+
+ if (base64_len < 2)
+ goto not_enough_data;
+
+ /* img_data_base64 points to a temporary copy of the base64 encoded data, so
+ * it's safe to do inpace decoding here
+ * TODO: glib 2.20 and later provides g_base64_decode_inplace, so change this
+ * to use glib's API instead once it's in wider use:
+ * http://bugzilla.gnome.org/show_bug.cgi?id=564728
+ * http://svn.gnome.org/viewvc/glib?view=revision&revision=7807 */
+ out = (guchar *) img_data_base64;
+ img_len = g_base64_decode_step (img_data_base64, base64_len,
+ out, &state, &save);
+
+ if (img_len == 0)
+ goto decode_failed;
+
+ img = gst_tag_image_data_to_image_buffer (out, img_len,
+ GST_TAG_IMAGE_TYPE_NONE);
+
+ if (img == NULL)
+ goto convert_failed;
+
+ gst_tag_list_add (tags, GST_TAG_MERGE_APPEND,
+ GST_TAG_PREVIEW_IMAGE, img, NULL);
+
+ gst_buffer_unref (img);
+ return;
+
+/* ERRORS */
+not_enough_data:
+ {
+ GST_WARNING ("COVERART tag with too little base64-encoded data");
+ return;
+ }
+decode_failed:
+ {
+ GST_WARNING ("Couldn't decode base64 image data from COVERART tag");
+ return;
+ }
+convert_failed:
+ {
+ GST_WARNING ("Couldn't extract image or image type from COVERART tag");
+ return;
+ }
+}
+
/**
* gst_tag_list_from_vorbiscomment_buffer:
* @buffer: buffer to convert
@@ -353,7 +412,7 @@
guint cur_size;
guint iterations;
guint8 *data;
- guint size;
+ guint size, value_len;
GstTagList *list;
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
@@ -365,14 +424,19 @@
if (size < 11 || size <= id_data_length + 4)
goto error;
+
if (id_data_length > 0 && memcmp (data, id_data, id_data_length) != 0)
goto error;
+
ADVANCE (id_data_length);
+
if (vendor_string)
*vendor_string = g_strndup (cur, cur_size);
+
ADVANCE (cur_size);
iterations = cur_size;
cur_size = 0;
+
while (iterations) {
ADVANCE (cur_size);
iterations--;
@@ -384,11 +448,19 @@
}
*value = '\0';
value++;
- if (!g_utf8_validate (value, -1, NULL)) {
+ value_len = strlen (value);
+ if (value_len == 0 || !g_utf8_validate (value, value_len, NULL)) {
g_free (cur);
continue;
}
- gst_vorbis_tag_add (list, cur, value);
+ /* we'll just ignore COVERARTMIME and typefind the image data */
+ if (g_ascii_strcasecmp (cur, "COVERARTMIME") == 0) {
+ continue;
+ } else if (g_ascii_strcasecmp (cur, "COVERART") == 0) {
+ gst_vorbis_tag_add_coverart (list, value, value_len);
+ } else {
+ gst_vorbis_tag_add (list, cur, value);
+ }
g_free (cur);
}
@@ -399,6 +471,7 @@
return NULL;
#undef ADVANCE
}
+
typedef struct
{
guint count;
@@ -407,6 +480,39 @@
}
MyForEach;
+static GList *
+gst_tag_to_coverart (const GValue * image_value)
+{
+ gchar *coverart_data, *data_result, *mime_result;
+ const gchar *mime_type;
+ GstStructure *mime_struct;
+ GstBuffer *buffer;
+ GList *l = NULL;
+
+ g_return_val_if_fail (image_value != NULL, NULL);
+
+ buffer = gst_value_get_buffer (image_value);
+ g_return_val_if_fail (gst_caps_is_fixed (buffer->caps), NULL);
+ mime_struct = gst_caps_get_structure (buffer->caps, 0);
+ mime_type = gst_structure_get_name (mime_struct);
+
+ if (strcmp (mime_type, "text/uri-list") == 0) {
+ /* URI reference */
+ coverart_data = g_strndup ((gchar *) buffer->data, buffer->size);
+ } else {
+ coverart_data = g_base64_encode (buffer->data, buffer->size);
+ }
+
+ data_result = g_strdup_printf ("COVERART=%s", coverart_data);
+ mime_result = g_strdup_printf ("COVERARTMIME=%s", mime_type);
+ g_free (coverart_data);
+
+ l = g_list_append (l, data_result);
+ l = g_list_append (l, mime_result);
+
+ return l;
+}
+
/**
* gst_tag_to_vorbis_comments:
* @list: a #GstTagList
@@ -432,6 +538,18 @@
g_return_val_if_fail (list != NULL, NULL);
g_return_val_if_fail (tag != NULL, NULL);
+ /* Special case: cover art is split into two tags to store data and
+ * MIME-type. Even if the tag list contains multiple entries, there is
+ * no reasonable way to save more than one.
+ * If both, preview image and image, are present we prefer the
+ * image tag.
+ */
+ if ((strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0 &&
+ gst_tag_list_get_tag_size (list, GST_TAG_IMAGE) == 0) ||
+ strcmp (tag, GST_TAG_IMAGE) == 0) {
+ return gst_tag_to_coverart (gst_tag_list_get_value_index (list, tag, 0));
+ }
+
if (strcmp (tag, GST_TAG_EXTENDED_COMMENT) != 0) {
vorbis_tag = gst_tag_to_vorbis_tag (tag);
if (!vorbis_tag)