]> git.sesse.net Git - ffmpeg/blob - libavformat/id3v2.c
id3v2: add support for non-text and GEOB type tag frames
[ffmpeg] / libavformat / id3v2.c
1 /*
2  * ID3v2 header parser
3  * Copyright (c) 2003 Fabrice Bellard
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include "id3v2.h"
23 #include "id3v1.h"
24 #include "libavutil/avstring.h"
25 #include "libavutil/intreadwrite.h"
26 #include "libavutil/dict.h"
27 #include "avio_internal.h"
28
29 int ff_id3v2_match(const uint8_t *buf, const char * magic)
30 {
31     return  buf[0]         == magic[0] &&
32             buf[1]         == magic[1] &&
33             buf[2]         == magic[2] &&
34             buf[3]         != 0xff &&
35             buf[4]         != 0xff &&
36            (buf[6] & 0x80) ==    0 &&
37            (buf[7] & 0x80) ==    0 &&
38            (buf[8] & 0x80) ==    0 &&
39            (buf[9] & 0x80) ==    0;
40 }
41
42 int ff_id3v2_tag_len(const uint8_t * buf)
43 {
44     int len = ((buf[6] & 0x7f) << 21) +
45               ((buf[7] & 0x7f) << 14) +
46               ((buf[8] & 0x7f) << 7) +
47                (buf[9] & 0x7f) +
48               ID3v2_HEADER_SIZE;
49     if (buf[5] & 0x10)
50         len += ID3v2_HEADER_SIZE;
51     return len;
52 }
53
54 static unsigned int get_size(AVIOContext *s, int len)
55 {
56     int v = 0;
57     while (len--)
58         v = (v << 7) + (avio_r8(s) & 0x7F);
59     return v;
60 }
61
62 /**
63  * Free GEOB type extra metadata.
64  */
65 static void free_geobtag(ID3v2ExtraMetaGEOB *geob)
66 {
67     av_free(geob->mime_type);
68     av_free(geob->file_name);
69     av_free(geob->description);
70     av_free(geob->data);
71     av_free(geob);
72 }
73
74 /**
75  * Decode characters to UTF-8 according to encoding type. The decoded buffer is
76  * always null terminated.
77  *
78  * @param dst Pointer where the address of the buffer with the decoded bytes is
79  * stored. Buffer must be freed by caller.
80  * @param dstlen Pointer to an int where the length of the decoded string
81  * is stored (in bytes, incl. null termination)
82  * @param maxread Pointer to maximum number of characters to read from the
83  * AVIOContext. After execution the value is decremented by the number of bytes
84  * actually read.
85  * @seeknull If true, decoding stops after the first U+0000 character found, if
86  * there is any before maxread is reached
87  * @returns 0 if no error occured, dst is uninitialized on error
88  */
89 static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
90                       uint8_t **dst, int *dstlen, int *maxread, const int seeknull)
91 {
92     int len, ret;
93     uint8_t tmp;
94     uint32_t ch = 1;
95     int left = *maxread;
96     unsigned int (*get)(AVIOContext*) = avio_rb16;
97     AVIOContext *dynbuf;
98
99     if ((ret = avio_open_dyn_buf(&dynbuf)) < 0) {
100         av_log(s, AV_LOG_ERROR, "Error opening memory stream\n");
101         return ret;
102     }
103
104     switch (encoding) {
105
106     case ID3v2_ENCODING_ISO8859:
107         while (left && (!seeknull || ch)) {
108             ch = avio_r8(pb);
109             PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
110             left--;
111         }
112         break;
113
114     case ID3v2_ENCODING_UTF16BOM:
115         if ((left -= 2) < 0) {
116             av_log(s, AV_LOG_ERROR, "Cannot read BOM value, input too short\n");
117             avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
118             av_freep(dst);
119             return AVERROR_INVALIDDATA;
120         }
121         switch (avio_rb16(pb)) {
122         case 0xfffe:
123             get = avio_rl16;
124         case 0xfeff:
125             break;
126         default:
127             av_log(s, AV_LOG_ERROR, "Incorrect BOM value\n");
128             avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
129             av_freep(dst);
130             *maxread = left;
131             return AVERROR_INVALIDDATA;
132         }
133         // fall-through
134
135     case ID3v2_ENCODING_UTF16BE:
136         while ((left > 1) && (!seeknull || ch)) {
137             GET_UTF16(ch, ((left -= 2) >= 0 ? get(pb) : 0), break;)
138             PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
139         }
140         if (left < 0)
141             left += 2; /* did not read last char from pb */
142         break;
143
144     case ID3v2_ENCODING_UTF8:
145         while (left && (!seeknull || ch)) {
146             ch = avio_r8(pb);
147             avio_w8(dynbuf, ch);
148             left--;
149         }
150         break;
151     default:
152         av_log(s, AV_LOG_WARNING, "Unknown encoding\n");
153     }
154
155     if (ch)
156         avio_w8(dynbuf, 0);
157
158     len = avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
159     if (dstlen)
160         *dstlen = len;
161
162     *maxread = left;
163
164     return 0;
165 }
166
167 /**
168  * Parse a text tag.
169  */
170 static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key)
171 {
172     uint8_t *dst;
173     const char *val = NULL;
174     int len, dstlen;
175     unsigned genre;
176
177     if (taglen < 1)
178         return;
179
180     taglen--; /* account for encoding type byte */
181
182     if (decode_str(s, pb, avio_r8(pb), &dst, &dstlen, &taglen, 0) < 0) {
183         av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
184         return;
185     }
186
187     if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
188         && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
189         && genre <= ID3v1_GENRE_MAX)
190         val = ff_id3v1_genre_str[genre];
191     else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
192         /* dst now contains two 0-terminated strings */
193         dst[dstlen] = 0;
194         len = strlen(dst);
195         key = dst;
196         val = dst + FFMIN(len + 1, dstlen);
197     }
198     else if (*dst)
199         val = dst;
200
201     if (val)
202         av_dict_set(&s->metadata, key, val, AV_DICT_DONT_OVERWRITE);
203
204     av_free(dst);
205 }
206
207 /**
208  * Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
209  */
210 static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta)
211 {
212     ID3v2ExtraMetaGEOB *geob_data = NULL;
213     ID3v2ExtraMeta *new_extra = NULL;
214     char encoding;
215     unsigned int len;
216
217     if (taglen < 1)
218         return;
219
220     geob_data = av_mallocz(sizeof(ID3v2ExtraMetaGEOB));
221     if (!geob_data) {
222         av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMetaGEOB));
223         return;
224     }
225
226     new_extra = av_mallocz(sizeof(ID3v2ExtraMeta));
227     if (!new_extra) {
228         av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMeta));
229         goto fail;
230     }
231
232     /* read encoding type byte */
233     encoding = avio_r8(pb);
234     taglen--;
235
236     /* read MIME type (always ISO-8859) */
237     if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type, NULL, &taglen, 1) < 0
238         || taglen <= 0)
239         goto fail;
240
241     /* read file name */
242     if (decode_str(s, pb, encoding, &geob_data->file_name, NULL, &taglen, 1) < 0
243         || taglen <= 0)
244         goto fail;
245
246     /* read content description */
247     if (decode_str(s, pb, encoding, &geob_data->description, NULL, &taglen, 1) < 0
248         || taglen < 0)
249         goto fail;
250
251     if (taglen) {
252         /* save encapsulated binary data */
253         geob_data->data = av_malloc(taglen);
254         if (!geob_data->data) {
255             av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", taglen);
256             goto fail;
257         }
258         if ((len = avio_read(pb, geob_data->data, taglen)) < taglen)
259             av_log(s, AV_LOG_WARNING, "Error reading GEOB frame, data truncated.\n");
260         geob_data->datasize = len;
261     } else {
262         geob_data->data = NULL;
263         geob_data->datasize = 0;
264     }
265
266     /* add data to the list */
267     new_extra->tag = "GEOB";
268     new_extra->data = geob_data;
269     new_extra->next = *extra_meta;
270     *extra_meta = new_extra;
271
272     return;
273
274 fail:
275     av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", tag);
276     free_geobtag(geob_data);
277     av_free(new_extra);
278     return;
279 }
280
281 static int is_number(const char *str)
282 {
283     while (*str >= '0' && *str <= '9') str++;
284     return !*str;
285 }
286
287 static AVDictionaryEntry* get_date_tag(AVDictionary *m, const char *tag)
288 {
289     AVDictionaryEntry *t;
290     if ((t = av_dict_get(m, tag, NULL, AV_DICT_MATCH_CASE)) &&
291         strlen(t->value) == 4 && is_number(t->value))
292         return t;
293     return NULL;
294 }
295
296 static void merge_date(AVDictionary **m)
297 {
298     AVDictionaryEntry *t;
299     char date[17] = {0};      // YYYY-MM-DD hh:mm
300
301     if (!(t = get_date_tag(*m, "TYER")) &&
302         !(t = get_date_tag(*m, "TYE")))
303         return;
304     av_strlcpy(date, t->value, 5);
305     av_dict_set(m, "TYER", NULL, 0);
306     av_dict_set(m, "TYE",  NULL, 0);
307
308     if (!(t = get_date_tag(*m, "TDAT")) &&
309         !(t = get_date_tag(*m, "TDA")))
310         goto finish;
311     snprintf(date + 4, sizeof(date) - 4, "-%.2s-%.2s", t->value + 2, t->value);
312     av_dict_set(m, "TDAT", NULL, 0);
313     av_dict_set(m, "TDA",  NULL, 0);
314
315     if (!(t = get_date_tag(*m, "TIME")) &&
316         !(t = get_date_tag(*m, "TIM")))
317         goto finish;
318     snprintf(date + 10, sizeof(date) - 10, " %.2s:%.2s", t->value, t->value + 2);
319     av_dict_set(m, "TIME", NULL, 0);
320     av_dict_set(m, "TIM",  NULL, 0);
321
322 finish:
323     if (date[0])
324         av_dict_set(m, "date", date, 0);
325 }
326
327 /**
328  * Get the corresponding ID3v2EMFunc struct for a tag.
329  * @param isv34 Determines if v2.2 or v2.3/4 strings are used
330  * @return A pointer to the ID3v2EMFunc struct if found, NULL otherwise.
331  */
332 static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
333 {
334     int i = 0;
335     while (ff_id3v2_extra_meta_funcs[i].tag3) {
336         if (!memcmp(tag,
337                     (isv34 ?
338                         ff_id3v2_extra_meta_funcs[i].tag4 :
339                         ff_id3v2_extra_meta_funcs[i].tag3),
340                     (isv34 ? 4 : 3)))
341             return &ff_id3v2_extra_meta_funcs[i];
342         i++;
343     }
344     return NULL;
345 }
346
347 static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags, ID3v2ExtraMeta **extra_meta)
348 {
349     int isv34, tlen, unsync;
350     char tag[5];
351     int64_t next, end = avio_tell(s->pb) + len;
352     int taghdrlen;
353     const char *reason = NULL;
354     AVIOContext pb;
355     AVIOContext *pbx;
356     unsigned char *buffer = NULL;
357     int buffer_size = 0;
358     void (*extra_func)(AVFormatContext*, AVIOContext*, int, char*, ID3v2ExtraMeta**) = NULL;
359
360     switch (version) {
361     case 2:
362         if (flags & 0x40) {
363             reason = "compression";
364             goto error;
365         }
366         isv34 = 0;
367         taghdrlen = 6;
368         break;
369
370     case 3:
371     case 4:
372         isv34 = 1;
373         taghdrlen = 10;
374         break;
375
376     default:
377         reason = "version";
378         goto error;
379     }
380
381     unsync = flags & 0x80;
382
383     if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
384         avio_skip(s->pb, get_size(s->pb, 4));
385
386     while (len >= taghdrlen) {
387         unsigned int tflags = 0;
388         int tunsync = 0;
389
390         if (isv34) {
391             avio_read(s->pb, tag, 4);
392             tag[4] = 0;
393             if(version==3){
394                 tlen = avio_rb32(s->pb);
395             }else
396                 tlen = get_size(s->pb, 4);
397             tflags = avio_rb16(s->pb);
398             tunsync = tflags & ID3v2_FLAG_UNSYNCH;
399         } else {
400             avio_read(s->pb, tag, 3);
401             tag[3] = 0;
402             tlen = avio_rb24(s->pb);
403         }
404         if (tlen <= 0 || tlen > len - taghdrlen) {
405             av_log(s, AV_LOG_WARNING, "Invalid size in frame %s, skipping the rest of tag.\n", tag);
406             break;
407         }
408         len -= taghdrlen + tlen;
409         next = avio_tell(s->pb) + tlen;
410
411         if (tflags & ID3v2_FLAG_DATALEN) {
412             avio_rb32(s->pb);
413             tlen -= 4;
414         }
415
416         if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
417             av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
418             avio_skip(s->pb, tlen);
419         /* check for text tag or supported special meta tag */
420         } else if (tag[0] == 'T' || (extra_meta && (extra_func = get_extra_meta_func(tag, isv34)->read))) {
421             if (unsync || tunsync) {
422                 int i, j;
423                 av_fast_malloc(&buffer, &buffer_size, tlen);
424                 if (!buffer) {
425                     av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen);
426                     goto seek;
427                 }
428                 for (i = 0, j = 0; i < tlen; i++, j++) {
429                     buffer[j] = avio_r8(s->pb);
430                     if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
431                         /* Unsynchronised byte, skip it */
432                         j--;
433                     }
434                 }
435                 ffio_init_context(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
436                 tlen = j;
437                 pbx = &pb; // read from sync buffer
438             } else {
439                 pbx = s->pb; // read straight from input
440             }
441             if (tag[0] == 'T')
442                 /* parse text tag */
443                 read_ttag(s, pbx, tlen, tag);
444             else
445                 /* parse special meta tag */
446                 extra_func(s, pbx, tlen, tag, extra_meta);
447         }
448         else if (!tag[0]) {
449             if (tag[1])
450                 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
451             avio_skip(s->pb, tlen);
452             break;
453         }
454         /* Skip to end of tag */
455 seek:
456         avio_seek(s->pb, next, SEEK_SET);
457     }
458
459     if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
460         end += 10;
461
462   error:
463     if (reason)
464         av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
465     avio_seek(s->pb, end, SEEK_SET);
466     av_free(buffer);
467     return;
468 }
469
470 void ff_id3v2_read_all(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta)
471 {
472     int len, ret;
473     uint8_t buf[ID3v2_HEADER_SIZE];
474     int     found_header;
475     int64_t off;
476
477     do {
478         /* save the current offset in case there's nothing to read/skip */
479         off = avio_tell(s->pb);
480         ret = avio_read(s->pb, buf, ID3v2_HEADER_SIZE);
481         if (ret != ID3v2_HEADER_SIZE)
482             break;
483             found_header = ff_id3v2_match(buf, magic);
484             if (found_header) {
485             /* parse ID3v2 header */
486             len = ((buf[6] & 0x7f) << 21) |
487                   ((buf[7] & 0x7f) << 14) |
488                   ((buf[8] & 0x7f) << 7) |
489                    (buf[9] & 0x7f);
490             ff_id3v2_parse(s, len, buf[3], buf[5], extra_meta);
491         } else {
492             avio_seek(s->pb, off, SEEK_SET);
493         }
494     } while (found_header);
495     ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv);
496     ff_metadata_conv(&s->metadata, NULL, ff_id3v2_2_metadata_conv);
497     ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv);
498     merge_date(&s->metadata);
499 }
500
501 void ff_id3v2_read(AVFormatContext *s, const char *magic)
502 {
503     ff_id3v2_read_all(s, magic, NULL);
504 }
505
506 void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta)
507 {
508     ID3v2ExtraMeta *current = *extra_meta, *next;
509     void (*free_func)(ID3v2ExtraMeta*);
510
511     while (current) {
512         if ((free_func = get_extra_meta_func(current->tag, 1)->free))
513             free_func(current->data);
514         next = current->next;
515         av_freep(&current);
516         current = next;
517     }
518 }
519
520 const ID3v2EMFunc ff_id3v2_extra_meta_funcs[] = {
521     { "GEO", "GEOB", read_geobtag, free_geobtag },
522     { NULL }
523 };
524
525 const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
526     { "TALB", "album"},
527     { "TCOM", "composer"},
528     { "TCON", "genre"},
529     { "TCOP", "copyright"},
530     { "TENC", "encoded_by"},
531     { "TIT2", "title"},
532     { "TLAN", "language"},
533     { "TPE1", "artist"},
534     { "TPE2", "album_artist"},
535     { "TPE3", "performer"},
536     { "TPOS", "disc"},
537     { "TPUB", "publisher"},
538     { "TRCK", "track"},
539     { "TSSE", "encoder"},
540     { 0 }
541 };
542
543 const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
544     { "TDRL", "date"},
545     { "TDRC", "date"},
546     { "TDEN", "creation_time"},
547     { "TSOA", "album-sort"},
548     { "TSOP", "artist-sort"},
549     { "TSOT", "title-sort"},
550     { 0 }
551 };
552
553 const AVMetadataConv ff_id3v2_2_metadata_conv[] = {
554     { "TAL",  "album"},
555     { "TCO",  "genre"},
556     { "TT2",  "title"},
557     { "TEN",  "encoded_by"},
558     { "TP1",  "artist"},
559     { "TP2",  "album_artist"},
560     { "TP3",  "performer"},
561     { "TRK",  "track"},
562     { 0 }
563 };
564
565
566 const char ff_id3v2_tags[][4] = {
567    "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
568    "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
569    "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
570    "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
571    { 0 },
572 };
573
574 const char ff_id3v2_4_tags[][4] = {
575    "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
576    "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
577    { 0 },
578 };
579
580 const char ff_id3v2_3_tags[][4] = {
581    "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
582    { 0 },
583 };