mpv.py: improve shutdown handling, replace wait_for_playback
This commit is contained in:
parent
cc368710bd
commit
ad68ec5927
1 changed files with 38 additions and 11 deletions
49
mpv.py
49
mpv.py
|
|
@ -53,6 +53,9 @@ else:
|
||||||
fs_enc = sys.getfilesystemencoding()
|
fs_enc = sys.getfilesystemencoding()
|
||||||
|
|
||||||
|
|
||||||
|
class ShutdownError(SystemError):
|
||||||
|
pass
|
||||||
|
|
||||||
class MpvHandle(c_void_p):
|
class MpvHandle(c_void_p):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -633,7 +636,7 @@ def _event_generator(handle):
|
||||||
yield event
|
yield event
|
||||||
|
|
||||||
|
|
||||||
def _event_loop(event_handle, playback_cond, event_callbacks, message_handlers, property_handlers, log_handler):
|
def _event_loop(event_handle, event_callbacks, message_handlers, property_handlers, log_handler):
|
||||||
for event in _event_generator(event_handle):
|
for event in _event_generator(event_handle):
|
||||||
try:
|
try:
|
||||||
devent = event.as_dict(decoder=lazy_decoder) # copy data from ctypes
|
devent = event.as_dict(decoder=lazy_decoder) # copy data from ctypes
|
||||||
|
|
@ -641,10 +644,6 @@ def _event_loop(event_handle, playback_cond, event_callbacks, message_handlers,
|
||||||
for callback in event_callbacks:
|
for callback in event_callbacks:
|
||||||
callback(devent)
|
callback(devent)
|
||||||
|
|
||||||
if eid in (MpvEventID.SHUTDOWN, MpvEventID.END_FILE):
|
|
||||||
with playback_cond:
|
|
||||||
playback_cond.notify_all()
|
|
||||||
|
|
||||||
if eid == MpvEventID.PROPERTY_CHANGE:
|
if eid == MpvEventID.PROPERTY_CHANGE:
|
||||||
pc = devent['event']
|
pc = devent['event']
|
||||||
name, value, _fmt = pc['name'], pc['value'], pc['format']
|
name, value, _fmt = pc['name'], pc['value'], pc['format']
|
||||||
|
|
@ -859,11 +858,11 @@ class MPV(object):
|
||||||
|
|
||||||
self._event_callbacks = []
|
self._event_callbacks = []
|
||||||
self._property_handlers = collections.defaultdict(lambda: [])
|
self._property_handlers = collections.defaultdict(lambda: [])
|
||||||
|
self._quit_handlers = set()
|
||||||
self._message_handlers = {}
|
self._message_handlers = {}
|
||||||
self._key_binding_handlers = {}
|
self._key_binding_handlers = {}
|
||||||
self._playback_cond = threading.Condition()
|
|
||||||
self._event_handle = _mpv_create_client(self.handle, b'py_event_handler')
|
self._event_handle = _mpv_create_client(self.handle, b'py_event_handler')
|
||||||
self._loop = partial(_event_loop, self._event_handle, self._playback_cond, self._event_callbacks,
|
self._loop = partial(_event_loop, self._event_handle, self._event_callbacks,
|
||||||
self._message_handlers, self._property_handlers, log_handler)
|
self._message_handlers, self._property_handlers, log_handler)
|
||||||
self._stream_protocol_cbs = {}
|
self._stream_protocol_cbs = {}
|
||||||
self._stream_protocol_frontends = collections.defaultdict(lambda: {})
|
self._stream_protocol_frontends = collections.defaultdict(lambda: {})
|
||||||
|
|
@ -881,15 +880,30 @@ class MPV(object):
|
||||||
else:
|
else:
|
||||||
self._event_thread = None
|
self._event_thread = None
|
||||||
|
|
||||||
def wait_for_playback(self):
|
self._core_shutdown = False
|
||||||
"""Waits until playback of the current title is paused or done."""
|
# This is the first callback in line, so other event callback-based mechanisms can use core_shutdown
|
||||||
with self._playback_cond:
|
@self.event_callback('shutdown')
|
||||||
self._playback_cond.wait()
|
def shutdown_event_callback(event):
|
||||||
|
nonlocal self
|
||||||
|
self._core_shutdown = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def core_shutdown(self):
|
||||||
|
return self._core_shutdown
|
||||||
|
|
||||||
def wait_until_paused(self):
|
def wait_until_paused(self):
|
||||||
"""Waits until playback of the current title is paused or done."""
|
"""Waits until playback of the current title is paused or done."""
|
||||||
self.wait_for_property('core-idle')
|
self.wait_for_property('core-idle')
|
||||||
|
|
||||||
|
def wait_for_playback(self):
|
||||||
|
"""Waits until playback of the current title is paused or done.
|
||||||
|
|
||||||
|
NOTE: This function changed from an event-based implementation to a property observer-based implementation in
|
||||||
|
v0.5.0. This may cause different results in certain cases. If you find one such case, for documentation please
|
||||||
|
tell the world in an issue on the github project."""
|
||||||
|
self.wait_until_playing()
|
||||||
|
self.wait_until_paused()
|
||||||
|
|
||||||
def wait_until_playing(self):
|
def wait_until_playing(self):
|
||||||
"""Waits until playback of the current title has started."""
|
"""Waits until playback of the current title has started."""
|
||||||
self.wait_for_property('core-idle', lambda idle: not idle)
|
self.wait_for_property('core-idle', lambda idle: not idle)
|
||||||
|
|
@ -899,12 +913,22 @@ class MPV(object):
|
||||||
properties such as ``idle_active`` indicating the player is done with regular playback and just idling around
|
properties such as ``idle_active`` indicating the player is done with regular playback and just idling around
|
||||||
"""
|
"""
|
||||||
sema = threading.Semaphore(value=0)
|
sema = threading.Semaphore(value=0)
|
||||||
|
|
||||||
def observer(name, val):
|
def observer(name, val):
|
||||||
if cond(val):
|
if cond(val):
|
||||||
sema.release()
|
sema.release()
|
||||||
self.observe_property(name, observer)
|
self.observe_property(name, observer)
|
||||||
|
|
||||||
|
@self.event_callback('shutdown')
|
||||||
|
def shutdown_handler(event):
|
||||||
|
sema.release()
|
||||||
|
|
||||||
if not level_sensitive or not cond(getattr(self, name.replace('-', '_'))):
|
if not level_sensitive or not cond(getattr(self, name.replace('-', '_'))):
|
||||||
sema.acquire()
|
sema.acquire()
|
||||||
|
|
||||||
|
if self._core_shutdown:
|
||||||
|
raise ShutdownError('libmpv core has been shutdown')
|
||||||
|
|
||||||
self.unobserve_property(name, observer)
|
self.unobserve_property(name, observer)
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
|
|
@ -1229,6 +1253,9 @@ class MPV(object):
|
||||||
print("It's loud!", volume)
|
print("It's loud!", volume)
|
||||||
|
|
||||||
my_handler.unregister_mpv_properties()
|
my_handler.unregister_mpv_properties()
|
||||||
|
|
||||||
|
exit_handler is a function taking no arguments that is called when the underlying mpv handle is terminated (e.g.
|
||||||
|
from calling MPV.terminate() or issuing a "quit" input command).
|
||||||
"""
|
"""
|
||||||
self._property_handlers[name].append(handler)
|
self._property_handlers[name].append(handler)
|
||||||
_mpv_observe_property(self._event_handle, hash(name)&0xffffffffffffffff, name.encode('utf-8'), MpvFormat.NODE)
|
_mpv_observe_property(self._event_handle, hash(name)&0xffffffffffffffff, name.encode('utf-8'), MpvFormat.NODE)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue