Mercurial > audlegacy-plugins
comparison src/madplug/plugin.c @ 2939:3877a02782bb
Adjust probing again.
| author | Matti Hamalainen <ccr@tnsp.org> |
|---|---|
| date | Mon, 22 Sep 2008 06:39:32 +0300 |
| parents | f1b6f1b2cdb3 |
| children | 0910d4d2714d |
comparison
equal
deleted
inserted
replaced
| 2938:597857a52f7c | 2939:3877a02782bb |
|---|---|
| 265 } | 265 } |
| 266 | 266 |
| 267 return 0; | 267 return 0; |
| 268 } | 268 } |
| 269 | 269 |
| 270 static int | 270 static guint32 |
| 271 mp3_head_convert(const guchar * hbuf) | 271 mp3_head_convert(const guchar * hbuf) |
| 272 { | 272 { |
| 273 return | 273 return |
| 274 ((guint32) hbuf[0] << 24) | | 274 ((guint32) hbuf[0] << 24) | |
| 275 ((guint32) hbuf[1] << 16) | | 275 ((guint32) hbuf[1] << 16) | |
| 276 ((guint32) hbuf[2] << 8) | | 276 ((guint32) hbuf[2] << 8) | |
| 277 ((guint32) hbuf[3]); | 277 ((guint32) hbuf[3]); |
| 278 } | 278 } |
| 279 | 279 |
| 280 #undef MADPROBE_DEBUG | 280 #undef MADPROBE_DEBUG |
| 281 //#define MADPROBE_DEBUG | |
| 281 | 282 |
| 282 #ifdef MADPROBE_DEBUG | 283 #ifdef MADPROBE_DEBUG |
| 283 static gchar *mp3_ver_table[4] = { "2.5", "INVALID", "2", "1" }; | 284 static gchar *mp3_ver_table[4] = { "2.5", "INVALID", "2", "1" }; |
| 284 #define LULZ(...) do { fprintf(stderr, "madprobe: "); fprintf(stderr, __VA_ARGS__); } while (0) | 285 #define LULZ(...) do { fprintf(stderr, "madprobe: "); fprintf(stderr, __VA_ARGS__); } while (0) |
| 285 #define LOL(...) do { fprintf(stderr, __VA_ARGS__); } while (0) | 286 #define LOL(...) do { fprintf(stderr, __VA_ARGS__); } while (0) |
| 287 #define LULZ(...) do { } while(0) | 288 #define LULZ(...) do { } while(0) |
| 288 #define LOL(...) do { } while(0) | 289 #define LOL(...) do { } while(0) |
| 289 #endif | 290 #endif |
| 290 | 291 |
| 291 // audacious vfs fast version | 292 // audacious vfs fast version |
| 292 static int | 293 static gint |
| 293 audmad_is_our_fd(gchar *filename, VFSFile *fin) | 294 audmad_is_our_fd(gchar *filename, VFSFile *fin) |
| 294 { | 295 { |
| 295 gchar *ext = extname(filename); | 296 gchar *ext = extname(filename); |
| 297 const gint max_resync_bytes = 32, max_resync_tries = 8; | |
| 296 guint32 head = 0; | 298 guint32 head = 0; |
| 297 guchar chkbuf[2048]; | 299 guchar chkbuf[1024]; |
| 298 gint state, | 300 gint state, |
| 299 next = -1, | 301 next = -1, |
| 300 tries = 0, | 302 tries = 0, |
| 301 chksize = 0, | 303 chksize = 0, |
| 302 chkpos = 0, | 304 chkpos = 0, |
| 333 return 0; | 335 return 0; |
| 334 } | 336 } |
| 335 | 337 |
| 336 state = STATE_REBUFFER; | 338 state = STATE_REBUFFER; |
| 337 next = STATE_HEADERS; | 339 next = STATE_HEADERS; |
| 338 | 340 |
| 339 /* Check stream data for frame header(s). We employ a simple | 341 /* Check stream data for frame header(s). We employ a simple |
| 340 * state-machine approach here to find number of sequential | 342 * state-machine approach here to find number of sequential |
| 341 * valid MPEG frame headers (with similar attributes). | 343 * valid MPEG frame headers (with similar attributes). |
| 342 */ | 344 */ |
| 343 do { | 345 do { |
| 344 switch (state) { | 346 switch (state) { |
| 345 case STATE_HEADERS: | 347 case STATE_HEADERS: |
| 346 LULZ("check headers\n"); | 348 LULZ("check headers (size=%d, pos=%d)\n", chksize, chkpos); |
| 347 /* Check read size */ | 349 /* Check read size */ |
| 348 if (chksize < 32) { | 350 if (chksize - chkpos < 16) { |
| 349 LULZ("headers check failed, not enough data!\n"); | 351 LULZ("headers check failed, not enough data!\n"); |
| 350 state = STATE_FATAL; | 352 state = STATE_FATAL; |
| 351 } else { | 353 } else { |
| 352 state = STATE_GET_NEXT; | 354 state = STATE_GET_NEXT; |
| 353 | 355 |
| 356 guint tagsize = (chkbuf[chkpos+6] & 0x7f); tagsize <<= 7; | 358 guint tagsize = (chkbuf[chkpos+6] & 0x7f); tagsize <<= 7; |
| 357 tagsize |= (chkbuf[chkpos+7] & 0x7f); tagsize <<= 7; | 359 tagsize |= (chkbuf[chkpos+7] & 0x7f); tagsize <<= 7; |
| 358 tagsize |= (chkbuf[chkpos+8] & 0x7f); tagsize <<= 7; | 360 tagsize |= (chkbuf[chkpos+8] & 0x7f); tagsize <<= 7; |
| 359 tagsize |= (chkbuf[chkpos+9] & 0x7f); | 361 tagsize |= (chkbuf[chkpos+9] & 0x7f); |
| 360 | 362 |
| 361 LULZ("ID3 size = %08x\n", tagsize); | 363 LULZ("ID3 size = %d\n", tagsize); |
| 362 state = STATE_GOTO_NEXT; | 364 state = STATE_GOTO_NEXT; |
| 363 skip = tagsize + 10; | 365 skip = tagsize + 10; |
| 364 } else | 366 } else |
| 365 if (memcmp(&chkbuf[chkpos], "OggS", 4) == 0) | 367 if (memcmp(&chkbuf[chkpos], "OggS", 4) == 0) |
| 366 return 0; | 368 return 0; |
| 371 } | 373 } |
| 372 break; | 374 break; |
| 373 | 375 |
| 374 case STATE_REBUFFER: | 376 case STATE_REBUFFER: |
| 375 streampos = aud_vfs_ftell(fin); | 377 streampos = aud_vfs_ftell(fin); |
| 376 if ((chksize = aud_vfs_fread(chkbuf, 1, sizeof(chkbuf), fin)) == 0) | 378 if ((chksize = aud_vfs_fread(chkbuf, 1, sizeof(chkbuf), fin)) == 0) { |
| 377 state = STATE_FATAL; | 379 state = STATE_FATAL; |
| 378 else { | 380 LULZ("fatal error rebuffering @ %08lx!\n", streampos); |
| 381 } else { | |
| 379 chkpos = 0; | 382 chkpos = 0; |
| 380 state = next; | 383 state = next; |
| 384 LULZ("rebuffered = %d bytes @ %08lx\n", chksize, streampos); | |
| 381 } | 385 } |
| 382 LULZ("rebuffered = %d bytes\n", chksize); | |
| 383 break; | 386 break; |
| 384 | 387 |
| 385 case STATE_VALIDATE: | 388 case STATE_VALIDATE: |
| 386 LULZ("validate %08x .. ", head); | 389 LULZ("validate %08x .. ", head); |
| 387 /* Check for valid header */ | 390 /* Check for valid header */ |
| 413 } else { | 416 } else { |
| 414 /* Nope, try (re)synchronizing */ | 417 /* Nope, try (re)synchronizing */ |
| 415 if (chkcount > 1) { | 418 if (chkcount > 1) { |
| 416 LOL("no (%d), trying quick resync ..\n", res); | 419 LOL("no (%d), trying quick resync ..\n", res); |
| 417 state = STATE_RESYNC_DO; | 420 state = STATE_RESYNC_DO; |
| 418 resync_max = 32; | 421 resync_max = max_resync_bytes; |
| 419 } else { | 422 } else { |
| 420 LOL("no (%d)\n", res); | 423 LOL("no (%d)\n", res); |
| 421 state = STATE_RESYNC; | 424 state = STATE_RESYNC; |
| 422 } | 425 } |
| 423 } | 426 } |
| 424 break; | 427 break; |
| 425 | 428 |
| 426 case STATE_GOTO_NEXT: | 429 case STATE_GOTO_NEXT: |
| 427 LULZ("goto next (%x :: %x < %x) ? ", chkpos, skip, chksize); | 430 LULZ("goto next (cpos=%x, csiz=%d :: skip=%d :: fpos=%lx) ? ", chkpos, chksize, skip, aud_vfs_ftell(fin)); |
| 428 /* Check if we have the next possible header in buffer? */ | 431 /* Check if we have the next possible header in buffer? */ |
| 429 gint tmppos = chkpos + skip + sizeof(guint32); | 432 gint tmppos = chkpos + skip + 16; |
| 430 if (tmppos < chksize) { | 433 if (tmppos < chksize) { |
| 431 LOL("[in buffer]\n"); | 434 LOL("[in buffer]\n"); |
| 432 chkpos += skip; | 435 chkpos += skip; |
| 433 state = STATE_GET_NEXT; | 436 state = STATE_GET_NEXT; |
| 434 } else { | 437 } else { |
| 435 /* No, re-fill buffer and try again .. */ | 438 /* No, re-fill buffer and try again .. */ |
| 436 LOL("[rebuffering: %x, %x]\n", skip, chkpos + skip - chksize); | 439 glong tmppos = skip - (chksize - chkpos); |
| 437 aud_vfs_fseek(fin, chkpos + skip - chksize, SEEK_CUR); | 440 gint tmpres = aud_vfs_fseek(fin, tmppos, SEEK_CUR); |
| 441 LOL("[skipping: %ld -> %d]\n", tmppos, tmpres); | |
| 438 next = STATE_GET_NEXT; | 442 next = STATE_GET_NEXT; |
| 439 state = STATE_REBUFFER; | 443 state = STATE_REBUFFER; |
| 440 } | 444 } |
| 441 break; | 445 break; |
| 442 | 446 |
| 443 case STATE_GET_NEXT: | 447 case STATE_GET_NEXT: |
| 444 /* Get a header */ | 448 /* Get a header */ |
| 445 LULZ("get next @ bufpos=%08x, streampos=%08lx, realpos=%08lx\n", chkpos, streampos, streampos+chkpos); | 449 LULZ("get next @ chkpos=%08x, realpos=%08lx\n", chkpos, streampos+chkpos); |
| 446 head = mp3_head_convert(&chkbuf[chkpos]); | 450 head = mp3_head_convert(&chkbuf[chkpos]); |
| 447 //chkpos += sizeof(guint32); | |
| 448 state = STATE_VALIDATE; | 451 state = STATE_VALIDATE; |
| 449 break; | 452 break; |
| 450 | 453 |
| 451 case STATE_RESYNC: | 454 case STATE_RESYNC: |
| 452 LULZ("resyncing try #%d ..\n", tries); | 455 LULZ("resyncing try #%d ..\n", tries); |
| 465 head |= chkbuf[chkpos]; | 468 head |= chkbuf[chkpos]; |
| 466 | 469 |
| 467 if (mp3_head_validate(head, &frame) >= 0) { | 470 if (mp3_head_validate(head, &frame) >= 0) { |
| 468 /* Found, exit resync */ | 471 /* Found, exit resync */ |
| 469 chkpos -= 3; | 472 chkpos -= 3; |
| 470 LULZ("resync found @ %x\n", chkpos); | 473 LULZ("resync found @ %x (%lx)\n", chkpos, streampos + chkpos); |
| 471 state = STATE_VALIDATE; | 474 state = STATE_VALIDATE; |
| 472 break; | 475 break; |
| 473 } | 476 } |
| 474 | 477 |
| 475 /* Check for maximum bytes to search */ | 478 /* Check for maximum bytes to search */ |
| 486 next = state; | 489 next = state; |
| 487 state = STATE_REBUFFER; | 490 state = STATE_REBUFFER; |
| 488 } | 491 } |
| 489 break; | 492 break; |
| 490 } | 493 } |
| 491 } while (state != STATE_FATAL && tries < 16); | 494 } while (state != STATE_FATAL && tries < max_resync_tries); |
| 492 /* Give up after 16 failed resync attempts or fatal errors */ | 495 /* Give up after given number of failed resync attempts or fatal error */ |
| 493 | 496 |
| 494 g_message("Rejecting %s (not an MP3 file?)", filename); | 497 g_message("Rejecting %s (not an MP3 file?)", filename); |
| 495 return 0; | 498 return 0; |
| 496 } | 499 } |
| 497 | 500 |
