Add MPV render context API for OpenGL rendering

Created render.go with CGO bindings for mpv_render_context:
- NewRenderContext: Create render context with parameters
- SetUpdateCallback: Register frame update callbacks
- Render: Issue render calls with FBO/dimension params
- Fixed CGO type conversions (int vs mpv_render_param_type)

This enables hardware-accelerated OpenGL rendering of MPV video
frames in the GTK player.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Stu 2025-12-15 05:24:27 -05:00
parent bd1b90be03
commit bbe45c6524

82
player/mpvembed/render.go Normal file
View File

@ -0,0 +1,82 @@
package mpvembed
/*
#cgo pkg-config: mpv
#include <mpv/render.h>
#include <stdlib.h>
static inline const char* mpv_errstr_render(int err) { return mpv_error_string(err); }
*/
import "C"
import (
"fmt"
"unsafe"
)
// RenderParam is a small helper to build mpv_render_param arrays.
type RenderParam struct {
Type int
Data unsafe.Pointer
}
// RenderContext wraps mpv_render_context for render API (OpenGL/Vulkan, etc.).
type RenderContext struct {
ctx *C.mpv_render_context
}
// NewRenderContext creates a render context for the given client with the provided params.
// The params slice is terminated with MPV_RENDER_PARAM_INVALID automatically.
func NewRenderContext(c *Client, params []RenderParam) (*RenderContext, error) {
if c == nil || c.handle == nil {
return nil, fmt.Errorf("mpv client is nil")
}
cparams := make([]C.mpv_render_param, len(params)+1)
for i, p := range params {
cparams[i]._type = C.int(p.Type)
cparams[i].data = p.Data
}
cparams[len(params)]._type = C.MPV_RENDER_PARAM_INVALID
var rctx *C.mpv_render_context
if res := C.mpv_render_context_create(&rctx, c.handle, &cparams[0]); res < 0 {
return nil, fmt.Errorf("mpv_render_context_create failed: %s", C.GoString(C.mpv_errstr_render(res)))
}
return &RenderContext{ctx: rctx}, nil
}
// Destroy frees the render context.
func (r *RenderContext) Destroy() {
if r != nil && r.ctx != nil {
C.mpv_render_context_free(r.ctx)
r.ctx = nil
}
}
// SetUpdateCallback registers a callback that mpv will invoke when a new frame should be drawn.
// The callback must be thread-safe.
func (r *RenderContext) SetUpdateCallback(cb unsafe.Pointer, userdata unsafe.Pointer) error {
if r == nil || r.ctx == nil {
return fmt.Errorf("render context is nil")
}
C.mpv_render_context_set_update_callback(r.ctx, (C.mpv_render_update_fn)(cb), userdata)
return nil
}
// Render issues a render call with the provided params (e.g., target FBO, dimensions).
// The params slice is terminated automatically.
func (r *RenderContext) Render(params []RenderParam) error {
if r == nil || r.ctx == nil {
return fmt.Errorf("render context is nil")
}
cparams := make([]C.mpv_render_param, len(params)+1)
for i, p := range params {
cparams[i]._type = C.int(p.Type)
cparams[i].data = p.Data
}
cparams[len(params)]._type = C.MPV_RENDER_PARAM_INVALID
if res := C.mpv_render_context_render(r.ctx, &cparams[0]); res < 0 {
return fmt.Errorf("mpv_render_context_render failed: %s", C.GoString(C.mpv_errstr_render(res)))
}
return nil
}