summaryrefslogtreecommitdiff
path: root/content/projects/python-mpv
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2023-12-30 16:38:02 +0100
committerjaseg <git@jaseg.de>2023-12-30 16:38:02 +0100
commit458a5fdfc598517b9fbddd02d3e1ae7cc70ceb9d (patch)
tree0ba3319ddb214bc65dd402de13939cb9ca283574 /content/projects/python-mpv
parent9ee28abd5041ebbbc8acd39ddc84ca37e7255076 (diff)
parent58d54c5debedca8c91b28026f520b226ac8682f6 (diff)
downloadblog-deploy.tar.gz
blog-deploy.tar.bz2
blog-deploy.zip
deploy.py auto-commitdeploy
Diffstat (limited to 'content/projects/python-mpv')
-rw-r--r--content/projects/python-mpv/README.rst401
-rw-r--r--content/projects/python-mpv/index.rst18
2 files changed, 0 insertions, 419 deletions
diff --git a/content/projects/python-mpv/README.rst b/content/projects/python-mpv/README.rst
deleted file mode 100644
index 26815d1..0000000
--- a/content/projects/python-mpv/README.rst
+++ /dev/null
@@ -1,401 +0,0 @@
-.. vim: tw=120 sw=4 et
-
-python-mpv is a ctypes-based python interface to the mpv media player. It gives you more or less full control of all
-features of the player, just as the lua interface does.
-
-Installation
-------------
-
-.. code:: bash
-
- pip install mpv
-
-
-...though you can also realistically just copy `mpv.py`_ into your project as it's all nicely contained in one file.
-
-Requirements
-~~~~~~~~~~~~
-
-libmpv
-......
-``libmpv.so`` either locally (in your current working directory) or somewhere in your system library search path. This
-module is somewhat lenient as far as ``libmpv`` versions are concerned but since ``libmpv`` is changing quite frequently
-you'll only get all the newest features when using an up-to-date version of this module. The unit tests for this module
-do some basic automatic version compatibility checks. If you discover anything missing here, please open an `issue`_ or
-submit a `pull request`_ on github.
-
-On Windows you can place libmpv anywhere in your ``%PATH%`` (e.g. next to ``python.exe``) or next to this module's
-``mpv.py``. Before falling back to looking in the mpv module's directory, python-mpv uses the DLL search order built
-into ctypes, which is different to the one Windows uses internally. Consult `this stackoverflow post
-<https://stackoverflow.com/a/23805306>`__ for details.
-
-Python >= 3.7 (officially)
-..........................
-The ``main`` branch officially only supports recent python releases (3.5 onwards), but there is the somewhat outdated
-but functional `py2compat branch`_ providing Python 2 compatibility.
-
-.. _`py2compat branch`: https://github.com/jaseg/python-mpv/tree/py2compat
-.. _`issue`: https://github.com/jaseg/python-mpv/issues
-.. _`pull request`: https://github.com/jaseg/python-mpv/pulls
-
-Supported Platforms
-...................
-
-**Linux**, **Windows** and **OSX** all seem to work mostly fine. For some notes on the installation on Windows see
-`this comment`__. Shared library handling is quite bad on windows, so expect some pain there. On OSX there seems to be
-some bug int the event logic. See `issue 36`_ and `issue 61`_ for details. Creating a pyQT window and having mpv draw
-into it seems to be a workaround (about 10loc), but in case you want this fixed please weigh in on the issue tracker
-since right now there is not many OSX users.
-
-.. __: https://github.com/jaseg/python-mpv/issues/60#issuecomment-352719773
-.. _`issue 61`: https://github.com/jaseg/python-mpv/issues/61
-.. _`issue 36`: https://github.com/jaseg/python-mpv/issues/36
-
-Usage
------
-
-.. code:: python
-
- 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/main/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
-~~~~~~~~~
-
-The ``mpv`` module starts one thread for event handling, since MPV sends events that must be processed quickly. The
-event queue has a fixed maxmimum size and some operations can cause a large number of events to be sent.
-
-If you want to handle threading yourself, you can pass ``start_event_thread=False`` to the ``MPV`` constructor and
-manually call the ``MPV`` object's ``_loop`` function. If you have some strong need to not use threads and use some
-external event loop (such as asyncio) instead you can do that, too with some work. The API of the backend C ``libmpv``
-has a function for producing a sort of event file descriptor for a handle. You can use that to produce a file descriptor
-that can be passed to an event loop to tell it to wake up the python-mpv event handler on every incoming event.
-
-All API functions are thread-safe. If one is not, please file an issue on github.
-
-Advanced Usage
-~~~~~~~~~~~~~~
-
-Logging, Properties, Python Key Bindings, Screenshots and youtube-dl
-....................................................................
-
-.. code:: python
-
- #!/usr/bin/env python3
- import mpv
-
- def my_log(loglevel, component, message):
- print('[{}] {}: {}'.format(loglevel, component, message))
-
- player = mpv.MPV(log_handler=my_log, ytdl=True, input_default_bindings=True, input_vo_keyboard=True)
-
- # Property access, these can be changed at runtime
- @player.property_observer('time-pos')
- def time_observer(_name, value):
- # Here, _value is either None if nothing is playing or a float containing
- # fractional seconds since the beginning of the file.
- print('Now playing at {:.2f}s'.format(value))
-
- player.fullscreen = True
- player.loop_playlist = 'inf'
- # Option access, in general these require the core to reinitialize
- player['vo'] = 'gpu'
-
- @player.on_key_press('q')
- def my_q_binding():
- print('THERE IS NO ESCAPE')
-
- @player.on_key_press('s')
- def my_s_binding():
- pillow_img = player.screenshot_raw()
- pillow_img.save('screenshot.png')
-
- player.play('https://youtu.be/DLzxrzFCyOs')
- player.wait_for_playback()
-
- del player
-
-Skipping silence using libav filters
-....................................
-
-The following code uses the libav silencedetect filter to skip silence at the beginning of a file. It works by loading
-the filter, then parsing its output from mpv's log. Thanks to Sean DeNigris on github (#202) for the original code!
-
-.. code:: python
-
- #!/usr/bin/env python3
- import sys
- import mpv
-
- p = mpv.MPV()
- p.play(sys.argv[1])
-
- def skip_silence():
- p.set_loglevel('debug')
- p.af = 'lavfi=[silencedetect=n=-20dB:d=1]'
- p.speed = 100
- def check(evt):
- toks = evt['event']['text'].split()
- if 'silence_end:' in toks:
- return float(toks[2])
- p.time_pos = p.wait_for_event('log_message', cond=check)
- p.speed = 1
- p.af = ''
-
- skip_silence()
- p.wait_for_playback()
-
-Video overlays
-..............
-
-.. code:: python
-
- #!/usr/bin/env python3
- import time
- from PIL import Image, ImageDraw, ImageFont
- import mpv
-
- player = mpv.MPV()
-
- player.loop = True
- player.play('test.webm')
- player.wait_until_playing()
-
- font = ImageFont.truetype('DejaVuSans.ttf', 40)
-
- while not player.core_idle:
-
- time.sleep(0.5)
- overlay = player.create_image_overlay()
-
- for pos in range(0, 500, 5):
- ts = player.time_pos
- if ts is None:
- break
-
- img = Image.new('RGBA', (400, 150), (255, 255, 255, 0))
- d = ImageDraw.Draw(img)
- d.text((10, 10), 'Hello World', font=font, fill=(0, 255, 255, 128))
- d.text((10, 60), f't={ts:.3f}', font=font, fill=(255, 0, 255, 255))
-
- overlay.update(img, pos=(2*pos, pos))
- time.sleep(0.05)
-
- overlay.remove()
-
-
-Playlist handling
-.................
-
-.. code:: python
-
- #!/usr/bin/env python3
- import mpv
-
- player = mpv.MPV(ytdl=True, input_default_bindings=True, input_vo_keyboard=True)
-
- player.playlist_append('https://youtu.be/PHIGke6Yzh8')
- player.playlist_append('https://youtu.be/Ji9qSuQapFY')
- player.playlist_append('https://youtu.be/6f78_Tf4Tdk')
-
- player.playlist_pos = 0
-
- while True:
- # To modify the playlist, use player.playlist_{append,clear,move,remove}. player.playlist is read-only
- print(player.playlist)
- player.wait_for_playback()
-
-Directly feeding mpv data from python
-.....................................
-
-.. code:: python
-
- #!/usr/bin/env python3
- import mpv
-
- player = mpv.MPV()
- @player.python_stream('foo')
- def reader():
- with open('test.webm', 'rb') as f:
- while True:
- yield f.read(1024*1024)
-
- player.play('python://foo')
- player.wait_for_playback()
-
-Using external subtitles
-........................
-
-The easiest way to load custom subtitles from a file is to pass the ``--sub-file`` option to the ``loadfile`` call:
-
-.. code:: python
-
- #!/usr/bin/env python3
- import mpv
-
- player = mpv.MPV()
- player.loadfile('test.webm', sub_file='test.srt')
- player.wait_for_playback()
-
-Note that you can also pass many other options to ``loadfile``. See the mpv docs for details.
-
-If you want to add subtitle files or streams at runtime, you can use the ``sub-add`` command. ``sub-add`` can only be
-called once the player is done loading the file and starts playing. An easy way to wait for this is to wait for the
-``core-idle`` property.
-
-.. code:: python
-
- #!/usr/bin/env python3
- import mpv
-
- player = mpv.MPV()
- player.play('test.webm')
- player.wait_until_playing()
- player.sub_add('test.srt')
- 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
-..............
-
-.. code:: python
-
- #!/usr/bin/env python3
- import mpv
- import sys
-
- from PyQt5.QtWidgets import *
- from PyQt5.QtCore import *
-
- class Test(QMainWindow):
- def __init__(self, parent=None):
- super().__init__(parent)
- self.container = QWidget(self)
- self.setCentralWidget(self.container)
- self.container.setAttribute(Qt.WA_DontCreateNativeAncestors)
- self.container.setAttribute(Qt.WA_NativeWindow)
- player = mpv.MPV(wid=str(int(self.container.winId())),
- vo='x11', # You may not need this
- log_handler=print,
- loglevel='debug')
- player.play('test.webm')
-
- app = QApplication(sys.argv)
-
- # This is necessary since PyQT stomps over the locale settings needed by libmpv.
- # This needs to happen after importing PyQT before creating the first mpv.MPV instance.
- import locale
- locale.setlocale(locale.LC_NUMERIC, 'C')
- win = Test()
- win.show()
- sys.exit(app.exec_())
-
-PyGObject embedding
-...................
-
-.. code:: python
-
- #!/usr/bin/env python3
- import gi
-
- import mpv
-
- gi.require_version('Gtk', '3.0')
- from gi.repository import Gtk
-
-
- class MainClass(Gtk.Window):
-
- def __init__(self):
- super(MainClass, self).__init__()
- self.set_default_size(600, 400)
- self.connect("destroy", self.on_destroy)
-
- widget = Gtk.Frame()
- self.add(widget)
- self.show_all()
-
- # Must be created >after< the widget is shown, else property 'window' will be None
- self.mpv = mpv.MPV(wid=str(widget.get_property("window").get_xid()))
- self.mpv.play("test.webm")
-
- def on_destroy(self, widget, data=None):
- self.mpv.terminate()
- Gtk.main_quit()
-
-
- if __name__ == '__main__':
- # This is necessary since like Qt, Gtk stomps over the locale settings needed by libmpv.
- # Like with Qt, this needs to happen after importing Gtk but before creating the first mpv.MPV instance.
- import locale
- locale.setlocale(locale.LC_NUMERIC, 'C')
-
- application = MainClass()
- Gtk.main()
-
-Using OpenGL from PyGObject
-...........................
-
-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 from PyQt5/QML
-...........................
-
-Robozman_ has mangaed to `make mpv render into a PyQt5/QML widget using OpenGL
-<https://gitlab.com/robozman/python-mpv-qml-example>`__ through this python API.
-
-Using mpv inside imgui inside OpenGL via GLFW
-.............................................
-
-dfaker_ has written a demo (`link <https://github.com/dfaker/imgui_glfw_pythonmpv_demo/blob/main/main.py>`__) that uses mpv to render video into an `imgui <https://github.com/ocornut/imgui>`__ UI running on an OpenGL context inside `GLFW <https://www.glfw.org/>`__. Check out their demo to see how to integrate with imgui/OpenGL and how to access properties and manage the lifecycle of an MPV instance.
-
-Running tests
--------------
-
-Use pytest to run tests.
-
-Coding Conventions
-------------------
-
-The general aim is `PEP 8`_, with liberal application of the "consistency" section. 120 cells line width. Four spaces.
-No tabs. Probably don't bother making pure-formatting PRs except if you think it *really* helps readability or it
-*really* irks you if you don't.
-
-License
--------
-
-python-mpv inherits the underlying libmpv's license, which can be either GPLv2 or later (default) or LGPLv2.1 or later.
-For details, see `the mpv copyright page`_.
-
-.. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/
-.. _`mpv.py`: https://raw.githubusercontent.com/jaseg/python-mpv/main/mpv.py
-.. _cosven: https://github.com/cosven
-.. _Robozman: https://gitlab.com/robozman
-.. _dfaker: https://github.com/dfaker
-.. _`the mpv copyright page`: https://github.com/mpv-player/mpv/blob/master/Copyright
-
diff --git a/content/projects/python-mpv/index.rst b/content/projects/python-mpv/index.rst
deleted file mode 100644
index 12b1c18..0000000
--- a/content/projects/python-mpv/index.rst
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: "python-mpv"
-external_links:
- - name: Sources
- url: "https://git.jaseg.de/python-mpv.git"
- - name: Issues
- url: "https://github.com/jaseg/python-mpv/issues"
- - name: Docs
- url: "https://neinseg.gitlab.io/python-mpv"
- - name: PyPI
- url: "https://pypi.org/project/mpv"
-summary: >
- python-mpv is a small, ctypes-based Python library wrapping the libmpv media player library. Despite its small size
- and simple API, python-mpv allows advanced control over libmpv and beyond simple remote control of mpv can be used
- to embed mpv in OpenGL, Qt, and GTK-based Python applications.
----
-
-.. include:: content/projects/python-mpv/README.rst