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 #include "avio_internal.h"
00028
00029 int ff_id3v2_match(const uint8_t *buf, const char * magic)
00030 {
00031 return buf[0] == magic[0] &&
00032 buf[1] == magic[1] &&
00033 buf[2] == magic[2] &&
00034 buf[3] != 0xff &&
00035 buf[4] != 0xff &&
00036 (buf[6] & 0x80) == 0 &&
00037 (buf[7] & 0x80) == 0 &&
00038 (buf[8] & 0x80) == 0 &&
00039 (buf[9] & 0x80) == 0;
00040 }
00041
00042 int ff_id3v2_tag_len(const uint8_t * buf)
00043 {
00044 int len = ((buf[6] & 0x7f) << 21) +
00045 ((buf[7] & 0x7f) << 14) +
00046 ((buf[8] & 0x7f) << 7) +
00047 (buf[9] & 0x7f) +
00048 ID3v2_HEADER_SIZE;
00049 if (buf[5] & 0x10)
00050 len += ID3v2_HEADER_SIZE;
00051 return len;
00052 }
00053
00054 static unsigned int get_size(AVIOContext *s, int len)
00055 {
00056 int v = 0;
00057 while (len--)
00058 v = (v << 7) + (avio_r8(s) & 0x7F);
00059 return v;
00060 }
00061
00062 static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key)
00063 {
00064 char *q, dst[512];
00065 const char *val = NULL;
00066 int len, dstlen = sizeof(dst) - 1;
00067 unsigned genre;
00068 unsigned int (*get)(AVIOContext*) = avio_rb16;
00069
00070 dst[0] = 0;
00071 if (taglen < 1)
00072 return;
00073
00074 taglen--;
00075
00076 switch (avio_r8(pb)) {
00077
00078 case ID3v2_ENCODING_ISO8859:
00079 q = dst;
00080 while (taglen-- && q - dst < dstlen - 7) {
00081 uint8_t tmp;
00082 PUT_UTF8(avio_r8(pb), tmp, *q++ = tmp;)
00083 }
00084 *q = 0;
00085 break;
00086
00087 case ID3v2_ENCODING_UTF16BOM:
00088 taglen -= 2;
00089 switch (avio_rb16(pb)) {
00090 case 0xfffe:
00091 get = avio_rl16;
00092 case 0xfeff:
00093 break;
00094 default:
00095 av_log(s, AV_LOG_ERROR, "Incorrect BOM value in tag %s.\n", key);
00096 return;
00097 }
00098
00099
00100 case ID3v2_ENCODING_UTF16BE:
00101 q = dst;
00102 while (taglen > 1 && q - dst < dstlen - 7) {
00103 uint32_t ch;
00104 uint8_t tmp;
00105
00106 GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(pb) : 0), break;)
00107 PUT_UTF8(ch, tmp, *q++ = tmp;)
00108 }
00109 *q = 0;
00110 break;
00111
00112 case ID3v2_ENCODING_UTF8:
00113 len = FFMIN(taglen, dstlen);
00114 avio_read(pb, dst, len);
00115 dst[len] = 0;
00116 break;
00117 default:
00118 av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s.\n", key);
00119 }
00120
00121 if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
00122 && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
00123 && genre <= ID3v1_GENRE_MAX)
00124 val = ff_id3v1_genre_str[genre];
00125 else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
00126
00127 dst[dstlen] = 0;
00128 len = strlen(dst);
00129 key = dst;
00130 val = dst + FFMIN(len + 1, dstlen);
00131 }
00132 else if (*dst)
00133 val = dst;
00134
00135 if (val)
00136 av_metadata_set2(&s->metadata, key, val, AV_METADATA_DONT_OVERWRITE);
00137 }
00138
00139 static int is_number(const char *str)
00140 {
00141 while (*str >= '0' && *str <= '9') str++;
00142 return !*str;
00143 }
00144
00145 static AVMetadataTag* get_date_tag(AVMetadata *m, const char *tag)
00146 {
00147 AVMetadataTag *t;
00148 if ((t = av_metadata_get(m, tag, NULL, AV_METADATA_MATCH_CASE)) &&
00149 strlen(t->value) == 4 && is_number(t->value))
00150 return t;
00151 return NULL;
00152 }
00153
00154 static void merge_date(AVMetadata **m)
00155 {
00156 AVMetadataTag *t;
00157 char date[17] = {0};
00158
00159 if (!(t = get_date_tag(*m, "TYER")) &&
00160 !(t = get_date_tag(*m, "TYE")))
00161 return;
00162 av_strlcpy(date, t->value, 5);
00163 av_metadata_set2(m, "TYER", NULL, 0);
00164 av_metadata_set2(m, "TYE", NULL, 0);
00165
00166 if (!(t = get_date_tag(*m, "TDAT")) &&
00167 !(t = get_date_tag(*m, "TDA")))
00168 goto finish;
00169 snprintf(date + 4, sizeof(date) - 4, "-%.2s-%.2s", t->value + 2, t->value);
00170 av_metadata_set2(m, "TDAT", NULL, 0);
00171 av_metadata_set2(m, "TDA", NULL, 0);
00172
00173 if (!(t = get_date_tag(*m, "TIME")) &&
00174 !(t = get_date_tag(*m, "TIM")))
00175 goto finish;
00176 snprintf(date + 10, sizeof(date) - 10, " %.2s:%.2s", t->value, t->value + 2);
00177 av_metadata_set2(m, "TIME", NULL, 0);
00178 av_metadata_set2(m, "TIM", NULL, 0);
00179
00180 finish:
00181 if (date[0])
00182 av_metadata_set2(m, "date", date, 0);
00183 }
00184
00185 static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
00186 {
00187 int isv34, unsync;
00188 unsigned tlen;
00189 char tag[5];
00190 int64_t next;
00191 int taghdrlen;
00192 const char *reason;
00193 AVIOContext pb;
00194 unsigned char *buffer = NULL;
00195 int buffer_size = 0;
00196
00197 switch (version) {
00198 case 2:
00199 if (flags & 0x40) {
00200 reason = "compression";
00201 goto error;
00202 }
00203 isv34 = 0;
00204 taghdrlen = 6;
00205 break;
00206
00207 case 3:
00208 case 4:
00209 isv34 = 1;
00210 taghdrlen = 10;
00211 break;
00212
00213 default:
00214 reason = "version";
00215 goto error;
00216 }
00217
00218 unsync = flags & 0x80;
00219
00220 if (isv34 && flags & 0x40)
00221 avio_skip(s->pb, get_size(s->pb, 4));
00222
00223 while (len >= taghdrlen) {
00224 unsigned int tflags;
00225 int tunsync = 0;
00226
00227 if (isv34) {
00228 avio_read(s->pb, tag, 4);
00229 tag[4] = 0;
00230 if(version==3){
00231 tlen = avio_rb32(s->pb);
00232 }else
00233 tlen = get_size(s->pb, 4);
00234 tflags = avio_rb16(s->pb);
00235 tunsync = tflags & ID3v2_FLAG_UNSYNCH;
00236 } else {
00237 avio_read(s->pb, tag, 3);
00238 tag[3] = 0;
00239 tlen = avio_rb24(s->pb);
00240 }
00241 if (tlen > (1<<28))
00242 break;
00243 len -= taghdrlen + tlen;
00244
00245 if (len < 0)
00246 break;
00247
00248 next = avio_tell(s->pb) + tlen;
00249
00250 if (tflags & ID3v2_FLAG_DATALEN) {
00251 avio_rb32(s->pb);
00252 tlen -= 4;
00253 }
00254
00255 if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
00256 av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
00257 avio_skip(s->pb, tlen);
00258 } else if (tag[0] == 'T') {
00259 if (unsync || tunsync) {
00260 int i, j;
00261 av_fast_malloc(&buffer, &buffer_size, tlen);
00262 for (i = 0, j = 0; i < tlen; i++, j++) {
00263 buffer[j] = avio_r8(s->pb);
00264 if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
00265
00266 j--;
00267 }
00268 }
00269 ffio_init_context(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
00270 read_ttag(s, &pb, j, tag);
00271 } else {
00272 read_ttag(s, s->pb, tlen, tag);
00273 }
00274 }
00275 else if (!tag[0]) {
00276 if (tag[1])
00277 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
00278 avio_skip(s->pb, tlen);
00279 break;
00280 }
00281
00282 avio_seek(s->pb, next, SEEK_SET);
00283 }
00284
00285 if (len > 0) {
00286
00287 avio_skip(s->pb, len);
00288 }
00289 if (version == 4 && flags & 0x10)
00290 avio_skip(s->pb, 10);
00291
00292 av_free(buffer);
00293 return;
00294
00295 error:
00296 av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
00297 avio_seek(s->pb, len, SEEK_CUR);
00298 av_free(buffer);
00299 }
00300
00301 void ff_id3v2_read(AVFormatContext *s, const char *magic)
00302 {
00303 int len, ret;
00304 uint8_t buf[ID3v2_HEADER_SIZE];
00305 int found_header;
00306 int64_t off;
00307
00308 do {
00309
00310 off = avio_tell(s->pb);
00311 ret = avio_read(s->pb, buf, ID3v2_HEADER_SIZE);
00312 if (ret != ID3v2_HEADER_SIZE)
00313 break;
00314 found_header = ff_id3v2_match(buf, magic);
00315 if (found_header) {
00316
00317 len = ((buf[6] & 0x7f) << 21) |
00318 ((buf[7] & 0x7f) << 14) |
00319 ((buf[8] & 0x7f) << 7) |
00320 (buf[9] & 0x7f);
00321 ff_id3v2_parse(s, len, buf[3], buf[5]);
00322 } else {
00323 avio_seek(s->pb, off, SEEK_SET);
00324 }
00325 } while (found_header);
00326 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv);
00327 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_2_metadata_conv);
00328 ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv);
00329 merge_date(&s->metadata);
00330 }
00331
00332 const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
00333 { "TALB", "album"},
00334 { "TCOM", "composer"},
00335 { "TCON", "genre"},
00336 { "TCOP", "copyright"},
00337 { "TENC", "encoded_by"},
00338 { "TIT2", "title"},
00339 { "TLAN", "language"},
00340 { "TPE1", "artist"},
00341 { "TPE2", "album_artist"},
00342 { "TPE3", "performer"},
00343 { "TPOS", "disc"},
00344 { "TPUB", "publisher"},
00345 { "TRCK", "track"},
00346 { "TSSE", "encoder"},
00347 { 0 }
00348 };
00349
00350 const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
00351 { "TDRL", "date"},
00352 { "TDRC", "date"},
00353 { "TDEN", "creation_time"},
00354 { "TSOA", "album-sort"},
00355 { "TSOP", "artist-sort"},
00356 { "TSOT", "title-sort"},
00357 { 0 }
00358 };
00359
00360 const AVMetadataConv ff_id3v2_2_metadata_conv[] = {
00361 { "TAL", "album"},
00362 { "TCO", "genre"},
00363 { "TT2", "title"},
00364 { "TEN", "encoded_by"},
00365 { "TP1", "artist"},
00366 { "TP2", "album_artist"},
00367 { "TP3", "performer"},
00368 { "TRK", "track"},
00369 { 0 }
00370 };
00371
00372
00373 const char ff_id3v2_tags[][4] = {
00374 "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
00375 "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
00376 "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
00377 "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
00378 { 0 },
00379 };
00380
00381 const char ff_id3v2_4_tags[][4] = {
00382 "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
00383 "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
00384 { 0 },
00385 };
00386
00387 const char ff_id3v2_3_tags[][4] = {
00388 "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
00389 { 0 },
00390 };