From faedc4f1e263069994e2f4c1bf2cdb8a26fa13ec Mon Sep 17 00:00:00 2001 From: kub Date: Sat, 12 Dec 2020 14:30:50 +0100 Subject: [PATCH] mcd, add minimp3 playback support, fix libavcodec playback --- .gitmodules | 3 ++ Makefile | 3 +- platform/common/minimp3 | 1 + platform/common/mp3_helix.c | 7 ++- platform/common/mp3_libavcodec.c | 84 +++++++++++++++++++++++--------- platform/common/mp3_minimp3.c | 65 ++++++++++++++++++++++++ 6 files changed, 133 insertions(+), 30 deletions(-) create mode 160000 platform/common/minimp3 create mode 100644 platform/common/mp3_minimp3.c diff --git a/.gitmodules b/.gitmodules index b778188f..6d6f9193 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "pico/sound/emu2413"] path = pico/sound/emu2413 url = https://github.com/digital-sound-antiques/emu2413.git +[submodule "platform/common/minimp3"] + path = platform/common/minimp3 + url = https://github.com/lieff/minimp3 diff --git a/Makefile b/Makefile index 369de2f3..1a36870e 100644 --- a/Makefile +++ b/Makefile @@ -205,12 +205,11 @@ endif # USE_FRONTEND OBJS += platform/common/mp3.o platform/common/mp3_sync.o ifeq "$(PLATFORM_MP3)" "1" -platform/common/mp3_helix.o: CFLAGS += -Iplatform/libpicofe OBJS += platform/common/mp3_helix.o else ifeq "$(HAVE_LIBAVCODEC)" "1" OBJS += platform/common/mp3_libavcodec.o else -OBJS += platform/common/mp3_dummy.o +OBJS += platform/common/mp3_minimp3.o endif ifeq "$(PLATFORM_ZLIB)" "1" diff --git a/platform/common/minimp3 b/platform/common/minimp3 new file mode 160000 index 00000000..95864e8e --- /dev/null +++ b/platform/common/minimp3 @@ -0,0 +1 @@ +Subproject commit 95864e8e0d3b34402a49ae9af6c66f7e98c13c35 diff --git a/platform/common/mp3_helix.c b/platform/common/mp3_helix.c index 75be8df3..0e53bf8f 100644 --- a/platform/common/mp3_helix.c +++ b/platform/common/mp3_helix.c @@ -12,10 +12,8 @@ #include #include -#include #include "helix/pub/mp3dec.h" #include "mp3.h" -#include "lprintf.h" static HMP3Decoder mp3dec; static unsigned char mp3_input_buffer[2 * 1024]; @@ -37,6 +35,7 @@ int mp3dec_decode(FILE *f, int *file_pos, int file_len) int offset; // mp3 frame offset from readPtr int had_err; int err = 0; + int retry = 3; do { @@ -85,9 +84,9 @@ int mp3dec_decode(FILE *f, int *file_pos, int file_len) } *file_pos += readPtr - mp3_input_buffer; } - while (0); + while (err && --retry > 0); - return 0; + return !!err; } int mp3dec_start(FILE *f, int fpos_start) diff --git a/platform/common/mp3_libavcodec.c b/platform/common/mp3_libavcodec.c index 9a528c1e..6ed0fcd5 100644 --- a/platform/common/mp3_libavcodec.c +++ b/platform/common/mp3_libavcodec.c @@ -13,14 +13,17 @@ #include #include -#include "../libpicofe/lprintf.h" #include "mp3.h" #if LIBAVCODEC_VERSION_MAJOR < 55 #define AVCodecID CodecID #define AV_CODEC_ID_MP3 CODEC_ID_MP3 +#define AV_CH_LAYOUT_STEREO CH_LAYOUT_STEREO +#define AV_SAMPLE_FMT_S16 SAMPLE_FMT_S16 +#define request_sample_fmt sample_fmt #endif +static void *libavcodec; static AVCodecContext *ctx; /* avoid compile time linking to libavcodec due to huge list of it's deps.. @@ -37,7 +40,8 @@ int mp3dec_decode(FILE *f, int *file_pos, int file_len) int bytes_in; int bytes_out; int offset; - int len; + int len = -1; + int retry = 3; p_av_init_packet(&avpkt); @@ -56,6 +60,7 @@ int mp3dec_decode(FILE *f, int *file_pos, int file_len) *file_pos = file_len; return 1; // EOF } + *file_pos += offset; // to avoid being flooded with "incorrect frame size" errors, // we must calculate and pass exact frame size - lame @@ -65,7 +70,6 @@ int mp3dec_decode(FILE *f, int *file_pos, int file_len) if (offset > 0 && bytes_in - offset < frame_size) { // underflow - *file_pos += offset; continue; } @@ -85,47 +89,60 @@ int mp3dec_decode(FILE *f, int *file_pos, int file_len) *file_pos, file_len, len); // attempt to skip the offending frame.. - *file_pos += offset + 1; - continue; - } - - *file_pos += offset + len; + *file_pos += 1; + } else + *file_pos += len; } - while (0); + while (len <= 0 && --retry > 0); - return 0; + return len <= 0; } int mp3dec_start(FILE *f, int fpos_start) { void (*avcodec_register_all)(void); AVCodec *(*avcodec_find_decoder)(enum AVCodecID id); +#if LIBAVCODEC_VERSION_MAJOR < 54 AVCodecContext *(*avcodec_alloc_context)(void); int (*avcodec_open)(AVCodecContext *avctx, AVCodec *codec); +#else + AVCodecContext *(*avcodec_alloc_context)(AVCodec *); + int (*avcodec_open)(AVCodecContext *avctx, AVCodec *codec, AVDictionary **); +#endif void (*av_free)(void *ptr); AVCodec *codec; - void *soh; int ret; if (ctx != NULL) return 0; +#if LIBAVCODEC_VERSION_MAJOR < 54 // either v52 or v53 should be ok - soh = dlopen("libavcodec.so.52", RTLD_NOW); - if (soh == NULL) - soh = dlopen("libavcodec.so.53", RTLD_NOW); - if (soh == NULL) { + if (libavcodec == NULL) + libavcodec = dlopen("libavcodec.so.52", RTLD_NOW); + if (libavcodec == NULL) + libavcodec = dlopen("libavcodec.so.53", RTLD_NOW); +#else + if (libavcodec == NULL) + libavcodec = dlopen("libavcodec.so", RTLD_NOW); +#endif + if (libavcodec == NULL) { lprintf("mp3dec: load libavcodec.so: %s\n", dlerror()); return -1; } - avcodec_register_all = dlsym(soh, "avcodec_register_all"); - avcodec_find_decoder = dlsym(soh, "avcodec_find_decoder"); - avcodec_alloc_context = dlsym(soh, "avcodec_alloc_context"); - avcodec_open = dlsym(soh, "avcodec_open"); - av_free = dlsym(soh, "av_free"); - p_av_init_packet = dlsym(soh, "av_init_packet"); - p_avcodec_decode_audio3 = dlsym(soh, "avcodec_decode_audio3"); + avcodec_register_all = dlsym(libavcodec, "avcodec_register_all"); + avcodec_find_decoder = dlsym(libavcodec, "avcodec_find_decoder"); +#if LIBAVCODEC_VERSION_MAJOR < 54 + avcodec_alloc_context = dlsym(libavcodec, "avcodec_alloc_context"); + avcodec_open = dlsym(libavcodec, "avcodec_open"); +#else + avcodec_alloc_context = dlsym(libavcodec, "avcodec_alloc_context3"); + avcodec_open = dlsym(libavcodec, "avcodec_open2"); +#endif + av_free = dlsym(libavcodec, "av_free"); + p_av_init_packet = dlsym(libavcodec, "av_init_packet"); + p_avcodec_decode_audio3 = dlsym(libavcodec, "avcodec_decode_audio3"); if (avcodec_register_all == NULL || avcodec_find_decoder == NULL || avcodec_alloc_context == NULL || avcodec_open == NULL @@ -133,7 +150,6 @@ int mp3dec_start(FILE *f, int fpos_start) || p_av_init_packet == NULL || p_avcodec_decode_audio3 == NULL) { lprintf("mp3dec: missing symbol(s) in libavcodec.so\n"); - dlclose(soh); return -1; } @@ -148,12 +164,24 @@ int mp3dec_start(FILE *f, int fpos_start) return -1; } +#if LIBAVCODEC_VERSION_MAJOR < 54 ctx = avcodec_alloc_context(); if (ctx == NULL) { lprintf("mp3dec: avcodec_alloc_context failed\n"); return -1; } +#else + ctx = avcodec_alloc_context(codec); + if (ctx == NULL) { + lprintf("mp3dec: avcodec_alloc_context failed\n"); + return -1; + } +#endif + ctx->request_channel_layout = AV_CH_LAYOUT_STEREO; + ctx->request_sample_fmt = AV_SAMPLE_FMT_S16; + ctx->sample_rate = 44100; +#if LIBAVCODEC_VERSION_MAJOR < 54 ret = avcodec_open(ctx, codec); if (ret < 0) { lprintf("mp3dec: avcodec_open failed: %d\n", ret); @@ -161,6 +189,14 @@ int mp3dec_start(FILE *f, int fpos_start) ctx = NULL; return -1; } - +#else + ret = avcodec_open(ctx, codec, NULL); + if (ret < 0) { + lprintf("mp3dec: avcodec_open failed: %d\n", ret); + av_free(ctx); + ctx = NULL; + return -1; + } +#endif return 0; } diff --git a/platform/common/mp3_minimp3.c b/platform/common/mp3_minimp3.c new file mode 100644 index 00000000..ee96e3b4 --- /dev/null +++ b/platform/common/mp3_minimp3.c @@ -0,0 +1,65 @@ +/* + * MP3 decoding using minimp3 + * (C) kub, 2020 + * + * This work is licensed under the terms of MAME license. + * See COPYING file in the top-level directory. + */ + +#include + +#include +#define MINIMP3_IMPLEMENTATION +#include "minimp3/minimp3.h" +#include "mp3.h" + +static mp3dec_t mp3dec; +static unsigned char mp3_input_buffer[2 * 1024]; + +int mp3dec_start(FILE *f, int fpos_start) +{ + mp3dec_init(&mp3dec); + return 0; +} + +int mp3dec_decode(FILE *f, int *file_pos, int file_len) +{ + mp3dec_frame_info_t info; + unsigned char *readPtr; + int bytesLeft; + int offset; // mp3 frame offset from readPtr + int len; + int retry = 3; + + do + { + if (*file_pos >= file_len) + return 1; /* EOF, nothing to do */ + + fseek(f, *file_pos, SEEK_SET); + bytesLeft = fread(mp3_input_buffer, 1, sizeof(mp3_input_buffer), f); + + offset = mp3_find_sync_word(mp3_input_buffer, bytesLeft); + if (offset < 0) { + lprintf("find_sync_word (%i/%i) err %i\n", + *file_pos, file_len, offset); + *file_pos = file_len; + return 1; // EOF + } + *file_pos += offset; + readPtr = mp3_input_buffer + offset; + bytesLeft -= offset; + + len = mp3dec_decode_frame(&mp3dec, readPtr, bytesLeft, cdda_out_buffer, &info); + if (len > 0) // retrieved decoded data + *file_pos += info.frame_bytes; + else if (info.frame_bytes > 0) // no output but input consumed? + *file_pos += 1; // try to skip frame + else if (offset == 0) // bad frame? + *file_pos += 1; // try resyncing + // else // truncated frame, try more data + } + while (len <= 0 && --retry > 0); + + return len <= 0; +} -- 2.39.5