Use OpenGL

This commit is contained in:
Jan Hamal Dvořák 2025-03-16 20:34:32 +01:00
parent d389fbd6d5
commit d2ba406d05
Signed by: mordae
GPG key ID: 1782BCC23EE007B9
2 changed files with 88 additions and 110 deletions

View file

@ -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)

View file

@ -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();