# HG changeset patch # User cehoyos # Date 1282148986 0 # Node ID dd54b36d1b8c8fc89785a82dfbb254f9cd2950d1 # Parent ea409874020e943b9530c80b5dd4e273e6d0515f Support unsynchronisation for id3v2 tags. Patch by Alexander Kojevnikov, alexander kojevnikov com diff -r ea409874020e -r dd54b36d1b8c id3v2.c --- a/id3v2.c Wed Aug 18 09:39:21 2010 +0000 +++ b/id3v2.c Wed Aug 18 16:29:46 2010 +0000 @@ -77,7 +77,7 @@ return v; } -static void read_ttag(AVFormatContext *s, int taglen, const char *key) +static void read_ttag(AVFormatContext *s, ByteIOContext *pb, int taglen, const char *key) { char *q, dst[512]; const char *val = NULL; @@ -91,20 +91,20 @@ taglen--; /* account for encoding type byte */ - switch (get_byte(s->pb)) { /* encoding type */ + switch (get_byte(pb)) { /* encoding type */ case 0: /* ISO-8859-1 (0 - 255 maps directly into unicode) */ q = dst; while (taglen-- && q - dst < dstlen - 7) { uint8_t tmp; - PUT_UTF8(get_byte(s->pb), tmp, *q++ = tmp;) + PUT_UTF8(get_byte(pb), tmp, *q++ = tmp;) } *q = 0; break; case 1: /* UTF-16 with BOM */ taglen -= 2; - switch (get_be16(s->pb)) { + switch (get_be16(pb)) { case 0xfffe: get = get_le16; case 0xfeff: @@ -121,7 +121,7 @@ uint32_t ch; uint8_t tmp; - GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(s->pb) : 0), break;) + GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(pb) : 0), break;) PUT_UTF8(ch, tmp, *q++ = tmp;) } *q = 0; @@ -129,7 +129,7 @@ case 3: /* UTF-8 */ len = FFMIN(taglen, dstlen); - get_buffer(s->pb, dst, len); + get_buffer(pb, dst, len); dst[len] = 0; break; default: @@ -156,11 +156,14 @@ void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags) { - int isv34, tlen; + int isv34, tlen, unsync; char tag[5]; int64_t next; int taghdrlen; const char *reason; + ByteIOContext pb; + unsigned char *buffer = NULL; + int buffer_size = 0; switch (version) { case 2: @@ -183,15 +186,15 @@ goto error; } - if (flags & 0x80) { - reason = "unsynchronization"; - goto error; - } + unsync = flags & 0x80; if (isv34 && flags & 0x40) /* Extended header present, just skip over it */ url_fskip(s->pb, get_size(s->pb, 4)); while (len >= taghdrlen) { + unsigned int tflags; + int tunsync = 0; + if (isv34) { get_buffer(s->pb, tag, 4); tag[4] = 0; @@ -199,7 +202,8 @@ tlen = get_be32(s->pb); }else tlen = get_size(s->pb, 4); - get_be16(s->pb); /* flags */ + tflags = get_be16(s->pb); + tunsync = tflags & 0x02; } else { get_buffer(s->pb, tag, 3); tag[3] = 0; @@ -212,8 +216,23 @@ next = url_ftell(s->pb) + tlen; - if (tag[0] == 'T') - read_ttag(s, tlen, tag); + if (tag[0] == 'T') { + if (unsync || tunsync) { + int i, j; + av_fast_malloc(&buffer, &buffer_size, tlen); + for (i = 0, j = 0; i < tlen; i++, j++) { + buffer[j] = get_byte(s->pb); + if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) { + /* Unsynchronised byte, skip it */ + j--; + } + } + init_put_byte(&pb, buffer, j, 0, NULL, NULL, NULL, NULL); + read_ttag(s, &pb, j, tag); + } else { + read_ttag(s, s->pb, tlen, tag); + } + } else if (!tag[0]) { if (tag[1]) av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding"); @@ -230,11 +249,14 @@ } if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */ url_fskip(s->pb, 10); + + av_free(buffer); return; error: av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason); url_fskip(s->pb, len); + av_free(buffer); } const AVMetadataConv ff_id3v2_metadata_conv[] = {