Use OpenGL
This commit is contained in:
parent
d389fbd6d5
commit
d2ba406d05
2 changed files with 88 additions and 110 deletions
|
@ -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)
|
||||
|
|
196
src/main.c
196
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();
|
||||
|
||||
|
|
Loading…
Reference in a new issue