Statistics
| Branch: | Revision:

ffmpeg / libavformat / id3v2.c @ f7fcd6a2

History | View | Annotate | Download (8.89 KB)

1 2ea512a6 Alex Converse
/*
2
 * ID3v2 header parser
3
 * Copyright (c) 2003 Fabrice Bellard
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg 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
 * FFmpeg 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 FFmpeg; 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 75411182 Patrick Dehne
#include "id3v1.h"
24
#include "libavutil/avstring.h"
25 3a1350e8 Michael Karcher
#include "libavutil/intreadwrite.h"
26 03700d39 Anton Khirnov
#include "metadata.h"
27 2ea512a6 Alex Converse
28 3a1350e8 Michael Karcher
int ff_id3v2_match(const uint8_t *buf, const char * magic)
29 2ea512a6 Alex Converse
{
30 3a1350e8 Michael Karcher
    return  buf[0]         == magic[0] &&
31
            buf[1]         == magic[1] &&
32
            buf[2]         == magic[2] &&
33 7d7b8c32 Diego Biurrun
            buf[3]         != 0xff &&
34
            buf[4]         != 0xff &&
35
           (buf[6] & 0x80) ==    0 &&
36
           (buf[7] & 0x80) ==    0 &&
37
           (buf[8] & 0x80) ==    0 &&
38 1d4b1bf2 Diego Biurrun
           (buf[9] & 0x80) ==    0;
39 2ea512a6 Alex Converse
}
40 ac3ef4a4 Alex Converse
41
int ff_id3v2_tag_len(const uint8_t * buf)
42
{
43
    int len = ((buf[6] & 0x7f) << 21) +
44 7d7b8c32 Diego Biurrun
              ((buf[7] & 0x7f) << 14) +
45
              ((buf[8] & 0x7f) << 7) +
46
               (buf[9] & 0x7f) +
47
              ID3v2_HEADER_SIZE;
48 ac3ef4a4 Alex Converse
    if (buf[5] & 0x10)
49
        len += ID3v2_HEADER_SIZE;
50
    return len;
51
}
52 75411182 Patrick Dehne
53
static unsigned int get_size(ByteIOContext *s, int len)
54
{
55 7d7b8c32 Diego Biurrun
    int v = 0;
56
    while (len--)
57
        v = (v << 7) + (get_byte(s) & 0x7F);
58 75411182 Patrick Dehne
    return v;
59
}
60
61 18bbe9df Alexander Kojevnikov
static void read_ttag(AVFormatContext *s, ByteIOContext *pb, int taglen, const char *key)
62 75411182 Patrick Dehne
{
63
    char *q, dst[512];
64 41770abf Anton Khirnov
    const char *val = NULL;
65 75411182 Patrick Dehne
    int len, dstlen = sizeof(dst) - 1;
66
    unsigned genre;
67 20c68378 Anton Khirnov
    unsigned int (*get)(ByteIOContext*) = get_be16;
68 75411182 Patrick Dehne
69 7d7b8c32 Diego Biurrun
    dst[0] = 0;
70
    if (taglen < 1)
71 75411182 Patrick Dehne
        return;
72
73
    taglen--; /* account for encoding type byte */
74
75 18bbe9df Alexander Kojevnikov
    switch (get_byte(pb)) { /* encoding type */
76 75411182 Patrick Dehne
77
    case 0:  /* ISO-8859-1 (0 - 255 maps directly into unicode) */
78
        q = dst;
79 787f8fad Anton Khirnov
        while (taglen-- && q - dst < dstlen - 7) {
80 75411182 Patrick Dehne
            uint8_t tmp;
81 18bbe9df Alexander Kojevnikov
            PUT_UTF8(get_byte(pb), tmp, *q++ = tmp;)
82 75411182 Patrick Dehne
        }
83 9aa1bcce Anton Khirnov
        *q = 0;
84 75411182 Patrick Dehne
        break;
85
86 20c68378 Anton Khirnov
    case 1:  /* UTF-16 with BOM */
87
        taglen -= 2;
88 18bbe9df Alexander Kojevnikov
        switch (get_be16(pb)) {
89 20c68378 Anton Khirnov
        case 0xfffe:
90
            get = get_le16;
91
        case 0xfeff:
92
            break;
93
        default:
94
            av_log(s, AV_LOG_ERROR, "Incorrect BOM value in tag %s.\n", key);
95
            return;
96
        }
97
        // fall-through
98
99
    case 2:  /* UTF-16BE without BOM */
100
        q = dst;
101
        while (taglen > 1 && q - dst < dstlen - 7) {
102
            uint32_t ch;
103
            uint8_t tmp;
104
105 18bbe9df Alexander Kojevnikov
            GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(pb) : 0), break;)
106 20c68378 Anton Khirnov
            PUT_UTF8(ch, tmp, *q++ = tmp;)
107
        }
108
        *q = 0;
109
        break;
110
111 75411182 Patrick Dehne
    case 3:  /* UTF-8 */
112 037e9afd Jai Menon
        len = FFMIN(taglen, dstlen);
