From a93b09cb45b86427d6e81fa51c660877d8d5fd17 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 25 Feb 2012 09:45:38 +0100 Subject: [PATCH] id3v2: read attached pictures and export them in ID3v2ExtraMeta. --- libavformat/id3v2.c | 112 ++++++++++++++++++++++++++++++++++++++++++++ libavformat/id3v2.h | 13 +++++ 2 files changed, 125 insertions(+) diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index deb652d60c..853a04c78e 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 a296e0315b..f358d02892 100644 --- a/libavformat/id3v2.h +++ b/libavformat/id3v2.h @@ -24,6 +24,7 @@ #include #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 */