mpv.py: add support for asynchronous commands
This commit is contained in:
parent
e8c8736a1a
commit
107c563f8d
1 changed files with 48 additions and 4 deletions
52
mpv.py
52
mpv.py
|
|
@ -390,6 +390,7 @@ class MpvEvent(Structure):
|
||||||
|
|
||||||
def as_dict(self, decoder=identity_decoder):
|
def as_dict(self, decoder=identity_decoder):
|
||||||
dtype = {MpvEventID.END_FILE: MpvEventEndFile,
|
dtype = {MpvEventID.END_FILE: MpvEventEndFile,
|
||||||
|
MpvEventID.COMMAND_REPLY: MpvEventCommand,
|
||||||
MpvEventID.PROPERTY_CHANGE: MpvEventProperty,
|
MpvEventID.PROPERTY_CHANGE: MpvEventProperty,
|
||||||
MpvEventID.GET_PROPERTY_REPLY: MpvEventProperty,
|
MpvEventID.GET_PROPERTY_REPLY: MpvEventProperty,
|
||||||
MpvEventID.LOG_MESSAGE: MpvEventLogMessage,
|
MpvEventID.LOG_MESSAGE: MpvEventLogMessage,
|
||||||
|
|
@ -455,6 +456,14 @@ class MpvEventClientMessage(Structure):
|
||||||
def as_dict(self, decoder=identity_decoder):
|
def as_dict(self, decoder=identity_decoder):
|
||||||
return { 'args': [ self.args[i].decode('utf-8') for i in range(self.num_args) ] }
|
return { 'args': [ self.args[i].decode('utf-8') for i in range(self.num_args) ] }
|
||||||
|
|
||||||
|
|
||||||
|
class MpvEventCommand(Structure):
|
||||||
|
_fields_ = [('result', MpvNode)]
|
||||||
|
|
||||||
|
def as_dict(self, decoder=identity_decoder):
|
||||||
|
return {'result': self.result.node_value(decoder)}
|
||||||
|
|
||||||
|
|
||||||
StreamReadFn = CFUNCTYPE(c_int64, c_void_p, POINTER(c_char), c_uint64)
|
StreamReadFn = CFUNCTYPE(c_int64, c_void_p, POINTER(c_char), c_uint64)
|
||||||
StreamSeekFn = CFUNCTYPE(c_int64, c_void_p, c_int64)
|
StreamSeekFn = CFUNCTYPE(c_int64, c_void_p, c_int64)
|
||||||
StreamSizeFn = CFUNCTYPE(c_int64, c_void_p)
|
StreamSizeFn = CFUNCTYPE(c_int64, c_void_p)
|
||||||
|
|
@ -544,7 +553,6 @@ _handle_func('mpv_command', [POINTER(c_char_p)],
|
||||||
_handle_func('mpv_command_string', [c_char_p, c_char_p], c_int, ec_errcheck)
|
_handle_func('mpv_command_string', [c_char_p, c_char_p], c_int, ec_errcheck)
|
||||||
_handle_func('mpv_command_async', [c_ulonglong, POINTER(c_char_p)], c_int, ec_errcheck)
|
_handle_func('mpv_command_async', [c_ulonglong, POINTER(c_char_p)], c_int, ec_errcheck)
|
||||||
_handle_func('mpv_command_node', [POINTER(MpvNode), POINTER(MpvNode)], c_int, ec_errcheck)
|
_handle_func('mpv_command_node', [POINTER(MpvNode), POINTER(MpvNode)], c_int, ec_errcheck)
|
||||||
_handle_func('mpv_command_async', [c_ulonglong, POINTER(MpvNode)], c_int, ec_errcheck)
|
|
||||||
|
|
||||||
_handle_func('mpv_set_property', [c_char_p, MpvFormat, c_void_p], c_int, ec_errcheck)
|
_handle_func('mpv_set_property', [c_char_p, MpvFormat, c_void_p], c_int, ec_errcheck)
|
||||||
_handle_func('mpv_set_property_string', [c_char_p, c_char_p], c_int, ec_errcheck)
|
_handle_func('mpv_set_property_string', [c_char_p, c_char_p], c_int, ec_errcheck)
|
||||||
|
|
@ -641,6 +649,12 @@ def _event_generator(handle):
|
||||||
yield event
|
yield event
|
||||||
|
|
||||||
|
|
||||||
|
def _create_null_term_cmd_arg_array(name, args):
|
||||||
|
args = [name.encode('utf-8')] + [(arg if type(arg) is bytes else str(arg).encode('utf-8'))
|
||||||
|
for arg in args if arg is not None] + [None]
|
||||||
|
return (c_char_p * len(args))(*args)
|
||||||
|
|
||||||
|
|
||||||
_py_to_mpv = lambda name: name.replace('_', '-')
|
_py_to_mpv = lambda name: name.replace('_', '-')
|
||||||
_mpv_to_py = lambda name: name.replace('-', '_')
|
_mpv_to_py = lambda name: name.replace('-', '_')
|
||||||
|
|
||||||
|
|
@ -805,6 +819,9 @@ class MPV(object):
|
||||||
|
|
||||||
To make your program not barf hard the first time its used on a weird file system **always** access properties
|
To make your program not barf hard the first time its used on a weird file system **always** access properties
|
||||||
containing file names or file tags through ``MPV.raw``. """
|
containing file names or file tags through ``MPV.raw``. """
|
||||||
|
|
||||||
|
_UINT_64_MAX = 2 ** 64 - 1
|
||||||
|
|
||||||
def __init__(self, *extra_mpv_flags, log_handler=None, start_event_thread=True, loglevel=None, **extra_mpv_opts):
|
def __init__(self, *extra_mpv_flags, log_handler=None, start_event_thread=True, loglevel=None, **extra_mpv_opts):
|
||||||
"""Create an MPV instance.
|
"""Create an MPV instance.
|
||||||
|
|
||||||
|
|
@ -832,6 +849,9 @@ class MPV(object):
|
||||||
self.lazy = _DecoderPropertyProxy(self, lazy_decoder)
|
self.lazy = _DecoderPropertyProxy(self, lazy_decoder)
|
||||||
|
|
||||||
self._event_callbacks = []
|
self._event_callbacks = []
|
||||||
|
self._event_async_callbacks = {}
|
||||||
|
self._event_async_callback_counter = 0
|
||||||
|
self._event_async_callback_counter_lock = threading.Lock()
|
||||||
self._event_handler_lock = threading.Lock()
|
self._event_handler_lock = threading.Lock()
|
||||||
self._property_handlers = collections.defaultdict(lambda: [])
|
self._property_handlers = collections.defaultdict(lambda: [])
|
||||||
self._quit_handlers = set()
|
self._quit_handlers = set()
|
||||||
|
|
@ -884,6 +904,15 @@ class MPV(object):
|
||||||
if target in self._message_handlers:
|
if target in self._message_handlers:
|
||||||
self._message_handlers[target](*args)
|
self._message_handlers[target](*args)
|
||||||
|
|
||||||
|
if eid == MpvEventID.COMMAND_REPLY:
|
||||||
|
key = devent['reply_userdata']
|
||||||
|
err = devent['error']
|
||||||
|
callback = self._event_async_callbacks.pop(key, None)
|
||||||
|
if callback:
|
||||||
|
callback(err, devent['event']['result'])
|
||||||
|
elif err:
|
||||||
|
warn('Error while executing asynchronous command')
|
||||||
|
|
||||||
if eid == MpvEventID.SHUTDOWN:
|
if eid == MpvEventID.SHUTDOWN:
|
||||||
_mpv_destroy(self._event_handle)
|
_mpv_destroy(self._event_handle)
|
||||||
return
|
return
|
||||||
|
|
@ -1072,9 +1101,17 @@ class MPV(object):
|
||||||
|
|
||||||
def string_command(self, name, *args):
|
def string_command(self, name, *args):
|
||||||
"""Execute a raw command."""
|
"""Execute a raw command."""
|
||||||
args = [name.encode('utf-8')] + [ (arg if type(arg) is bytes else str(arg).encode('utf-8'))
|
args = _create_null_term_cmd_arg_array(name, args)
|
||||||
for arg in args if arg is not None ] + [None]
|
_mpv_command(self.handle, args)
|
||||||
_mpv_command(self.handle, (c_char_p*len(args))(*args))
|
|
||||||
|
def command_async(self, name, *args, callback=None):
|
||||||
|
"""Same as mpv_command, but run the command asynchronously. Once the command ran, the callback will be invoked,
|
||||||
|
if provided. The first argument of the callback will be a boolean value. It will be set to True, if there was an
|
||||||
|
error, False else. The second argument of the callback depends on the command.
|
||||||
|
"""
|
||||||
|
args = _create_null_term_cmd_arg_array(name, args)
|
||||||
|
key = self._register_async_callback(callback)
|
||||||
|
_mpv_command_async(self._event_handle, key, args)
|
||||||
|
|
||||||
def node_command(self, name, *args, decoder=strict_decoder):
|
def node_command(self, name, *args, decoder=strict_decoder):
|
||||||
self.command(name, *args, decoder=decoder)
|
self.command(name, *args, decoder=decoder)
|
||||||
|
|
@ -1853,6 +1890,13 @@ class MPV(object):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _register_async_callback(self, callback):
|
||||||
|
with self._event_async_callback_counter_lock:
|
||||||
|
key = self._event_async_callback_counter = (self._event_async_callback_counter + 1) % MPV._UINT_64_MAX
|
||||||
|
self._event_async_callbacks[key] = callback
|
||||||
|
return key
|
||||||
|
|
||||||
|
|
||||||
class MpvRenderContext:
|
class MpvRenderContext:
|
||||||
def __init__(self, mpv, api_type, **kwargs):
|
def __init__(self, mpv, api_type, **kwargs):
|
||||||
self._mpv = mpv
|
self._mpv = mpv
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue