add mpv demo
This commit is contained in:
@@ -25,10 +25,15 @@ set_target_properties(xplayer PROPERTIES CXX_STANDARD 17)
|
|||||||
target_include_directories(xplayer PRIVATE ${CMAKE_SOURCE_DIR})
|
target_include_directories(xplayer PRIVATE ${CMAKE_SOURCE_DIR})
|
||||||
target_compile_definitions(xplayer PRIVATE ${RENDER_DRIVER})
|
target_compile_definitions(xplayer PRIVATE ${RENDER_DRIVER})
|
||||||
|
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_search_module(MPV REQUIRED mpv)
|
||||||
|
target_include_directories(xplayer PRIVATE ${MPV_INCLUDE_DIRS})
|
||||||
|
|
||||||
if (NINTENDO_SWITCH)
|
if (NINTENDO_SWITCH)
|
||||||
target_link_libraries(xplayer
|
target_link_libraries(xplayer
|
||||||
PRIVATE
|
PRIVATE
|
||||||
sdl2 glapi drm_nouveau nx m
|
sdl2 glapi drm_nouveau nx m
|
||||||
|
${MPV_LINK_LIBRARIES}
|
||||||
)
|
)
|
||||||
nx_generate_nacp(xplayer.nacp NAME "xplayer demo" AUTHOR dragonflylee VERSION 1.0)
|
nx_generate_nacp(xplayer.nacp NAME "xplayer demo" AUTHOR dragonflylee VERSION 1.0)
|
||||||
nx_create_nro(xplayer ICON ${CMAKE_SOURCE_DIR}/icon.jpg NACP xplayer.nacp)
|
nx_create_nro(xplayer ICON ${CMAKE_SOURCE_DIR}/icon.jpg NACP xplayer.nacp)
|
||||||
@@ -37,6 +42,6 @@ else ()
|
|||||||
if (MINGW)
|
if (MINGW)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
|
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
|
||||||
endif ()
|
endif ()
|
||||||
target_link_libraries(xplayer PRIVATE ${SDL2_LIBRARIES})
|
target_link_libraries(xplayer PRIVATE ${SDL2_LIBRARIES} ${MPV_LINK_LIBRARIES})
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -12,7 +12,7 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
TARGET := xPlayer
|
TARGET := xPlayer
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SRCS := src imgui
|
SRCS := src
|
||||||
DATA := data
|
DATA := data
|
||||||
#ROMFS := romfs
|
#ROMFS := romfs
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ CFLAGS += $(INCLUDE) -D__SWITCH__
|
|||||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -DIMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -DIMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
||||||
ASFLAGS := -g $(ARCH)
|
ASFLAGS := -g $(ARCH)
|
||||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
LIBS := `$(PREFIX)pkg-config sdl2 --libs`
|
LIBS := `$(PREFIX)pkg-config sdl2 mpv --libs` -lnx
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# list of directories containing libraries, this must be the top level containing
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ OBJS = $(SRCS:.cpp=.o)
|
|||||||
INCLUDES := -I$(CURDIR)
|
INCLUDES := -I$(CURDIR)
|
||||||
CFLAGS := -g -Wall $(INCLUDES)
|
CFLAGS := -g -Wall $(INCLUDES)
|
||||||
CXXFLAGS := $(CFLAGS) -std=c++17
|
CXXFLAGS := $(CFLAGS) -std=c++17
|
||||||
LDFLAGS := `pkg-config sdl2 --libs`
|
LDFLAGS := `pkg-config sdl2 mpv --libs`
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
|
|||||||
140
src/main.cpp
140
src/main.cpp
@@ -1,7 +1,6 @@
|
|||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
#include <mpv/client.h>
|
||||||
|
#include <mpv/render_gl.h>
|
||||||
|
|
||||||
#ifdef __SWITCH__
|
#ifdef __SWITCH__
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
@@ -10,32 +9,30 @@ extern "C" void userAppInit() {
|
|||||||
socketInitializeDefault();
|
socketInitializeDefault();
|
||||||
nxlinkStdio();
|
nxlinkStdio();
|
||||||
appletSetWirelessPriorityMode(AppletWirelessPriorityMode_OptimizedForWlan);
|
appletSetWirelessPriorityMode(AppletWirelessPriorityMode_OptimizedForWlan);
|
||||||
plInitialize(PlServiceType_User);
|
sslInitialize(0x3);
|
||||||
|
csrngInitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void userAppExit() {
|
extern "C" void userAppExit() {
|
||||||
plExit();
|
csrngExit();
|
||||||
|
sslExit();
|
||||||
socketExit();
|
socketExit();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// some switch buttons
|
|
||||||
#define JOY_A 0
|
#define JOY_A 0
|
||||||
#define JOY_B 1
|
|
||||||
#define JOY_X 2
|
|
||||||
#define JOY_Y 3
|
|
||||||
#define JOY_PLUS 10
|
#define JOY_PLUS 10
|
||||||
#define JOY_MINUS 11
|
#define JOY_MINUS 11
|
||||||
#define JOY_LEFT 12
|
|
||||||
#define JOY_UP 13
|
|
||||||
#define JOY_RIGHT 14
|
|
||||||
#define JOY_DOWN 15
|
|
||||||
|
|
||||||
static void die(const char* msg) {
|
static void die(const char* msg) {
|
||||||
fprintf(stderr, "%s\n", msg);
|
SDL_Log("%s\n", msg);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void check_error(int status) {
|
||||||
|
if (status < 0) SDL_Log("mpv error: %s\n", mpv_error_string(status));
|
||||||
|
}
|
||||||
|
|
||||||
// Main code
|
// Main code
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc < 2) die("pass a single media file as argument");
|
if (argc < 2) die("pass a single media file as argument");
|
||||||
@@ -45,36 +42,145 @@ int main(int argc, char* argv[]) {
|
|||||||
SDL_JoystickEventState(SDL_ENABLE);
|
SDL_JoystickEventState(SDL_ENABLE);
|
||||||
SDL_JoystickOpen(0);
|
SDL_JoystickOpen(0);
|
||||||
|
|
||||||
|
mpv_render_context* mpv_context = nullptr;
|
||||||
|
mpv_handle* mpv = mpv_create();
|
||||||
|
mpv_set_option_string(mpv, "subs-fallback", "yes");
|
||||||
|
mpv_set_option_string(mpv, "video-timing-offset", "0"); // 60fps
|
||||||
|
mpv_set_option_string(mpv, "ytdl", "no");
|
||||||
|
mpv_set_option_string(mpv, "hwdec", "auto-copy");
|
||||||
|
mpv_set_option_string(mpv, "vo", "libmpv");
|
||||||
|
if (mpv_initialize(mpv) < 0) die("init mpv failed");
|
||||||
|
|
||||||
SDL_Window* window = SDL_CreateWindow(argv[1], 0, 0, 1280, 720, 0);
|
SDL_Window* window = SDL_CreateWindow(argv[1], 0, 0, 1280, 720, 0);
|
||||||
if (!window) die("failed to create SDL window");
|
if (!window) die("failed to create SDL window");
|
||||||
|
|
||||||
SDL_GLContext context = SDL_GL_CreateContext(window);
|
SDL_GLContext context = SDL_GL_CreateContext(window);
|
||||||
SDL_GL_MakeCurrent(window, context);
|
SDL_GL_MakeCurrent(window, context);
|
||||||
|
|
||||||
|
mpv_opengl_init_params gl_init_params{
|
||||||
|
[](void* fn_ctx, const char* name) { return (void*)SDL_GL_GetProcAddress(name); }, nullptr};
|
||||||
|
mpv_render_param params[] = {
|
||||||
|
{MPV_RENDER_PARAM_API_TYPE, const_cast<char*>(MPV_RENDER_API_TYPE_OPENGL)},
|
||||||
|
{MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params},
|
||||||
|
{MPV_RENDER_PARAM_INVALID, nullptr},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mpv_render_context_create(&mpv_context, mpv, params) < 0) die("init mpv context failed");
|
||||||
|
|
||||||
|
static uint32_t SDL_MPV_RENDER = SDL_RegisterEvents(1);
|
||||||
|
static uint32_t SDL_MPV_EVENT = SDL_RegisterEvents(1);
|
||||||
|
|
||||||
|
mpv_set_wakeup_callback(
|
||||||
|
mpv,
|
||||||
|
[](void* obj) {
|
||||||
|
SDL_Event event = {.type = SDL_MPV_EVENT};
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
},
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
mpv_render_context_set_update_callback(
|
||||||
|
mpv_context,
|
||||||
|
[](void* obj) {
|
||||||
|
SDL_Event event = {.type = SDL_MPV_RENDER};
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
},
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
const char* args[] = {"loadfile", argv[1], nullptr};
|
||||||
|
if (mpv_command_async(mpv, 0, args) < 0) die("load file failed");
|
||||||
|
|
||||||
|
int fbw = 0, fbh = 0;
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while (SDL_WaitEvent(&event)) {
|
while (SDL_WaitEvent(&event)) {
|
||||||
|
int redraw = 0;
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
goto done;
|
goto done;
|
||||||
|
case SDL_WINDOWEVENT:
|
||||||
|
if (event.window.event == SDL_WINDOWEVENT_EXPOSED) redraw = 1;
|
||||||
|
break;
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
switch (event.key.keysym.sym) {
|
switch (event.key.keysym.sym) {
|
||||||
case SDLK_ESCAPE:
|
case SDLK_ESCAPE:
|
||||||
goto done;
|
goto done;
|
||||||
|
case SDLK_RETURN:
|
||||||
|
mpv_command_string(mpv, "script-binding stats/display-stats-toggle");
|
||||||
|
break;
|
||||||
|
case SDLK_SPACE:
|
||||||
|
mpv_command_string(mpv, "cycle pause");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDL_JOYBUTTONDOWN:
|
case SDL_JOYBUTTONDOWN:
|
||||||
switch (event.jbutton.button) {
|
switch (event.jbutton.button) {
|
||||||
case JOY_PLUS:
|
case JOY_PLUS:
|
||||||
goto done;
|
goto done;
|
||||||
}
|
case JOY_MINUS:
|
||||||
SDL_Log("Joystick %d button %d down\n", event.jbutton.which, event.jbutton.button);
|
mpv_command_string(mpv, "script-binding stats/display-stats-toggle");
|
||||||
break;
|
break;
|
||||||
default:;
|
case JOY_A:
|
||||||
|
mpv_command_string(mpv, "cycle pause");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SDL_Log("Joystick %d button %d down\n", event.jbutton.which, event.jbutton.button);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (event.type == SDL_MPV_RENDER) {
|
||||||
|
uint64_t flags = mpv_render_context_update(mpv_context);
|
||||||
|
if (flags & MPV_RENDER_UPDATE_FRAME) redraw = 1;
|
||||||
|
} else if (event.type == SDL_MPV_EVENT) {
|
||||||
|
while (true) {
|
||||||
|
mpv_event* mp_event = mpv_wait_event(mpv, 0);
|
||||||
|
if (mp_event->event_id == MPV_EVENT_NONE) {
|
||||||
|
break;
|
||||||
|
} else if (mp_event->event_id == MPV_EVENT_START_FILE) {
|
||||||
|
SDL_Log("MPV => START FILE\n");
|
||||||
|
} else if (mp_event->event_id == MPV_EVENT_FILE_LOADED) {
|
||||||
|
SDL_Log("MPV => FILE LOADED\n");
|
||||||
|
} else if (mp_event->event_id == MPV_EVENT_PLAYBACK_RESTART) {
|
||||||
|
SDL_Log("MPV => PLAYBACK RESTART\n");
|
||||||
|
} else if (mp_event->event_id == MPV_EVENT_COMMAND_REPLY) {
|
||||||
|
if (mp_event->error) {
|
||||||
|
SDL_Log("MPV => COMMAND ERROR: %s\n", mpv_error_string(mp_event->error));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (mp_event->event_id == MPV_EVENT_END_FILE) {
|
||||||
|
auto node = (mpv_event_end_file*)mp_event->data;
|
||||||
|
if (node->reason == MPV_END_FILE_REASON_ERROR) {
|
||||||
|
SDL_Log("MPV => FILE ERROR: %s\n", mpv_error_string(node->error));
|
||||||
|
} else if (node->reason == MPV_END_FILE_REASON_EOF) {
|
||||||
|
SDL_Log("MPV => END_OF_FILE\n");
|
||||||
|
} else {
|
||||||
|
SDL_Log("MPV => STOP\n");
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
} else if (mp_event->event_id == MPV_EVENT_PROPERTY_CHANGE) {
|
||||||
|
/// https://mpv.io/manual/stable/#property-list
|
||||||
|
mpv_event_property* prop = (mpv_event_property*)mp_event->data;
|
||||||
|
SDL_Log("MPV => PROPERTY `%s` type %d\n", prop->name, int(prop->format));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (redraw) {
|
||||||
|
SDL_GL_GetDrawableSize(window, &fbw, &fbh);
|
||||||
|
mpv_opengl_fbo mpv_fbo{0, fbw, fbh};
|
||||||
|
int flip_y{1};
|
||||||
|
mpv_render_param mpv_params[3] = {
|
||||||
|
{MPV_RENDER_PARAM_OPENGL_FBO, &mpv_fbo},
|
||||||
|
{MPV_RENDER_PARAM_FLIP_Y, &flip_y},
|
||||||
|
{MPV_RENDER_PARAM_INVALID, nullptr},
|
||||||
|
};
|
||||||
|
mpv_render_context_render(mpv_context, mpv_params);
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
done:
|
done:
|
||||||
|
mpv_render_context_free(mpv_context);
|
||||||
|
mpv_terminate_destroy(mpv);
|
||||||
|
|
||||||
SDL_GL_DeleteContext(context);
|
SDL_GL_DeleteContext(context);
|
||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(window);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
|||||||
Reference in New Issue
Block a user