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