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