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
|
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)
|
set_property(TARGET lazier-player PROPERTY C_STANDARD 23)
|
||||||
target_compile_options(lazier-player PRIVATE -Wall -Wextra -Wnull-dereference)
|
target_compile_options(lazier-player PRIVATE -Wall -Wextra -Wnull-dereference)
|
||||||
target_include_directories(lazier-player PRIVATE include)
|
target_include_directories(lazier-player PRIVATE include)
|
||||||
|
|
196
src/main.c
196
src/main.c
|
@ -1,20 +1,18 @@
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <mpv/client.h>
|
#include <mpv/render_gl.h>
|
||||||
#include <mpv/render.h>
|
#include <GL/gl.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mpv_handle *mpv;
|
mpv_handle *mpv;
|
||||||
mpv_render_context *render_ctx;
|
mpv_render_context *render_ctx;
|
||||||
SDL_Window *window;
|
SDL_Window *window;
|
||||||
SDL_Renderer *renderer;
|
SDL_Renderer *renderer;
|
||||||
SDL_Texture *texture;
|
bool running;
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
int running;
|
|
||||||
int needs_redraw;
|
|
||||||
} App;
|
} App;
|
||||||
|
|
||||||
static void SDL_PrintError(const char *msg)
|
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));
|
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)
|
static void handle_mpv_events(App *app)
|
||||||
{
|
{
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -35,38 +39,17 @@ static void handle_mpv_events(App *app)
|
||||||
if (event->event_id == MPV_EVENT_NONE)
|
if (event->event_id == MPV_EVENT_NONE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
printf("mpv: event=%s\n", mpv_event_name(event->event_id));
|
|
||||||
|
|
||||||
if (event->event_id == MPV_EVENT_PROPERTY_CHANGE) {
|
if (event->event_id == MPV_EVENT_PROPERTY_CHANGE) {
|
||||||
mpv_event_property *prop = event->data;
|
mpv_event_property *prop = event->data;
|
||||||
|
printf("mpv: event=%s, name=%s\n", mpv_event_name(event->event_id), prop->name);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (event->event_id == MPV_EVENT_END_FILE) {
|
} 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;
|
int err;
|
||||||
|
|
||||||
// Clear the renderer
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
if (!SDL_SetRenderDrawColor(app->renderer, 0, 0, 0, 255))
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
SDL_PrintError("SDL_SetRenderDrawColor");
|
|
||||||
|
|
||||||
if (!SDL_RenderClear(app->renderer))
|
glColor3f(1.0f, 1.0f, 1.0f);
|
||||||
SDL_PrintError("SDL_RenderClear");
|
glBegin(GL_LINES);
|
||||||
|
glVertex2d(-0.5, 0.5);
|
||||||
|
glVertex2d(0.5, -0.5);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
// Render MPV frame
|
int w, h;
|
||||||
if (app->texture && app->render_ctx) {
|
if (!SDL_GetCurrentRenderOutputSize(app->renderer, &w, &h)) {
|
||||||
void *pixels;
|
SDL_PrintError("SDL_GetCurrentRenderOutputSize");
|
||||||
int stride = 0;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!SDL_LockTexture(app->texture, NULL, &pixels, &stride)) {
|
// Render MPV frame using OpenGL
|
||||||
SDL_PrintError("SDL_LockTexture");
|
if (app->render_ctx) {
|
||||||
return;
|
int flip_y = 1;
|
||||||
}
|
|
||||||
|
|
||||||
float w, h;
|
mpv_opengl_fbo mpv_fbo = {
|
||||||
if (!SDL_GetTextureSize(app->texture, &w, &h))
|
.fbo = 0,
|
||||||
SDL_PrintError("SDL_GetTextureSize");
|
.w = w,
|
||||||
|
.h = h,
|
||||||
int size[] = { w, h };
|
.internal_format = 0,
|
||||||
|
};
|
||||||
|
|
||||||
mpv_render_param params[] = {
|
mpv_render_param params[] = {
|
||||||
{ MPV_RENDER_PARAM_SW_SIZE, &size }, //
|
{ MPV_RENDER_PARAM_OPENGL_FBO, &mpv_fbo },
|
||||||
{ MPV_RENDER_PARAM_SW_FORMAT, "rgb0" }, //
|
{ MPV_RENDER_PARAM_FLIP_Y, &flip_y },
|
||||||
{ MPV_RENDER_PARAM_SW_STRIDE, &stride }, //
|
|
||||||
{ MPV_RENDER_PARAM_SW_POINTER, pixels }, //
|
|
||||||
{ MPV_RENDER_PARAM_INVALID, NULL },
|
{ MPV_RENDER_PARAM_INVALID, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((err = mpv_render_context_render(app->render_ctx, params)))
|
if ((err = mpv_render_context_render(app->render_ctx, params)))
|
||||||
mpv_print_error(err, "mpv_render_context_render");
|
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
|
glColor3f(1.0f, 1.0f, 1.0f);
|
||||||
// 1. Red rectangle
|
glBegin(GL_LINES);
|
||||||
if (!SDL_SetRenderDrawColor(app->renderer, 255, 0, 0, 128))
|
{
|
||||||
SDL_PrintError("SDL_SetRenderDrawColor");
|
glVertex2d(-0.5, -0.5);
|
||||||
|
glVertex2d(0.5, 0.5);
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
glEnd();
|
||||||
|
|
||||||
// 3. Green line
|
if (!SDL_GL_SwapWindow(app->window))
|
||||||
if (!SDL_SetRenderDrawColor(app->renderer, 0, 255, 0, 200))
|
SDL_PrintError("SDL_GL_SwapWindow");
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
@ -165,8 +117,6 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
static App app = { 0 };
|
static App app = { 0 };
|
||||||
app.running = 1;
|
app.running = 1;
|
||||||
app.width = 800;
|
|
||||||
app.height = 600;
|
|
||||||
|
|
||||||
// Initialize SDL
|
// Initialize SDL
|
||||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||||
|
@ -175,15 +125,41 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create window
|
// 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) {
|
if (!app.window) {
|
||||||
SDL_PrintError("SDL_CreateWindow");
|
SDL_PrintError("SDL_CreateWindow");
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create renderer
|
// Create OpenGL renderer
|
||||||
app.renderer = SDL_CreateRenderer(app.window, "software");
|
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) {
|
if (!app.renderer) {
|
||||||
SDL_PrintError("SDL_CreateRenderer");
|
SDL_PrintError("SDL_CreateRenderer");
|
||||||
SDL_DestroyWindow(app.window);
|
SDL_DestroyWindow(app.window);
|
||||||
|
@ -211,9 +187,14 @@ int main(int argc, char *argv[])
|
||||||
if ((err = mpv_initialize(app.mpv)))
|
if ((err = mpv_initialize(app.mpv)))
|
||||||
mpv_print_error(err, "mpv_initialize");
|
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 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 },
|
{ MPV_RENDER_PARAM_INVALID, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -248,15 +229,12 @@ int main(int argc, char *argv[])
|
||||||
SDL_Delay(16); // ~60fps
|
SDL_Delay(16); // ~60fps
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
if (app.texture)
|
|
||||||
SDL_DestroyTexture(app.texture);
|
|
||||||
|
|
||||||
if (app.render_ctx)
|
if (app.render_ctx)
|
||||||
mpv_render_context_free(app.render_ctx);
|
mpv_render_context_free(app.render_ctx);
|
||||||
|
|
||||||
mpv_terminate_destroy(app.mpv);
|
mpv_terminate_destroy(app.mpv);
|
||||||
SDL_DestroyRenderer(app.renderer);
|
SDL_DestroyRenderer(app.renderer);
|
||||||
|
SDL_GL_DestroyContext(gl_ctx);
|
||||||
SDL_DestroyWindow(app.window);
|
SDL_DestroyWindow(app.window);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue