Mercurial > libavformat.hg
comparison id3v2.c @ 6386:dd54b36d1b8c libavformat
Support unsynchronisation for id3v2 tags.
Patch by Alexander Kojevnikov, alexander kojevnikov com
author | cehoyos |
---|---|
date | Wed, 18 Aug 2010 16:29:46 +0000 |
parents | f5fec1ab4925 |
children | 1a62da965733 |
comparison
equal
deleted
inserted
replaced
6385:ea409874020e | 6386:dd54b36d1b8c |
---|---|
75 while (len--) | 75 while (len--) |
76 v = (v << 7) + (get_byte(s) & 0x7F); | 76 v = (v << 7) + (get_byte(s) & 0x7F); |
77 return v; | 77 return v; |
78 } | 78 } |
79 | 79 |
80 static void read_ttag(AVFormatContext *s, int taglen, const char *key) | 80 static void read_ttag(AVFormatContext *s, ByteIOContext *pb, int taglen, const char *key) |
81 { | 81 { |
82 char *q, dst[512]; | 82 char *q, dst[512]; |
83 const char *val = NULL; | 83 const char *val = NULL; |
84 int len, dstlen = sizeof(dst) - 1; | 84 int len, dstlen = sizeof(dst) - 1; |
85 unsigned genre; | 85 unsigned genre; |
89 if (taglen < 1) | 89 if (taglen < 1) |
90 return; | 90 return; |
91 | 91 |
92 taglen--; /* account for encoding type byte */ | 92 taglen--; /* account for encoding type byte */ |
93 | 93 |
94 switch (get_byte(s->pb)) { /* encoding type */ | 94 switch (get_byte(pb)) { /* encoding type */ |
95 | 95 |
96 case 0: /* ISO-8859-1 (0 - 255 maps directly into unicode) */ | 96 case 0: /* ISO-8859-1 (0 - 255 maps directly into unicode) */ |
97 q = dst; | 97 q = dst; |
98 while (taglen-- && q - dst < dstlen - 7) { | 98 while (taglen-- && q - dst < dstlen - 7) { |
99 uint8_t tmp; | 99 uint8_t tmp; |
100 PUT_UTF8(get_byte(s->pb), tmp, *q++ = tmp;) | 100 PUT_UTF8(get_byte(pb), tmp, *q++ = tmp;) |
101 } | 101 } |
102 *q = 0; | 102 *q = 0; |
103 break; | 103 break; |
104 | 104 |
105 case 1: /* UTF-16 with BOM */ | 105 case 1: /* UTF-16 with BOM */ |
106 taglen -= 2; | 106 taglen -= 2; |
107 switch (get_be16(s->pb)) { | 107 switch (get_be16(pb)) { |
108 case 0xfffe: | 108 case 0xfffe: |
109 get = get_le16; | 109 get = get_le16; |
110 case 0xfeff: | 110 case 0xfeff: |
111 break; | 111 break; |
112 default: | 112 default: |
119 q = dst; | 119 q = dst; |
120 while (taglen > 1 && q - dst < dstlen - 7) { | 120 while (taglen > 1 && q - dst < dstlen - 7) { |
121 uint32_t ch; | 121 uint32_t ch; |
122 uint8_t tmp; | 122 uint8_t tmp; |
123 | 123 |
124 GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(s->pb) : 0), break;) | 124 GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(pb) : 0), break;) |
125 PUT_UTF8(ch, tmp, *q++ = tmp;) | 125 PUT_UTF8(ch, tmp, *q++ = tmp;) |
126 } | 126 } |
127 *q = 0; | 127 *q = 0; |
128 break; | 128 break; |
129 | 129 |
130 case 3: /* UTF-8 */ | 130 case 3: /* UTF-8 */ |
131 len = FFMIN(taglen, dstlen); | 131 len = FFMIN(taglen, dstlen); |
132 get_buffer(s->pb, dst, len); | 132 get_buffer(pb, dst, len); |
133 dst[len] = 0; | 133 dst[len] = 0; |
134 break; | 134 break; |
135 default: | 135 default: |
136 av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s\n.", key); | 136 av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s\n.", key); |
137 } | 137 } |
154 av_metadata_set2(&s->metadata, key, val, 0); | 154 av_metadata_set2(&s->metadata, key, val, 0); |
155 } | 155 } |
156 | 156 |
157 void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags) | 157 void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags) |
158 { | 158 { |
159 int isv34, tlen; | 159 int isv34, tlen, unsync; |
160 char tag[5]; | 160 char tag[5]; |
161 int64_t next; | 161 int64_t next; |
162 int taghdrlen; | 162 int taghdrlen; |
163 const char *reason; | 163 const char *reason; |
164 ByteIOContext pb; | |
165 unsigned char *buffer = NULL; | |
166 int buffer_size = 0; | |
164 | 167 |
165 switch (version) { | 168 switch (version) { |
166 case 2: | 169 case 2: |
167 if (flags & 0x40) { | 170 if (flags & 0x40) { |
168 reason = "compression"; | 171 reason = "compression"; |
181 default: | 184 default: |
182 reason = "version"; | 185 reason = "version"; |
183 goto error; | 186 goto error; |
184 } | 187 } |
185 | 188 |
186 if (flags & 0x80) { | 189 unsync = flags & 0x80; |
187 reason = "unsynchronization"; | |
188 goto error; | |
189 } | |
190 | 190 |
191 if (isv34 && flags & 0x40) /* Extended header present, just skip over it */ | 191 if (isv34 && flags & 0x40) /* Extended header present, just skip over it */ |
192 url_fskip(s->pb, get_size(s->pb, 4)); | 192 url_fskip(s->pb, get_size(s->pb, 4)); |
193 | 193 |
194 while (len >= taghdrlen) { | 194 while (len >= taghdrlen) { |
195 unsigned int tflags; | |
196 int tunsync = 0; | |
197 | |
195 if (isv34) { | 198 if (isv34) { |
196 get_buffer(s->pb, tag, 4); | 199 get_buffer(s->pb, tag, 4); |
197 tag[4] = 0; | 200 tag[4] = 0; |
198 if(version==3){ | 201 if(version==3){ |
199 tlen = get_be32(s->pb); | 202 tlen = get_be32(s->pb); |
200 }else | 203 }else |
201 tlen = get_size(s->pb, 4); | 204 tlen = get_size(s->pb, 4); |
202 get_be16(s->pb); /* flags */ | 205 tflags = get_be16(s->pb); |
206 tunsync = tflags & 0x02; | |
203 } else { | 207 } else { |
204 get_buffer(s->pb, tag, 3); | 208 get_buffer(s->pb, tag, 3); |
205 tag[3] = 0; | 209 tag[3] = 0; |
206 tlen = get_be24(s->pb); | 210 tlen = get_be24(s->pb); |
207 } | 211 } |
210 if (len < 0) | 214 if (len < 0) |
211 break; | 215 break; |
212 | 216 |
213 next = url_ftell(s->pb) + tlen; | 217 next = url_ftell(s->pb) + tlen; |
214 | 218 |
215 if (tag[0] == 'T') | 219 if (tag[0] == 'T') { |
216 read_ttag(s, tlen, tag); | 220 if (unsync || tunsync) { |
221 int i, j; | |
222 av_fast_malloc(&buffer, &buffer_size, tlen); | |
223 for (i = 0, j = 0; i < tlen; i++, j++) { | |
224 buffer[j] = get_byte(s->pb); | |
225 if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) { | |
226 /* Unsynchronised byte, skip it */ | |
227 j--; | |
228 } | |
229 } | |
230 init_put_byte(&pb, buffer, j, 0, NULL, NULL, NULL, NULL); | |
231 read_ttag(s, &pb, j, tag); | |
232 } else { | |
233 read_ttag(s, s->pb, tlen, tag); | |
234 } | |
235 } | |
217 else if (!tag[0]) { | 236 else if (!tag[0]) { |
218 if (tag[1]) | 237 if (tag[1]) |
219 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding"); | 238 av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding"); |
220 url_fskip(s->pb, tlen); | 239 url_fskip(s->pb, tlen); |
221 break; | 240 break; |
228 /* Skip padding */ | 247 /* Skip padding */ |
229 url_fskip(s->pb, len); | 248 url_fskip(s->pb, len); |
230 } | 249 } |
231 if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */ | 250 if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */ |
232 url_fskip(s->pb, 10); | 251 url_fskip(s->pb, 10); |
252 | |
253 av_free(buffer); | |
233 return; | 254 return; |
234 | 255 |
235 error: | 256 error: |
236 av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason); | 257 av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason); |
237 url_fskip(s->pb, len); | 258 url_fskip(s->pb, len); |
259 av_free(buffer); | |
238 } | 260 } |
239 | 261 |
240 const AVMetadataConv ff_id3v2_metadata_conv[] = { | 262 const AVMetadataConv ff_id3v2_metadata_conv[] = { |
241 { "TALB", "album"}, | 263 { "TALB", "album"}, |
242 { "TAL", "album"}, | 264 { "TAL", "album"}, |