[FFmpeg-devel] [RFC][PATCH] Rudimentary support for id3v2 APIC tags.

Adrian Drzewiecki adrian.drzewiecki at gmail.com
Sat Dec 24 20:22:01 CET 2011


When parsing id3 tags, if an APIC tag is encountered, add it
to the tag dictionary encoded as "<mime type>\0<4 byte data len>\0<data>".
---
 libavformat/id3v2.c |  115 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 115 insertions(+), 0 deletions(-)

diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
index 60a780c..93b1be4 100644
--- a/libavformat/id3v2.c
+++ b/libavformat/id3v2.c
@@ -274,6 +274,118 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const cha
         av_dict_set(&s->metadata, key, dst, dict_flags);
 }
 
+/*
+ * Parse an image tag.
+ * The image will be prefixed by the mime-type string (\0 terminated) and
+ * 32bit byte size of the image.
+ */
+static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, const char *tag)
+{
+    /* from http://id3.org/id3v2.4.0-frames #4.14 */
+    const char *key[] = {
+        "other_picture",
+        "32x32_icon",
+        "other_icon",
+        "front_cover",
+        "back_cover",
+        "leaflet_page",
+        "media_picture",
+        "lead_performer_picture",
+        "artist_picture",
+        "conductor_picture",
+        "band_picture",
+        "compose_picture",
+        "lyricist_picture",
+        "location_picture",
+        "recording_picture",
+        "performance_picture",
+        "screen_capture",
+        "a_bright_coloured_fish",
+        "illustration",
+        "band_logo",
+        "studio_logo"
+    };
+    static int max_key = sizeof(key)/sizeof(key[0]);
+    char *val, *mime_type = NULL;
+    unsigned char text_encoding;
+    unsigned char picture_type;
+    int i, len;
+
+    text_encoding = avio_r8(pb);
+    taglen --;
+
+    /* read mime type */
+    i = len = 0;
+    for (;;) {
+        unsigned char c = avio_r8(pb);
+        taglen --;
+        if (i == len) {
+            len = len ? (2 * len) : 8;
+            mime_type = av_realloc_f(mime_type, len, 1);
+            if (!mime_type) {
+                av_free(mime_type);
+                av_log(s, AV_LOG_ERROR, "Alloc of mime type failed\n");
+                return;
+            }
+        }
+        mime_type[i++] = c;
+        if (!c)
+            break;
+        if (!taglen) {
+            av_log(s, AV_LOG_ERROR, "Couldn't find end of mime type\n");
+            av_free(mime_type);
+            return;
+        }
+    }
+    len = i;
+
+    if (!taglen) {
+        av_log(s, AV_LOG_ERROR, "Truncated APIC tag.\n");
+        av_free(mime_type);
+        return;
+    }
+
+    /* which tag */
+    picture_type = avio_r8(pb);
+    taglen --;
+
+    av_log(s, AV_LOG_INFO, "Found %s APIC\n", mime_type);
+
+    if (picture_type >= max_key || !key[picture_type]) {
+        av_log(s, AV_LOG_INFO, "Unsupported picture type %x\n", picture_type);
+        av_free(mime_type);
+        return;
+    }
+
+    av_log(s, AV_LOG_INFO, "APIC is %s\n", key[picture_type]);
+
+    /* skip over description */
+    while (taglen && avio_r8(pb))
+        taglen --;
+
+    if (!taglen) {
+        av_log(s, AV_LOG_ERROR, "Truncated APIC tag.\n");
+        av_free(mime_type);
+        return;
+    }
+
+    /* len includes \0 */
+    val = av_malloc(len + taglen + sizeof(taglen));
+    if (!val) {
+        av_log(s, AV_LOG_ERROR, "Failed to allocate image buffer.\n");
+        av_free(mime_type);
+        return;
+    }
+
+    memcpy(val, mime_type, len);
+    memcpy(val + len, &taglen, sizeof (taglen));
+    avio_read(pb, val + len + sizeof(taglen), taglen);
+    av_free(mime_type);
+
+    av_log(s, AV_LOG_INFO, "Read image buffer of %d bytes\n", taglen);
+    av_dict_set(&s->metadata, key[picture_type], val, AV_DICT_DONT_STRDUP_VAL);
+}
+
 /**
  * Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
  */
@@ -597,6 +709,9 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
                 /* parse special meta tag */
                 extra_func->read(s, pbx, tlen, tag, extra_meta);
         }
+        else if (!strcmp(tag, "APIC"))
+          /* an image! */
+          read_apic(s, pbx, tlen, tag);
         else if (!tag[0]) {
             if (tag[1])
                 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
-- 
1.7.8.1



More information about the ffmpeg-devel mailing list