From 3e888a14c1e87b8c1ada48a011b381431cdf4e7e Mon Sep 17 00:00:00 2001 From: Mahyar Koshkouei Date: Sun, 10 Dec 2017 22:35:47 +0000 Subject: [PATCH] Working example Signed-off-by: Mahyar Koshkouei --- Makefile | 139 +++++++++++++++++++++++++++++++ link.T | 4 + mpv-libretro.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 360 insertions(+), 5 deletions(-) create mode 100644 Makefile create mode 100644 link.T diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..685b23d --- /dev/null +++ b/Makefile @@ -0,0 +1,139 @@ +STATIC_LINKING := 0 +AR := ar + +ifeq ($(platform),) +platform = unix +ifeq ($(shell uname -a),) + platform = win +else ifneq ($(findstring MINGW,$(shell uname -a)),) + platform = win +else ifneq ($(findstring Darwin,$(shell uname -a)),) + platform = osx +else ifneq ($(findstring win,$(shell uname -a)),) + platform = win +endif +endif + +# system platform +system_platform = unix +ifeq ($(shell uname -a),) + EXE_EXT = .exe + system_platform = win +else ifneq ($(findstring Darwin,$(shell uname -a)),) + system_platform = osx + arch = intel +ifeq ($(shell uname -p),powerpc) + arch = ppc +endif +else ifneq ($(findstring MINGW,$(shell uname -a)),) + system_platform = win +endif + +TARGET_NAME := mpv +LIBM = -lm + +ifeq ($(ARCHFLAGS),) +ifeq ($(archs),ppc) + ARCHFLAGS = -arch ppc -arch ppc64 +else + ARCHFLAGS = -arch i386 -arch x86_64 +endif +endif + +ifeq ($(platform), osx) +ifndef ($(NOUNIVERSAL)) + CFLAGS += $(ARCHFLAGS) + LFLAGS += $(ARCHFLAGS) +endif +endif + +ifeq ($(STATIC_LINKING), 1) +EXT := a +endif + +ifeq ($(platform), unix) + EXT ?= so + TARGET := $(TARGET_NAME)_libretro.$(EXT) + fpic := -fPIC + SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined +else ifeq ($(platform), linux-portable) + TARGET := $(TARGET_NAME)_libretro.$(EXT) + fpic := -fPIC -nostdlib + SHARED := -shared -Wl,--version-script=link.T + LIBM := +else ifneq (,$(findstring osx,$(platform))) + TARGET := $(TARGET_NAME)_libretro.dylib + fpic := -fPIC + SHARED := -dynamiclib +else ifneq (,$(findstring ios,$(platform))) + TARGET := $(TARGET_NAME)_libretro_ios.dylib + fpic := -fPIC + SHARED := -dynamiclib + +ifeq ($(IOSSDK),) + IOSSDK := $(shell xcodebuild -version -sdk iphoneos Path) +endif + + DEFINES := -DIOS + CC = cc -arch armv7 -isysroot $(IOSSDK) +ifeq ($(platform),ios9) +CC += -miphoneos-version-min=8.0 +CFLAGS += -miphoneos-version-min=8.0 +else +CC += -miphoneos-version-min=5.0 +CFLAGS += -miphoneos-version-min=5.0 +endif +else ifneq (,$(findstring qnx,$(platform))) + TARGET := $(TARGET_NAME)_libretro_qnx.so + fpic := -fPIC + SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined +else ifeq ($(platform), emscripten) + TARGET := $(TARGET_NAME)_libretro_emscripten.bc + fpic := -fPIC + SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined +else ifeq ($(platform), vita) + TARGET := $(TARGET_NAME)_vita.a + CC = arm-vita-eabi-gcc + AR = arm-vita-eabi-ar + CFLAGS += -Wl,-q -Wall -O3 + STATIC_LINKING = 1 +else + CC = gcc + TARGET := $(TARGET_NAME)_libretro.dll + SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T -Wl,--no-undefined +endif + +LDFLAGS += $(LIBM) -lmpv + +ifeq ($(DEBUG), 1) + CFLAGS += -O0 -g +else + CFLAGS += -O3 +endif + +OBJECTS := mpv-libretro.o +CFLAGS += -Wall -pedantic $(fpic) + +ifneq (,$(findstring qnx,$(platform))) +CFLAGS += -Wc,-std=c99 +else +CFLAGS += -std=gnu99 +endif + +all: $(TARGET) + +$(TARGET): $(OBJECTS) +ifeq ($(STATIC_LINKING), 1) + $(AR) rcs $@ $(OBJECTS) +else + $(CC) $(fpic) $(SHARED) $(INCLUDES) -o $@ $(OBJECTS) $(LDFLAGS) +endif + +%.o: %.c + $(CC) $(CFLAGS) $(fpic) -c -o $@ $< + +clean: + rm -f $(OBJECTS) $(TARGET) + +.PHONY: clean + diff --git a/link.T b/link.T new file mode 100644 index 0000000..9e82b5d --- /dev/null +++ b/link.T @@ -0,0 +1,4 @@ +{ + global: retro_*; + local: *; +}; diff --git a/mpv-libretro.c b/mpv-libretro.c index cb94124..4918c45 100644 --- a/mpv-libretro.c +++ b/mpv-libretro.c @@ -1,18 +1,74 @@ +#include +#include +#include +#include +#include + +#include +#include + #include "libretro.h" +static struct retro_log_callback logging; +static retro_log_printf_t log_cb; + +static retro_video_refresh_t video_cb; +static retro_audio_sample_t audio_cb; +static retro_audio_sample_batch_t audio_batch_cb; +static retro_environment_t environ_cb; +static retro_input_poll_t input_poll_cb; +static retro_input_state_t input_state_cb; + +static mpv_handle *mpv; +static mpv_opengl_cb_context *mpv_gl; + +static void fallback_log(enum retro_log_level level, const char *fmt, ...) +{ + (void)level; + va_list va; + va_start(va, fmt); + vfprintf(stderr, fmt, va); + va_end(va); +} + +void retro_init(void) +{ + mpv = mpv_create(); + + log_cb(RETRO_LOG_DEBUG, "Test\n"); + + if(!mpv) + log_cb(RETRO_LOG_ERROR, "failed creating context\n"); + + if(mpv_initialize(mpv) < 0) + log_cb(RETRO_LOG_ERROR, "mpv init failed"); + + // The OpenGL API is somewhat separate from the normal mpv API. This only + // returns NULL if no OpenGL support is compiled. + mpv_opengl_cb_context *mpv_gl = mpv_get_sub_api(mpv, MPV_SUB_API_OPENGL_CB); + if(!mpv_gl) + { + log_cb(RETRO_LOG_ERROR, "failed to create mpv GL API handle"); + } + + return; +} + +void retro_deinit(void) +{ + mpv_terminate_destroy(mpv); + return; +} + unsigned retro_api_version(void) { return RETRO_API_VERSION; } -void retro_init(void) -{ - return; -} - void retro_set_controller_port_device(unsigned port, unsigned device) { log_cb(RETRO_LOG_INFO, "Plugging device %u into port %u.\n", device, port); + return; } void retro_get_system_info(struct retro_system_info *info) @@ -24,3 +80,159 @@ void retro_get_system_info(struct retro_system_info *info) info->valid_extensions = "mkv|avi|f4v|f4f|3gp|ogm|flv|mp4|mp3|flac|ogg|m4a|webm|3g2|mov|wmv|mpg|mpeg|vob|asf|divx|m2p|m2ts|ps|ts|mxf|wma|wav"; } +void retro_get_system_av_info(struct retro_system_av_info *info) +{ + float sampling_rate = 30000.0f; + + struct retro_variable var = { .key = "test_aspect" }; + environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var); + + var.key = "test_samplerate"; + + if(environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + sampling_rate = strtof(var.value, NULL); + + info->timing = (struct retro_system_timing) { + .fps = 60.0, + .sample_rate = sampling_rate, + }; + + info->geometry = (struct retro_game_geometry) { + .base_width = 320, + .base_height = 240, + .max_width = 320, + .max_height = 240, + }; +} + +void retro_set_environment(retro_environment_t cb) +{ + environ_cb = cb; + + static const struct retro_variable vars[] = { + { "test_samplerate", "Sample Rate; 30000|20000" }, + { "test_opt0", "Test option #0; false|true" }, + { "test_opt1", "Test option #1; 0" }, + { "test_opt2", "Test option #2; 0|1|foo|3" }, + { NULL, NULL }, + }; + + cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars); + + bool no_content = true; + cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_content); + + if (cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &logging)) + log_cb = logging.log; + else + log_cb = fallback_log; +} + +void retro_set_audio_sample(retro_audio_sample_t cb) +{ + audio_cb = cb; +} + +void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) +{ + audio_batch_cb = cb; +} + +void retro_set_input_poll(retro_input_poll_t cb) +{ + input_poll_cb = cb; +} + +void retro_set_input_state(retro_input_state_t cb) +{ + input_state_cb = cb; +} + +void retro_set_video_refresh(retro_video_refresh_t cb) +{ + video_cb = cb; +} + +void retro_reset(void) +{ + return; +} + +static void audio_callback(void) +{ + static unsigned phase; + + for (unsigned i = 0; i < 30000 / 60; i++, phase++) + { + int16_t val = 0x800 * sinf(2.0f * M_PI * phase * 300.0f / 30000.0f); + audio_cb(val, val); + } + + phase %= 100; +} + +void retro_run(void) +{ + audio_callback(); + + return; +} + +/* No save-state support */ +size_t retro_serialize_size(void) +{ + return 0; +} + +bool retro_serialize(void *data_, size_t size) +{ + return true; +} + +bool retro_unserialize(const void *data_, size_t size) +{ + return true; +} + +bool retro_load_game(const struct retro_game_info *info) +{ + const char *cmd[] = {"loadfile", info->path, NULL}; + //mpv_command(mpv, cmd); + + return true; +} + +bool retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num) +{ + return false; +} + +void retro_unload_game(void) +{ + return; +} + +unsigned retro_get_region(void) +{ + return RETRO_REGION_NTSC; +} + +void *retro_get_memory_data(unsigned id) +{ + return NULL; +} + +size_t retro_get_memory_size(unsigned id) +{ + return 0; +} + +void retro_cheat_reset(void) +{ + return; +} + +void retro_cheat_set(unsigned index, bool enabled, const char *code) +{ + return; +}