Statistics
| Branch: | Revision:

ffmpeg / libavformat / id3v2.c @ 2912e87a

History | View | Annotate | Download (10.6 KB)

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 "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 int is_number(const char *str)
140
{
141
    while (*str >= '0' && *str <= '9') str++;
142
    return !*str;
143
}
144

    
145
static AVMetadataTag* get_date_tag(AVMetadata *m, const char *tag)
146
{
147
    AVMetadataTag *t;
148
    if ((t = av_metadata_get(m, tag, NULL, AV_METADATA_MATCH_CASE)) &&
149
        strlen(t->value) == 4 && is_number(t->value))
150
        return t;
151
    return NULL;
152
}
153

    
154
static void merge_date(AVMetadata **m)
155
{
156
    AVMetadataTag *t;
157
    char date[17] = {0};      // YYYY-MM-DD hh:mm
158

    
159
    if (!(t = get_date_tag(*m, "TYER")) &&
160
        !(t = get_date_tag(*m, "TYE")))
161
        return;
162
    av_strlcpy(date, t->value, 5);
163
    av_metadata_set2(m, "TYER", NULL, 0);
164
    av_metadata_set2(m, "TYE",  NULL, 0);
165

    
166
    if (!(t = get_date_tag(*m, "TDAT")) &&
167
        !(t = get_date_tag(*m, "TDA")))
168
        goto finish;
169
    snprintf(date + 4, sizeof(date) - 4, "-%.2s-%.2s", t->value + 2, t->value);
170
    av_metadata_set2(m, "TDAT", NULL, 0);
171
    av_metadata_set2(m, "TDA",  NULL, 0);
172

    
173
    if (!(t = get_date_tag(*m, "TIME")) &&
174
        !(t = get_date_tag(*m, "TIM")))
175
        goto finish;
176
    snprintf(date + 10, sizeof(date) - 10, " %.2s:%.2s", t->value, t->value + 2);
177
    av_metadata_set2(m, "TIME", NULL, 0);
178
    av_metadata_set2(m, "TIM",  NULL, 0);
179

    
180
finish:
181
    if (date[0])
182
        av_metadata_set2(m, "date", date, 0);
183
}
184

    
185
static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
186
{
187
    int isv34, tlen, unsync;
188
    char tag[5];
189
    int64_t next;
190
    int taghdrlen;
191
    const char *reason;
192
    AVIOContext pb;
193
    unsigned char *buffer = NULL;
194
    int buffer_size = 0;
195

    
196
    switch (version) {
197
    case 2:
198
        if (flags & 0x40) {
199
            reason = "compression";
200
            goto error;
201
        }
202
        isv34 = 0;
203
        taghdrlen = 6;
204
        break;
205

    
206
    case 3:
207
    case 4:
208
        isv34 = 1;
209
        taghdrlen = 10;
210
        break;
211

    
212
    default:
213
        reason = "version";
214
        goto error;
215
    }
216

    
217
    unsync = flags & 0x80;
218

    
219
    if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
220
        avio_skip(s->pb, get_size(s->pb, 4));
221

    
222
    while (len >= taghdrlen) {
223
        unsigned int tflags;
224
        int tunsync = 0;
225

    
226
        if (isv34) {
227
            avio_read(s->pb, tag, 4);
228
            tag[4] = 0;
229
            if(version==3){
230
                tlen = avio_rb32(s->pb);
231
            }else
232
                tlen = get_size(s->pb, 4);
233
            tflags = avio_rb16(s->pb);
234
            tunsync = tflags & ID3v2_FLAG_UNSYNCH;
235
        } else {
236
            avio_read(s->pb, tag, 3);
237
            tag[3] = 0;
238
            tlen = avio_rb24(s->pb);
239
        }
240
        len -= taghdrlen + tlen;
241

    
242
        if (len < 0)
243
            break;
244

    
245
        next = avio_tell(s->pb) + tlen;
246

    
247
        if (tflags & ID3v2_FLAG_DATALEN) {
248
            avio_rb32(s->pb);
249
            tlen -= 4;
250
        }
251

    
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) {
257
                int i, j;
258
                av_fast_malloc(&buffer, &buffer_size, tlen);
259
                for (i = 0, j = 0; i < tlen; i++, j++) {
260
                    buffer[j] = avio_r8(s->pb);
261
                    if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
262
                        /* Unsynchronised byte, skip it */
263
                        j--;
264
                    }
265
                }
266
                ffio_init_context(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
267
                read_ttag(s, &pb, j, tag);
268
            } else {
269
                read_ttag(s, s->pb, tlen, tag);
270
            }
271
        }
