Hello community, here is the log from the commit of package python-python-mpv for openSUSE:Leap:15.2 checked in at 2020-04-14 14:22:09 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:15.2/python-python-mpv (Old) and /work/SRC/openSUSE:Leap:15.2/.python-python-mpv.new.3248 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-python-mpv" Tue Apr 14 14:22:09 2020 rev:15 rq:793620 version:0.4.6 Changes: -------- --- /work/SRC/openSUSE:Leap:15.2/python-python-mpv/python-python-mpv.changes 2020-03-21 16:47:21.169659252 +0100 +++ /work/SRC/openSUSE:Leap:15.2/.python-python-mpv.new.3248/python-python-mpv.changes 2020-04-14 14:24:01.661410920 +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.xW3OOa/_old 2020-04-14 14:24:01.969411151 +0200 +++ /var/tmp/diff_new_pack.xW3OOa/_new 2020-04-14 14:24:01.973411154 +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 = [
