comparison src/madplug/plugin.c @ 801:dd06b14a43a9 trunk

[svn] - implement stricter detection rules for MP3. patch by Matti Hamalainen (ccr).
author nenolod
date Sun, 11 Mar 2007 10:09:52 -0700
parents d200de50a1fc
children 7ac48f3855b1
comparison
equal deleted inserted replaced
800:549f88da5311 801:dd06b14a43a9
51 #ifndef NOGUI 51 #ifndef NOGUI
52 static GtkWidget *error_dialog = 0; 52 static GtkWidget *error_dialog = 0;
53 #endif 53 #endif
54 54
55 extern gboolean scan_file(struct mad_info_t *info, gboolean fast); 55 extern gboolean scan_file(struct mad_info_t *info, gboolean fast);
56
57 static gint mp3_bitrate_table[5][16] = {
58 { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 }, /* MPEG1 L1 */
59 { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 }, /* MPEG1 L2 */
60 { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 }, /* MPEG1 L3 */
61 { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 }, /* MPEG2(.5) L1 */
62 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 } /* MPEG2(.5) L2,L3 */
63 };
64
65 static gint mp3_samplerate_table[4][4] = {
66 { 11025, 12000, 8000, -1 }, /* MPEG2.5 */
67 { -1, -1, -1, -1 }, /* Reserved */
68 { 22050, 24000, 16000, -1 }, /* MPEG2 */
69 { 44100, 48000, 32000, -1 } /* MPEG1 */
70 };
56 71
57 /* 72 /*
58 * Function extname (filename) 73 * Function extname (filename)
59 * 74 *
60 * Return pointer within filename to its extenstion, or NULL if 75 * Return pointer within filename to its extenstion, or NULL if
160 175
161 static void audmad_cleanup() 176 static void audmad_cleanup()
162 { 177 {
163 } 178 }
164 179
165 static gboolean mp3_head_check(guint32 head) 180 static gboolean mp3_head_check(guint32 head, gint *frameSize)
166 { 181 {
167 /* 182 gint version, layer, bitIndex, bitRate, sampleIndex, sampleRate, padding;
168 * First two bytes must be a sync header (11 bits all 1) 183
169 * http://www.mp3-tech.org/programmer/frame_header.html 184 /* http://www.mp3-tech.org/programmer/frame_header.html
185 * Bits 21-31 must be set (frame sync)
170 */ 186 */
171 if ((head & 0xffe00000) != 0xffe00000) 187 if ((head & 0xffe00000) != 0xffe00000)
172 return FALSE; 188 return FALSE;
173 189
174 /* check if bits 18 and 19 are set */ 190 /* check if layer bits (17-18) are good */
175 if (!((head >> 17) & 3)) 191 layer = (head >> 17) & 0x3;
192 if (!layer)
193 return FALSE; /* 00 = reserved */
194 layer = 3 - layer;
195
196 /* check if bitrate index bits (12-15) are acceptable */
197 bitIndex = (head >> 12) & 0xf;
198
199 /* 1111 and 0000 are reserved values for all layers */
200 if (bitIndex == 0xf || bitIndex == 0)
176 return FALSE; 201 return FALSE;
177 202
178 /* check if bits 13 - 16 are all set */ 203 /* check samplerate index bits (10-11) */
179 if (((head >> 12) & 0xf) == 0xf) 204 sampleIndex = (head >> 10) & 0x3;
205 if (sampleIndex == 0x3)
180 return FALSE; 206 return FALSE;
181 207
182 /* check if bits 13 - 16 are all not set */ 208 /* check version bits (19-20) and get bitRate */
183 if (!((head >> 12) & 0xf)) 209 version = (head >> 19) & 0x03;
184 return FALSE; 210 switch (version) {
185 211 case 0: /* 00 = MPEG Version 2.5 */
186 /* check if bit 11 and 12 are both set */ 212 case 2: /* 10 = MPEG Version 2 */
187 if (((head >> 10) & 0x3) == 0x3) 213 if (layer == 1)
188 return FALSE; 214 bitRate = mp3_bitrate_table[3][bitIndex];
189 215 else
190 /* check if bits 17 - 20 are all set */ 216 bitRate = mp3_bitrate_table[4][bitIndex];
217 break;
218
219 case 1: /* 01 = reserved */
220 return FALSE;
221
222 case 3: /* 11 = MPEG Version 1 */
223 bitRate = mp3_bitrate_table[layer][bitIndex];
224 break;
225
226 default:
227 return FALSE;
228 }
229
230 /* check layer II restrictions vs. bitrate */
231 if (layer == 2) {
232 gint chanMode = (head >> 6) & 0x3;
233
234 if (chanMode == 0x3) {
235 /* single channel with bitrate > 192 */
236 if (bitRate > 192)
237 return FALSE;
238 } else {
239 /* any other mode with bitrates 32-56 and 80 */
240 if (((bitRate >= 32 && bitRate <= 56) || bitRate == 80))
241 return FALSE;
242 }
243 }
244
245 /* calculate approx. frame size */
246 padding = (head >> 9) & 1;
247 sampleRate = mp3_samplerate_table[version][sampleIndex];
248 *frameSize = (144 * bitRate * 1000) / (sampleRate + padding);
249
250 /* check if bits 16 - 19 are all set (MPEG 1 Layer I, not protected?) */
191 if (((head >> 19) & 1) == 1 && 251 if (((head >> 19) & 1) == 1 &&
192 ((head >> 17) & 3) == 3 && ((head >> 16) & 1) == 1) 252 ((head >> 17) & 3) == 3 && ((head >> 16) & 1) == 1)
193 return FALSE; 253 return FALSE;
194 254
195 /* not sure why we check this, but ok! */ 255 /* not sure why we check this, but ok! */
217 // audacious vfs fast version 277 // audacious vfs fast version
218 static int audmad_is_our_fd(char *filename, VFSFile *fin) 278 static int audmad_is_our_fd(char *filename, VFSFile *fin)
219 { 279 {
220 guint32 check; 280 guint32 check;
221 gchar *ext = extname(filename); 281 gchar *ext = extname(filename);
222 gint cyc = 0; 282 gint cyc = 0, chkcount = 0, chksize = 4096;
223 guchar buf[4]; 283 guchar buf[4];
224 guchar tmp[4096]; 284 guchar tmp[4096];
225 gint ret, i; 285 gint ret, i, frameSize;
226 286
227 info.remote = FALSE; 287 info.remote = FALSE;
228 288
229 if(audmad_is_remote(filename)) 289 if(audmad_is_remote(filename))
230 info.remote = TRUE; 290 info.remote = TRUE;
245 305
246 if(vfs_fread(buf, 1, 4, fin) == 0) { 306 if(vfs_fread(buf, 1, 4, fin) == 0) {
247 gchar *tmp = g_filename_to_utf8(filename, -1, NULL, NULL, NULL); 307 gchar *tmp = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
248 g_message("vfs_fread failed @1 %s", tmp); 308 g_message("vfs_fread failed @1 %s", tmp);
249 g_free(tmp); 309 g_free(tmp);
310 return 0;
250 } 311 }
251 312
252 check = mp3_head_convert(buf); 313 check = mp3_head_convert(buf);
253 314
254 if (memcmp(buf, "ID3", 3) == 0) 315 if (memcmp(buf, "ID3", 3) == 0)
260 vfs_fseek(fin, 4, SEEK_CUR); 321 vfs_fseek(fin, 4, SEEK_CUR);
261 if(vfs_fread(buf, 1, 4, fin) == 0) { 322 if(vfs_fread(buf, 1, 4, fin) == 0) {
262 gchar *tmp = g_filename_to_utf8(filename, -1, NULL, NULL, NULL); 323 gchar *tmp = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
263 g_message("vfs_fread failed @2 %s", tmp); 324 g_message("vfs_fread failed @2 %s", tmp);
264 g_free(tmp); 325 g_free(tmp);
326 return 0;
265 } 327 }
266 328
267 if (memcmp(buf, "RMP3", 4) == 0) 329 if (memcmp(buf, "RMP3", 4) == 0)
268 return 1; 330 return 1;
269 } 331 }
270 332
271 while (!mp3_head_check(check)) 333 // check data for frame header
334 while (!mp3_head_check(check, &frameSize))
272 { 335 {
273 if((ret = vfs_fread(tmp, 1, 4096, fin)) == 0){ 336 if((ret = vfs_fread(tmp, 1, chksize, fin)) == 0){
274 gchar *tmp = g_filename_to_utf8(filename, -1, NULL, NULL, NULL); 337 gchar *tmp = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
275 g_message("vfs_fread failed @3 %s", tmp); 338 g_message("vfs_fread failed @3 %s", tmp);
276 g_free(tmp); 339 g_free(tmp);
340 return 0;
277 } 341 }
278 for (i = 0; i < ret; i++) 342 for (i = 0; i < ret; i++)
279 { 343 {
280 check <<= 8; 344 check <<= 8;
281 check |= tmp[i]; 345 check |= tmp[i];
282 346
283 if (mp3_head_check(check)) 347 if (mp3_head_check(check, &frameSize)) {
284 return 1; 348 /* when the first matching frame header is found, we check for
349 * another frame by seeking to the approximate start of the
350 * next header ... also reduce the check size.
351 */
352 if (++chkcount >= 3) return 1;
353 vfs_fseek(fin, frameSize-4, SEEK_CUR);
354 check = 0;
355 chksize = 8;
356 }
285 } 357 }
286 358
287 if (++cyc > 1024) 359 if (++cyc > 32)
288 return 0; 360 return 0;
289 } 361 }
290 362
291 return 1; 363 return 1;
292 } 364 }