Mercurial > audlegacy-plugins
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 } |
