00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 #include "id3v2.h"
00023 #include "id3v1.h"
00024 #include "libavutil/avstring.h"
00025 
00026 int ff_id3v2_match(const uint8_t *buf)
00027 {
00028     return  buf[0]         ==  'I' &&
00029             buf[1]         ==  'D' &&
00030             buf[2]         ==  '3' &&
00031             buf[3]         != 0xff &&
00032             buf[4]         != 0xff &&
00033            (buf[6] & 0x80) ==    0 &&
00034            (buf[7] & 0x80) ==    0 &&
00035            (buf[8] & 0x80) ==    0 &&
00036            (buf[9] & 0x80) ==    0;
00037 }
00038 
00039 int ff_id3v2_tag_len(const uint8_t * buf)
00040 {
00041     int len = ((buf[6] & 0x7f) << 21) +
00042               ((buf[7] & 0x7f) << 14) +
00043               ((buf[8] & 0x7f) << 7) +
00044                (buf[9] & 0x7f) +
00045               ID3v2_HEADER_SIZE;
00046     if (buf[5] & 0x10)
00047         len += ID3v2_HEADER_SIZE;
00048     return len;
00049 }
00050 
00051 void ff_id3v2_read(AVFormatContext *s)
00052 {
00053     int len, ret;
00054     uint8_t buf[ID3v2_HEADER_SIZE];
00055 
00056     ret = get_buffer(s->pb, buf, ID3v2_HEADER_SIZE);
00057     if (ret != ID3v2_HEADER_SIZE)
00058         return;
00059     if (ff_id3v2_match(buf)) {
00060         
00061         len = ((buf[6] & 0x7f) << 21) |
00062             ((buf[7] & 0x7f) << 14) |
00063             ((buf[8] & 0x7f) << 7) |
00064             (buf[9] & 0x7f);
00065         ff_id3v2_parse(s, len, buf[3], buf[5]);
00066     } else {
00067         url_fseek(s->pb, 0, SEEK_SET);
00068     }
00069 }
00070 
00071 static unsigned int get_size(ByteIOContext *s, int len)
00072 {
00073     int v = 0;
00074     while (len--)
00075         v = (v << 7) + (get_byte(s) & 0x7F);
00076     return v;
00077 }
00078 
00079 static void read_ttag(AVFormatContext *s, int taglen, const char *key)
00080 {
00081     char *q, dst[512];
00082     const char *val = NULL;
00083     int len, dstlen = sizeof(dst) - 1;
00084     unsigned genre;
00085     unsigned int (*get)(ByteIOContext*) = get_be16;
00086 
00087     dst[0] = 0;
00088     if (taglen < 1)
00089         return;
00090 
00091     taglen--; 
00092 
00093     switch (get_byte(s->pb)) { 
00094 
00095     case 0:  
00096         q = dst;
00097         while (taglen-- && q - dst < dstlen - 7) {
00098             uint8_t tmp;
00099             PUT_UTF8(get_byte(s->pb), tmp, *q++ = tmp;)
00100         }
00101         *q = 0;
00102         break;
00103 
00104     case 1:  
00105         taglen -= 2;
00106         switch (get_be16(s->pb)) {
00107         case 0xfffe:
00108             get = get_le16;
00109         case 0xfeff:
00110             break;
00111         default:
00112             av_log(s, AV_LOG_ERROR, "Incorrect BOM value in tag %s.\n", key);
00113             return;
00114         }
00115         
00116 
00117     case 2:  
00118         q = dst;
00119         while (taglen > 1 && q - dst < dstlen - 7) {
00120             uint32_t ch;
00121             uint8_t tmp;
00122 
00123             GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(s->pb) : 0), break;)
00124             PUT_UTF8(ch, tmp, *q++ = tmp;)
00125         }
00126         *q = 0;
00127         break;
00128 
00129     case 3:  
00130         len = FFMIN(taglen, dstlen);
00131         get_buffer(s->pb, dst, len);
00132         dst[len] = 0;
00133         break;
00134     default:
00135         av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s\n.", key);
00136     }
00137 
00138     if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
00139         && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
00140         && genre <= ID3v1_GENRE_MAX)
00141         val = ff_id3v1_genre_str[genre];
00142     else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
00143         
00144         dst[dstlen] = 0;
00145         len = strlen(dst);
00146         key = dst;
00147         val = dst + FFMIN(len + 1, dstlen);
00148     }
00149     else if (*dst)
00150         val = dst;
00151 
00152     if (val)
00153         av_metadata_set2(&s->metadata, key, val, 0);
00154 }
00155 
00156 void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
00157 {
00158     int isv34, tlen;
00159     char tag[5];
00160     int64_t next;
00161     int taghdrlen;
00162     const char *reason;
00163 
00164     switch (version) {
00165     case 2:
00166         if (flags & 0x40) {
00167             reason = "compression";
00168             goto error;
00169         }
00170         isv34 = 0;
00171         taghdrlen = 6;
00172         break;
00173 
00174     case 3:
00175     case 4:
00176         isv34 = 1;
00177         taghdrlen = 10;
00178         break;
00179 
00180     default:
00181         reason = "version";
00182         goto error;
00183     }
00184 
00185     if (flags & 0x80) {
00186         reason = "unsynchronization";
00187         goto error;
00188     }
00189 
00190     if (isv34 && flags & 0x40) { 
00191         int extlen = get_size(s->pb, 4);
00192         if (version == 4)
00193             extlen -= 4;     
00194 
00195         if (extlen < 0) {
00196             reason = "invalid extended header length";
00197             goto error;
00198         }
00199         url_fskip(s->pb, extlen);
00200     }
00201 
00202     while (len >= taghdrlen) {
00203         if (isv34) {
00204             get_buffer(s->pb, tag, 4);
00205             tag[4] = 0;
00206             if(version==3){
00207                 tlen = get_be32(s->pb);
00208             }else
00209                 tlen = get_size(s->pb, 4);
00210             get_be16(s->pb); 
00211         } else {
00212             get_buffer(s->pb, tag, 3);
00213             tag[3] = 0;
00214             tlen = get_be24(s->pb);
00215         }
00216         len -= taghdrlen + tlen;
00217 
00218         if (len < 0)
00219             break;
00220 
00221         next = url_ftell(s->pb) + tlen;
00222 
00223         if (tag[0] == 'T')
00224             read_ttag(s, tlen, tag);
00225         else if (!tag[0]) {
00226             if (tag[1])
00227                 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
00228             url_fskip(s->pb, len);
00229             break;
00230         }
00231         
00232         url_fseek(s->pb, next, SEEK_SET);
00233     }
00234 
00235     if (version == 4 && flags & 0x10) 
00236         url_fskip(s->pb, 10);
00237     return;
00238 
00239   error:
00240     av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
00241     url_fskip(s->pb, len);
00242 }
00243 
00244 const AVMetadataConv ff_id3v2_metadata_conv[] = {
00245     { "TALB", "album"},
00246     { "TAL",  "album"},
00247     { "TCOM", "composer"},
00248     { "TCON", "genre"},
00249     { "TCO",  "genre"},
00250     { "TCOP", "copyright"},
00251     { "TDRL", "date"},
00252     { "TDRC", "date"},
00253     { "TENC", "encoded_by"},
00254     { "TEN",  "encoded_by"},
00255     { "TIT2", "title"},
00256     { "TT2",  "title"},
00257     { "TLAN", "language"},
00258     { "TPE1", "artist"},
00259     { "TP1",  "artist"},
00260     { "TPE2", "album_artist"},
00261     { "TP2",  "album_artist"},
00262     { "TPE3", "performer"},
00263     { "TP3",  "performer"},
00264     { "TPOS", "disc"},
00265     { "TPUB", "publisher"},
00266     { "TRCK", "track"},
00267     { "TRK",  "track"},
00268     { "TSOA", "album-sort"},
00269     { "TSOP", "artist-sort"},
00270     { "TSOT", "title-sort"},
00271     { "TSSE", "encoder"},
00272     { 0 }
00273 };
00274 
00275 const char ff_id3v2_tags[][4] = {
00276    "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDEN", "TDLY", "TDOR", "TDRC",
00277    "TDRL", "TDTG", "TENC", "TEXT", "TFLT", "TIPL", "TIT1", "TIT2", "TIT3",
00278    "TKEY", "TLAN", "TLEN", "TMCL", "TMED", "TMOO", "TOAL", "TOFN", "TOLY",
00279    "TOPE", "TOWN", "TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPRO", "TPUB",
00280    "TRCK", "TRSN", "TRSO", "TSOA", "TSOP", "TSOT", "TSRC", "TSSE", "TSST",
00281    { 0 },
00282 };