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 typedef struct ID3v2EMFunc {
00512     const char *tag3;
00513     const char *tag4;
00514     void (*read)(AVFormatContext*, AVIOContext*, int, char*, ID3v2ExtraMeta **);
00515     void (*free)(void *obj);
00516 } ID3v2EMFunc;
00517 
00518 static const ID3v2EMFunc id3v2_extra_meta_funcs[] = {
00519     { "GEO", "GEOB", read_geobtag, free_geobtag },
00520     { "PIC", "APIC", read_apic,    free_apic },
00521     { NULL }
00522 };
00523 
00529 static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
00530 {
00531     int i = 0;
00532     while (id3v2_extra_meta_funcs[i].tag3) {
00533         if (tag && !memcmp(tag,
00534                     (isv34 ? id3v2_extra_meta_funcs[i].tag4 :
00535                              id3v2_extra_meta_funcs[i].tag3),
00536                     (isv34 ? 4 : 3)))
00537             return &id3v2_extra_meta_funcs[i];
00538         i++;
00539     }
00540     return NULL;
00541 }
00542 
00543 static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags, ID3v2ExtraMeta **extra_meta)
00544 {
00545     int isv34, unsync;
00546     unsigned tlen;
00547     char tag[5];
00548     int64_t next, end = avio_tell(s->pb) + len;
00549     int taghdrlen;
00550     const char *reason = NULL;
00551     AVIOContext pb;
00552     AVIOContext *pbx;
00553     unsigned char *buffer = NULL;
00554     int buffer_size = 0;
00555     const ID3v2EMFunc *extra_func = NULL;
00556     unsigned char *compressed_buffer = NULL;
00557     int compressed_buffer_size = 0;
00558 
00559     switch (version) {
00560     case 2:
00561         if (flags & 0x40) {
00562             reason = "compression";
00563             goto error;
00564         }
00565         isv34 = 0;
00566         taghdrlen = 6;
00567         break;
00568 
00569     case 3:
00570     case 4:
00571         isv34 = 1;
00572         taghdrlen = 10;
00573         break;
00574 
00575     default:
00576         reason = "version";
00577         goto error;
00578     }
00579 
00580     unsync = flags & 0x80;
00581 
00582     if (isv34 && flags & 0x40) { 
00583         int extlen = get_size(s->pb, 4);
00584         if (version == 4)
00585             extlen -= 4;     
00586 
00587         if (extlen < 0) {
00588             reason = "invalid extended header length";
00589             goto error;
00590         }
00591         avio_skip(s->pb, extlen);
00592         len -= extlen + 4;
00593         if (len < 0) {
00594             reason = "extended header too long.";
00595             goto error;
00596         }
00597     }
00598 
00599     while (len >= taghdrlen) {
00600         unsigned int tflags = 0;
00601         int tunsync = 0;
00602         int tcomp = 0;
00603         int tencr = 0;
00604         unsigned long dlen;
00605 
00606         if (isv34) {
00607             avio_read(s->pb, tag, 4);
00608             tag[4] = 0;
00609             if(version==3){
00610                 tlen = avio_rb32(s->pb);
00611             }else
00612                 tlen = get_size(s->pb, 4);
00613             tflags = avio_rb16(s->pb);
00614             tunsync = tflags & ID3v2_FLAG_UNSYNCH;
00615         } else {
00616             avio_read(s->pb, tag, 3);
00617             tag[3] = 0;
00618             tlen = avio_rb24(s->pb);
00619         }
00620         if (tlen > (1<<28))
00621             break;
00622         len -= taghdrlen + tlen;
00623 
00624         if (len < 0)
00625             break;
00626 
00627         next = avio_tell(s->pb) + tlen;
00628 
00629         if (!tlen) {
00630             if (tag[0])
00631                 av_log(s, AV_LOG_DEBUG, "Invalid empty frame %s, skipping.\n", tag);
00632             continue;
00633         }
00634 
00635         if (tflags & ID3v2_FLAG_DATALEN) {
00636             if (tlen < 4)
00637                 break;
00638             dlen = avio_rb32(s->pb);
00639             tlen -= 4;
00640         } else
00641             dlen = tlen;
00642 
00643         tcomp = tflags & ID3v2_FLAG_COMPRESSION;
00644         tencr = tflags & ID3v2_FLAG_ENCRYPTION;
00645 
00646         
00647         if (tencr || (!CONFIG_ZLIB && tcomp)) {
00648             const char *type;
00649             if (!tcomp)
00650                 type = "encrypted";
00651             else if (!tencr)
00652                 type = "compressed";
00653             else
00654                 type = "encrypted and compressed";
00655 
00656             av_log(s, AV_LOG_WARNING, "Skipping %s ID3v2 frame %s.\n", type, tag);
00657             avio_skip(s->pb, tlen);
00658         
00659         } else if (tag[0] == 'T' || (extra_meta && (extra_func = get_extra_meta_func(tag, isv34)))) {
00660             if (unsync || tunsync || tcomp) {
00661                 int i, j;
00662 
00663                 av_fast_malloc(&buffer, &buffer_size, dlen);
00664                 if (!buffer) {
00665                     av_log(s, AV_LOG_ERROR, "Failed to alloc %ld bytes\n", dlen);
00666                     goto seek;
00667                 }
00668 #if CONFIG_ZLIB
00669                 if (tcomp) {
00670                     int n, err;
00671 
00672                     av_log(s, AV_LOG_DEBUG, "Compresssed frame %s tlen=%d dlen=%ld\n", tag, tlen, dlen);
00673 
00674                     av_fast_malloc(&compressed_buffer, &compressed_buffer_size, tlen);
00675                     if (!compressed_buffer) {
00676                         av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen);
00677                         goto seek;
00678                     }
00679 
00680                     n = avio_read(s->pb, compressed_buffer, tlen);
00681                     if (n < 0) {
00682                         av_log(s, AV_LOG_ERROR, "Failed to read compressed tag\n");
00683                         goto seek;
00684                     }
00685 
00686                     err = uncompress(buffer, &dlen, compressed_buffer, n);
00687                     if (err != Z_OK) {
00688                         av_log(s, AV_LOG_ERROR, "Failed to uncompress tag: %d\n", err);
00689                         goto seek;
00690                     }
00691                 }
00692 #endif
00693 
00694                 for (i = 0, j = 0; i < dlen; i++, j++) {
00695                     if (!tcomp)
00696                         buffer[j] = avio_r8(s->pb);
00697                     if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
00698                         
00699                         j--;
00700                     }
00701                 }
00702                 ffio_init_context(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
00703                 tlen = j;
00704                 pbx = &pb; 
00705             } else {
00706                 pbx = s->pb; 
00707             }
00708             if (tag[0] == 'T')
00709                 
00710                 read_ttag(s, pbx, tlen, tag);
00711             else
00712                 
00713                 extra_func->read(s, pbx, tlen, tag, extra_meta);
00714         }
00715         else if (!tag[0]) {
00716             if (tag[1])
00717                 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding\n");
00718             avio_skip(s->pb, tlen);
00719             break;
00720         }
00721         
00722 seek:
00723         avio_seek(s->pb, next, SEEK_SET);
00724     }
00725 
00726     if (version == 4 && flags & 0x10) 
00727         end += 10;
00728 
00729   error:
00730     if (reason)
00731         av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
00732     avio_seek(s->pb, end, SEEK_SET);
00733     av_free(buffer);
00734     av_free(compressed_buffer);
00735     return;
00736 }
00737 
00738 void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta)
00739 {
00740     int len, ret;
00741     uint8_t buf[ID3v2_HEADER_SIZE];
00742     int     found_header;
00743     int64_t off;
00744 
00745     do {
00746         
00747         off = avio_tell(s->pb);
00748         ret = avio_read(s->pb, buf, ID3v2_HEADER_SIZE);
00749         if (ret != ID3v2_HEADER_SIZE)
00750             break;
00751             found_header = ff_id3v2_match(buf, magic);
00752             if (found_header) {
00753             
00754             len = ((buf[6] & 0x7f) << 21) |
00755                   ((buf[7] & 0x7f) << 14) |
00756                   ((buf[8] & 0x7f) << 7) |
00757                    (buf[9] & 0x7f);
00758             ff_id3v2_parse(s, len, buf[3], buf[5], extra_meta);
00759         } else {
00760             avio_seek(s->pb, off, SEEK_SET);
00761         }
00762     } while (found_header);
00763     ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv);
00764     ff_metadata_conv(&s->metadata, NULL, id3v2_2_metadata_conv);
00765     ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv);
00766     merge_date(&s->metadata);
00767 }
00768 
00769 void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta)
00770 {
00771     ID3v2ExtraMeta *current = *extra_meta, *next;
00772     const ID3v2EMFunc *extra_func;
00773 
00774     while (current) {
00775         if ((extra_func = get_extra_meta_func(current->tag, 1)))
00776             extra_func->free(current->data);
00777         next = current->next;
00778         av_freep(¤t);
00779         current = next;
00780     }
00781 }
00782 
00783 int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta)
00784 {
00785     ID3v2ExtraMeta *cur;
00786 
00787     for (cur = *extra_meta; cur; cur = cur->next) {
00788         ID3v2ExtraMetaAPIC *apic;
00789         AVStream *st;
00790 
00791         if (strcmp(cur->tag, "APIC"))
00792             continue;
00793         apic = cur->data;
00794 
00795         if (!(st = avformat_new_stream(s, NULL)))
00796             return AVERROR(ENOMEM);
00797 
00798         st->disposition      |= AV_DISPOSITION_ATTACHED_PIC;
00799         st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00800         st->codec->codec_id   = apic->id;
00801         av_dict_set(&st->metadata, "title",   apic->description, 0);
00802         av_dict_set(&st->metadata, "comment", apic->type, 0);
00803 
00804         av_init_packet(&st->attached_pic);
00805         st->attached_pic.data         = apic->data;
00806         st->attached_pic.size         = apic->len;
00807         st->attached_pic.destruct     = av_destruct_packet;
00808         st->attached_pic.stream_index = st->index;
00809         st->attached_pic.flags       |= AV_PKT_FLAG_KEY;
00810 
00811         apic->data = NULL;
00812         apic->len  = 0;
00813     }
00814 
00815     return 0;
00816 }