Initial libmpv/render.h mapping

For an example using this with GTK see:
https://gist.github.com/jaseg/657e8ecca3267c0d82ec85d40f423caa
This commit is contained in:
jaseg 2020-01-02 16:21:47 +01:00
parent 3205f1b6f8
commit 3c21d679da

206
mpv.py
View file

@ -56,6 +56,9 @@ else:
class MpvHandle(c_void_p): class MpvHandle(c_void_p):
pass pass
class MpvRenderCtxHandle(c_void_p):
pass
class MpvOpenGLCbContext(c_void_p): class MpvOpenGLCbContext(c_void_p):
pass pass
@ -125,6 +128,106 @@ class ErrorCode(object):
if ex: if ex:
raise ex(ec, *args) raise ex(ec, *args)
MpvGlGetProcAddressFn = CFUNCTYPE(c_void_p, c_void_p, c_char_p)
class MpvOpenGLInitParams(Structure):
_fields_ = [('get_proc_address', MpvGlGetProcAddressFn),
('get_proc_address_ctx', c_void_p),
('extra_exts', c_void_p)]
def __init__(self, get_proc_address):
self.get_proc_address = get_proc_address
self.get_proc_address_ctx = None
self.extra_exts = None
class MpvOpenGLFBO(Structure):
_fields_ = [('fbo', c_int),
('w', c_int),
('h', c_int),
('internal_format', c_int)]
def __init__(self, w, h, fbo=0, internal_format=0):
self.w, self.h = w, h
self.fbo = fbo
self.internal_format = internal_format
class MpvRenderFrameInfo(Structure):
_fields_ = [('flags', c_int64),
('target_time', c_int64)]
def as_dict(self):
return {'flags': self.flags,
'target_time': self.target_time}
class MpvOpenGLDRMParams(Structure):
_fields_ = [('fd', c_int),
('crtc_id', c_int),
('connector_id', c_int),
('atomic_request_ptr', c_void_p),
('render_fd', c_int)]
class MpvOpenGLDRMDrawSurfaceSize(Structure):
_fields_ = [('width', c_int), ('height', c_int)]
class MpvOpenGLDRMParamsV2(Structure):
_fields_ = [('fd', c_int),
('crtc_id', c_int),
('connector_id', c_int),
('atomic_request_ptr', c_void_p),
('render_fd', c_int)]
def __init__(self, crtc_id, connector_id, atomic_request_ptr, fd=-1, render_fd=-1):
self.crtc_id, self.connector_id = crtc_id, connector_id
self.atomic_request_ptr = atomic_request_ptr
self.fd, self.render_fd = fd, render_fd
class MpvRenderParam(Structure):
_fields_ = [('type_id', c_int),
('data', c_void_p)]
# maps human-readable type name to (type_id, argtype) tuple.
# The type IDs come from libmpv/render.h
TYPES = {"invalid" :(0, None),
"api_type" :(1, str),
"opengl_init_params" :(2, MpvOpenGLInitParams),
"opengl_fbo" :(3, MpvOpenGLFBO),
"flip_y" :(4, bool),
"depth" :(5, int),
"icc_profile" :(6, bytes),
"ambient_light" :(7, int),
"x11_display" :(8, c_void_p),
"wl_display" :(9, c_void_p),
"advanced_control" :(10, bool),
"next_frame_info" :(11, MpvRenderFrameInfo),
"block_for_target_time" :(12, bool),
"skip_rendering" :(13, bool),
"drm_display" :(14, MpvOpenGLDRMParams),
"drm_draw_surface_size" :(15, MpvOpenGLDRMDrawSurfaceSize),
"drm_display_v2" :(16, MpvOpenGLDRMParamsV2)}
def __init__(self, name, value=None):
if name not in self.TYPES:
raise ValueError('unknown render param type "{}"'.format(name))
self.type_id, cons = self.TYPES[name]
if cons is None:
self.value = None
self.data = c_void_p()
elif cons is str:
self.value = value
self.data = cast(c_char_p(value.encode('utf-8')), c_void_p)
elif cons is bytes:
self.value = MpvByteArray(value)
self.data = cast(pointer(self.value), c_void_p)
elif cons is bool:
self.value = c_int(int(bool(value)))
self.data = cast(pointer(self.value), c_void_p)
else:
self.value = cons(**value)
self.data = cast(pointer(self.value), c_void_p)
def kwargs_to_render_param_array(kwargs):
t = MpvRenderParam * (len(kwargs)+1)
return t(*kwargs.items(), ('invalid', None))
class MpvFormat(c_int): class MpvFormat(c_int):
NONE = 0 NONE = 0
@ -211,6 +314,11 @@ class MpvByteArray(Structure):
_fields_ = [('data', c_void_p), _fields_ = [('data', c_void_p),
('size', c_size_t)] ('size', c_size_t)]
def __init__(self, value):
self._value = value
self.data = cast(c_char_p(value), c_void_p)
self.size = len(value)
def bytes_value(self): def bytes_value(self):
return cast(self.data, POINTER(c_char))[:self.size] return cast(self.data, POINTER(c_char))[:self.size]
@ -357,17 +465,30 @@ StreamOpenFn = CFUNCTYPE(c_int, c_void_p, c_char_p, POINTER(StreamCallbackInfo))
WakeupCallback = CFUNCTYPE(None, c_void_p) WakeupCallback = CFUNCTYPE(None, c_void_p)
RenderUpdateFn = CFUNCTYPE(None, c_void_p)
OpenGlCbUpdateFn = CFUNCTYPE(None, c_void_p) OpenGlCbUpdateFn = CFUNCTYPE(None, c_void_p)
OpenGlCbGetProcAddrFn = CFUNCTYPE(c_void_p, c_void_p, c_char_p) OpenGlCbGetProcAddrFn = CFUNCTYPE(c_void_p, c_void_p, c_char_p)
def _handle_func(name, args, restype, errcheck, ctx=MpvHandle): def _handle_func(name, args, restype, errcheck, ctx=MpvHandle, deprecated=False):
func = getattr(backend, name) func = getattr(backend, name)
func.argtypes = [ctx] + args if ctx else args func.argtypes = [ctx] + args if ctx else args
if restype is not None: if restype is not None:
func.restype = restype func.restype = restype
if errcheck is not None: if errcheck is not None:
func.errcheck = errcheck func.errcheck = errcheck
globals()['_'+name] = func if deprecated:
@wraps(func)
def wrapper(*args, **kwargs):
if not wrapper.warned: # Only warn on first invocation to prevent spamming
warn("Backend C api has been deprecated: " + name, DeprecationWarning, stacklevel=2)
wrapper.warned = True
return func(*args, **kwargs)
wrapper.warned = False
globals()['_'+name] = wrapper
else:
globals()['_'+name] = func
def bytes_free_errcheck(res, func, *args): def bytes_free_errcheck(res, func, *args):
notnull_errcheck(res, func, *args) notnull_errcheck(res, func, *args)
@ -383,8 +504,8 @@ def notnull_errcheck(res, func, *args):
ec_errcheck = ErrorCode.raise_for_ec ec_errcheck = ErrorCode.raise_for_ec
def _handle_gl_func(name, args=[], restype=None): def _handle_gl_func(name, args=[], restype=None, deprecated=False):
_handle_func(name, args, restype, errcheck=None, ctx=MpvOpenGLCbContext) _handle_func(name, args, restype, errcheck=None, ctx=MpvOpenGLCbContext, deprecated=deprecated)
backend.mpv_client_api_version.restype = c_ulong backend.mpv_client_api_version.restype = c_ulong
def _mpv_client_api_version(): def _mpv_client_api_version():
@ -439,14 +560,26 @@ _handle_func('mpv_get_wakeup_pipe', [],
_handle_func('mpv_stream_cb_add_ro', [c_char_p, c_void_p, StreamOpenFn], c_int, ec_errcheck) _handle_func('mpv_stream_cb_add_ro', [c_char_p, c_void_p, StreamOpenFn], c_int, ec_errcheck)
_handle_func('mpv_get_sub_api', [MpvSubApi], c_void_p, notnull_errcheck) _handle_func('mpv_render_context_create', [MpvRenderCtxHandle, MpvHandle, POINTER(MpvRenderParam)], c_int, ec_errcheck, ctx=None)
_handle_func('mpv_render_context_set_parameter', [MpvRenderParam], c_int, ec_errcheck, ctx=MpvRenderCtxHandle)
_handle_func('mpv_render_context_get_info', [MpvRenderParam], c_int, ec_errcheck, ctx=MpvRenderCtxHandle)
_handle_func('mpv_render_context_set_update_callback', [RenderUpdateFn, c_void_p], None, errcheck=None, ctx=MpvRenderCtxHandle)
_handle_func('mpv_render_context_update', [], c_int64, errcheck=None, ctx=MpvRenderCtxHandle)
_handle_func('mpv_render_context_render', [POINTER(MpvRenderParam)], c_int, ec_errcheck, ctx=MpvRenderCtxHandle)
_handle_func('mpv_render_context_report_swap', [], None, errcheck=None, ctx=MpvRenderCtxHandle)
_handle_func('mpv_render_context_free', [], None, errcheck=None, ctx=MpvRenderCtxHandle)
_handle_gl_func('mpv_opengl_cb_set_update_callback', [OpenGlCbUpdateFn, c_void_p])
_handle_gl_func('mpv_opengl_cb_init_gl', [c_char_p, OpenGlCbGetProcAddrFn, c_void_p], c_int) # Deprecated in v0.29.0 and may disappear eventually
_handle_gl_func('mpv_opengl_cb_draw', [c_int, c_int, c_int], c_int) if hasattr(backend, 'mpv_get_sub_api'):
_handle_gl_func('mpv_opengl_cb_render', [c_int, c_int], c_int) _handle_func('mpv_get_sub_api', [MpvSubApi], c_void_p, notnull_errcheck, deprecated=True)
_handle_gl_func('mpv_opengl_cb_report_flip', [c_ulonglong], c_int)
_handle_gl_func('mpv_opengl_cb_uninit_gl', [], c_int) _handle_gl_func('mpv_opengl_cb_set_update_callback', [OpenGlCbUpdateFn, c_void_p], deprecated=True)
_handle_gl_func('mpv_opengl_cb_init_gl', [c_char_p, OpenGlCbGetProcAddrFn, c_void_p], c_int, deprecated=True)
_handle_gl_func('mpv_opengl_cb_draw', [c_int, c_int, c_int], c_int, deprecated=True)
_handle_gl_func('mpv_opengl_cb_render', [c_int, c_int], c_int, deprecated=True)
_handle_gl_func('mpv_opengl_cb_report_flip', [c_ulonglong], c_int, deprecated=True)
_handle_gl_func('mpv_opengl_cb_uninit_gl', [], c_int, deprecated=True)
def _mpv_coax_proptype(value, proptype=str): def _mpv_coax_proptype(value, proptype=str):
@ -1371,3 +1504,54 @@ class MPV(object):
return self._get_property('option-info/'+name) return self._get_property('option-info/'+name)
except AttributeError: except AttributeError:
return None return None
class MpvRenderContext:
def __init__(self, mpv, api_type, **kwargs):
self._mpv = mpv
kwargs['api_type'] = api_type
buf = cast(create_string_buffer(sizeof(MpvRenderCtxHandle)), POINTER(MpvRenderCtxHandle))
_mpv_render_context_create(buf, mpv.handle, kwargs_to_render_param_array(kwargs))
self._handle = buf.contents
def free(self):
_mpv_render_context_free(self._handle)
def __setattr__(self, name, value):
if name.startswith('_'):
super().__setattr__(name, value)
elif name == 'update_cb':
func = value if value else (lambda: None)
self._update_cb = value
self._update_fn_wrapper = RenderUpdateFn(lambda _userdata: func())
_mpv_render_context_set_update_callback(self._handle, self._update_fn_wrapper, None)
else:
param = MpvRenderParam(name, value)
_mpv_render_context_set_parameter(self._handle, param)
def __getattr__(self, name):
if name == 'update_cb':
return self._update_cb
elif name == 'handle':
return self._handle
param = MpvRenderParam(name)
data_type = type(param.data.contents)
buf = cast(create_string_buffer(sizeof(data_type)), POINTER(data_type))
param.data = buf
_mpv_render_context_get_info(self._handle, param)
return buf.contents.as_dict()
def update(self):
""" Calls mpv_render_context_update and returns the MPV_RENDER_UPDATE_FRAME flag (see render.h) """
return bool(_mpv_render_context_update(self._handle) & 1)
def render(self, **kwargs):
_mpv_render_context_render(self._handle, kwargs_to_render_param_array(kwargs))
def report_swap(self):
_mpv_render_context_report_swap(self._handle)