diff --git a/player/mpvembed/render.go b/player/mpvembed/render.go new file mode 100644 index 0000000..245c1d4 --- /dev/null +++ b/player/mpvembed/render.go @@ -0,0 +1,82 @@ +package mpvembed + +/* +#cgo pkg-config: mpv +#include +#include + +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 +}