Skip to content

Instantly share code, notes, and snippets.

@hooke007
Last active March 15, 2024 03:23
Show Gist options
  • Save hooke007/e502688c60ef1c5f9ef507cf4db25b34 to your computer and use it in GitHub Desktop.
Save hooke007/e502688c60ef1c5f9ef507cf4db25b34 to your computer and use it in GitHub Desktop.
windows10+快速部署一体化便携式mpv-vs工具链

Important

此教程限定仅适用于 Python 3.8-3.11 & VapourSynth R57-R65

1. 基础工具

编译或下载主要文件

注意python和VapourSynth的版本匹配
解压全部文件到同一路径下。该目录下建立子文件夹 portable_config 来使mpv“便携化”

形象化的文件树可参考懒人包维基

2. 自定义库和脚本

自行选择下载解压插件到目录 vapoursynth64\plugins 中,python脚本可直接放置在mpv.exe所在目录。 在mpv.exe所在位置打开终端,可依次执行指令以检查插件的安装情况: (仅适用于R60之前的版本,此后的版本的变通方案 vapoursynth/vapoursynth#923 (comment)

./python
import vapoursynth as vs
from vapoursynth import core
print(core. version())
print(core.list_functions())

具体插件安装的演示实例可在末尾处的关联文档中找到。

2.1. 安装 pip (可选)

部分脚本已转变为python package形式,由于此类版本的python不含pip,因此需要手动操作。

首先编辑 python3x._pth 文件内容,删除掉 import site 前的注释符,修改后的内容大概长这样:

python3x.zip
.

# Uncomment to run site.main() automatically
import site

在mpv.exe所在位置打开终端,依次执行以下指令安装pip:

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
./python get-pip.py

安装完成后可用以下指令检查pip的版本和通过pip安装的包:

./python -m pip --version
./python -m pip list

此后可用pip安装其它包(演示案例为 vsutil ):

./python -m pip install vsutil

对应的更新指定包的指令为:

./python -m pip install --upgrade vsutil

2.2. 不安装 pip (可选)

依旧是前例,如果你不想通过pip来安装vsutil,按以下步骤操作:

  • (同上)首先编辑 python3x._pth 文件内容,删除掉 import site 前的注释符
  • 下载vsutil仓库,把文件夹 vsutil (内含 __init__.py 等文件)放到 <mpv.exe所在位置>\Lib\site-packages 路径下,由于未安装pip所以需要你手动创建子文件夹

3. 运行检验

快速编写一个最简化的脚本以测试mpv中的vs滤镜是否正常工作,保存为 test.vpy :

video_in.set_output()

自行决定mpv中的对应触发方式,mpv.conf/input.conf或终端/控制台 mpv可正常播放即整体部署无误。

使用插件的演示实例可在末尾的关联文档中找到

4. 关联文档

hooke007/MPV_lazy#66

@verygoodlee
Copy link

verygoodlee commented Mar 14, 2024

VapourSynth64-Portable-R66 有较大改动

  • 插件目录改为vs-plugins
  • pip是必须安装的了,要用pip手动安装wheel,python -m pip install wheel\VapourSynth-66-cp312-cp312-win_amd64.whl

官方已经提供了一键安装的powershell脚本

edit:
似乎不装pip也行,.whl本身就是一个压缩包,可以用7zip等软件解压,把里面的vapoursynth.cp312-win_amd64.pyd VapourSynth-66.data/data/Lib/site-packages/vapoursynth.dll 两个文件拷贝到根目录就行了。
旧版本这两个文件是直接提供在便携包里的,新版不知道为啥要做这种改动,让用户多操作一步。

@hooke007
Copy link
Author

Improve packaging/initial user experience. This includes things like setting up a suitable python install and having package management in some form that isn't broken/split in undocumented ways.

改进没感觉到,弄个核心滤镜都要多做一步给我整无语了。

@verygoodlee
Copy link

verygoodlee commented Mar 14, 2024

k7sfunc 0.4.8 目前在 python3.12.2 + vapoursynth R66 上跑不起来 ModuleNotFoundError: No module named 'distutils'
看了一下python-3.12.2-embed-amd64.zip里面的 python312.zip,distutils已经不包含在里面了,要额外安装

@hooke007
Copy link
Author

理论上不想增加任何外部库,,distutils被正式淘汰之后标准库里也没了替代品,只能外部装依赖了 https://peps.python.org/pep-0632/

@verygoodlee
Copy link

只用到了distutils.version里面的LooseVersion,最简单的解决方案,就是从python3.11里把相关源码拷过来,实测可行

# from distutils.version import LooseVersion
# python3.12开始 distutils已从标准库中移除,从python3.11中拷贝
# https://github.com/python/cpython/blob/3.11/Lib/distutils/version.py
import re
class Version:
    def __init__ (self, vstring=None):
        if vstring:
            self.parse(vstring)
    def __repr__ (self):
        return "%s ('%s')" % (self.__class__.__name__, str(self))
    def __eq__(self, other):
        c = self._cmp(other)
        if c is NotImplemented:
            return c
        return c == 0
    def __lt__(self, other):
        c = self._cmp(other)
        if c is NotImplemented:
            return c
        return c < 0
    def __le__(self, other):
        c = self._cmp(other)
        if c is NotImplemented:
            return c
        return c <= 0
    def __gt__(self, other):
        c = self._cmp(other)
        if c is NotImplemented:
            return c
        return c > 0
    def __ge__(self, other):
        c = self._cmp(other)
        if c is NotImplemented:
            return c
        return c >= 0
# end class Version
class LooseVersion (Version):
    component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE)
    def __init__ (self, vstring=None):
        if vstring:
            self.parse(vstring)
    def parse (self, vstring):
        self.vstring = vstring
        components = [x for x in self.component_re.split(vstring)
                              if x and x != '.']
        for i, obj in enumerate(components):
            try:
                components[i] = int(obj)
            except ValueError:
                pass
        self.version = components
    def __str__ (self):
        return self.vstring
    def __repr__ (self):
        return "LooseVersion ('%s')" % str(self)
    def _cmp (self, other):
        if isinstance(other, str):
            other = LooseVersion(other)
        elif not isinstance(other, LooseVersion):
            return NotImplemented
        if self.version == other.version:
            return 0
        if self.version < other.version:
            return -1
        if self.version > other.version:
            return 1
# end class LooseVersion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment