• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/id3v2.c

Go to the documentation of this file.
00001 /*
00002  * ID3v2 header parser
00003  * Copyright (c) 2003 Fabrice Bellard
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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         /* parse ID3v2 header */
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--; /* account for encoding type byte */
00092 
00093     switch (get_byte(s->pb)) { /* encoding type */
00094 
00095     case 0:  /* ISO-8859-1 (0 - 255 maps directly into unicode) */
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:  /* UTF-16 with BOM */
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         // fall-through
00116 
00117     case 2:  /* UTF-16BE without BOM */
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:  /* UTF-8 */
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         /* dst now contains two 0-terminated strings */
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) /* Extended header present, just skip over it */
00191         url_fskip(s->pb, get_size(s->pb, 4));
00192 
00193     while (len >= taghdrlen) {
00194         if (isv34) {
00195             get_buffer(s->pb, tag, 4);
00196             tag[4] = 0;
00197             if(version==3){
00198                 tlen = get_be32(s->pb);
00199             }else
00200                 tlen = get_size(s->pb, 4);
00201             get_be16(s->pb); /* flags */
00202         } else {
00203             get_buffer(s->pb, tag, 3);
00204             tag[3] = 0;
00205             tlen = get_be24(s->pb);
00206         }
00207         len -= taghdrlen + tlen;
00208 
00209         if (len < 0)
00210             break;
00211 
00212         next = url_ftell(s->pb) + tlen;
00213 
00214         if (tag[0] == 'T')
00215             read_ttag(s, tlen, tag);
00216         else if (!tag[0]) {
00217             if (tag[1])
00218                 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
00219             url_fskip(s->pb, len);
00220             break;
00221         }
00222         /* Skip to end of tag */
00223         url_fseek(s->pb, next, SEEK_SET);
00224     }
00225 
00226     if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
00227         url_fskip(s->pb, 10);
00228     return;
00229 
00230   error:
00231     av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
00232     url_fskip(s->pb, len);
00233 }
00234 
00235 const AVMetadataConv ff_id3v2_metadata_conv[] = {
00236     { "TALB", "album"},
00237     { "TAL",  "album"},
00238     { "TCOM", "composer"},
00239     { "TCON", "genre"},
00240     { "TCO",  "genre"},
00241     { "TCOP", "copyright"},
00242     { "TDRL", "date"},
00243     { "TDRC", "date"},
00244     { "TENC", "encoded_by"},
00245     { "TEN",  "encoded_by"},
00246     { "TIT2", "title"},
00247     { "TT2",  "title"},
00248     { "TLAN", "language"},
00249     { "TPE1", "artist"},
00250     { "TP1",  "artist"},
00251     { "TPE2", "album_artist"},
00252     { "TP2",  "album_artist"},
00253     { "TPE3", "performer"},
00254     { "TP3",  "performer"},
00255     { "TPOS", "disc"},
00256     { "TPUB", "publisher"},
00257     { "TRCK", "track"},
00258     { "TRK",  "track"},
00259     { "TSOA", "album-sort"},
00260     { "TSOP", "artist-sort"},
00261     { "TSOT", "title-sort"},
00262     { "TSSE", "encoder"},
00263     { 0 }
00264 };
00265 
00266 const char ff_id3v2_tags[][4] = {
00267    "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDEN", "TDLY", "TDOR", "TDRC",
00268    "TDRL", "TDTG", "TENC", "TEXT", "TFLT", "TIPL", "TIT1", "TIT2", "TIT3",
00269    "TKEY", "TLAN", "TLEN", "TMCL", "TMED", "TMOO", "TOAL", "TOFN", "TOLY",
00270    "TOPE", "TOWN", "TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPRO", "TPUB",
00271    "TRCK", "TRSN", "TRSO", "TSOA", "TSOP", "TSOT", "TSRC", "TSSE", "TSST",
00272    { 0 },
00273 };

Generated on Fri Sep 16 2011 17:17:48 for FFmpeg by  doxygen 1.7.1