mp3_helix.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. * Some mp3 related code for Sega/Mega CD.
  3. * Uses the Helix Fixed-point MP3 decoder
  4. * (C) notaz, 2007-2009
  5. *
  6. * This work is licensed under the terms of MAME license.
  7. * See COPYING file in the top-level directory.
  8. */
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <dlfcn.h>
  12. #include <pico/pico_int.h>
  13. #include "helix/pub/mp3dec.h"
  14. #include "mp3.h"
  15. static HMP3Decoder mp3dec;
  16. static unsigned char mp3_input_buffer[2 * 1024];
  17. #ifdef __GP2X__
  18. #define mp3dec_decode _mp3dec_decode
  19. #define mp3dec_start _mp3dec_start
  20. #endif
  21. static void *libhelix;
  22. HMP3Decoder (*p_MP3InitDecoder)(void);
  23. void (*p_MP3FreeDecoder)(HMP3Decoder);
  24. int (*p_MP3Decode)(HMP3Decoder, unsigned char **, int *, short *, int);
  25. int mp3dec_decode(FILE *f, int *file_pos, int file_len)
  26. {
  27. unsigned char *readPtr;
  28. int bytesLeft;
  29. int offset; // mp3 frame offset from readPtr
  30. int had_err;
  31. int err = 0;
  32. int retry = 3;
  33. do
  34. {
  35. if (*file_pos >= file_len)
  36. return 1; /* EOF, nothing to do */
  37. fseek(f, *file_pos, SEEK_SET);
  38. bytesLeft = fread(mp3_input_buffer, 1, sizeof(mp3_input_buffer), f);
  39. offset = mp3_find_sync_word(mp3_input_buffer, bytesLeft);
  40. if (offset < 0) {
  41. lprintf("find_sync_word (%i/%i) err %i\n",
  42. *file_pos, file_len, offset);
  43. *file_pos = file_len;
  44. return 1; // EOF
  45. }
  46. readPtr = mp3_input_buffer + offset;
  47. bytesLeft -= offset;
  48. had_err = err;
  49. err = p_MP3Decode(mp3dec, &readPtr, &bytesLeft, cdda_out_buffer, 0);
  50. if (err) {
  51. if (err == ERR_MP3_MAINDATA_UNDERFLOW && !had_err) {
  52. // just need another frame
  53. *file_pos += readPtr - mp3_input_buffer;
  54. continue;
  55. }
  56. if (err == ERR_MP3_INDATA_UNDERFLOW && !had_err) {
  57. if (offset == 0)
  58. // something's really wrong here, frame had to fit
  59. *file_pos = file_len;
  60. else
  61. *file_pos += offset;
  62. continue;
  63. }
  64. if (-12 <= err && err <= -6) {
  65. // ERR_MP3_INVALID_FRAMEHEADER, ERR_MP3_INVALID_*
  66. // just try to skip the offending frame..
  67. *file_pos += offset + 1;
  68. continue;
  69. }
  70. lprintf("MP3Decode err (%i/%i) %i\n",
  71. *file_pos, file_len, err);
  72. *file_pos = file_len;
  73. return 1;
  74. }
  75. *file_pos += readPtr - mp3_input_buffer;
  76. }
  77. while (err && --retry > 0);
  78. return !!err;
  79. }
  80. int mp3dec_start(FILE *f, int fpos_start)
  81. {
  82. if (libhelix == NULL) {
  83. libhelix = dlopen("./libhelix.so", RTLD_NOW);
  84. if (libhelix == NULL) {
  85. lprintf("mp3dec: load libhelix.so: %s\n", dlerror());
  86. return -1;
  87. }
  88. p_MP3InitDecoder = dlsym(libhelix, "MP3InitDecoder");
  89. p_MP3FreeDecoder = dlsym(libhelix, "MP3FreeDecoder");
  90. p_MP3Decode = dlsym(libhelix, "MP3Decode");
  91. if (p_MP3InitDecoder == NULL || p_MP3FreeDecoder == NULL
  92. || p_MP3Decode == NULL)
  93. {
  94. lprintf("mp3dec: missing symbol(s) in libhelix.so\n");
  95. dlclose(libhelix);
  96. libhelix = NULL;
  97. return -1;
  98. }
  99. }
  100. // must re-init decoder for new track
  101. if (mp3dec)
  102. p_MP3FreeDecoder(mp3dec);
  103. mp3dec = p_MP3InitDecoder();
  104. return (mp3dec == 0) ? -1 : 0;
  105. }