113 18bbe9df Alexander Kojevnikov
        get_buffer(pb, dst, len);
114 75411182 Patrick Dehne
        dst[len] = 0;
115
        break;
116 20c68378 Anton Khirnov
    default:
117
        av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s\n.", key);
118 75411182 Patrick Dehne
    }
119
120 41770abf Anton Khirnov
    if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
121 75411182 Patrick Dehne
        && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
122
        && genre <= ID3v1_GENRE_MAX)
123 41770abf Anton Khirnov
        val = ff_id3v1_genre_str[genre];
124
    else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
125
        /* dst now contains two 0-terminated strings */
126
        dst[dstlen] = 0;
127
        len = strlen(dst);
128
        key = dst;
129
        val = dst + FFMIN(len + 1, dstlen);
130
    }
131
    else if (*dst)
132
        val = dst;
133 75411182 Patrick Dehne
134 41770abf Anton Khirnov
    if (val)
135 2ef6c124 Stefano Sabatini
        av_metadata_set2(&s->metadata, key, val, 0);
136 75411182 Patrick Dehne
}
137
138 46a2da76 Anton Khirnov
static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
139 75411182 Patrick Dehne
{
140 18bbe9df Alexander Kojevnikov
    int isv34, tlen, unsync;
141 41770abf Anton Khirnov
    char tag[5];
142 75411182 Patrick Dehne
    int64_t next;
143
    int taghdrlen;
144
    const char *reason;
145 18bbe9df Alexander Kojevnikov
    ByteIOContext pb;
146
    unsigned char *buffer = NULL;
147
    int buffer_size = 0;
148 75411182 Patrick Dehne
149 7d7b8c32 Diego Biurrun
    switch (version) {
150 75411182 Patrick Dehne
    case 2:
151 7d7b8c32 Diego Biurrun
        if (flags & 0x40) {
152 75411182 Patrick Dehne
            reason = "compression";
153
            goto error;
154
        }
155
        isv34 = 0;
156
        taghdrlen = 6;
157
        break;
158
159
    case 3:
160
    case 4:
161
        isv34 = 1;
162
        taghdrlen = 10;
163
        break;
164
165
    default:
166
        reason = "version";
167
        goto error;
168
    }
169
170 18bbe9df Alexander Kojevnikov
    unsync = flags & 0x80;
171 75411182 Patrick Dehne
172 7d7b8c32 Diego Biurrun
    if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
173 75411182 Patrick Dehne
        url_fskip(s->pb, get_size(s->pb, 4));
174
175 7d7b8c32 Diego Biurrun
    while (len >= taghdrlen) {
176 18bbe9df Alexander Kojevnikov
        unsigned int tflags;
177
        int tunsync = 0;
178
179 7d7b8c32 Diego Biurrun
        if (isv34) {
180 41770abf Anton Khirnov
            get_buffer(s->pb, tag, 4);
181
            tag[4] = 0;
182 3fd5a75b Michael Niedermayer
            if(version==3){
183 d004179e Michael Niedermayer
                tlen = get_be32(s->pb);
184 3fd5a75b Michael Niedermayer
            }else
185
                tlen = get_size(s->pb, 4);
186 18bbe9df Alexander Kojevnikov
            tflags = get_be16(s->pb);
187 7a07d158 Anton Khirnov
            tunsync = tflags & ID3v2_FLAG_UNSYNCH;
188 75411182 Patrick Dehne
        } else {
189 41770abf Anton Khirnov
            get_buffer(s->pb, tag, 3);
190
            tag[3] = 0;
191 1cd44221 Michael Niedermayer
            tlen = get_be24(s->pb);
192 75411182 Patrick Dehne
        }
193
        len -= taghdrlen + tlen;
194
195 7d7b8c32 Diego Biurrun
        if (len < 0)
196 75411182 Patrick Dehne
            break;
197
198
        next = url_ftell(s->pb) + tlen;
199
200 a152c77f Anton Khirnov
        if (tflags & ID3v2_FLAG_DATALEN) {
201
            get_be32(s->pb);
202
            tlen -= 4;
203
        }
204
205 407d3d5a Anton Khirnov
        if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
206
            av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
207
            url_fskip(s->pb, tlen);
208
        } else if (tag[0] == 'T') {
209 18bbe9df Alexander Kojevnikov
            if (unsync || tunsync) {
210
                int i, j;
211
                av_fast_malloc(&buffer, &buffer_size, tlen);
212
                for (i = 0, j = 0; i < tlen; i++, j++) {
213
                    buffer[j] = get_byte(s->pb);
214
                    if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
215
                        /* Unsynchronised byte, skip it */
216
                        j--;
217
                    }
218
                }
219
                init_put_byte(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
220
                read_ttag(s, &pb, j, tag);
221
            } else {
222
                read_ttag(s, s->pb, tlen, tag);
223
            }
224
        }
225 2e3ca1ff Jai Menon
        else if (!tag[0]) {
226
            if (tag[1])
227
                av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
228 ff58de29 Alexander Kojevnikov
            url_fskip(s->pb, tlen);
229 2e3ca1ff Jai Menon
            break;
230
        }
231 75411182 Patrick Dehne
        /* Skip to end of tag */
232
        url_fseek(s->pb, next, SEEK_SET);
233
    }
