Browse Source

mcd, add minimp3 playback support, fix libavcodec playback

kub 3 years ago
parent
commit
faedc4f1e2
6 changed files with 133 additions and 30 deletions
  1. 3 0
      .gitmodules
  2. 1 2
      Makefile
  3. 1 0
      platform/common/minimp3
  4. 3 4
      platform/common/mp3_helix.c
  5. 60 24
      platform/common/mp3_libavcodec.c
  6. 65 0
      platform/common/mp3_minimp3.c

+ 3 - 0
.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

+ 1 - 2
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"

+ 1 - 0
platform/common/minimp3

@@ -0,0 +1 @@
+Subproject commit 95864e8e0d3b34402a49ae9af6c66f7e98c13c35

+ 3 - 4
platform/common/mp3_helix.c

@@ -12,10 +12,8 @@
 #include <dlfcn.h>
 
 #include <pico/pico_int.h>
-#include <pico/sound/mix.h>
 #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)

+ 60 - 24
platform/common/mp3_libavcodec.c

@@ -13,14 +13,17 @@
 #include <dlfcn.h>
 
 #include <pico/pico_int.h>
-#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;
 }

+ 65 - 0
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 <stdio.h>
+
+#include <pico/pico_int.h>
+#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;
+}