Statistics
| Branch: | Revision:

ffmpeg / libavformat / id3v2.c @ da9e6c42

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