234
235 ff58de29 Alexander Kojevnikov
    if (len > 0) {
236
        /* Skip padding */
237
        url_fskip(s->pb, len);
238
    }
239 7d7b8c32 Diego Biurrun
    if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
240 75411182 Patrick Dehne
        url_fskip(s->pb, 10);
241 18bbe9df Alexander Kojevnikov
242
    av_free(buffer);
243 75411182 Patrick Dehne
    return;
244
245
  error:
246
    av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
247
    url_fskip(s->pb, len);
248 18bbe9df Alexander Kojevnikov
    av_free(buffer);
249 75411182 Patrick Dehne
}
250 6378b062 Anton Khirnov
251 46a2da76 Anton Khirnov
void ff_id3v2_read(AVFormatContext *s, const char *magic)
252
{
253
    int len, ret;
254
    uint8_t buf[ID3v2_HEADER_SIZE];
255
    int     found_header;
256
    int64_t off;
257
258
    do {
259
        /* save the current offset in case there's nothing to read/skip */
260
        off = url_ftell(s->pb);
261
        ret = get_buffer(s->pb, buf, ID3v2_HEADER_SIZE);
262
        if (ret != ID3v2_HEADER_SIZE)
263 f7fcd6a2 Anton Khirnov
            break;
264 46a2da76 Anton Khirnov
            found_header = ff_id3v2_match(buf, magic);
265
            if (found_header) {
266
            /* parse ID3v2 header */
267
            len = ((buf[6] & 0x7f) << 21) |
268
                  ((buf[7] & 0x7f) << 14) |
269
                  ((buf[8] & 0x7f) << 7) |
270
                   (buf[9] & 0x7f);
271
            ff_id3v2_parse(s, len, buf[3], buf[5]);
272
        } else {
273
            url_fseek(s->pb, off, SEEK_SET);
274
        }
275
    } while (found_header);
276 f7fcd6a2 Anton Khirnov
    ff_metadata_conv(&s->metadata, NULL, ff_id3v2_metadata_conv);
277 46a2da76 Anton Khirnov
}
278
279 6378b062 Anton Khirnov
const AVMetadataConv ff_id3v2_metadata_conv[] = {
280
    { "TALB", "album"},
281 dfe9ee6b Michael Niedermayer
    { "TAL",  "album"},
282 6378b062 Anton Khirnov
    { "TCOM", "composer"},
283
    { "TCON", "genre"},
284 dfe9ee6b Michael Niedermayer
    { "TCO",  "genre"},
285 6378b062 Anton Khirnov
    { "TCOP", "copyright"},
286
    { "TDRL", "date"},
287 ca76a119 Anton Khirnov
    { "TDRC", "date"},
288 bcb5d217 Anton Khirnov
    { "TDEN", "creation_time"},
289 ca76a119 Anton Khirnov
    { "TENC", "encoded_by"},
290
    { "TEN",  "encoded_by"},
291 6378b062 Anton Khirnov
    { "TIT2", "title"},
292 dfe9ee6b Michael Niedermayer
    { "TT2",  "title"},
293 6378b062 Anton Khirnov
    { "TLAN", "language"},
294 8a98be1a Michael Niedermayer
    { "TPE1", "artist"},
295 dfe9ee6b Michael Niedermayer
    { "TP1",  "artist"},
296 ca76a119 Anton Khirnov
    { "TPE2", "album_artist"},
297
    { "TP2",  "album_artist"},
298
    { "TPE3", "performer"},
299
    { "TP3",  "performer"},
300 6378b062 Anton Khirnov
    { "TPOS", "disc"},
301
    { "TPUB", "publisher"},
302
    { "TRCK", "track"},
303 dfe9ee6b Michael Niedermayer
    { "TRK",  "track"},
304 ca76a119 Anton Khirnov
    { "TSOA", "album-sort"},
305
    { "TSOP", "artist-sort"},
306
    { "TSOT", "title-sort"},
307
    { "TSSE", "encoder"},
308 6378b062 Anton Khirnov
    { 0 }
309
};
310 078d89a2 Anton Khirnov
311
const char ff_id3v2_tags[][4] = {
312
   "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDEN", "TDLY", "TDOR", "TDRC",
313
   "TDRL", "TDTG", "TENC", "TEXT", "TFLT", "TIPL", "TIT1", "TIT2", "TIT3",
314
   "TKEY", "TLAN", "TLEN", "TMCL", "TMED", "TMOO", "TOAL", "TOFN", "TOLY",
315
   "TOPE", "TOWN", "TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPRO", "TPUB",
316
   "TRCK", "TRSN", "TRSO", "TSOA", "TSOP", "TSOT", "TSRC", "TSSE", "TSST",
317
   { 0 },
318
};