00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00029 #include "config.h"
00030
00031 #if CONFIG_ZLIB
00032 #include <zlib.h>
00033 #endif
00034
00035 #include "id3v2.h"
00036 #include "id3v1.h"
00037 #include "libavutil/avstring.h"
00038 #include "libavutil/intreadwrite.h"
00039 #include "libavutil/dict.h"
00040 #include "avio_internal.h"
00041 #include "internal.h"
00042
00043 const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
00044 { "TALB", "album"},
00045 { "TCOM", "composer"},
00046 { "TCON", "genre"},
00047 { "TCOP", "copyright"},
00048 { "TENC", "encoded_by"},
00049 { "TIT2", "title"},
00050 { "TLAN", "language"},
00051 { "TPE1", "artist"},
00052 { "TPE2", "album_artist"},
00053 { "TPE3", "performer"},
00054 { "TPOS", "disc"},
00055 { "TPUB", "publisher"},
00056 { "TRCK", "track"},
00057 { "TSSE", "encoder"},
00058 { 0 }
00059 };
00060
00061 const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
00062 { "TDRL", "date"},
00063 { "TDRC", "date"},
00064 { "TDEN", "creation_time"},
00065 { "TSOA", "album-sort"},
00066 { "TSOP", "artist-sort"},
00067 { "TSOT", "title-sort"},
00068 { 0 }
00069 };
00070
00071 static const AVMetadataConv id3v2_2_metadata_conv[] = {
00072 { "TAL", "album"},
00073 { "TCO", "genre"},
00074 { "TT2", "title"},
00075 { "TEN", "encoded_by"},
00076 { "TP1", "artist"},
00077 { "TP2", "album_artist"},
00078 { "TP3", "performer"},
00079 { "TRK", "track"},
00080 { 0 }
00081 };
00082
00083
00084 const char ff_id3v2_tags[][4] = {
00085 "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
00086 "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
00087 "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
00088 "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
00089 { 0 },
00090 };
00091
00092 const char ff_id3v2_4_tags[][4] = {
00093 "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
00094 "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
00095 { 0 },
00096 };
00097
00098 const char ff_id3v2_3_tags[][4] = {
00099 "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
00100 { 0 },
00101 };
00102
00103 const char *ff_id3v2_picture_types[21] = {
00104 "Other",
00105 "32x32 pixels 'file icon'",
00106 "Other file icon",
00107 "Cover (front)",
00108 "Cover (back)",
00109 "Leaflet page",
00110 "Media (e.g. label side of CD)",
00111 "Lead artist/lead performer/soloist",
00112 "Artist/performer",
00113 "Conductor",
00114 "Band/Orchestra",
00115 "Composer",
00116 "Lyricist/text writer",
00117 "Recording Location",
00118 "During recording",
00119 "During performance",
00120 "Movie/video screen capture",
00121 "A bright coloured fish",
00122 "Illustration",
00123 "Band/artist logotype",
00124 "Publisher/Studio logotype",
00125 };
00126
00127 const CodecMime ff_id3v2_mime_tags[] = {
00128 {"image/gif" , AV_CODEC_ID_GIF},
00129 {"image/jpeg", AV_CODEC_ID_MJPEG},
00130 {"image/jpg", AV_CODEC_ID_MJPEG},
00131 {"image/png" , AV_CODEC_ID_PNG},
00132 {"image/tiff", AV_CODEC_ID_TIFF},
00133 {"image/bmp", AV_CODEC_ID_BMP},
00134 {"JPG", AV_CODEC_ID_MJPEG},
00135 {"PNG" , AV_CODEC_ID_PNG},
00136 {"", AV_CODEC_ID_NONE},
00137 };
00138
00139 int ff_id3v2_match(const uint8_t *buf, const char * magic)
00140 {
00141 return buf[0] == magic[0] &&
00142 buf[1] == magic[1] &&
00143 buf[2] == magic[2] &&
00144 buf[3] != 0xff &&
00145 buf[4] != 0xff &&
00146 (buf[6] & 0x80) == 0 &&
00147 (buf[7] & 0x80) == 0 &&
00148 (buf[8] & 0x80) == 0 &&
00149 (buf[9] & 0x80) == 0;
00150 }
00151
00152 int ff_id3v2_tag_len(const uint8_t * buf)
00153 {
00154 int len = ((buf[6] & 0x7f) << 21) +
00155 ((buf[7] & 0x7f) << 14) +
00156 ((buf[8] & 0x7f) << 7) +
00157 (buf[9] & 0x7f) +
00158 ID3v2_HEADER_SIZE;
00159 if (buf[5] & 0x10)
00160 len += ID3v2_HEADER_SIZE;
00161 return len;
00162 }
00163
00164 static unsigned int get_size(AVIOContext *s, int len)
00165 {
00166 int v = 0;
00167 while (len--)
00168 v = (v << 7) + (avio_r8(s) & 0x7F);
00169 return v;
00170 }
00171
00175 static void free_geobtag(void *obj)
00176 {
00177 ID3v2ExtraMetaGEOB *geob = obj;
00178 av_free(geob->mime_type);
00179 av_free(geob->file_name);
00180 av_free(geob->description);
00181 av_free(geob->data);
00182 av_free(geob);
00183 }
00184
00197 static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
00198 uint8_t **dst, int *maxread)
00199 {
00200 int ret;
00201 uint8_t tmp;
00202 uint32_t ch = 1;
00203 int left = *maxread;
00204 unsigned int (*get)(AVIOContext*) = avio_rb16;
00205 AVIOContext *dynbuf;
00206
00207 if ((ret = avio_open_dyn_buf(&dynbuf)) < 0) {
00208 av_log(s, AV_LOG_ERROR, "Error opening memory stream\n");
00209 return ret;
00210 }
00211
00212 switch (encoding) {
00213
00214 case ID3v2_ENCODING_ISO8859:
00215 while (left && ch) {
00216 ch = avio_r8(pb);
00217 PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
00218 left--;
00219 }
00220 break;
00221
00222 case ID3v2_ENCODING_UTF16BOM:
00223 if ((left -= 2) < 0) {
00224 av_log(s, AV_LOG_ERROR, "Cannot read BOM value, input too short\n");
00225 avio_close_dyn_buf(dynbuf, dst);
00226 av_freep(dst);
00227 return AVERROR_INVALIDDATA;
00228 }
00229 switch (avio_rb16(pb)) {
00230 case 0xfffe:
00231 get = avio_rl16;
00232 case 0xfeff:
00233 break;
00234 default:
00235 av_log(s, AV_LOG_ERROR, "Incorrect BOM value\n");
00236 avio_close_dyn_buf(dynbuf, dst);
00237 av_freep(dst);
00238 *maxread = left;
00239 return AVERROR_INVALIDDATA;
00240 }
00241
00242
00243 case ID3v2_ENCODING_UTF16BE:
00244 while ((left > 1) && ch) {
00245 GET_UTF16(ch, ((left -= 2) >= 0 ? get(pb) : 0), break;)
00246 PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
00247 }
00248 if (left < 0)
00249 left += 2;
00250 break;
00251
00252 case ID3v2_ENCODING_UTF8:
00253 while (left && ch) {
00254 ch = avio_r8(pb);
00255 avio_w8(dynbuf, ch);
00256 left--;
00257 }
00258 break;
00259 default:
00260 av_log(s, AV_LOG_WARNING, "Unknown encoding\n");
00261 }
00262
00263 if (ch)
00264 avio_w8(dynbuf, 0);
00265
00266 avio_close_dyn_buf(dynbuf, dst);
00267 *maxread = left;
00268
00269 return 0;
00270 }
00271
00275 static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key)
00276 {
00277 uint8_t *dst;
00278 int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL;
00279 unsigned genre;
00280
00281 if (taglen < 1)
00282 return;
00283
00284 encoding = avio_r8(pb);
00285 taglen--;
00286
00287 if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
00288 av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
00289 return;
00290 }
00291
00292 if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
00293 && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
00294 && genre <= ID3v1_GENRE_MAX) {
00295 av_freep(&dst);
00296 dst = av_strdup(ff_id3v1_genre_str[genre]);
00297 } else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
00298
00299 key = dst;
00300 if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
00301 av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
00302 av_freep(&key);
00303 return;
00304 }
00305 dict_flags |= AV_DICT_DONT_STRDUP_KEY;
00306 } else if (!*dst)
00307 av_freep(&dst);
00308
00309 if (dst)
00310 av_dict_set(&s->metadata, key, dst, dict_flags);
00311 }
00312
00316 static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta)
00317 {
00318 ID3v2ExtraMetaGEOB *geob_data = NULL;
00319 ID3v2ExtraMeta *new_extra = NULL;
00320 char encoding;
00321 unsigned int len;
00322
00323 if (taglen < 1)
00324 return;
00325
00326 geob_data = av_mallocz(sizeof(ID3v2ExtraMetaGEOB));
00327 if (!geob_data) {
00328 av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMetaGEOB));
00329 return;
00330 }
00331
00332 new_extra = av_mallocz(sizeof(ID3v2ExtraMeta));
00333 if (!new_extra) {
00334 av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMeta));
00335 goto fail;
00336 }
00337
00338
00339 encoding = avio_r8(pb);
00340 taglen--;
00341
00342
00343 if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type, &taglen) < 0
00344 || taglen <= 0)
00345 goto fail;
00346
00347
00348 if (decode_str(s, pb, encoding, &geob_data->file_name, &taglen) < 0
00349 || taglen <= 0)
00350 goto fail;
00351
00352
00353 if (decode_str(s, pb, encoding, &geob_data->description, &taglen) < 0
00354 || taglen < 0)
00355 goto fail;
00356
00357 if (taglen) {
00358
00359 geob_data->data = av_malloc(taglen);
00360 if (!geob_data->data) {
00361 av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", taglen);
00362 goto fail;
00363 }
00364 if ((len = avio_read(pb, geob_data->data, taglen)) < taglen)
00365 av_log(s, AV_LOG_WARNING, "Error reading GEOB frame, data truncated.\n");
00366 geob_data->datasize = len;
00367 } else {
00368 geob_data->data = NULL;
00369 geob_data->datasize = 0;
00370 }
00371
00372
00373 new_extra->tag = "GEOB";
00374 new_extra->data = geob_data;
00375 new_extra->next = *extra_meta;
00376 *extra_meta = new_extra;
00377
00378 return;
00379
00380 fail:
00381 av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", tag);
00382 free_geobtag(geob_data);
00383 av_free(new_extra);
00384 return;
00385 }
00386
00387 static int is_number(const char *str)
00388 {
00389 while (*str >= '0' && *str <= '9') str++;
00390 return !*str;
00391 }
00392
00393 static AVDictionaryEntry* get_date_tag(AVDictionary *m, const char *tag)
00394 {
00395 AVDictionaryEntry *t;
00396 if ((t = av_dict_get(m, tag, NULL, AV_DICT_MATCH_CASE)) &&
00397 strlen(t->value) == 4 && is_number(t->value))
00398 return t;
00399 return NULL;
00400 }
00401
00402 static void merge_date(AVDictionary **m)
00403 {
00404 AVDictionaryEntry *t;
00405 char date[17] = {0};
00406
00407 if (!(t = get_date_tag(*m, "TYER")) &&
00408 !(t = get_date_tag(*m, "TYE")))
00409 return;
00410 av_strlcpy(date, t->value, 5);
00411 av_dict_set(m, "TYER", NULL, 0);
00412 av_dict_set(m, "TYE", NULL, 0);
00413
00414 if (!(t = get_date_tag(*m, "TDAT")) &&
00415 !(t = get_date_tag(*m, "TDA")))
00416 goto finish;
00417 snprintf(date + 4, sizeof(date) - 4, "-%.2s-%.2s", t->value + 2, t->value);
00418 av_dict_set(m, "TDAT", NULL, 0);
00419 av_dict_set(m, "TDA", NULL, 0);
00420
00421 if (!(t = get_date_tag(*m, "TIME")) &&
00422 !(t = get_date_tag(*m, "TIM")))
00423 goto finish;
00424 snprintf(date + 10, sizeof(date) - 10, " %.2s:%.2s", t->value, t->value + 2);
00425 av_dict_set(m, "TIME", NULL, 0);
00426 av_dict_set(m, "TIM", NULL, 0);
00427
00428 finish:
00429 if (date[0])
00430 av_dict_set(m, "date", date, 0);
00431 }
00432
00433 static void free_apic(void *obj)
00434 {
00435 ID3v2ExtraMetaAPIC *apic = obj;
00436 av_freep(&apic->data);
00437 av_freep(&apic->description);
00438 av_freep(&apic);
00439 }
00440
00441 static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta)
00442 {
00443 int enc, pic_type;
00444 char mimetype[64];
00445 const CodecMime *mime = ff_id3v2_mime_tags;
00446 enum AVCodecID id = AV_CODEC_ID_NONE;
00447 ID3v2ExtraMetaAPIC *apic = NULL;
00448 ID3v2ExtraMeta *new_extra = NULL;
00449 int64_t end = avio_tell(pb) + taglen;
00450
00451 if (taglen <= 4)
00452 goto fail;
00453
00454 new_extra = av_mallocz(sizeof(*new_extra));
00455 apic = av_mallocz(sizeof(*apic));
00456 if (!new_extra || !apic)
00457 goto fail;
00458
00459 enc = avio_r8(pb);
00460 taglen--;
00461
00462
00463 taglen -= avio_get_str(pb, taglen, mimetype, sizeof(mimetype));
00464 while (mime->id != AV_CODEC_ID_NONE) {
00465 if (!av_strncasecmp(mime->str, mimetype, sizeof(mimetype))) {
00466 id = mime->id;
00467 break;
00468 }
00469 mime++;
00470 }
00471 if (id == AV_CODEC_ID_NONE) {
00472 av_log(s, AV_LOG_WARNING, "Unknown attached picture mimetype: %s, skipping.\n", mimetype);
00473 goto fail;
00474 }
00475 apic->id = id;
00476
00477
00478 pic_type = avio_r8(pb);
00479 taglen--;
00480 if (pic_type < 0 || pic_type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types)) {
00481 av_log(s, AV_LOG_WARNING, "Unknown attached picture type %d.\n", pic_type);
00482 pic_type = 0;
00483 }
00484 apic->type = ff_id3v2_picture_types[pic_type];
00485
00486
00487 if (decode_str(s, pb, enc, &apic->description, &taglen) < 0) {
00488 av_log(s, AV_LOG_ERROR, "Error decoding attached picture description.\n");
00489 goto fail;
00490 }
00491
00492 apic->len = taglen;
00493 apic->data = av_malloc(taglen);
00494 if (!apic->data || !apic->len || avio_read(pb, apic->data, taglen) != taglen)
00495 goto fail;
00496
00497 new_extra->tag = "APIC";
00498 new_extra->data = apic;
00499 new_extra->next = *extra_meta;
00500 *extra_meta = new_extra;
00501
00502 return;
00503
00504 fail:
00505 if (apic)
00506 free_apic(apic);
00507 av_freep(&new_extra);
00508 avio_seek(pb, end, SEEK_SET);
00509 }
00510
00511 static void read_chapter(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta)
00512 {
00513 AVRational time_base = {1, 1000};
00514 char title[1024];
00515 uint32_t start, end;
00516
00517 taglen -= avio_get_str(pb, taglen, title, sizeof(title));
00518 if (taglen < 16)
00519 return;
00520
00521 start = avio_rb32(pb);
00522 end = avio_rb32(pb);
00523 taglen -= 27;
00524 if (taglen > 0) {
00525 char tag[4];
00526
00527 avio_skip(pb, 8);
00528 avio_read(pb, tag, 4);
00529 if (!memcmp(tag, "TIT2", 4)) {
00530 taglen = FFMIN(taglen, avio_rb32(pb));
00531 if (taglen < 0)
00532 return;
00533 avio_skip(pb, 3);
00534 avio_get_str(pb, taglen, title, sizeof(title));
00535 }
00536 }
00537
00538 avpriv_new_chapter(s, s->nb_chapters + 1, time_base, start, end, title);
00539 }
00540
00541 typedef struct ID3v2EMFunc {
00542 const char *tag3;
00543 const char *tag4;
00544 void (*read)(AVFormatContext*, AVIOContext*, int, char*, ID3v2ExtraMeta **);
00545 void (*free)(void *obj);
00546 } ID3v2EMFunc;
00547
00548 static const ID3v2EMFunc id3v2_extra_meta_funcs[] = {
00549 { "GEO", "GEOB", read_geobtag, free_geobtag },
00550 { "PIC", "APIC", read_apic, free_apic },
00551 { "CHAP","CHAP", read_chapter, NULL },
00552 { NULL }
00553 };
00554
00560 static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
00561 {
00562 int i = 0;
00563 while (id3v2_extra_meta_funcs[i].tag3) {
00564 if (tag && !memcmp(tag,
00565 (isv34 ? id3v2_extra_meta_funcs[i].tag4 :
00566 id3v2_extra_meta_funcs[i].tag3),
00567 (isv34 ? 4 : 3)))
00568 return &id3v2_extra_meta_funcs[i];
00569 i++;
00570 }
00571 return NULL;
00572 }
00573
00574 static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags, ID3v2ExtraMeta **extra_meta)
00575 {
00576 int isv34, unsync;
00577 unsigned tlen;
00578 char tag[5];
00579 int64_t next, end = avio_tell(s->pb) + len;
00580 int taghdrlen;
00581 const char *reason = NULL;
00582 AVIOContext pb;
00583 AVIOContext *pbx;
00584 unsigned char *buffer = NULL;
00585 int buffer_size = 0;
00586 const ID3v2EMFunc *extra_func = NULL;
00587 unsigned char *uncompressed_buffer = NULL;
00588 int uncompressed_buffer_size = 0;
00589
00590 av_log(s, AV_LOG_DEBUG, "id3v2 ver:%d flags:%02X len:%d\n", version, flags, len);
00591
00592 switch (version) {
00593 case 2:
00594 if (flags & 0x40) {
00595 reason = "compression";
00596 goto error;
00597 }
00598 isv34 = 0;
00599 taghdrlen = 6;
00600 break;
00601
00602 case 3:
00603 case 4:
00604 isv34 = 1;
00605 taghdrlen = 10;
00606 break;
00607
00608 default:
00609 reason = "version";
00610 goto error;
00611 }
00612
00613 unsync = flags & 0x80;
00614
00615 if (isv34 && flags & 0x40) {
00616 int extlen = get_size(s->pb, 4);
00617 if (version == 4)
00618 extlen -= 4;
00619
00620 if (extlen < 0) {
00621 reason = "invalid extended header length";
00622 goto error;
00623 }
00624 avio_skip(s->pb, extlen);
00625 len -= extlen + 4;
00626 if (len < 0) {
00627 reason = "extended header too long.";
00628 goto error;
00629 }
00630 }
00631
00632 while (len >= taghdrlen) {
00633 unsigned int tflags = 0;
00634 int tunsync = 0;
00635 int tcomp = 0;
00636 int tencr = 0;
00637 unsigned long dlen;
00638
00639 if (isv34) {
00640 avio_read(s->pb, tag, 4);
00641 tag[4] = 0;
00642 if(version==3){
00643 tlen = avio_rb32(s->pb);
00644 }else
00645 tlen = get_size(s->pb, 4);
00646 tflags = avio_rb16(s->pb);
00647 tunsync = tflags & ID3v2_FLAG_UNSYNCH;
00648 } else {
00649 avio_read(s->pb, tag, 3);
00650 tag[3] = 0;
00651 tlen = avio_rb24(s->pb);
00652 }
00653 if (tlen > (1<<28))
00654 break;
00655 len -= taghdrlen + tlen;
00656
00657 if (len < 0)
00658 break;
00659
00660 next = avio_tell(s->pb) + tlen;
00661
00662 if (!tlen) {
00663 if (tag[0])
00664 av_log(s, AV_LOG_DEBUG, "Invalid empty frame %s, skipping.\n", tag);
00665 continue;
00666 }
00667
00668 if (tflags & ID3v2_FLAG_DATALEN) {
00669 if (tlen < 4)
00670 break;
00671 dlen = avio_rb32(s->pb);
00672 tlen -= 4;
00673 } else
00674 dlen = tlen;
00675
00676 tcomp = tflags & ID3v2_FLAG_COMPRESSION;
00677 tencr = tflags & ID3v2_FLAG_ENCRYPTION;
00678
00679
00680 if (tencr || (!CONFIG_ZLIB && tcomp)) {
00681 const char *type;
00682 if (!tcomp)
00683 type = "encrypted";
00684 else if (!tencr)
00685 type = "compressed";
00686 else
00687 type = "encrypted and compressed";
00688
00689 av_log(s, AV_LOG_WARNING, "Skipping %s ID3v2 frame %s.\n", type, tag);
00690 avio_skip(s->pb, tlen);
00691
00692 } else if (tag[0] == 'T' || (extra_meta && (extra_func = get_extra_meta_func(tag, isv34)))) {
00693 pbx = s->pb;
00694
00695 if (unsync || tunsync || tcomp) {
00696 av_fast_malloc(&buffer, &buffer_size, tlen);
00697 if (!buffer) {
00698 av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen);
00699 goto seek;
00700 }
00701 }
00702 if (unsync || tunsync) {
00703 int64_t end = avio_tell(s->pb) + tlen;
00704 uint8_t *b;
00705
00706 b = buffer;
00707 while (avio_tell(s->pb) < end && b - buffer < tlen) {
00708 *b++ = avio_r8(s->pb);
00709 if (*(b - 1) == 0xff && avio_tell(s->pb) < end - 1 && b - buffer < tlen) {
00710 uint8_t val = avio_r8(s->pb);
00711 *b++ = val ? val : avio_r8(s->pb);
00712 }
00713 }
00714 ffio_init_context(&pb, buffer, b - buffer, 0, NULL, NULL, NULL, NULL);
00715 tlen = b - buffer;
00716 pbx = &pb;
00717 }
00718
00719 #if CONFIG_ZLIB
00720 if (tcomp) {
00721 int err;
00722
00723 av_log(s, AV_LOG_DEBUG, "Compresssed frame %s tlen=%d dlen=%ld\n", tag, tlen, dlen);
00724
00725 av_fast_malloc(&uncompressed_buffer, &uncompressed_buffer_size, dlen);
00726 if (!uncompressed_buffer) {
00727 av_log(s, AV_LOG_ERROR, "Failed to alloc %ld bytes\n", dlen);
00728 goto seek;
00729 }
00730
00731 if (!(unsync || tunsync)) {
00732 err = avio_read(s->pb, buffer, tlen);
00733 if (err < 0) {
00734 av_log(s, AV_LOG_ERROR, "Failed to read compressed tag\n");
00735 goto seek;
00736 }
00737 tlen = err;
00738 }
00739
00740 err = uncompress(uncompressed_buffer, &dlen, buffer, tlen);
00741 if (err != Z_OK) {
00742 av_log(s, AV_LOG_ERROR, "Failed to uncompress tag: %d\n", err);
00743 goto seek;
00744 }
00745 ffio_init_context(&pb, uncompressed_buffer, dlen, 0, NULL, NULL, NULL, NULL);
00746 tlen = dlen;
00747 pbx = &pb;
00748 }
00749 #endif
00750 if (tag[0] == 'T')
00751
00752 read_ttag(s, pbx, tlen, tag);
00753 else
00754
00755 extra_func->read(s, pbx, tlen, tag, extra_meta);
00756 }
00757 else if (!tag[0]) {
00758 if (tag[1])
00759 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding\n");
00760 avio_skip(s->pb, tlen);
00761 break;
00762 }
00763
00764 seek:
00765 avio_seek(s->pb, next, SEEK_SET);
00766 }
00767
00768 if (version == 4 && flags & 0x10)
00769 end += 10;
00770
00771 error:
00772 if (reason)
00773 av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
00774 avio_seek(s->pb, end, SEEK_SET);
00775 av_free(buffer);
00776 av_free(uncompressed_buffer);
00777 return;
00778 }
00779
00780 void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta)
00781 {
00782 int len, ret;
00783 uint8_t buf[ID3v2_HEADER_SIZE];
00784 int found_header;
00785 int64_t off;
00786
00787 do {
00788
00789 off = avio_tell(s->pb);
00790 ret = avio_read(s->pb, buf, ID3v2_HEADER_SIZE);
00791 if (ret != ID3v2_HEADER_SIZE)
00792 break;
00793 found_header = ff_id3v2_match(buf, magic);
00794 if (found_header) {
00795
00796 len = ((buf[6] & 0x7f) << 21) |
00797 ((buf[7] & 0x7f) << 14) |
00798 ((buf[8] & 0x7f) << 7) |
00799 (buf[9] & 0x7f);
00800 ff_id3v2_parse(s, len, buf[3], buf[5], extra_meta);
00801 } else {
00802 avio_seek(s->pb, off, SEEK_SET);
00803 }
00804 } while (found_header);
00805 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv);
00806 ff_metadata_conv(&s->metadata, NULL, id3v2_2_metadata_conv);
00807 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv);
00808 merge_date(&s->metadata);
00809 }
00810
00811 void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta)
00812 {
00813 ID3v2ExtraMeta *current = *extra_meta, *next;
00814 const ID3v2EMFunc *extra_func;
00815
00816 while (current) {
00817 if ((extra_func = get_extra_meta_func(current->tag, 1)))
00818 extra_func->free(current->data);
00819 next = current->next;
00820 av_freep(¤t);
00821 current = next;
00822 }
00823 }
00824
00825 int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta)
00826 {
00827 ID3v2ExtraMeta *cur;
00828
00829 for (cur = *extra_meta; cur; cur = cur->next) {
00830 ID3v2ExtraMetaAPIC *apic;
00831 AVStream *st;
00832
00833 if (strcmp(cur->tag, "APIC"))
00834 continue;
00835 apic = cur->data;
00836
00837 if (!(st = avformat_new_stream(s, NULL)))
00838 return AVERROR(ENOMEM);
00839
00840 st->disposition |= AV_DISPOSITION_ATTACHED_PIC;
00841 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00842 st->codec->codec_id = apic->id;
00843 av_dict_set(&st->metadata, "title", apic->description, 0);
00844 av_dict_set(&st->metadata, "comment", apic->type, 0);
00845
00846 av_init_packet(&st->attached_pic);
00847 st->attached_pic.data = apic->data;
00848 st->attached_pic.size = apic->len;
00849 st->attached_pic.destruct = av_destruct_packet;
00850 st->attached_pic.stream_index = st->index;
00851 st->attached_pic.flags |= AV_PKT_FLAG_KEY;
00852
00853 apic->data = NULL;
00854 apic->len = 0;
00855 }
00856
00857 return 0;
00858 }