[FFmpeg-cvslog] id3v2: read attached pictures and export them in ID3v2ExtraMeta.

Anton Khirnov git at videolan.org
Thu Mar 1 03:20:18 CET 2012


ffmpeg | branch: master | Anton Khirnov <anton at khirnov.net> | Sat Feb 25 09:45:38 2012 +0100| [a93b09cb45b86427d6e81fa51c660877d8d5fd17] | committer: Anton Khirnov

id3v2: read attached pictures and export them in ID3v2ExtraMeta.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=a93b09cb45b86427d6e81fa51c660877d8d5fd17
---

 libavformat/id3v2.c |  112 +++++++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/id3v2.h |   13 ++++++
 2 files changed, 125 insertions(+), 0 deletions(-)

diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
index deb652d..853a04c 100644
--- a/libavformat/id3v2.c
+++ b/libavformat/id3v2.c
@@ -25,6 +25,7 @@
 #include "libavutil/intreadwrite.h"
 #include "libavutil/dict.h"
 #include "avio_internal.h"
+#include "internal.h"
 
 const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
     { "TALB", "album"},
@@ -86,6 +87,38 @@ const char ff_id3v2_3_tags[][4] = {
    { 0 },
 };
 
+const char *ff_id3v2_picture_types[21] = {
+    "Other",
+    "32x32 pixels 'file icon'",
+    "Other file icon",
+    "Cover (front)",
+    "Cover (back)",
+    "Leaflet page",
+    "Media (e.g. label side of CD)",
+    "Lead artist/lead performer/soloist",
+    "Artist/performer",
+    "Conductor",
+    "Band/Orchestra",
+    "Composer",
+    "Lyricist/text writer",
+    "Recording Location",
+    "During recording",
+    "During performance",
+    "Movie/video screen capture",
+    "A bright coloured fish",
+    "Illustration",
+    "Band/artist logotype",
+    "Publisher/Studio logotype",
+};
+
+const CodecMime ff_id3v2_mime_tags[] = {
+    {"image/gif" , CODEC_ID_GIF},
+    {"image/jpeg", CODEC_ID_MJPEG},
+    {"image/png" , CODEC_ID_PNG},
+    {"image/tiff", CODEC_ID_TIFF},
+    {"",           CODEC_ID_NONE},
+};
+
 int ff_id3v2_match(const uint8_t *buf, const char * magic)
 {
     return  buf[0]         == magic[0] &&
@@ -381,6 +414,84 @@ finish:
         av_dict_set(m, "date", date, 0);
 }
 
+static void free_apic(void *obj)
+{
+    ID3v2ExtraMetaAPIC *apic = obj;
+    av_freep(&apic->data);
+    av_freep(&apic->description);
+    av_freep(&apic);
+}
+
+static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta)
+{
+    int enc, pic_type;
+    char             mimetype[64];
+    const CodecMime     *mime = ff_id3v2_mime_tags;
+    enum CodecID           id = CODEC_ID_NONE;
+    ID3v2ExtraMetaAPIC  *apic = NULL;
+    ID3v2ExtraMeta *new_extra = NULL;
+    int64_t               end = avio_tell(pb) + taglen;
+
+    if (taglen <= 4)
+        goto fail;
+
+    new_extra = av_mallocz(sizeof(*new_extra));
+    apic      = av_mallocz(sizeof(*apic));
+    if (!new_extra || !apic)
+        goto fail;
+
+    enc = avio_r8(pb);
+    taglen--;
+
+    /* mimetype */
+    taglen -= avio_get_str(pb, taglen, mimetype, sizeof(mimetype));
+    while (mime->id != CODEC_ID_NONE) {
+        if (!strncmp(mime->str, mimetype, sizeof(mimetype))) {
+            id = mime->id;
+            break;
+        }
+        mime++;
+    }
+    if (id == CODEC_ID_NONE) {
+        av_log(s, AV_LOG_WARNING, "Unknown attached picture mimetype: %s, skipping.\n", mimetype);
+        goto fail;
+    }
+    apic->id = id;
+
+    /* picture type */
+    pic_type = avio_r8(pb);
+    taglen--;
+    if (pic_type < 0 || pic_type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types)) {
+        av_log(s, AV_LOG_WARNING, "Unknown attached picture type %d.\n", pic_type);
+        pic_type = 0;
+    }
+    apic->type = ff_id3v2_picture_types[pic_type];
+
+    /* description and picture data */
+    if (decode_str(s, pb, enc, &apic->description, &taglen) < 0) {
+        av_log(s, AV_LOG_ERROR, "Error decoding attached picture description.\n");
+        goto fail;
+    }
+
+    apic->len   = taglen;
+    apic->data  = av_malloc(taglen);
+    if (!apic->data || avio_read(pb, apic->data, taglen) != taglen)
+        goto fail;
+
+    new_extra->tag    = "APIC";
+    new_extra->data   = apic;
+    new_extra->next   = *extra_meta;
+    *extra_meta       = new_extra;
+
+    return;
+
+fail:
+    if (apic)
+        free_apic(apic);
+    av_freep(&new_extra);
+    avio_seek(pb, end, SEEK_SET);
+}
+
 typedef struct ID3v2EMFunc {
     const char *tag3;
     const char *tag4;
@@ -390,6 +501,7 @@ typedef struct ID3v2EMFunc {
 
 static const ID3v2EMFunc id3v2_extra_meta_funcs[] = {
     { "GEO", "GEOB", read_geobtag, free_geobtag },
+    { "PIC", "APIC", read_apic,    free_apic },
     { NULL }
 };
 
diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h
index a296e03..f358d02 100644
--- a/libavformat/id3v2.h
+++ b/libavformat/id3v2.h
@@ -24,6 +24,7 @@
 
 #include <stdint.h>
 #include "avformat.h"
+#include "internal.h"
 #include "metadata.h"
 
 #define ID3v2_HEADER_SIZE 10
@@ -59,6 +60,14 @@ typedef struct ID3v2ExtraMetaGEOB {
     uint8_t *data;
 } ID3v2ExtraMetaGEOB;
 
+typedef struct ID3v2ExtraMetaAPIC {
+    uint8_t     *data;
+    int          len;
+    const char  *type;
+    uint8_t     *description;
+    enum CodecID id;
+} ID3v2ExtraMetaAPIC;
+
 /**
  * Detect ID3v2 Header.
  * @param buf   must be ID3v2_HEADER_SIZE byte long
@@ -120,4 +129,8 @@ extern const char ff_id3v2_4_tags[][4];
  */
 extern const char ff_id3v2_3_tags[][4];
 
+extern const CodecMime ff_id3v2_mime_tags[];
+
+extern const char *ff_id3v2_picture_types[21];
+
 #endif /* AVFORMAT_ID3V2_H */



More information about the ffmpeg-cvslog mailing list