diff options
author | jaseg <git@jaseg.de> | 2023-03-19 00:54:56 +0100 |
---|---|---|
committer | jaseg <git@jaseg.de> | 2023-03-19 00:54:56 +0100 |
commit | 490ca12809a2625549aae16311affdd546e9c201 (patch) | |
tree | 58024389e48d91731efa352ae772a058b376b8cf /projects/python-mpv/index.html | |
parent | 92e3b5f49f6f5336530988e7839ab3ed283b86e4 (diff) | |
parent | f21dea91904d7bf9628457a5758016c9a0df6d38 (diff) | |
download | blog-490ca12809a2625549aae16311affdd546e9c201.tar.gz blog-490ca12809a2625549aae16311affdd546e9c201.tar.bz2 blog-490ca12809a2625549aae16311affdd546e9c201.zip |
deploy.py auto-commit
Diffstat (limited to 'projects/python-mpv/index.html')
-rw-r--r-- | projects/python-mpv/index.html | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/projects/python-mpv/index.html b/projects/python-mpv/index.html new file mode 100644 index 0000000..e789ace --- /dev/null +++ b/projects/python-mpv/index.html @@ -0,0 +1,391 @@ +<!DOCTYPE html> +<html><head> + <meta charset="utf-8"> + <title>python-mpv | Home</title> + <meta name="description" content=""> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <meta name="mobile-web-app-capable" content="yes"> + <meta name="color-scheme" content="dark light"> + <link rel="stylesheet" href="/style.css"> +</head> +<body><nav> + + <a href="/" title="Home">Home</a> + <a href="/blog/" title="Blog">Blog</a> + <a href="/projects/" title="Projects">Projects</a> + <a href="/about/" title="About">About</a> + <span class="spacer"></span> + <a href="https://git.jaseg.de/" title="cgit">cgit</a> + <a href="https://github.com/jaseg" title="Github">Github</a> + <a href="https://gitlab.com/neinseg" title="Gitlab">Gitlab</a> + <a href="https://chaos.social/jaseg" title="Mastodon">Mastodon</a> +</nav> + + <header> + <h1>python-mpv</h1> +<ul class="breadcrumbs"> + <li><a href="/">jaseg.de</a></li> + <li><a href="/projects/">Projects</a></li><li><a href="/projects/python-mpv/">python-mpv</a></li> +</ul> + + </header> + <main> + <div class="document"> + + +<!-- vim: tw=120 sw=4 et --> +<p>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.</p> +<div class="section" id="installation"> +<h2>Installation</h2> +<pre class="code bash literal-block"> +pip<span class="whitespace"> </span>install<span class="whitespace"> </span>mpv +</pre> +<p>...though you can also realistically just copy <a class="reference external" href="https://raw.githubusercontent.com/jaseg/python-mpv/main/mpv.py">mpv.py</a> into your project as it's all nicely contained in one file.</p> +<div class="section" id="requirements"> +<h3>Requirements</h3> +<div class="section" id="libmpv"> +<h4>libmpv</h4> +<p><tt class="docutils literal">libmpv.so</tt> either locally (in your current working directory) or somewhere in your system library search path. This +module is somewhat lenient as far as <tt class="docutils literal">libmpv</tt> versions are concerned but since <tt class="docutils literal">libmpv</tt> 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 <a class="reference external" href="https://github.com/jaseg/python-mpv/issues">issue</a> or +submit a <a class="reference external" href="https://github.com/jaseg/python-mpv/pulls">pull request</a> on github.</p> +<p>On Windows you can place libmpv anywhere in your <tt class="docutils literal">%PATH%</tt> (e.g. next to <tt class="docutils literal">python.exe</tt>) or next to this module's +<tt class="docutils literal">mpv.py</tt>. 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 <a class="reference external" href="https://stackoverflow.com/a/23805306">this stackoverflow post</a> for details.</p> +</div> +<div class="section" id="python-3-7-officially"> +<h4>Python >= 3.7 (officially)</h4> +<p>The <tt class="docutils literal">main</tt> branch officially only supports recent python releases (3.5 onwards), but there is the somewhat outdated +but functional <a class="reference external" href="https://github.com/jaseg/python-mpv/tree/py2compat">py2compat branch</a> providing Python 2 compatibility.</p> +</div> +<div class="section" id="supported-platforms"> +<h4>Supported Platforms</h4> +<p><strong>Linux</strong>, <strong>Windows</strong> and <strong>OSX</strong> all seem to work mostly fine. For some notes on the installation on Windows see +<a class="reference external" href="https://github.com/jaseg/python-mpv/issues/60#issuecomment-352719773">this comment</a>. 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 <a class="reference external" href="https://github.com/jaseg/python-mpv/issues/36">issue 36</a> and <a class="reference external" href="https://github.com/jaseg/python-mpv/issues/61">issue 61</a> 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.</p> +</div> +</div> +</div> +<div class="section" id="usage"> +<h2>Usage</h2> +<pre class="code python literal-block"> +<span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace"> +</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">ytdl</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string single">'https://youtu.be/DOmdB7D-pUU'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span> +</pre> +<p>python-mpv mostly exposes mpv's built-in API to python, adding only some porcelain on top. Most "<a class="reference external" href="https://mpv.io/manual/master/#list-of-input-commands">input commands</a>" are mapped to methods of the MPV class. Check out these methods and their docstrings in <a class="reference external" href="https://github.com/jaseg/python-mpv/blob/main/mpv.py">the source</a> for things you can do. Additional controls and status information are exposed through <a class="reference external" href="https://mpv.io/manual/master/#properties">MPV properties</a>. These can be accessed like <tt class="docutils literal">player.metadata</tt>, <tt class="docutils literal">player.fullscreen</tt> and <tt class="docutils literal">player.loop_playlist</tt>.</p> +<div class="section" id="threading"> +<h3>Threading</h3> +<p>The <tt class="docutils literal">mpv</tt> 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.</p> +<p>If you want to handle threading yourself, you can pass <tt class="docutils literal">start_event_thread=False</tt> to the <tt class="docutils literal">MPV</tt> constructor and +manually call the <tt class="docutils literal">MPV</tt> object's <tt class="docutils literal">_loop</tt> 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 <tt class="docutils literal">libmpv</tt> +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.</p> +<p>All API functions are thread-safe. If one is not, please file an issue on github.</p> +</div> +<div class="section" id="advanced-usage"> +<h3>Advanced Usage</h3> +<div class="section" id="logging-properties-python-key-bindings-screenshots-and-youtube-dl"> +<h4>Logging, Properties, Python Key Bindings, Screenshots and youtube-dl</h4> +<pre class="code python literal-block"> +<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace"> + +</span><span class="keyword">def</span> <span class="name function">my_log</span><span class="punctuation">(</span><span class="name">loglevel</span><span class="punctuation">,</span> <span class="name">component</span><span class="punctuation">,</span> <span class="name">message</span><span class="punctuation">):</span><span class="whitespace"> +</span> <span class="name builtin">print</span><span class="punctuation">(</span><span class="literal string single">'[</span><span class="literal string interpol">{}</span><span class="literal string single">] </span><span class="literal string interpol">{}</span><span class="literal string single">: </span><span class="literal string interpol">{}</span><span class="literal string single">'</span><span class="operator">.</span><span class="name">format</span><span class="punctuation">(</span><span class="name">loglevel</span><span class="punctuation">,</span> <span class="name">component</span><span class="punctuation">,</span> <span class="name">message</span><span class="punctuation">))</span><span class="whitespace"> + +</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">log_handler</span><span class="operator">=</span><span class="name">my_log</span><span class="punctuation">,</span> <span class="name">ytdl</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span> <span class="name">input_default_bindings</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span> <span class="name">input_vo_keyboard</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">)</span><span class="whitespace"> + +</span><span class="comment single"># Property access, these can be changed at runtime</span><span class="whitespace"> +</span><span class="name decorator">@player</span><span class="operator">.</span><span class="name">property_observer</span><span class="punctuation">(</span><span class="literal string single">'time-pos'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="keyword">def</span> <span class="name function">time_observer</span><span class="punctuation">(</span><span class="name">_name</span><span class="punctuation">,</span> <span class="name">value</span><span class="punctuation">):</span><span class="whitespace"> +</span> <span class="comment single"># Here, _value is either None if nothing is playing or a float containing</span><span class="whitespace"> +</span> <span class="comment single"># fractional seconds since the beginning of the file.</span><span class="whitespace"> +</span> <span class="name builtin">print</span><span class="punctuation">(</span><span class="literal string single">'Now playing at </span><span class="literal string interpol">{:.2f}</span><span class="literal string single">s'</span><span class="operator">.</span><span class="name">format</span><span class="punctuation">(</span><span class="name">value</span><span class="punctuation">))</span><span class="whitespace"> + +</span><span class="name">player</span><span class="operator">.</span><span class="name">fullscreen</span> <span class="operator">=</span> <span class="keyword constant">True</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">loop_playlist</span> <span class="operator">=</span> <span class="literal string single">'inf'</span><span class="whitespace"> +</span><span class="comment single"># Option access, in general these require the core to reinitialize</span><span class="whitespace"> +</span><span class="name">player</span><span class="punctuation">[</span><span class="literal string single">'vo'</span><span class="punctuation">]</span> <span class="operator">=</span> <span class="literal string single">'gpu'</span><span class="whitespace"> + +</span><span class="name decorator">@player</span><span class="operator">.</span><span class="name">on_key_press</span><span class="punctuation">(</span><span class="literal string single">'q'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="keyword">def</span> <span class="name function">my_q_binding</span><span class="punctuation">():</span><span class="whitespace"> +</span> <span class="name builtin">print</span><span class="punctuation">(</span><span class="literal string single">'THERE IS NO ESCAPE'</span><span class="punctuation">)</span><span class="whitespace"> + +</span><span class="name decorator">@player</span><span class="operator">.</span><span class="name">on_key_press</span><span class="punctuation">(</span><span class="literal string single">'s'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="keyword">def</span> <span class="name function">my_s_binding</span><span class="punctuation">():</span><span class="whitespace"> +</span> <span class="name">pillow_img</span> <span class="operator">=</span> <span class="name">player</span><span class="operator">.</span><span class="name">screenshot_raw</span><span class="punctuation">()</span><span class="whitespace"> +</span> <span class="name">pillow_img</span><span class="operator">.</span><span class="name">save</span><span class="punctuation">(</span><span class="literal string single">'screenshot.png'</span><span class="punctuation">)</span><span class="whitespace"> + +</span><span class="name">player</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string single">'https://youtu.be/DLzxrzFCyOs'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span><span class="whitespace"> + +</span><span class="keyword">del</span> <span class="name">player</span> +</pre> +</div> +<div class="section" id="skipping-silence-using-libav-filters"> +<h4>Skipping silence using libav filters</h4> +<p>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!</p> +<pre class="code python literal-block"> +<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">sys</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace"> + +</span><span class="name">p</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">()</span><span class="whitespace"> +</span><span class="name">p</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="name">sys</span><span class="operator">.</span><span class="name">argv</span><span class="punctuation">[</span><span class="literal number integer">1</span><span class="punctuation">])</span><span class="whitespace"> + +</span><span class="keyword">def</span> <span class="name function">skip_silence</span><span class="punctuation">():</span><span class="whitespace"> +</span> <span class="name">p</span><span class="operator">.</span><span class="name">set_loglevel</span><span class="punctuation">(</span><span class="literal string single">'debug'</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name">p</span><span class="operator">.</span><span class="name">af</span> <span class="operator">=</span> <span class="literal string single">'lavfi=[silencedetect=n=-20dB:d=1]'</span><span class="whitespace"> +</span> <span class="name">p</span><span class="operator">.</span><span class="name">speed</span> <span class="operator">=</span> <span class="literal number integer">100</span><span class="whitespace"> +</span> <span class="keyword">def</span> <span class="name function">check</span><span class="punctuation">(</span><span class="name">evt</span><span class="punctuation">):</span><span class="whitespace"> +</span> <span class="name">toks</span> <span class="operator">=</span> <span class="name">evt</span><span class="punctuation">[</span><span class="literal string single">'event'</span><span class="punctuation">][</span><span class="literal string single">'text'</span><span class="punctuation">]</span><span class="operator">.</span><span class="name">split</span><span class="punctuation">()</span><span class="whitespace"> +</span> <span class="keyword">if</span> <span class="literal string single">'silence_end:'</span> <span class="operator word">in</span> <span class="name">toks</span><span class="punctuation">:</span><span class="whitespace"> +</span> <span class="keyword">return</span> <span class="name builtin">float</span><span class="punctuation">(</span><span class="name">toks</span><span class="punctuation">[</span><span class="literal number integer">2</span><span class="punctuation">])</span><span class="whitespace"> +</span> <span class="name">p</span><span class="operator">.</span><span class="name">time_pos</span> <span class="operator">=</span> <span class="name">p</span><span class="operator">.</span><span class="name">wait_for_event</span><span class="punctuation">(</span><span class="literal string single">'log_message'</span><span class="punctuation">,</span> <span class="name">cond</span><span class="operator">=</span><span class="name">check</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name">p</span><span class="operator">.</span><span class="name">speed</span> <span class="operator">=</span> <span class="literal number integer">1</span><span class="whitespace"> +</span> <span class="name">p</span><span class="operator">.</span><span class="name">af</span> <span class="operator">=</span> <span class="literal string single">''</span><span class="whitespace"> + +</span><span class="name">skip_silence</span><span class="punctuation">()</span><span class="whitespace"> +</span><span class="name">p</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span> +</pre> +</div> +<div class="section" id="video-overlays"> +<h4>Video overlays</h4> +<pre class="code python literal-block"> +<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">time</span><span class="whitespace"> +</span><span class="keyword namespace">from</span> <span class="name namespace">PIL</span> <span class="keyword namespace">import</span> <span class="name">Image</span><span class="punctuation">,</span> <span class="name">ImageDraw</span><span class="punctuation">,</span> <span class="name">ImageFont</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace"> + +</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">()</span><span class="whitespace"> + +</span><span class="name">player</span><span class="operator">.</span><span class="name">loop</span> <span class="operator">=</span> <span class="keyword constant">True</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string single">'test.webm'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_until_playing</span><span class="punctuation">()</span><span class="whitespace"> + +</span><span class="name">font</span> <span class="operator">=</span> <span class="name">ImageFont</span><span class="operator">.</span><span class="name">truetype</span><span class="punctuation">(</span><span class="literal string single">'DejaVuSans.ttf'</span><span class="punctuation">,</span> <span class="literal number integer">40</span><span class="punctuation">)</span><span class="whitespace"> + +</span><span class="keyword">while</span> <span class="operator word">not</span> <span class="name">player</span><span class="operator">.</span><span class="name">core_idle</span><span class="punctuation">:</span><span class="whitespace"> + +</span> <span class="name">time</span><span class="operator">.</span><span class="name">sleep</span><span class="punctuation">(</span><span class="literal number float">0.5</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name">overlay</span> <span class="operator">=</span> <span class="name">player</span><span class="operator">.</span><span class="name">create_image_overlay</span><span class="punctuation">()</span><span class="whitespace"> + +</span> <span class="keyword">for</span> <span class="name">pos</span> <span class="operator word">in</span> <span class="name builtin">range</span><span class="punctuation">(</span><span class="literal number integer">0</span><span class="punctuation">,</span> <span class="literal number integer">500</span><span class="punctuation">,</span> <span class="literal number integer">5</span><span class="punctuation">):</span><span class="whitespace"> +</span> <span class="name">ts</span> <span class="operator">=</span> <span class="name">player</span><span class="operator">.</span><span class="name">time_pos</span><span class="whitespace"> +</span> <span class="keyword">if</span> <span class="name">ts</span> <span class="operator word">is</span> <span class="keyword constant">None</span><span class="punctuation">:</span><span class="whitespace"> +</span> <span class="keyword">break</span><span class="whitespace"> + +</span> <span class="name">img</span> <span class="operator">=</span> <span class="name">Image</span><span class="operator">.</span><span class="name">new</span><span class="punctuation">(</span><span class="literal string single">'RGBA'</span><span class="punctuation">,</span> <span class="punctuation">(</span><span class="literal number integer">400</span><span class="punctuation">,</span> <span class="literal number integer">150</span><span class="punctuation">),</span> <span class="punctuation">(</span><span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">0</span><span class="punctuation">))</span><span class="whitespace"> +</span> <span class="name">d</span> <span class="operator">=</span> <span class="name">ImageDraw</span><span class="operator">.</span><span class="name">Draw</span><span class="punctuation">(</span><span class="name">img</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name">d</span><span class="operator">.</span><span class="name">text</span><span class="punctuation">((</span><span class="literal number integer">10</span><span class="punctuation">,</span> <span class="literal number integer">10</span><span class="punctuation">),</span> <span class="literal string single">'Hello World'</span><span class="punctuation">,</span> <span class="name">font</span><span class="operator">=</span><span class="name">font</span><span class="punctuation">,</span> <span class="name">fill</span><span class="operator">=</span><span class="punctuation">(</span><span class="literal number integer">0</span><span class="punctuation">,</span> <span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">128</span><span class="punctuation">))</span><span class="whitespace"> +</span> <span class="name">d</span><span class="operator">.</span><span class="name">text</span><span class="punctuation">((</span><span class="literal number integer">10</span><span class="punctuation">,</span> <span class="literal number integer">60</span><span class="punctuation">),</span> <span class="literal string affix">f</span><span class="literal string single">'t=</span><span class="literal string interpol">{</span><span class="name">ts</span><span class="literal string interpol">:</span><span class="literal string single">.3f</span><span class="literal string interpol">}</span><span class="literal string single">'</span><span class="punctuation">,</span> <span class="name">font</span><span class="operator">=</span><span class="name">font</span><span class="punctuation">,</span> <span class="name">fill</span><span class="operator">=</span><span class="punctuation">(</span><span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">0</span><span class="punctuation">,</span> <span class="literal number integer">255</span><span class="punctuation">,</span> <span class="literal number integer">255</span><span class="punctuation">))</span><span class="whitespace"> + +</span> <span class="name">overlay</span><span class="operator">.</span><span class="name">update</span><span class="punctuation">(</span><span class="name">img</span><span class="punctuation">,</span> <span class="name">pos</span><span class="operator">=</span><span class="punctuation">(</span><span class="literal number integer">2</span><span class="operator">*</span><span class="name">pos</span><span class="punctuation">,</span> <span class="name">pos</span><span class="punctuation">))</span><span class="whitespace"> +</span> <span class="name">time</span><span class="operator">.</span><span class="name">sleep</span><span class="punctuation">(</span><span class="literal number float">0.05</span><span class="punctuation">)</span><span class="whitespace"> + +</span> <span class="name">overlay</span><span class="operator">.</span><span class="name">remove</span><span class="punctuation">()</span> +</pre> +</div> +<div class="section" id="playlist-handling"> +<h4>Playlist handling</h4> +<pre class="code python literal-block"> +<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace"> + +</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">ytdl</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span> <span class="name">input_default_bindings</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span> <span class="name">input_vo_keyboard</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">)</span><span class="whitespace"> + +</span><span class="name">player</span><span class="operator">.</span><span class="name">playlist_append</span><span class="punctuation">(</span><span class="literal string single">'https://youtu.be/PHIGke6Yzh8'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">playlist_append</span><span class="punctuation">(</span><span class="literal string single">'https://youtu.be/Ji9qSuQapFY'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">playlist_append</span><span class="punctuation">(</span><span class="literal string single">'https://youtu.be/6f78_Tf4Tdk'</span><span class="punctuation">)</span><span class="whitespace"> + +</span><span class="name">player</span><span class="operator">.</span><span class="name">playlist_pos</span> <span class="operator">=</span> <span class="literal number integer">0</span><span class="whitespace"> + +</span><span class="keyword">while</span> <span class="keyword constant">True</span><span class="punctuation">:</span><span class="whitespace"> +</span> <span class="comment single"># To modify the playlist, use player.playlist_{append,clear,move,remove}. player.playlist is read-only</span><span class="whitespace"> +</span> <span class="name builtin">print</span><span class="punctuation">(</span><span class="name">player</span><span class="operator">.</span><span class="name">playlist</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name">player</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span> +</pre> +</div> +<div class="section" id="directly-feeding-mpv-data-from-python"> +<h4>Directly feeding mpv data from python</h4> +<pre class="code python literal-block"> +<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace"> + +</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">()</span><span class="whitespace"> +</span><span class="name decorator">@player</span><span class="operator">.</span><span class="name">python_stream</span><span class="punctuation">(</span><span class="literal string single">'foo'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="keyword">def</span> <span class="name function">reader</span><span class="punctuation">():</span><span class="whitespace"> +</span> <span class="keyword">with</span> <span class="name builtin">open</span><span class="punctuation">(</span><span class="literal string single">'test.webm'</span><span class="punctuation">,</span> <span class="literal string single">'rb'</span><span class="punctuation">)</span> <span class="keyword">as</span> <span class="name">f</span><span class="punctuation">:</span><span class="whitespace"> +</span> <span class="keyword">while</span> <span class="keyword constant">True</span><span class="punctuation">:</span><span class="whitespace"> +</span> <span class="keyword">yield</span> <span class="name">f</span><span class="operator">.</span><span class="name">read</span><span class="punctuation">(</span><span class="literal number integer">1024</span><span class="operator">*</span><span class="literal number integer">1024</span><span class="punctuation">)</span><span class="whitespace"> + +</span><span class="name">player</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string single">'python://foo'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span> +</pre> +</div> +<div class="section" id="using-external-subtitles"> +<h4>Using external subtitles</h4> +<p>The easiest way to load custom subtitles from a file is to pass the <tt class="docutils literal"><span class="pre">--sub-file</span></tt> option to the <tt class="docutils literal">loadfile</tt> call:</p> +<pre class="code python literal-block"> +<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace"> + +</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">()</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">loadfile</span><span class="punctuation">(</span><span class="literal string single">'test.webm'</span><span class="punctuation">,</span> <span class="name">sub_file</span><span class="operator">=</span><span class="literal string single">'test.srt'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span> +</pre> +<p>Note that you can also pass many other options to <tt class="docutils literal">loadfile</tt>. See the mpv docs for details.</p> +<p>If you want to add subtitle files or streams at runtime, you can use the <tt class="docutils literal"><span class="pre">sub-add</span></tt> command. <tt class="docutils literal"><span class="pre">sub-add</span></tt> 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 +<tt class="docutils literal"><span class="pre">core-idle</span></tt> property.</p> +<pre class="code python literal-block"> +<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace"> + +</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">()</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string single">'test.webm'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_until_playing</span><span class="punctuation">()</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">sub_add</span><span class="punctuation">(</span><span class="literal string single">'test.srt'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="name">player</span><span class="operator">.</span><span class="name">wait_for_playback</span><span class="punctuation">()</span> +</pre> +</div> +<div class="section" id="using-mpv-s-built-in-gui"> +<h4>Using MPV's built-in GUI</h4> +<p>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 <a class="reference external" href="https://github.com/jaseg/python-mpv/issues/61">Issue 102</a> for more details</p> +<pre class="code python literal-block"> +<span class="comment single"># Enable the on-screen controller and keyboard shortcuts</span><span class="whitespace"> +</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">input_default_bindings</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span> <span class="name">input_vo_keyboard</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span> <span class="name">osc</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">)</span><span class="whitespace"> + +</span><span class="comment single"># Alternative version using the old "floating box" style on-screen controller</span><span class="whitespace"> +</span><span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">player_operation_mode</span><span class="operator">=</span><span class="literal string single">'pseudo-gui'</span><span class="punctuation">,</span><span class="whitespace"> +</span> <span class="name">script_opts</span><span class="operator">=</span><span class="literal string single">'osc-layout=box,osc-seekbarstyle=bar,osc-deadzonesize=0,osc-minmousemove=3'</span><span class="punctuation">,</span><span class="whitespace"> +</span> <span class="name">input_default_bindings</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span><span class="whitespace"> +</span> <span class="name">input_vo_keyboard</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">,</span><span class="whitespace"> +</span> <span class="name">osc</span><span class="operator">=</span><span class="keyword constant">True</span><span class="punctuation">)</span> +</pre> +</div> +<div class="section" id="pyqt-embedding"> +<h4>PyQT embedding</h4> +<pre class="code python literal-block"> +<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">sys</span><span class="whitespace"> + +</span><span class="keyword namespace">from</span> <span class="name namespace">PyQt5.QtWidgets</span> <span class="keyword namespace">import</span> <span class="operator">*</span><span class="whitespace"> +</span><span class="keyword namespace">from</span> <span class="name namespace">PyQt5.QtCore</span> <span class="keyword namespace">import</span> <span class="operator">*</span><span class="whitespace"> + +</span><span class="keyword">class</span> <span class="name class">Test</span><span class="punctuation">(</span><span class="name">QMainWindow</span><span class="punctuation">):</span><span class="whitespace"> +</span> <span class="keyword">def</span> <span class="name function magic">__init__</span><span class="punctuation">(</span><span class="name builtin pseudo">self</span><span class="punctuation">,</span> <span class="name">parent</span><span class="operator">=</span><span class="keyword constant">None</span><span class="punctuation">):</span><span class="whitespace"> +</span> <span class="name builtin">super</span><span class="punctuation">()</span><span class="operator">.</span><span class="name function magic">__init__</span><span class="punctuation">(</span><span class="name">parent</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">container</span> <span class="operator">=</span> <span class="name">QWidget</span><span class="punctuation">(</span><span class="name builtin pseudo">self</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">setCentralWidget</span><span class="punctuation">(</span><span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">container</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">container</span><span class="operator">.</span><span class="name">setAttribute</span><span class="punctuation">(</span><span class="name">Qt</span><span class="operator">.</span><span class="name">WA_DontCreateNativeAncestors</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">container</span><span class="operator">.</span><span class="name">setAttribute</span><span class="punctuation">(</span><span class="name">Qt</span><span class="operator">.</span><span class="name">WA_NativeWindow</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name">player</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">wid</span><span class="operator">=</span><span class="name builtin">str</span><span class="punctuation">(</span><span class="name builtin">int</span><span class="punctuation">(</span><span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">container</span><span class="operator">.</span><span class="name">winId</span><span class="punctuation">())),</span><span class="whitespace"> +</span> <span class="name">vo</span><span class="operator">=</span><span class="literal string single">'x11'</span><span class="punctuation">,</span> <span class="comment single"># You may not need this</span><span class="whitespace"> +</span> <span class="name">log_handler</span><span class="operator">=</span><span class="name builtin">print</span><span class="punctuation">,</span><span class="whitespace"> +</span> <span class="name">loglevel</span><span class="operator">=</span><span class="literal string single">'debug'</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name">player</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string single">'test.webm'</span><span class="punctuation">)</span><span class="whitespace"> + +</span><span class="name">app</span> <span class="operator">=</span> <span class="name">QApplication</span><span class="punctuation">(</span><span class="name">sys</span><span class="operator">.</span><span class="name">argv</span><span class="punctuation">)</span><span class="whitespace"> + +</span><span class="comment single"># This is necessary since PyQT stomps over the locale settings needed by libmpv.</span><span class="whitespace"> +</span><span class="comment single"># This needs to happen after importing PyQT before creating the first mpv.MPV instance.</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">locale</span><span class="whitespace"> +</span><span class="name">locale</span><span class="operator">.</span><span class="name">setlocale</span><span class="punctuation">(</span><span class="name">locale</span><span class="operator">.</span><span class="name">LC_NUMERIC</span><span class="punctuation">,</span> <span class="literal string single">'C'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="name">win</span> <span class="operator">=</span> <span class="name">Test</span><span class="punctuation">()</span><span class="whitespace"> +</span><span class="name">win</span><span class="operator">.</span><span class="name">show</span><span class="punctuation">()</span><span class="whitespace"> +</span><span class="name">sys</span><span class="operator">.</span><span class="name">exit</span><span class="punctuation">(</span><span class="name">app</span><span class="operator">.</span><span class="name">exec_</span><span class="punctuation">())</span> +</pre> +</div> +<div class="section" id="pygobject-embedding"> +<h4>PyGObject embedding</h4> +<pre class="code python literal-block"> +<span class="comment hashbang">#!/usr/bin/env python3</span><span class="whitespace"> +</span><span class="keyword namespace">import</span> <span class="name namespace">gi</span><span class="whitespace"> + +</span><span class="keyword namespace">import</span> <span class="name namespace">mpv</span><span class="whitespace"> + +</span><span class="name">gi</span><span class="operator">.</span><span class="name">require_version</span><span class="punctuation">(</span><span class="literal string single">'Gtk'</span><span class="punctuation">,</span> <span class="literal string single">'3.0'</span><span class="punctuation">)</span><span class="whitespace"> +</span><span class="keyword namespace">from</span> <span class="name namespace">gi.repository</span> <span class="keyword namespace">import</span> <span class="name">Gtk</span><span class="whitespace"> + + +</span><span class="keyword">class</span> <span class="name class">MainClass</span><span class="punctuation">(</span><span class="name">Gtk</span><span class="operator">.</span><span class="name">Window</span><span class="punctuation">):</span><span class="whitespace"> + +</span> <span class="keyword">def</span> <span class="name function magic">__init__</span><span class="punctuation">(</span><span class="name builtin pseudo">self</span><span class="punctuation">):</span><span class="whitespace"> +</span> <span class="name builtin">super</span><span class="punctuation">(</span><span class="name">MainClass</span><span class="punctuation">,</span> <span class="name builtin pseudo">self</span><span class="punctuation">)</span><span class="operator">.</span><span class="name function magic">__init__</span><span class="punctuation">()</span><span class="whitespace"> +</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">set_default_size</span><span class="punctuation">(</span><span class="literal number integer">600</span><span class="punctuation">,</span> <span class="literal number integer">400</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">connect</span><span class="punctuation">(</span><span class="literal string double">"destroy"</span><span class="punctuation">,</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">on_destroy</span><span class="punctuation">)</span><span class="whitespace"> + +</span> <span class="name">widget</span> <span class="operator">=</span> <span class="name">Gtk</span><span class="operator">.</span><span class="name">Frame</span><span class="punctuation">()</span><span class="whitespace"> +</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">add</span><span class="punctuation">(</span><span class="name">widget</span><span class="punctuation">)</span><span class="whitespace"> +</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">show_all</span><span class="punctuation">()</span><span class="whitespace"> + +</span> <span class="comment single"># Must be created >after< the widget is shown, else property 'window' will be None</span><span class="whitespace"> +</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">mpv</span> <span class="operator">=</span> <span class="name">mpv</span><span class="operator">.</span><span class="name">MPV</span><span class="punctuation">(</span><span class="name">wid</span><span class="operator">=</span><span class="name builtin">str</span><span class="punctuation">(</span><span class="name">widget</span><span class="operator">.</span><span class="name">get_property</span><span class="punctuation">(</span><span class="literal string double">"window"</span><span class="punctuation">)</span><span class="operator">.</span><span class="name">get_xid</span><span class="punctuation">()))</span><span class="whitespace"> +</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">mpv</span><span class="operator">.</span><span class="name">play</span><span class="punctuation">(</span><span class="literal string double">"test.webm"</span><span class="punctuation">)</span><span class="whitespace"> + +</span> <span class="keyword">def</span> <span class="name function">on_destroy</span><span class="punctuation">(</span><span class="name builtin pseudo">self</span><span class="punctuation">,</span> <span class="name">widget</span><span class="punctuation">,</span> <span class="name">data</span><span class="operator">=</span><span class="keyword constant">None</span><span class="punctuation">):</span><span class="whitespace"> +</span> <span class="name builtin pseudo">self</span><span class="operator">.</span><span class="name">mpv</span><span class="operator">.</span><span class="name">terminate</span><span class="punctuation">()</span><span class="whitespace"> +</span> <span class="name">Gtk</span><span class="operator">.</span><span class="name">main_quit</span><span class="punctuation">()</span><span class="whitespace"> + + +</span><span class="keyword">if</span> <span class="name variable magic">__name__</span> <span class="operator">==</span> <span class="literal string single">'__main__'</span><span class="punctuation">:</span><span class="whitespace"> +</span> <span class="comment single"># This is necessary since like Qt, Gtk stomps over the locale settings needed by libmpv.</span><span class="whitespace"> +</span> <span class="comment single"># Like with Qt, this needs to happen after importing Gtk but before creating the first mpv.MPV instance.</span><span class="whitespace"> +</span> <span class="keyword namespace">import</span> <span class="name namespace">locale</span><span class="whitespace"> +</span> <span class="name">locale</span><span class="operator">.</span><span class="name">setlocale</span><span class="punctuation">(</span><span class="name">locale</span><span class="operator">.</span><span class="name">LC_NUMERIC</span><span class="punctuation">,</span> <span class="literal string single">'C'</span><span class="punctuation">)</span><span class="whitespace"> + +</span> <span class="name">application</span> <span class="operator">=</span> <span class="name">MainClass</span><span class="punctuation">()</span><span class="whitespace"> +</span> <span class="name">Gtk</span><span class="operator">.</span><span class="name">main</span><span class="punctuation">()</span> +</pre> +</div> +<div class="section" id="using-opengl-from-pygobject"> +<h4>Using OpenGL from PyGObject</h4> +<p>Just like it is possible to render into a GTK widget through X11 windows, it <a class="reference external" href="https://gist.github.com/jaseg/657e8ecca3267c0d82ec85d40f423caa">also is possible to render into a GTK +widget using OpenGL</a> through this python API.</p> +</div> +<div class="section" id="using-opengl-from-pyqt5-qml"> +<h4>Using OpenGL from PyQt5/QML</h4> +<p><a class="reference external" href="https://gitlab.com/robozman">Robozman</a> has mangaed to <a class="reference external" href="https://gitlab.com/robozman/python-mpv-qml-example">make mpv render into a PyQt5/QML widget using OpenGL</a> through this python API.</p> +</div> +<div class="section" id="using-mpv-inside-imgui-inside-opengl-via-glfw"> +<h4>Using mpv inside imgui inside OpenGL via GLFW</h4> +<p><a class="reference external" href="https://github.com/dfaker">dfaker</a> has written a demo (<a class="reference external" href="https://github.com/dfaker/imgui_glfw_pythonmpv_demo/blob/main/main.py">link</a>) that uses mpv to render video into an <a class="reference external" href="https://github.com/ocornut/imgui">imgui</a> UI running on an OpenGL context inside <a class="reference external" href="https://www.glfw.org/">GLFW</a>. 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.</p> +</div> +</div> +</div> +<div class="section" id="running-tests"> +<h2>Running tests</h2> +<p>Use pytest to run tests.</p> +</div> +<div class="section" id="coding-conventions"> +<h2>Coding Conventions</h2> +<p>The general aim is <a class="reference external" href="https://www.python.org/dev/peps/pep-0008/">PEP 8</a>, 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 <em>really</em> helps readability or it +<em>really</em> irks you if you don't.</p> +</div> +<div class="section" id="license"> +<h2>License</h2> +<p>python-mpv inherits the underlying libmpv's license, which can be either GPLv2 or later (default) or LGPLv2.1 or later. +For details, see <a class="reference external" href="https://github.com/mpv-player/mpv/blob/master/Copyright">the mpv copyright page</a>.</p> +</div> +</div> + </main><footer> + Copyright © 2023 Jan Sebastian Götte + / <a href="http://jaseg.de/about/">About</a> + / <a href="http://jaseg.de/imprint/">Imprint</a> +</footer> +</body> +</html> |