Commit a93b09cb authored by Anton Khirnov's avatar Anton Khirnov

id3v2: read attached pictures and export them in ID3v2ExtraMeta.

parent b73ad746
......@@ -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 }
};
......
......@@ -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 */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment