Skip to content

Commit 1bc7e25

Browse files
author
jaseg
committed
Use callback id() instead of frame hash() to identify anonymous python streams
Frame hashes are not unique since the frame isn't kept around for the life time of the stream. Fixes #292.
1 parent e6e9313 commit 1bc7e25

File tree

1 file changed

+18
-9
lines changed

1 file changed

+18
-9
lines changed

mpv.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,6 +1956,10 @@ def python_stream(self, name=None, size=None):
19561956
Any given name can only be registered once. The catch-all can also only be registered once. To unregister a
19571957
stream, call the .unregister function set on the callback.
19581958
1959+
If name is None (the default), a name and corresponding python:// URI are automatically generated. You can
1960+
access the name through the .stream_name property set on the callback, and the stream URI for passing into
1961+
mpv.play(...) through the .stream_uri property.
1962+
19591963
The generator signals EOF by returning, manually raising StopIteration or by yielding b'', an empty bytes
19601964
object.
19611965
@@ -1972,16 +1976,25 @@ def reader():
19721976
reader.unregister()
19731977
"""
19741978
def register(cb):
1979+
nonlocal name
1980+
if name is None:
1981+
name = f'__python_mpv_anonymous_python_stream_{id(cb)}__'
1982+
19751983
if name in self._python_streams:
19761984
raise KeyError('Python stream name "{}" is already registered'.format(name))
1985+
19771986
self._python_streams[name] = (cb, size)
19781987
def unregister():
19791988
if name not in self._python_streams or\
19801989
self._python_streams[name][0] is not cb: # This is just a basic sanity check
19811990
raise RuntimeError('Python stream has already been unregistered')
19821991
del self._python_streams[name]
1992+
19831993
cb.unregister = unregister
1994+
cb.stream_name = name
1995+
cb.stream_uri = f'python://{name}'
19841996
return cb
1997+
19851998
return register
19861999

19872000
@contextmanager
@@ -2003,10 +2016,8 @@ def play_context(self):
20032016
"""
20042017
q = queue.Queue()
20052018

2006-
frame = sys._getframe()
2007-
stream_name = f'__python_mpv_play_generator_{hash(frame)}'
2008-
EOF = frame # Get some unique object as EOF marker
2009-
@self.python_stream(stream_name)
2019+
EOF = object() # Get some unique object as EOF marker
2020+
@self.python_stream()
20102021
def reader():
20112022
while (chunk := q.get()) is not EOF:
20122023
if chunk:
@@ -2017,21 +2028,19 @@ def write(chunk):
20172028
q.put(chunk)
20182029

20192030
# Start playback before yielding, the first call to reader() will block until write is called at least once.
2020-
self.play(f'python://{stream_name}')
2031+
self.play(reader.stream_uri)
20212032
yield write
20222033
q.put(EOF)
20232034

20242035
def play_bytes(self, data):
20252036
""" Play the given bytes object as a single file. """
2026-
frame = sys._getframe()
2027-
stream_name = f'__python_mpv_play_generator_{hash(frame)}'
20282037

2029-
@self.python_stream(stream_name)
2038+
@self.python_stream()
20302039
def reader():
20312040
yield data
20322041
reader.unregister() # unregister itself
20332042

2034-
self.play(f'python://{stream_name}')
2043+
self.play(reader.stream_uri)
20352044

20362045
def python_stream_catchall(self, cb):
20372046
""" Register a catch-all python stream to be called when no name matches can be found. Use this decorator on a

0 commit comments

Comments
 (0)