Statistics
| Branch: | Revision:

ffmpeg / libavformat / id3v2.c @ e63a3628

History | View | Annotate | Download (9.32 KB)

1
/*
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
#include "id3v1.h"
24
#include "libavutil/avstring.h"
25
#include "libavutil/intreadwrite.h"
26
#include "metadata.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
static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key)
63
{
64
    char *q, dst[512];
65
    const char *val = NULL;
66
    int len, dstlen = sizeof(dst) - 1;
67
    unsigned genre;
68
    unsigned int (*get)(AVIOContext*) = avio_rb16;
69

    
70
    dst[0] = 0;
71
    if (taglen < 1)
72
        return;
73

    
74
    taglen--; /* account for encoding type byte */
75

    
76
    switch (avio_r8(pb)) { /* encoding type */
77

    
78
    case ID3v2_ENCODING_ISO8859:
79
        q = dst;
80
        while (taglen-- && q - dst < dstlen - 7) {
81
            uint8_t tmp;
82
            PUT_UTF8(avio_r8(pb), tmp, *q++ = tmp;)
83
        }
84
        *q = 0;
85
        break;
86

    
87
    case ID3v2_ENCODING_UTF16BOM:
88
        taglen -= 2;
89
        switch (avio_rb16(pb)) {
90
        case 0xfffe:
91
            get = avio_rl16;
92
        case 0xfeff:
93
            break;
94
        default:
95
            av_log(s, AV_LOG_ERROR, "Incorrect BOM value in tag %s.\n", key);
96
            return;
97
        }
98
        // fall-through
99

    
100
    case ID3v2_ENCODING_UTF16BE:
101
        q = dst;
102
        while (taglen > 1 && q - dst < dstlen - 7) {
103
            uint32_t ch;
104
            uint8_t tmp;
105

    
106
            GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(pb) : 0), break;)
107
            PUT_UTF8(ch, tmp, *q++ = tmp;)
108
        }
109
        *q = 0;
110
        break;
111

    
112
    case ID3v2_ENCODING_UTF8:
113
        len = FFMIN(taglen, dstlen);
114
        avio_read(pb, dst, len);
115
        dst[len] = 0;
116
        break;
117
    default:
118
        av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s\n.", key);
119
    }
120

    
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 */
127
        dst[dstlen] = 0;
128
        len = strlen(dst);
129
        key = dst;
130
        val = dst + FFMIN(len + 1, dstlen);
131
    }
132
    else if (*dst)
133
        val = dst;
134

    
135
    if (val)
136
        av_metadata_set2(&s->metadata, key, val, AV_METADATA_DONT_OVERWRITE);
137
}
138

    
139
static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
140
{
141
    int isv34, tlen, unsync;
142
    char tag[5];
143
    int64_t next;
144
    int taghdrlen;
145
    const char *reason;
146
    AVIOContext pb;
147
    unsigned char *buffer = NULL;
148
    int buffer_size = 0;
149

    
150
    switch (version) {
151
    case 2:
152
        if (flags & 0x40) {
153
            reason = "compression";
154
            goto error;
155
        }
156
        isv34 = 0;
157
        taghdrlen = 6;
158
        break;
159

    
160
    case 3:
161
    case 4:
162
        isv34 = 1;
163
        taghdrlen = 10;
164
        break;
165

    
166
    default:
167
        reason = "version";
168
        goto error;
169
    }
170

    
171
    unsync = flags & 0x80;
172

    
173
    if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
174
        url_fskip(s->pb, get_size(s->pb, 4));
175

    
176
    while (len >= taghdrlen) {
177
        unsigned int tflags;
178
        int tunsync = 0;
179

    
180
        if (isv34) {
181
            avio_read(s->pb, tag, 4);
182
            tag[4] = 0;
183
            if(version==3){
184
                tlen = avio_rb32(s->pb);
185
            }else
186
                tlen = get_size(s->pb, 4);
187
            tflags = avio_rb16(s->pb);
188
            tunsync = tflags & ID3v2_FLAG_UNSYNCH;
189
        } else {
190
            avio_read(s->pb, tag, 3);
191
            tag[3] = 0;
192
            tlen = avio_rb24(s->pb);
193
        }
194
        len -= taghdrlen + tlen;
195

    
196
        if (len < 0)
197
            break;
198

    
199
        next = url_ftell(s->pb) + tlen;
200

    
201
        if (tflags & ID3v2_FLAG_DATALEN) {
202
            avio_rb32(s->pb);
203
            tlen -= 4;
204
        }
205

    
206
        if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
207
            av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
208
            url_fskip(s->pb, tlen);
209
        } else if (tag[0] == 'T') {
210
            if (unsync || tunsync) {
211
                int i, j;
212
                av_fast_malloc(&buffer, &buffer_size, tlen);
213
                for (i = 0, j = 0; i < tlen; i++, j++) {
214
                    buffer[j] = avio_r8(s->pb);
215
                    if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
216
                        /* Unsynchronised byte, skip it */
217
                        j--;
218
                    }
219
                }
220
                ffio_init_context(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
221
                read_ttag(s, &pb, j, tag);
222
            } else {
223
                read_ttag(s, s->pb, tlen, tag);
224
            }
225
        }
226
        else if (!tag[0]) {
227
            if (tag[1])
228
                av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
229
            url_fskip(s->pb, tlen);
230
            break;
231
        }
232
        /* Skip to end of tag */
233
        url_fseek(s->pb, next, SEEK_SET);
234
    }
