mp3_libavcodec.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /*
  2. * Some mp3 related code for Sega/Mega CD.
  3. * Uses Libav/FFmpeg libavcodec
  4. * (C) notaz, 2013
  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 <libavcodec/avcodec.h>
  12. #include <dlfcn.h>
  13. #include <pico/pico_int.h>
  14. #include "../libpicofe/lprintf.h"
  15. #include "mp3.h"
  16. static AVCodecContext *ctx;
  17. /* avoid compile time linking to libavcodec due to huge list of it's deps..
  18. * we also use this old API as newer one is not available on pandora */
  19. void (*p_av_init_packet)(AVPacket *pkt);
  20. int (*p_avcodec_decode_audio3)(AVCodecContext *avctx, int16_t *samples,
  21. int *frame_size_ptr, AVPacket *avpkt);
  22. int mp3dec_decode(FILE *f, int *file_pos, int file_len)
  23. {
  24. unsigned char input_buf[2 * 1024];
  25. int frame_size;
  26. AVPacket avpkt;
  27. int bytes_in;
  28. int bytes_out;
  29. int offset;
  30. int len;
  31. p_av_init_packet(&avpkt);
  32. do
  33. {
  34. if (*file_pos >= file_len)
  35. return 1; // EOF, nothing to do
  36. fseek(f, *file_pos, SEEK_SET);
  37. bytes_in = fread(input_buf, 1, sizeof(input_buf), f);
  38. offset = mp3_find_sync_word(input_buf, bytes_in);
  39. if (offset < 0) {
  40. lprintf("find_sync_word (%i/%i) err %i\n",
  41. *file_pos, file_len, offset);
  42. *file_pos = file_len;
  43. return 1; // EOF
  44. }
  45. // to avoid being flooded with "incorrect frame size" errors,
  46. // we must calculate and pass exact frame size - lame
  47. frame_size = mpeg1_l3_bitrates[input_buf[offset + 2] >> 4];
  48. frame_size = frame_size * 144000 / 44100;
  49. frame_size += (input_buf[offset + 2] >> 1) & 1;
  50. if (offset > 0 && bytes_in - offset < frame_size) {
  51. // underflow
  52. *file_pos += offset;
  53. continue;
  54. }
  55. avpkt.data = input_buf + offset;
  56. avpkt.size = frame_size;
  57. bytes_out = sizeof(cdda_out_buffer);
  58. #if LIBAVCODEC_VERSION_MAJOR < 53
  59. // stupidity in v52: enforces this size even when
  60. // it doesn't need/use that much at all
  61. bytes_out = AVCODEC_MAX_AUDIO_FRAME_SIZE;
  62. #endif
  63. len = p_avcodec_decode_audio3(ctx, cdda_out_buffer,
  64. &bytes_out, &avpkt);
  65. if (len <= 0) {
  66. lprintf("mp3 decode err (%i/%i) %i\n",
  67. *file_pos, file_len, len);
  68. // attempt to skip the offending frame..
  69. *file_pos += offset + 1;
  70. continue;
  71. }
  72. *file_pos += offset + len;
  73. }
  74. while (0);
  75. return 0;
  76. }
  77. int mp3dec_start(FILE *f, int fpos_start)
  78. {
  79. void (*avcodec_register_all)(void);
  80. AVCodec *(*avcodec_find_decoder)(enum CodecID id);
  81. AVCodecContext *(*avcodec_alloc_context)(void);
  82. int (*avcodec_open)(AVCodecContext *avctx, AVCodec *codec);
  83. void (*av_free)(void *ptr);
  84. AVCodec *codec;
  85. void *soh;
  86. int ret;
  87. if (ctx != NULL)
  88. return 0;
  89. // either v52 or v53 should be ok
  90. soh = dlopen("libavcodec.so.52", RTLD_NOW);
  91. if (soh == NULL)
  92. soh = dlopen("libavcodec.so.53", RTLD_NOW);
  93. if (soh == NULL) {
  94. lprintf("mp3dec: load libavcodec.so: %s\n", dlerror());
  95. return -1;
  96. }
  97. avcodec_register_all = dlsym(soh, "avcodec_register_all");
  98. avcodec_find_decoder = dlsym(soh, "avcodec_find_decoder");
  99. avcodec_alloc_context = dlsym(soh, "avcodec_alloc_context");
  100. avcodec_open = dlsym(soh, "avcodec_open");
  101. av_free = dlsym(soh, "av_free");
  102. p_av_init_packet = dlsym(soh, "av_init_packet");
  103. p_avcodec_decode_audio3 = dlsym(soh, "avcodec_decode_audio3");
  104. if (avcodec_register_all == NULL || avcodec_find_decoder == NULL
  105. || avcodec_alloc_context == NULL || avcodec_open == NULL
  106. || av_free == NULL
  107. || p_av_init_packet == NULL || p_avcodec_decode_audio3 == NULL)
  108. {
  109. lprintf("mp3dec: missing symbol(s) in libavcodec.so\n");
  110. dlclose(soh);
  111. return -1;
  112. }
  113. // init decoder
  114. //avcodec_init();
  115. avcodec_register_all();
  116. // AV_CODEC_ID_MP3 ?
  117. codec = avcodec_find_decoder(CODEC_ID_MP3);
  118. if (codec == NULL) {
  119. lprintf("mp3dec: codec missing\n");
  120. return -1;
  121. }
  122. ctx = avcodec_alloc_context();
  123. if (ctx == NULL) {
  124. lprintf("mp3dec: avcodec_alloc_context failed\n");
  125. return -1;
  126. }
  127. ret = avcodec_open(ctx, codec);
  128. if (ret < 0) {
  129. lprintf("mp3dec: avcodec_open failed: %d\n", ret);
  130. av_free(ctx);
  131. ctx = NULL;
  132. return -1;
  133. }
  134. return 0;
  135. }