3 * Copyright (c) 2003 Fabrice Bellard
5 * This file is part of Libav.
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.
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.
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
24 #include "libavutil/avstring.h"
25 #include "libavutil/intreadwrite.h"
26 #include "libavutil/dict.h"
27 #include "avio_internal.h"
29 int ff_id3v2_match(const uint8_t *buf, const char * magic)
31 return buf[0] == magic[0] &&
36 (buf[6] & 0x80) == 0 &&
37 (buf[7] & 0x80) == 0 &&
38 (buf[8] & 0x80) == 0 &&
42 int ff_id3v2_tag_len(const uint8_t * buf)
44 int len = ((buf[6] & 0x7f) << 21) +
45 ((buf[7] & 0x7f) << 14) +
46 ((buf[8] & 0x7f) << 7) +
50 len += ID3v2_HEADER_SIZE;
54 static unsigned int get_size(AVIOContext *s, int len)
58 v = (v << 7) + (avio_r8(s) & 0x7F);
62 static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key)
65 const char *val = NULL;
66 int len, dstlen = sizeof(dst) - 1;
68 unsigned int (*get)(AVIOContext*) = avio_rb16;
74 taglen--; /* account for encoding type byte */
76 switch (avio_r8(pb)) { /* encoding type */
78 case ID3v2_ENCODING_ISO8859:
80 while (taglen-- && q - dst < dstlen - 7) {
82 PUT_UTF8(avio_r8(pb), tmp, *q++ = tmp;)
87 case ID3v2_ENCODING_UTF16BOM:
89 switch (avio_rb16(pb)) {
95 av_log(s, AV_LOG_ERROR, "Incorrect BOM value in tag %s.\n", key);
100 case ID3v2_ENCODING_UTF16BE:
102 while (taglen > 1 && q - dst < dstlen - 7) {
106 GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(pb) : 0), break;)
107 PUT_UTF8(ch, tmp, *q++ = tmp;)
112 case ID3v2_ENCODING_UTF8:
113 len = FFMIN(taglen, dstlen);
114 avio_read(pb, dst, len);
118 av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s.\n", key);
121 if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
122 && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
123 && genre <= ID3v1_GENRE_MAX)
124 val = ff_id3v1_genre_str[genre];
125 else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
126 /* dst now contains two 0-terminated strings */
130 val = dst + FFMIN(len + 1, dstlen);
136 av_dict_set(&s->metadata, key, val, AV_DICT_DONT_OVERWRITE);
139 static int is_number(const char *str)
141 while (*str >= '0' && *str <= '9') str++;
145 static AVDictionaryEntry* get_date_tag(AVDictionary *m, const char *tag)
147 AVDictionaryEntry *t;
148 if ((t = av_dict_get(m, tag, NULL, AV_DICT_MATCH_CASE)) &&
149 strlen(t->value) == 4 && is_number(t->value))
154 static void merge_date(AVDictionary **m)
156 AVDictionaryEntry *t;
157 char date[17] = {0}; // YYYY-MM-DD hh:mm
159 if (!(t = get_date_tag(*m, "TYER")) &&
160 !(t = get_date_tag(*m, "TYE")))
162 av_strlcpy(date, t->value, 5);
163 av_dict_set(m, "TYER", NULL, 0);
164 av_dict_set(m, "TYE", NULL, 0);
166 if (!(t = get_date_tag(*m, "TDAT")) &&
167 !(t = get_date_tag(*m, "TDA")))
169 snprintf(date + 4, sizeof(date) - 4, "-%.2s-%.2s", t->value + 2, t->value);
170 av_dict_set(m, "TDAT", NULL, 0);
171 av_dict_set(m, "TDA", NULL, 0);
173 if (!(t = get_date_tag(*m, "TIME")) &&
174 !(t = get_date_tag(*m, "TIM")))
176 snprintf(date + 10, sizeof(date) - 10, " %.2s:%.2s", t->value, t->value + 2);
177 av_dict_set(m, "TIME", NULL, 0);
178 av_dict_set(m, "TIM", NULL, 0);
182 av_dict_set(m, "date", date, 0);
185 static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
187 int isv34, tlen, unsync;
189 int64_t next, end = avio_tell(s->pb) + len;
191 const char *reason = NULL;
193 unsigned char *buffer = NULL;
199 reason = "compression";
217 unsync = flags & 0x80;
219 if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
220 avio_skip(s->pb, get_size(s->pb, 4));
222 while (len >= taghdrlen) {
223 unsigned int tflags = 0;
227 avio_read(s->pb, tag, 4);
230 tlen = avio_rb32(s->pb);
232 tlen = get_size(s->pb, 4);
233 tflags = avio_rb16(s->pb);
234 tunsync = tflags & ID3v2_FLAG_UNSYNCH;
236 avio_read(s->pb, tag, 3);
238 tlen = avio_rb24(s->pb);
240 if (tlen <= 0 || tlen > len - taghdrlen) {
241 av_log(s, AV_LOG_WARNING, "Invalid size in frame %s, skipping the rest of tag.\n", tag);
244 len -= taghdrlen + tlen;
245 next = avio_tell(s->pb) + tlen;
247 if (tflags & ID3v2_FLAG_DATALEN) {
252 if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
253 av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
254 avio_skip(s->pb, tlen);
255 } else if (tag[0] == 'T') {
256 if (unsync || tunsync) {
258 av_fast_malloc(&buffer, &buffer_size, tlen);
260 av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen);
263 for (i = 0, j = 0; i < tlen; i++, j++) {
264 buffer[j] = avio_r8(s->pb);
265 if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
266 /* Unsynchronised byte, skip it */
270 ffio_init_context(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
271 read_ttag(s, &pb, j, tag);
273 read_ttag(s, s->pb, tlen, tag);
278 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
279 avio_skip(s->pb, tlen);
282 /* Skip to end of tag */
284 avio_seek(s->pb, next, SEEK_SET);
287 if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
292 av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
293 avio_seek(s->pb, end, SEEK_SET);
298 void ff_id3v2_read(AVFormatContext *s, const char *magic)
301 uint8_t buf[ID3v2_HEADER_SIZE];
306 /* save the current offset in case there's nothing to read/skip */
307 off = avio_tell(s->pb);
308 ret = avio_read(s->pb, buf, ID3v2_HEADER_SIZE);
309 if (ret != ID3v2_HEADER_SIZE)
311 found_header = ff_id3v2_match(buf, magic);
313 /* parse ID3v2 header */
314 len = ((buf[6] & 0x7f) << 21) |
315 ((buf[7] & 0x7f) << 14) |
316 ((buf[8] & 0x7f) << 7) |
318 ff_id3v2_parse(s, len, buf[3], buf[5]);
320 avio_seek(s->pb, off, SEEK_SET);
322 } while (found_header);
323 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv);
324 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_2_metadata_conv);
325 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv);
326 merge_date(&s->metadata);
329 const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
331 { "TCOM", "composer"},
333 { "TCOP", "copyright"},
334 { "TENC", "encoded_by"},
336 { "TLAN", "language"},
338 { "TPE2", "album_artist"},
339 { "TPE3", "performer"},
341 { "TPUB", "publisher"},
343 { "TSSE", "encoder"},
347 const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
350 { "TDEN", "creation_time"},
351 { "TSOA", "album-sort"},
352 { "TSOP", "artist-sort"},
353 { "TSOT", "title-sort"},
357 const AVMetadataConv ff_id3v2_2_metadata_conv[] = {
361 { "TEN", "encoded_by"},
363 { "TP2", "album_artist"},
364 { "TP3", "performer"},
370 const char ff_id3v2_tags[][4] = {
371 "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
372 "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
373 "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
374 "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
378 const char ff_id3v2_4_tags[][4] = {
379 "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
380 "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
384 const char ff_id3v2_3_tags[][4] = {
385 "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",