Hello community,
here is the log from the commit of package python-python-mpv for
openSUSE:Factory checked in at 2020-04-07 10:28:26
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-python-mpv (Old)
and /work/SRC/openSUSE:Factory/.python-python-mpv.new.3248 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-python-mpv"
Tue Apr 7 10:28:26 2020 rev:11 rq:791535 version:0.4.6
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-python-mpv/python-python-mpv.changes
2020-03-19 19:53:58.860277006 +0100
+++
/work/SRC/openSUSE:Factory/.python-python-mpv.new.3248/python-python-mpv.changes
2020-04-07 10:28:44.110323733 +0200
@@ -1,0 +2,11 @@
+Sun Apr 5 11:47:16 UTC 2020 - [email protected]
+
+- Update to version v0.4.6
+ * Make tests run headless using xvfbwrapper
+ * Add some high-level API information to README
+ * README: Add info on GUI modes
+ * README: add render context gtk example
+ * Initial libmpv/render.h mapping
+ * Add GTK/OpenGL example (#100)
+
+-------------------------------------------------------------------
Old:
----
python-mpv-0.4.5.tar.gz
New:
----
python-mpv-0.4.6.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-python-mpv.spec ++++++
--- /var/tmp/diff_new_pack.7TkJ2R/_old 2020-04-07 10:28:44.534324203 +0200
+++ /var/tmp/diff_new_pack.7TkJ2R/_new 2020-04-07 10:28:44.538324208 +0200
@@ -17,7 +17,7 @@
Name: python-python-mpv
-Version: 0.4.5
+Version: 0.4.6
Release: 0
Summary: Python interface to the mpv media player
License: AGPL-3.0-or-later
++++++ python-mpv-0.4.5.tar.gz -> python-mpv-0.4.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-mpv-0.4.5/PKG-INFO
new/python-mpv-0.4.6/PKG-INFO
--- old/python-mpv-0.4.5/PKG-INFO 2019-12-04 09:49:29.000000000 +0100
+++ new/python-mpv-0.4.6/PKG-INFO 2020-04-05 13:05:16.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: python-mpv
-Version: 0.4.5
+Version: 0.4.6
Summary: A python interface to the mpv media player
Home-page: https://github.com/jaseg/python-mpv
Author: jaseg
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-mpv-0.4.5/README.rst
new/python-mpv-0.4.6/README.rst
--- old/python-mpv-0.4.5/README.rst 2019-12-04 09:46:21.000000000 +0100
+++ new/python-mpv-0.4.6/README.rst 2020-04-05 12:47:34.000000000 +0200
@@ -62,6 +62,9 @@
import mpv
player = mpv.MPV(ytdl=True)
player.play('https://youtu.be/DOmdB7D-pUU')
+ player.wait_for_playback()
+
+python-mpv mostly exposes mpv's built-in API to python, adding only some
porcelain on top. Most "`input commands
<https://mpv.io/manual/master/#list-of-input-commands>`_" are mapped to methods
of the MPV class. Check out these methods and their docstrings in `the source
<https://github.com/jaseg/python-mpv/blob/master/mpv.py>`__ for things you can
do. Additional controls and status information are exposed through `MPV
properties <https://mpv.io/manual/master/#properties>`_. These can be accessed
like ``player.metadata``, ``player.fullscreen`` and ``player.loop_playlist``.
Threading
~~~~~~~~~
@@ -158,6 +161,27 @@
player.play('python://foo')
player.wait_for_playback()
+Using MPV's built-in GUI
+........................
+
+python-mpv is using mpv via libmpv. libmpv is meant for embedding into other
applications and by default disables most
+GUI features such as the OSD or keyboard input. To enable the built-in GUI,
use the following options when initializing
+the MPV instance. See `Issue 102`_ for more details
+
+.. _`issue 102`: https://github.com/jaseg/python-mpv/issues/61
+
+.. code:: python
+
+ # Enable the on-screen controller and keyboard shortcuts
+ player = mpv.MPV(input_default_bindings=True, input_vo_keyboard=True,
osc=True)
+
+ # Alternative version using the old "floating box" style on-screen
controller
+ player = mpv.MPV(player_operation_mode='pseudo-gui',
+
script_opts='osc-layout=box,osc-seekbarstyle=bar,osc-deadzonesize=0,osc-minmousemove=3',
+ input_default_bindings=True,
+ input_vo_keyboard=True,
+ osc=True)
+
PyQT embedding
..............
@@ -193,8 +217,8 @@
win.show()
sys.exit(app.exec_())
-PyGtk embedding
-..............
+PyGObject embedding
+...................
.. code:: python
@@ -231,12 +255,24 @@
application = MainClass()
Gtk.main()
-Using OpenGL from PyQT
-......................
+Using OpenGL from PyGObject via new render context API
+......................................................
+
+Just like it is possible to render into a GTK widget through X11 windows, it
`also is possible to render into a GTK
+widget using OpenGL
<https://gist.github.com/jaseg/657e8ecca3267c0d82ec85d40f423caa>`__ through
this python API.
+
+Using OpenGL via legacy opengl_cb backend from PyQT
+...................................................
Github user cosven_ has managed to `make mpv render into a Qt widget using
OpenGL
<https://gist.github.com/cosven/b313de2acce1b7e15afda263779c0afc>`__ through
this python API.
+Using OpenGL via legacy opengl_cb backend from PyGObject
+........................................................
+
+Just like it is possible to render into a Qt widget, it `also is possible to
render into a GTK widget
+<https://gist.github.com/trin94/a930f2a13cee1c9fd21cab0393bf4663>`__ through
this python API.
+
Coding Conventions
------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-mpv-0.4.5/mpv.py new/python-mpv-0.4.6/mpv.py
--- old/python-mpv-0.4.5/mpv.py 2019-12-04 09:48:07.000000000 +0100
+++ new/python-mpv-0.4.6/mpv.py 2020-01-03 01:08:05.000000000 +0100
@@ -56,6 +56,9 @@
class MpvHandle(c_void_p):
pass
+class MpvRenderCtxHandle(c_void_p):
+ pass
+
class MpvOpenGLCbContext(c_void_p):
pass
@@ -125,6 +128,106 @@
if ex:
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):
NONE = 0
@@ -211,6 +314,11 @@
_fields_ = [('data', c_void_p),
('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):
return cast(self.data, POINTER(c_char))[:self.size]
@@ -357,17 +465,30 @@
WakeupCallback = CFUNCTYPE(None, c_void_p)
+RenderUpdateFn = CFUNCTYPE(None, c_void_p)
+
OpenGlCbUpdateFn = CFUNCTYPE(None, c_void_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.argtypes = [ctx] + args if ctx else args
if restype is not None:
func.restype = restype
if errcheck is not None:
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):
notnull_errcheck(res, func, *args)
@@ -383,8 +504,8 @@
ec_errcheck = ErrorCode.raise_for_ec
-def _handle_gl_func(name, args=[], restype=None):
- _handle_func(name, args, restype, errcheck=None, ctx=MpvOpenGLCbContext)
+def _handle_gl_func(name, args=[], restype=None, deprecated=False):
+ _handle_func(name, args, restype, errcheck=None, ctx=MpvOpenGLCbContext,
deprecated=deprecated)
backend.mpv_client_api_version.restype = c_ulong
def _mpv_client_api_version():
@@ -439,14 +560,26 @@
_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_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)
-_handle_gl_func('mpv_opengl_cb_draw', [c_int, c_int, c_int],
c_int)
-_handle_gl_func('mpv_opengl_cb_render', [c_int, c_int],
c_int)
-_handle_gl_func('mpv_opengl_cb_report_flip', [c_ulonglong],
c_int)
-_handle_gl_func('mpv_opengl_cb_uninit_gl', [],
c_int)
+_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)
+
+
+# Deprecated in v0.29.0 and may disappear eventually
+if hasattr(backend, 'mpv_get_sub_api'):
+ _handle_func('mpv_get_sub_api', [MpvSubApi],
c_void_p, notnull_errcheck, deprecated=True)
+
+ _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):
@@ -1371,3 +1504,54 @@
return self._get_property('option-info/'+name)
except AttributeError:
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)
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-mpv-0.4.5/python_mpv.egg-info/PKG-INFO
new/python-mpv-0.4.6/python_mpv.egg-info/PKG-INFO
--- old/python-mpv-0.4.5/python_mpv.egg-info/PKG-INFO 2019-12-04
09:49:29.000000000 +0100
+++ new/python-mpv-0.4.6/python_mpv.egg-info/PKG-INFO 2020-04-05
13:05:16.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: python-mpv
-Version: 0.4.5
+Version: 0.4.6
Summary: A python interface to the mpv media player
Home-page: https://github.com/jaseg/python-mpv
Author: jaseg
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-mpv-0.4.5/setup.py
new/python-mpv-0.4.6/setup.py
--- old/python-mpv-0.4.5/setup.py 2019-12-04 09:48:54.000000000 +0100
+++ new/python-mpv-0.4.6/setup.py 2020-04-05 12:49:00.000000000 +0200
@@ -3,7 +3,7 @@
from setuptools import setup
setup(
name = 'python-mpv',
- version = '0.4.5',
+ version = '0.4.6',
py_modules = ['mpv'],
description = 'A python interface to the mpv media player',
url = 'https://github.com/jaseg/python-mpv',
@@ -13,6 +13,8 @@
extras_require = {
'screenshot_raw': ['Pillow']
},
+ tests_require = ['xvfbwrapper'],
+ test_suite = 'mpv-test',
keywords = ['mpv', 'library', 'video', 'audio', 'player', 'display',
'multimedia'],
classifiers = [