diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 84c7387..765ad18 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,7 +18,7 @@ add_executable( main.c ) -target_link_libraries(lazier-player PRIVATE SDL3::SDL3 mpv m) +target_link_libraries(lazier-player PRIVATE SDL3::SDL3 mpv m GL) set_property(TARGET lazier-player PROPERTY C_STANDARD 23) target_compile_options(lazier-player PRIVATE -Wall -Wextra -Wnull-dereference) target_include_directories(lazier-player PRIVATE include) diff --git a/src/main.c b/src/main.c index 4719db1..6f57c1e 100644 --- a/src/main.c +++ b/src/main.c @@ -1,20 +1,18 @@ #include <SDL3/SDL.h> -#include <mpv/client.h> -#include <mpv/render.h> +#include <mpv/render_gl.h> +#include <GL/gl.h> + #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <assert.h> typedef struct { mpv_handle *mpv; mpv_render_context *render_ctx; SDL_Window *window; SDL_Renderer *renderer; - SDL_Texture *texture; - int width; - int height; - int running; - int needs_redraw; + bool running; } App; static void SDL_PrintError(const char *msg) @@ -27,6 +25,12 @@ static void mpv_print_error(int code, const char *msg) fprintf(stderr, "mpv: %s: %s\n", msg, mpv_error_string(code)); } +static void *get_proc_address_mpv(void *ctx, const char *name) +{ + (void)ctx; + return SDL_GL_GetProcAddress(name); +} + static void handle_mpv_events(App *app) { while (true) { @@ -35,38 +39,17 @@ static void handle_mpv_events(App *app) if (event->event_id == MPV_EVENT_NONE) break; - printf("mpv: event=%s\n", mpv_event_name(event->event_id)); - if (event->event_id == MPV_EVENT_PROPERTY_CHANGE) { mpv_event_property *prop = event->data; - - if (!strcmp(prop->name, "width") || !strcmp(prop->name, "height")) { - int64_t width = 0; - int64_t height = 0; - - mpv_get_property(app->mpv, "width", MPV_FORMAT_INT64, &width); - mpv_get_property(app->mpv, "height", MPV_FORMAT_INT64, &height); - - if (width > 0 && height > 0 && (width != app->width || height != app->height)) { - app->width = width; - app->height = height; - - if (app->texture) - SDL_DestroyTexture(app->texture); - - app->texture = SDL_CreateTexture(app->renderer, SDL_PIXELFORMAT_XBGR8888, - SDL_TEXTUREACCESS_STREAMING, width, height); - - if (!app->texture) { - SDL_PrintError("SDL_CreateTexture"); - } else { - // Resize window to match video dimensions - SDL_SetWindowSize(app->window, app->width, app->height); - } - } - } + printf("mpv: event=%s, name=%s\n", mpv_event_name(event->event_id), prop->name); } else if (event->event_id == MPV_EVENT_END_FILE) { - app->running = 0; + printf("mpv: event=%s\n", mpv_event_name(event->event_id)); + app->running = false; + } else if (event->event_id == MPV_EVENT_START_FILE) { + printf("mpv: event=%s\n", mpv_event_name(event->event_id)); + app->running = true; + } else { + printf("mpv: event=%s\n", mpv_event_name(event->event_id)); } } } @@ -75,83 +58,52 @@ static void render_video(App *app) { int err; - // Clear the renderer - if (!SDL_SetRenderDrawColor(app->renderer, 0, 0, 0, 255)) - SDL_PrintError("SDL_SetRenderDrawColor"); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); - if (!SDL_RenderClear(app->renderer)) - SDL_PrintError("SDL_RenderClear"); + glColor3f(1.0f, 1.0f, 1.0f); + glBegin(GL_LINES); + glVertex2d(-0.5, 0.5); + glVertex2d(0.5, -0.5); + glEnd(); - // Render MPV frame - if (app->texture && app->render_ctx) { - void *pixels; - int stride = 0; + int w, h; + if (!SDL_GetCurrentRenderOutputSize(app->renderer, &w, &h)) { + SDL_PrintError("SDL_GetCurrentRenderOutputSize"); + return; + } - if (!SDL_LockTexture(app->texture, NULL, &pixels, &stride)) { - SDL_PrintError("SDL_LockTexture"); - return; - } + // Render MPV frame using OpenGL + if (app->render_ctx) { + int flip_y = 1; - float w, h; - if (!SDL_GetTextureSize(app->texture, &w, &h)) - SDL_PrintError("SDL_GetTextureSize"); - - int size[] = { w, h }; + mpv_opengl_fbo mpv_fbo = { + .fbo = 0, + .w = w, + .h = h, + .internal_format = 0, + }; mpv_render_param params[] = { - { MPV_RENDER_PARAM_SW_SIZE, &size }, // - { MPV_RENDER_PARAM_SW_FORMAT, "rgb0" }, // - { MPV_RENDER_PARAM_SW_STRIDE, &stride }, // - { MPV_RENDER_PARAM_SW_POINTER, pixels }, // + { MPV_RENDER_PARAM_OPENGL_FBO, &mpv_fbo }, + { MPV_RENDER_PARAM_FLIP_Y, &flip_y }, { MPV_RENDER_PARAM_INVALID, NULL }, }; if ((err = mpv_render_context_render(app->render_ctx, params))) mpv_print_error(err, "mpv_render_context_render"); - - SDL_UnlockTexture(app->texture); - - if (!SDL_RenderTexture(app->renderer, app->texture, NULL, NULL)) { - SDL_PrintError("SDL_RenderTexture"); - } } - // Draw shapes over the video - // 1. Red rectangle - if (!SDL_SetRenderDrawColor(app->renderer, 255, 0, 0, 128)) - SDL_PrintError("SDL_SetRenderDrawColor"); - - SDL_FRect rect = { 50, 50, 100, 80 }; - - if (!SDL_RenderFillRect(app->renderer, &rect)) - SDL_PrintError("SDL_RenderFillRect"); - - // 2. Blue circle (approximated with points) - if (!SDL_SetRenderDrawColor(app->renderer, 0, 0, 255, 128)) - SDL_PrintError("SDL_SetRenderDrawColor"); - - int centerX = app->width - 100; - int centerY = app->height - 100; - int radius = 40; - - for (int i = 0; i < 360; i++) { - float angle = i * 3.14159f / 180.0f; - float x = centerX + radius * SDL_cosf(angle); - float y = centerY + radius * SDL_sinf(angle); - - if (!SDL_RenderPoint(app->renderer, x, y)) - SDL_PrintError("SDL_RenderPoint"); + glColor3f(1.0f, 1.0f, 1.0f); + glBegin(GL_LINES); + { + glVertex2d(-0.5, -0.5); + glVertex2d(0.5, 0.5); } + glEnd(); - // 3. Green line - if (!SDL_SetRenderDrawColor(app->renderer, 0, 255, 0, 200)) - SDL_PrintError("SDL_SetRenderDrawColor"); - - if (!SDL_RenderLine(app->renderer, 0, 0, app->width, app->height)) - SDL_PrintError("SDL_RenderLine"); - - if (!SDL_RenderPresent(app->renderer)) - SDL_PrintError("SDL_RenderPresent"); + if (!SDL_GL_SwapWindow(app->window)) + SDL_PrintError("SDL_GL_SwapWindow"); } int main(int argc, char *argv[]) @@ -165,8 +117,6 @@ int main(int argc, char *argv[]) static App app = { 0 }; app.running = 1; - app.width = 800; - app.height = 600; // Initialize SDL if (!SDL_Init(SDL_INIT_VIDEO)) { @@ -175,15 +125,41 @@ int main(int argc, char *argv[]) } // Create window - app.window = SDL_CreateWindow("SDL3 + MPV Video Player", app.width, app.height, 0); + SDL_WindowFlags flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; + app.window = SDL_CreateWindow("Lazier Player", 800, 600, flags); + if (!app.window) { SDL_PrintError("SDL_CreateWindow"); SDL_Quit(); return 1; } - // Create renderer - app.renderer = SDL_CreateRenderer(app.window, "software"); + // Create OpenGL renderer + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + SDL_GLContext gl_ctx = SDL_GL_CreateContext(app.window); + if (!gl_ctx) { + SDL_PrintError("SDL_GL_CreateContext"); + SDL_DestroyWindow(app.window); + SDL_Quit(); + return 1; + } + + if (!SDL_GL_SetSwapInterval(1)) + SDL_PrintError("SDL_GL_SetSwapInterval"); + + if (!SDL_GL_MakeCurrent(app.window, gl_ctx)) { + SDL_PrintError("SDL_GL_MakeCurrent"); + SDL_GL_DestroyContext(gl_ctx); + SDL_DestroyWindow(app.window); + SDL_Quit(); + return 1; + } + + app.renderer = SDL_CreateRenderer(app.window, "opengl"); if (!app.renderer) { SDL_PrintError("SDL_CreateRenderer"); SDL_DestroyWindow(app.window); @@ -211,9 +187,14 @@ int main(int argc, char *argv[]) if ((err = mpv_initialize(app.mpv))) mpv_print_error(err, "mpv_initialize"); - // Initialize MPV render context + // Initialize MPV OpenGL render context + mpv_opengl_init_params gl_init_params = { + .get_proc_address = get_proc_address_mpv, + }; + mpv_render_param params[] = { - { MPV_RENDER_PARAM_API_TYPE, MPV_RENDER_API_TYPE_SW }, + { MPV_RENDER_PARAM_API_TYPE, MPV_RENDER_API_TYPE_OPENGL }, + { MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params }, { MPV_RENDER_PARAM_INVALID, NULL }, }; @@ -248,15 +229,12 @@ int main(int argc, char *argv[]) SDL_Delay(16); // ~60fps } - // Cleanup - if (app.texture) - SDL_DestroyTexture(app.texture); - if (app.render_ctx) mpv_render_context_free(app.render_ctx); mpv_terminate_destroy(app.mpv); SDL_DestroyRenderer(app.renderer); + SDL_GL_DestroyContext(gl_ctx); SDL_DestroyWindow(app.window); SDL_Quit();