VideoTools/player/mpvembed/mpv.go

181 lines
5.1 KiB
Go

package mpvembed
/*
#cgo pkg-config: mpv
#include <mpv/client.h>
#include <stdlib.h>
#include <locale.h>
static inline const char* mpv_errstr(int err) { return mpv_error_string(err); }
*/
import "C"
import (
"errors"
"fmt"
"unsafe"
)
// Client wraps a libmpv handle.
type Client struct {
handle *C.mpv_handle
}
// New creates a new mpv client.
func New() (*Client, error) {
// Ensure numeric locale is C to satisfy mpv.
C.setlocale(C.int(C.LC_NUMERIC), C.CString("C"))
h := C.mpv_create()
if h == nil {
return nil, errors.New("mpv_create returned nil")
}
return &Client{handle: h}, nil
}
// Initialize must be called before issuing commands.
func (c *Client) Initialize() error {
if c.handle == nil {
return errors.New("mpv handle is nil")
}
if res := C.mpv_initialize(c.handle); res < 0 {
return fmt.Errorf("mpv_initialize failed: %s", C.GoString(C.mpv_errstr(res)))
}
return nil
}
// Destroy terminates and frees the client.
func (c *Client) Destroy() {
if c.handle != nil {
C.mpv_terminate_destroy(c.handle)
c.handle = nil
}
}
// SetOptionString sets an option before initialize.
func (c *Client) SetOptionString(name, value string) error {
if c.handle == nil {
return errors.New("mpv handle is nil")
}
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
cval := C.CString(value)
defer C.free(unsafe.Pointer(cval))
if res := C.mpv_set_option_string(c.handle, cname, cval); res < 0 {
return fmt.Errorf("mpv_set_option_string %s failed: %s", name, C.GoString(C.mpv_errstr(res)))
}
return nil
}
// SetOptionInt sets an integer option.
func (c *Client) SetOptionInt(name string, val int64) error {
if c.handle == nil {
return errors.New("mpv handle is nil")
}
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
cval := C.longlong(val)
if res := C.mpv_set_option(c.handle, cname, C.mpv_format(C.MPV_FORMAT_INT64), unsafe.Pointer(&cval)); res < 0 {
return fmt.Errorf("mpv_set_option %s failed: %s", name, C.GoString(C.mpv_errstr(res)))
}
return nil
}
// SetWID binds a native window ID to mpv (for embedding).
func (c *Client) SetWID(wid uint64) error {
return c.SetOptionInt("wid", int64(wid))
}
// Command issues an mpv command with arguments.
func (c *Client) Command(args ...string) error {
if c.handle == nil {
return errors.New("mpv handle is nil")
}
// Build a NULL-terminated array of *char
cargs := make([]*C.char, len(args)+1)
for i, a := range args {
cstr := C.CString(a)
defer C.free(unsafe.Pointer(cstr))
cargs[i] = cstr
}
cargs[len(args)] = nil
if res := C.mpv_command(c.handle, &cargs[0]); res < 0 {
return fmt.Errorf("mpv_command %v failed: %s", args, C.GoString(C.mpv_errstr(res)))
}
return nil
}
// SetPropertyBool sets a boolean property.
func (c *Client) SetPropertyBool(name string, v bool) error {
if c.handle == nil {
return errors.New("mpv handle is nil")
}
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
cval := C.int(0)
if v {
cval = 1
}
if res := C.mpv_set_property(c.handle, cname, C.mpv_format(C.MPV_FORMAT_FLAG), unsafe.Pointer(&cval)); res < 0 {
return fmt.Errorf("mpv_set_property %s failed: %s", name, C.GoString(C.mpv_errstr(res)))
}
return nil
}
// SetPropertyDouble sets a double property.
func (c *Client) SetPropertyDouble(name string, v float64) error {
if c.handle == nil {
return errors.New("mpv handle is nil")
}
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
cval := C.double(v)
if res := C.mpv_set_property(c.handle, cname, C.mpv_format(C.MPV_FORMAT_DOUBLE), unsafe.Pointer(&cval)); res < 0 {
return fmt.Errorf("mpv_set_property %s failed: %s", name, C.GoString(C.mpv_errstr(res)))
}
return nil
}
// GetPropertyDouble gets a double property.
func (c *Client) GetPropertyDouble(name string) (float64, error) {
if c.handle == nil {
return 0, errors.New("mpv handle is nil")
}
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
var out C.double
if res := C.mpv_get_property(c.handle, cname, C.mpv_format(C.MPV_FORMAT_DOUBLE), unsafe.Pointer(&out)); res < 0 {
return 0, fmt.Errorf("mpv_get_property %s failed: %s", name, C.GoString(C.mpv_errstr(res)))
}
return float64(out), nil
}
// GetPropertyInt64 gets an int64 property.
func (c *Client) GetPropertyInt64(name string) (int64, error) {
if c.handle == nil {
return 0, errors.New("mpv handle is nil")
}
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
var out C.longlong
if res := C.mpv_get_property(c.handle, cname, C.mpv_format(C.MPV_FORMAT_INT64), unsafe.Pointer(&out)); res < 0 {
return 0, fmt.Errorf("mpv_get_property %s failed: %s", name, C.GoString(C.mpv_errstr(res)))
}
return int64(out), nil
}
// GetPropertyString gets a string property.
func (c *Client) GetPropertyString(name string) (string, error) {
if c.handle == nil {
return "", errors.New("mpv handle is nil")
}
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
var out *C.char
if res := C.mpv_get_property(c.handle, cname, C.mpv_format(C.MPV_FORMAT_STRING), unsafe.Pointer(&out)); res < 0 {
return "", fmt.Errorf("mpv_get_property %s failed: %s", name, C.GoString(C.mpv_errstr(res)))
}
if out == nil {
return "", nil
}
return C.GoString(out), nil
}