Mercurial > libavformat.hg
comparison mp3.c @ 2097:cab3fcb34077 libavformat
id3v2 reader
patch by Andreas ?man andreas olebyn nu
original thread: [FFmpeg-devel] [Ffmpeg-devel] ID3v2
author | benoit |
---|---|
date | Tue, 22 May 2007 08:23:45 +0000 |
parents | 85e48ffccf91 |
children | b51b57909b5f |
comparison
equal
deleted
inserted
replaced
2096:85e48ffccf91 | 2097:cab3fcb34077 |
---|---|
167 (buf[7] & 0x80) == 0 && | 167 (buf[7] & 0x80) == 0 && |
168 (buf[8] & 0x80) == 0 && | 168 (buf[8] & 0x80) == 0 && |
169 (buf[9] & 0x80) == 0); | 169 (buf[9] & 0x80) == 0); |
170 } | 170 } |
171 | 171 |
172 static unsigned int id3v2_get_size(ByteIOContext *s, int len) | |
173 { | |
174 int v=0; | |
175 while(len--) | |
176 v= (v<<7) + (get_byte(s)&0x7F); | |
177 return v; | |
178 } | |
179 | |
180 static void id3v2_read_ttag(AVFormatContext *s, int taglen, char *dst, int dstlen) | |
181 { | |
182 char *q; | |
183 int len; | |
184 | |
185 if(taglen < 1) | |
186 return; | |
187 | |
188 taglen--; /* account for encoding type byte */ | |
189 dstlen--; /* Leave space for zero terminator */ | |
190 | |
191 switch(get_byte(&s->pb)) { /* encoding type */ | |
192 | |
193 case 0: /* ISO-8859-1 (0 - 255 maps directly into unicode) */ | |
194 q = dst; | |
195 while(taglen--) { | |
196 uint8_t tmp; | |
197 PUT_UTF8(get_byte(&s->pb), tmp, if (q - dst < dstlen - 1) *q++ = tmp;) | |
198 } | |
199 *q = '\0'; | |
200 break; | |
201 | |
202 case 3: /* UTF-8 */ | |
203 len = FFMIN(taglen, dstlen); | |
204 get_buffer(&s->pb, dst, len); | |
205 dst[len] = 0; | |
206 break; | |
207 } | |
208 } | |
209 | |
210 /** | |
211 * ID3v2 parser | |
212 * | |
213 * Handles ID3v2.2, 2.3 and 2.4. | |
214 * | |
215 */ | |
216 | |
217 static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags) | |
218 { | |
219 int isv34, tlen; | |
220 uint32_t tag; | |
221 offset_t next; | |
222 char tmp[16]; | |
223 int taghdrlen; | |
224 const char *reason; | |
225 | |
226 switch(version) { | |
227 case 2: | |
228 if(flags & 0x40) { | |
229 reason = "compression"; | |
230 goto error; | |
231 } | |
232 isv34 = 0; | |
233 taghdrlen = 6; | |
234 break; | |
235 | |
236 case 3 ... 4: | |
237 isv34 = 1; | |
238 taghdrlen = 10; | |
239 break; | |
240 | |
241 default: | |
242 reason = "version"; | |
243 goto error; | |
244 } | |
245 | |
246 if(flags & 0x80) { | |
247 reason = "unsynchronization"; | |
248 goto error; | |
249 } | |
250 | |
251 if(isv34 && flags & 0x40) /* Extended header present, just skip over it */ | |
252 url_fskip(&s->pb, id3v2_get_size(&s->pb, 4)); | |
253 | |
254 while(len >= taghdrlen) { | |
255 if(isv34) { | |
256 tag = get_be32(&s->pb); | |
257 tlen = id3v2_get_size(&s->pb, 4); | |
258 get_be16(&s->pb); /* flags */ | |
259 } else { | |
260 tag = get_be24(&s->pb); | |
261 tlen = id3v2_get_size(&s->pb, 3); | |
262 } | |
263 len -= taghdrlen + tlen; | |
264 | |
265 if(len < 0) | |
266 break; | |
267 | |
268 next = url_ftell(&s->pb) + tlen; | |
269 | |
270 switch(tag) { | |
271 case MKBETAG('T', 'I', 'T', '2'): | |
272 case MKBETAG(0, 'T', 'T', '2'): | |
273 id3v2_read_ttag(s, tlen, s->title, sizeof(s->title)); | |
274 break; | |
275 case MKBETAG('T', 'P', 'E', '1'): | |
276 case MKBETAG(0, 'T', 'P', '1'): | |
277 id3v2_read_ttag(s, tlen, s->author, sizeof(s->author)); | |
278 break; | |
279 case MKBETAG('T', 'A', 'L', 'B'): | |
280 case MKBETAG(0, 'T', 'A', 'L'): | |
281 id3v2_read_ttag(s, tlen, s->album, sizeof(s->album)); | |
282 break; | |
283 case MKBETAG('T', 'C', 'O', 'N'): | |
284 case MKBETAG(0, 'T', 'C', 'O'): | |
285 id3v2_read_ttag(s, tlen, s->genre, sizeof(s->genre)); | |
286 break; | |
287 case MKBETAG('T', 'C', 'O', 'P'): | |
288 case MKBETAG(0, 'T', 'C', 'R'): | |
289 id3v2_read_ttag(s, tlen, s->copyright, sizeof(s->copyright)); | |
290 break; | |
291 case MKBETAG('T', 'R', 'C', 'K'): | |
292 case MKBETAG(0, 'T', 'R', 'K'): | |
293 id3v2_read_ttag(s, tlen, tmp, sizeof(tmp)); | |
294 s->track = atoi(tmp); | |
295 break; | |
296 case 0: | |
297 /* padding, skip to end */ | |
298 url_fskip(&s->pb, len); | |
299 len = 0; | |
300 continue; | |
301 } | |
302 /* Skip to end of tag */ | |
303 url_fseek(&s->pb, next, SEEK_SET); | |
304 } | |
305 | |
306 if(version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */ | |
307 url_fskip(&s->pb, 10); | |
308 return; | |
309 | |
310 error: | |
311 av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason); | |
312 url_fskip(&s->pb, len); | |
313 } | |
314 | |
172 static void id3v1_get_string(char *str, int str_size, | 315 static void id3v1_get_string(char *str, int str_size, |
173 const uint8_t *buf, int buf_size) | 316 const uint8_t *buf, int buf_size) |
174 { | 317 { |
175 int i, c; | 318 int i, c; |
176 char *q; | 319 char *q; |
311 /* if ID3v2 header found, skip it */ | 454 /* if ID3v2 header found, skip it */ |
312 ret = get_buffer(&s->pb, buf, ID3v2_HEADER_SIZE); | 455 ret = get_buffer(&s->pb, buf, ID3v2_HEADER_SIZE); |
313 if (ret != ID3v2_HEADER_SIZE) | 456 if (ret != ID3v2_HEADER_SIZE) |
314 return -1; | 457 return -1; |
315 if (id3v2_match(buf)) { | 458 if (id3v2_match(buf)) { |
316 /* skip ID3v2 header */ | 459 /* parse ID3v2 header */ |
317 len = ((buf[6] & 0x7f) << 21) | | 460 len = ((buf[6] & 0x7f) << 21) | |
318 ((buf[7] & 0x7f) << 14) | | 461 ((buf[7] & 0x7f) << 14) | |
319 ((buf[8] & 0x7f) << 7) | | 462 ((buf[8] & 0x7f) << 7) | |
320 (buf[9] & 0x7f); | 463 (buf[9] & 0x7f); |
321 url_fskip(&s->pb, len); | 464 id3v2_parse(s, len, buf[3], buf[5]); |
322 } else { | 465 } else { |
323 url_fseek(&s->pb, 0, SEEK_SET); | 466 url_fseek(&s->pb, 0, SEEK_SET); |
324 } | 467 } |
325 | 468 |
326 /* the parameters will be extracted from the compressed bitstream */ | 469 /* the parameters will be extracted from the compressed bitstream */ |