235

    
236
    if (len > 0) {
237
        /* Skip padding */
238
        url_fskip(s->pb, len);
239
    }
240
    if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
241
        url_fskip(s->pb, 10);
242

    
243
    av_free(buffer);
244
    return;
245

    
246
  error:
247
    av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
248
    url_fskip(s->pb, len);
249
    av_free(buffer);
250
}
251

    
252
void ff_id3v2_read(AVFormatContext *s, const char *magic)
253
{
254
    int len, ret;
255
    uint8_t buf[ID3v2_HEADER_SIZE];
256
    int     found_header;
257
    int64_t off;
258

    
259
    do {
260
        /* save the current offset in case there's nothing to read/skip */
261
        off = url_ftell(s->pb);
262
        ret = avio_read(s->pb, buf, ID3v2_HEADER_SIZE);
263
        if (ret != ID3v2_HEADER_SIZE)
264
            break;
265
            found_header = ff_id3v2_match(buf, magic);
266
            if (found_header) {
267
            /* parse ID3v2 header */
268
            len = ((buf[6] & 0x7f) << 21) |
269
                  ((buf[7] & 0x7f) << 14) |
270
                  ((buf[8] & 0x7f) << 7) |
271
                   (buf[9] & 0x7f);
272
            ff_id3v2_parse(s, len, buf[3], buf[5]);
273
        } else {
274
            url_fseek(s->pb, off, SEEK_SET);
275
        }
276
    } while (found_header);
277
    ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv);
278
    ff_metadata_conv(&s->metadata, NULL, ff_id3v2_2_metadata_conv);
279
    ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv);
280
}
281

    
282
const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
283
    { "TALB", "album"},
284
    { "TCOM", "composer"},
285
    { "TCON", "genre"},
286
    { "TCOP", "copyright"},
287
    { "TENC", "encoded_by"},
288
    { "TIT2", "title"},
289
    { "TLAN", "language"},
290
    { "TPE1", "artist"},
291
    { "TPE2", "album_artist"},
292
    { "TPE3", "performer"},
293
    { "TPOS", "disc"},
294
    { "TPUB", "publisher"},
295
    { "TRCK", "track"},
296
    { "TSSE", "encoder"},
297
    { 0 }
298
};
299

    
300
const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
301
    { "TDRL", "date"},
302
    { "TDRC", "date"},
303
    { "TDEN", "creation_time"},
304
    { "TSOA", "album-sort"},
305
    { "TSOP", "artist-sort"},
306
    { "TSOT", "title-sort"},
307
    { 0 }
308
};
309

    
310
const AVMetadataConv ff_id3v2_2_metadata_conv[] = {
311
    { "TAL",  "album"},
312
    { "TCO",  "genre"},
313
    { "TT2",  "title"},
314
    { "TEN",  "encoded_by"},
315
    { "TP1",  "artist"},
316
    { "TP2",  "album_artist"},
317
    { "TP3",  "performer"},
318
    { "TRK",  "track"},
319
    { 0 }
320
};
321

    
322

    
323
const char ff_id3v2_tags[][4] = {
324
   "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
325
   "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
326
   "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
327
   "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
328
   { 0 },
329
};
330

    
331
const char ff_id3v2_4_tags[][4] = {
332
   "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
333
   "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
334
   { 0 },
335
};
336

    
337
const char ff_id3v2_3_tags[][4] = {
338
   "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
339
   { 0 },
340
};