272
        else if (!tag[0]) {
273
            if (tag[1])
274
                av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
275
            avio_skip(s->pb, tlen);
276
            break;
277
        }
278
        /* Skip to end of tag */
279
        avio_seek(s->pb, next, SEEK_SET);
280
    }
281

    
282
    if (len > 0) {
283
        /* Skip padding */
284
        avio_skip(s->pb, len);
285
    }
286
    if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
287
        avio_skip(s->pb, 10);
288

    
289
    av_free(buffer);
290
    return;
291

    
292
  error:
293
    av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
294
    avio_seek(s->pb, len, SEEK_CUR);
295
    av_free(buffer);
296
}
297

    
298
void ff_id3v2_read(AVFormatContext *s, const char *magic)
299
{
300
    int len, ret;
301
    uint8_t buf[ID3v2_HEADER_SIZE];
302
    int     found_header;
303
    int64_t off;
304

    
305
    do {
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)
310
            break;
311
            found_header = ff_id3v2_match(buf, magic);
312
            if (found_header) {
313
            /* parse ID3v2 header */
314
            len = ((buf[6] & 0x7f) << 21) |
315
                  ((buf[7] & 0x7f) << 14) |
316
                  ((buf[8] & 0x7f) << 7) |
317
                   (buf[9] & 0x7f);
318
            ff_id3v2_parse(s, len, buf[3], buf[5]);
319
        } else {
320
            avio_seek(s->pb, off, SEEK_SET);
321
        }
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);
327
}
328

    
329
const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
330
    { "TALB", "album"},
331
    { "TCOM", "composer"},
332
    { "TCON", "genre"},
333
    { "TCOP", "copyright"},
334
    { "TENC", "encoded_by"},
335
    { "TIT2", "title"},
336
    { "TLAN", "language"},
337
    { "TPE1", "artist"},
338
    { "TPE2", "album_artist"},
339
    { "TPE3", "performer"},
340
    { "TPOS", "disc"},
341
    { "TPUB", "publisher"},
342
    { "TRCK", "track"},
343
    { "TSSE", "encoder"},
344
    { 0 }
345
};
346

    
347
const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
348
    { "TDRL", "date"},
349
    { "TDRC", "date"},
350
    { "TDEN", "creation_time"},
351
    { "TSOA", "album-sort"},
352
    { "TSOP", "artist-sort"},
353
    { "TSOT", "title-sort"},
354
    { 0 }
355
};
356

    
357
const AVMetadataConv ff_id3v2_2_metadata_conv[] = {
358
    { "TAL",  "album"},
359
    { "TCO",  "genre"},
360
    { "TT2",  "title"},
361
    { "TEN",  "encoded_by"},
362
    { "TP1",  "artist"},
363
    { "TP2",  "album_artist"},
364
    { "TP3",  "performer"},
365
    { "TRK",  "track"},
366
    { 0 }
367
};
368

    
369

    
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",
375
   { 0 },
376
};
377

    
378
const char ff_id3v2_4_tags[][4] = {
379
   "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
380
   "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
381
   { 0 },
382
};
383

    
384
const char ff_id3v2_3_tags[][4] = {
385
   "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
386
   { 0 },
387
};