diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..489bdd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,161 @@ +# ---> Python +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/Encode.bat b/Encode.bat new file mode 100644 index 0000000..06ebc8e --- /dev/null +++ b/Encode.bat @@ -0,0 +1,14 @@ +@ECHO OFF +REM TestWrapper.bat +cd /D "%~dp0" +SET args='%1' +:More +SHIFT +IF '%1' == '' GOTO Done +SET args=%args%,'%1' +GOTO More +:Done +cd Programs +Powershell.exe -noprofile -command "& {.\Script.ps1 %args%}" +pause +exit \ No newline at end of file diff --git a/Encode_Web.bat b/Encode_Web.bat new file mode 100644 index 0000000..82222b3 --- /dev/null +++ b/Encode_Web.bat @@ -0,0 +1,14 @@ +@ECHO OFF +REM TestWrapper.bat +cd /D "%~dp0" +SET args='%1' +:More +SHIFT +IF '%1' == '' GOTO Done +SET args=%args%,'%1' +GOTO More +:Done +cd Programs +Powershell.exe -noprofile -command "& {.\Script_Web.ps1 %args%}" +pause +exit \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7a3094a --- /dev/null +++ b/LICENSE @@ -0,0 +1,11 @@ +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +Version 2, December 2004 + +Copyright (C) 2004 Sam Hocevar + +Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. + +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/Programs/7z.dll b/Programs/7z.dll new file mode 100644 index 0000000..2ba9f27 Binary files /dev/null and b/Programs/7z.dll differ diff --git a/Programs/7z.exe b/Programs/7z.exe new file mode 100644 index 0000000..a739ca0 Binary files /dev/null and b/Programs/7z.exe differ diff --git a/Programs/AVFS.exe b/Programs/AVFS.exe new file mode 100644 index 0000000..0ee341d Binary files /dev/null and b/Programs/AVFS.exe differ diff --git a/Programs/LICENSE.txt b/Programs/LICENSE.txt new file mode 100644 index 0000000..7a0193a --- /dev/null +++ b/Programs/LICENSE.txt @@ -0,0 +1,702 @@ +A. HISTORY OF THE SOFTWARE +========================== + +Python was created in the early 1990s by Guido van Rossum at Stichting +Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands +as a successor of a language called ABC. Guido remains Python's +principal author, although it includes many contributions from others. + +In 1995, Guido continued his work on Python at the Corporation for +National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) +in Reston, Virginia where he released several versions of the +software. + +In May 2000, Guido and the Python core development team moved to +BeOpen.com to form the BeOpen PythonLabs team. In October of the same +year, the PythonLabs team moved to Digital Creations, which became +Zope Corporation. In 2001, the Python Software Foundation (PSF, see +https://www.python.org/psf/) was formed, a non-profit organization +created specifically to own Python-related Intellectual Property. +Zope Corporation was a sponsoring member of the PSF. + +All Python releases are Open Source (see https://opensource.org for +the Open Source Definition). Historically, most, but not all, Python +releases have also been GPL-compatible; the table below summarizes +the various releases. + + Release Derived Year Owner GPL- + from compatible? (1) + + 0.9.0 thru 1.2 1991-1995 CWI yes + 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes + 1.6 1.5.2 2000 CNRI no + 2.0 1.6 2000 BeOpen.com no + 1.6.1 1.6 2001 CNRI yes (2) + 2.1 2.0+1.6.1 2001 PSF no + 2.0.1 2.0+1.6.1 2001 PSF yes + 2.1.1 2.1+2.0.1 2001 PSF yes + 2.1.2 2.1.1 2002 PSF yes + 2.1.3 2.1.2 2002 PSF yes + 2.2 and above 2.1.1 2001-now PSF yes + +Footnotes: + +(1) GPL-compatible doesn't mean that we're distributing Python under + the GPL. All Python licenses, unlike the GPL, let you distribute + a modified version without making your changes open source. The + GPL-compatible licenses make it possible to combine Python with + other software that is released under the GPL; the others don't. + +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, + because its license has a choice of law clause. According to + CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 + is "not incompatible" with the GPL. + +Thanks to the many outside volunteers who have worked under Guido's +direction to make these releases possible. + + +B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON +=============================================================== + +Python software and documentation are licensed under the +Python Software Foundation License Version 2. + +Starting with Python 3.8.6, examples, recipes, and other code in +the documentation are dual licensed under the PSF License Version 2 +and the Zero-Clause BSD license. + +Some software incorporated into Python is under different licenses. +The licenses are listed with code falling under that license. + + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative version +prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION +---------------------------------------------------------------------- + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + + + +Additional Conditions for this Windows binary build +--------------------------------------------------- + +This program is linked with and uses Microsoft Distributable Code, +copyrighted by Microsoft Corporation. The Microsoft Distributable Code +is embedded in each .exe, .dll and .pyd file as a result of running +the code through a linker. + +If you further distribute programs that include the Microsoft +Distributable Code, you must comply with the restrictions on +distribution specified by Microsoft. In particular, you must require +distributors and external end users to agree to terms that protect the +Microsoft Distributable Code at least as much as Microsoft's own +requirements for the Distributable Code. See Microsoft's documentation +(included in its developer tools and on its website at microsoft.com) +for specific details. + +Redistribution of the Windows binary build of the Python interpreter +complies with this agreement, provided that you do not: + +- alter any copyright, trademark or patent notice in Microsoft's +Distributable Code; + +- use Microsoft's trademarks in your programs' names or in a way that +suggests your programs come from or are endorsed by Microsoft; + +- distribute Microsoft's Distributable Code to run on a platform other +than Microsoft operating systems, run-time technologies or application +platforms; or + +- include Microsoft Distributable Code in malicious, deceptive or +unlawful programs. + +These restrictions apply only to the Microsoft Distributable Code as +defined above, not to Python itself or any programs running on the +Python interpreter. The redistribution of the Python interpreter and +libraries is governed by the Python Software License included with this +file, or by other licenses as marked. + + + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2019 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@acm.org +bzip2/libbzip2 version 1.0.8 of 13 July 2019 + +-------------------------------------------------------------------------- + +libffi - Copyright (c) 1996-2022 Anthony Green, Red Hat, Inc and others. +See source files for details. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +``Software''), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + +This software is copyrighted by the Regents of the University of +California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState +Corporation and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7014 (b) (3) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. + +This software is copyrighted by the Regents of the University of +California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState +Corporation, Apple Inc. and other parties. The following terms apply to +all files associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (b) (3) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. + +Copyright (c) 1993-1999 Ioi Kim Lam. +Copyright (c) 2000-2001 Tix Project Group. +Copyright (c) 2004 ActiveState + +This software is copyrighted by the above entities +and other parties. The following terms apply to all files associated +with the software unless explicitly disclaimed in individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. + +---------------------------------------------------------------------- + +Parts of this software are based on the Tcl/Tk software copyrighted by +the Regents of the University of California, Sun Microsystems, Inc., +and other parties. The original license terms of the Tcl/Tk software +distribution is included in the file docs/license.tcltk. + +Parts of this software are based on the HTML Library software +copyrighted by Sun Microsystems, Inc. The original license terms of +the HTML Library software distribution is included in the file +docs/license.html_lib. + diff --git a/Programs/MANIFEST.in b/Programs/MANIFEST.in new file mode 100644 index 0000000..1acf32c --- /dev/null +++ b/Programs/MANIFEST.in @@ -0,0 +1,2 @@ +global-include *.dll portable.vs .keep VSPipe.exe +global-exclude VapourSynth.dll diff --git a/Programs/Script.ps1 b/Programs/Script.ps1 new file mode 100644 index 0000000..dcca873 --- /dev/null +++ b/Programs/Script.ps1 @@ -0,0 +1,31 @@ +param ( [string[]] $Paths ) + +Write-Host "" + +$Paths | foreach { + $Path = $_ + + $WithoutExtension = [IO.Path]::ChangeExtension($Path, '') + + $ScriptFile = $WithoutExtension + "script.vpy" + $ArchiveFile = $WithoutExtension + "archive.mkv" + + Write-Host "===============================================================================" + Write-Host "" + Write-Host " Input video: $Path" + Write-Host " Script file: $ScriptFile" + Write-Host " Output video: $ArchiveFile" + Write-Host "" + Write-Host "" + + (Get-Content template.vpy).replace('[INPUTFILE]', $Path.replace('\', '/')) | Set-Content -LiteralPath "$ScriptFile" + + .\ffmpeg.exe -hide_banner -y -f vapoursynth -i "$ScriptFile" -i "$Path" -map 0:v:0 -map 1:a:0 -c:v libx265 -profile:v main10 -crf 17.4 -x265-params "me=star:subme=5:limit-modes=1:rect=1:amp=1:max-merge=5:no-early-skip=1:bframes=16:ref=6:rc-lookahead=60:limit-refs=0:rd=6:rdoq-level=2:psy-rdoq=1.00:sao=0" -c:a copy "$ArchiveFile" + + Remove-Item $ScriptFile + Remove-Item "$($Path).lwi" + + .\Script_Web.ps1 "$ArchiveFile" + + Write-Host "===============================================================================" +} diff --git a/Programs/Script_Web.ps1 b/Programs/Script_Web.ps1 new file mode 100644 index 0000000..ef73d49 --- /dev/null +++ b/Programs/Script_Web.ps1 @@ -0,0 +1,24 @@ +param ( [string[]] $Paths ) + +$Paths | foreach { + $Path = $_ + + $WithoutExtension = [IO.Path]::ChangeExtension($Path, '') + + $WebFile = $WithoutExtension.replace('archive', 'web') + "webm" + $PictureFile = $WithoutExtension.replace('archive', 'web') + "png" + + Write-Host "===============================================================================" + Write-Host "" + Write-Host " Input video: $Path" + Write-Host " Web video: $WebFile" + Write-Host "" + Write-Host "" + + # .\ffmpeg.exe -hide_banner -y -i "$Path" -vf zscale=1280:720:filter=spline36 -c:v libsvtav1 -preset 5 -crf 28 -svtav1-params "enable-qm=1:fast-decode=1" -c:a libopus -b:a 192k -f matroska "$WebFile"; + + ffmpeg -hide_banner -y -ss 00:10:00 -i "$WebFile" -vframes 1 "$PictureFile" + + Write-Host "" + Write-Host "Done" +} diff --git a/Programs/VSPipe.exe b/Programs/VSPipe.exe new file mode 100644 index 0000000..00add01 Binary files /dev/null and b/Programs/VSPipe.exe differ diff --git a/Programs/VSScript.dll b/Programs/VSScript.dll new file mode 100644 index 0000000..138d47c Binary files /dev/null and b/Programs/VSScript.dll differ diff --git a/Programs/VSScriptPython38.dll b/Programs/VSScriptPython38.dll new file mode 100644 index 0000000..b907954 Binary files /dev/null and b/Programs/VSScriptPython38.dll differ diff --git a/Programs/VSVFW.dll b/Programs/VSVFW.dll new file mode 100644 index 0000000..49a93ba Binary files /dev/null and b/Programs/VSVFW.dll differ diff --git a/Programs/VapourSynth.dll b/Programs/VapourSynth.dll new file mode 100644 index 0000000..14c87a5 Binary files /dev/null and b/Programs/VapourSynth.dll differ diff --git a/Programs/concrt140.dll b/Programs/concrt140.dll new file mode 100644 index 0000000..a5e5bfa Binary files /dev/null and b/Programs/concrt140.dll differ diff --git a/Programs/doc/.buildinfo b/Programs/doc/.buildinfo new file mode 100644 index 0000000..0c4df40 --- /dev/null +++ b/Programs/doc/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 632bdf4b310a3f3964e4f568bada4510 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/Programs/doc/_sources/api/vapoursynth4.h.rst.txt b/Programs/doc/_sources/api/vapoursynth4.h.rst.txt new file mode 100644 index 0000000..a582d41 --- /dev/null +++ b/Programs/doc/_sources/api/vapoursynth4.h.rst.txt @@ -0,0 +1,2937 @@ +VapourSynth4.h +============== + +Table of contents +################# + +Introduction_ + + +Macros_ + VS_CC_ + + VS_EXTERNAL_API_ + + VAPOURSYNTH_API_MAJOR_ + + VAPOURSYNTH_API_MINOR_ + + VAPOURSYNTH_API_VERSION_ + + VS_AUDIO_FRAME_SAMPLES_ + + VS_MAKE_VERSION_ + + +Enums_ + VSColorFamily_ + + VSSampleType_ + + VSPresetVideoFormat_ + + VSFilterMode_ + + VSMediaType_ + + VSAudioChannels_ + + VSPropertyType_ + + VSMapPropertyError_ + + VSMapAppendMode_ + + VSActivationReason_ + + VSMessageType_ + + VSCoreCreationFlags_ + + VSPluginConfigFlags_ + + VSDataTypeHint_ + + VSRequestPattern_ + + VSCacheMode_ + + +Structs_ + VSFrame_ + + VSNode_ + + VSCore_ + + VSPlugin_ + + VSPluginFunction_ + + VSFunction_ + + VSMap_ + + VSLogHandle_ + + VSFrameContext_ + + VSVideoFormat_ + + VSVideoInfo_ + + VSAudioFormat_ + + VSAudioInfo_ + + VSCoreInfo_ + + VSFilterDependency_ + + VSPLUGINAPI_ + + VSAPI_ + + * Functions that deal with the core: + + * createCore_ + + * freeCore_ + + * setMaxCacheSize_ + + * setThreadCount_ + + * getCoreInfo_ + + * getAPIVersion_ + + * Functions that deal with logging + + * addLogHandler_ + + * removeLogHandler_ + + * logMessage_ + + * Functions that deal with frames: + + * newVideoFrame_ + + * newVideoFrame2_ + + * newAudioFrame_ + + * newAudioFrame2_ + + * freeFrame_ + + * addFrameRef_ + + * copyFrame_ + + * getFramePropertiesRO_ + + * getFramePropertiesRW_ + + * getStride_ + + * getReadPtr_ + + * getWritePtr_ + + * getVideoFrameFormat_ + + * getAudioFrameFormat_ + + * getFrameType_ + + * getFrameWidth_ + + * getFrameHeight_ + + * getFrameLength_ + + * Functions that deal with filters and nodes: + + * createVideoFilter_ + + * createVideoFilter2_ + + * createAudioFilter_ + + * createAudioFilter2_ + + * setLinearFilter_ + + * setCacheMode_ + + * setCacheOptions_ + + * freeNode_ + + * addNodeRef_ + + * getNodeType_ + + * getVideoInfo_ + + * getAudioInfo_ + + * Functions that deal with formats: + + * getVideoFormatName_ + + * getAudioFormatName_ + + * queryVideoFormat_ + + * queryAudioFormat_ + + * queryVideoFormatID_ + + * getVideoFormatByID_ + + * Functions that deal with maps: + + * createMap_ + + * freeMap_ + + * clearMap_ + + * mapGetError_ + + * mapSetError_ + + * mapNumKeys_ + + * mapGetKey_ + + * mapDeleteKey_ + + * mapNumElements_ + + * mapGetType_ + + * mapSetEmpty_ + + * mapGetInt_ + + * mapGetIntSaturated_ + + * mapGetIntArray_ + + * mapSetInt_ + + * mapSetIntArray_ + + * mapGetFloat_ + + * mapGetFloatSaturated_ + + * mapGetFloatArray_ + + * mapSetFloat_ + + * mapSetFloatArray_ + + * mapGetData_ + + * mapGetDataSize_ + + * mapGetDataTypeHint_ + + * mapSetData_ + + * mapGetNode_ + + * mapSetNode_ + + * mapConsumeNode_ + + * mapGetFrame_ + + * mapSetFrame_ + + * mapConsumeFrame_ + + * mapGetFunction_ + + * mapSetFunction_ + + * mapConsumeFunction_ + + * Functions that deal with plugins and plugin functions: + + * registerFunction_ + + * getPluginByID_ + + * getPluginByNamespace_ + + * getNextPlugin_ + + * getPluginName_ + + * getPluginID_ + + * getPluginNamespace_ + + * getNextPluginFunction_ + + * getPluginFunctionByName_ + + * getPluginFunctionName_ + + * getPluginFunctionArguments_ + + * getPluginFunctionReturnType_ + + * getPluginPath_ + + * getPluginVersion_ + + * invoke_ + + * Functions that deal with wrapped external functions: + + * createFunction_ + + * freeFunction_ + + * addFunctionRef_ + + * callFunction_ + + * Functions that are used to fetch frames and inside filters: + + * getFrame_ + + * getFrameAsync_ + + * getFrameFilter_ + + * requestFrameFilter_ + + * releaseFrameEarly_ + + * cacheFrame_ + + * setFilterError_ + + +Functions_ + getVapourSynthAPI_ + + +`Writing plugins`_ + VSInitPlugin_ + + VSFilterGetFrame_ + + VSFilterFree_ + + +Introduction +############ + +This is VapourSynth's main header file. Plugins and applications that use +the library must include it. + +VapourSynth's public API is all C. + + +Macros +###### + +VapourSynth4.h defines some preprocessor macros that make the programmer's life +easier. The relevant ones are described below. + +VS_CC +----- + +The ``VS_CC`` macro expands to the calling convention used by VapourSynth. +All functions meant to be called by VapourSynth must use this macro (a +filter's "init", "getframe", "free" functions, etc). + +Example: + +.. code-block:: c + + static void VS_CC fooInit(...) { ... } + + +VS_EXTERNAL_API +--------------- + +The ``VS_EXTERNAL_API`` macro expands to the platform-specific magic required +for functions exported by shared libraries. It also takes care of adding +``extern "C"`` when needed, and ``VS_CC``. + +This macro must be used for a plugin's entry point, like so: + +.. code-block:: c + + VS_EXTERNAL_API(void) VapourSynthPluginInit2(...) { ... } + + +VAPOURSYNTH_API_MAJOR +--------------------- + +Major API version. + + +VAPOURSYNTH_API_MINOR +--------------------- + +Minor API version. It is bumped when new functions are added to VSAPI_ or core behavior is noticeably changed. + + +VAPOURSYNTH_API_VERSION +----------------------- + +API version. The high 16 bits are VAPOURSYNTH_API_MAJOR_, the low 16 +bits are VAPOURSYNTH_API_MINOR_. + + +VS_AUDIO_FRAME_SAMPLES +---------------------- + +The number of audio samples in an audio frame. It is a static number to make it possible to calculate which audio frames are needed to retrieve specific samples. + + +VS_MAKE_VERSION +--------------- + +Used to create version numbers. The first argument is the major version and second is the minor. + + +Enums +##### + +.. _VSColorFamily: + +enum VSColorFamily +------------------ + + * cfUndefined + + * cfGray + + * cfRGB + + * cfYUV + + +.. _VSSampleType: + +enum VSSampleType +----------------- + + * stInteger + + * stFloat + + +.. _VSPresetVideoFormat: + +enum VSPresetVideoFormat +------------------------ + + The presets suffixed with H and S have floating point sample type. + The H and S suffixes stand for half precision and single precision, + respectively. All formats are planar. See the header for all currently + defined video format presets. + + * pf\* + + +.. _VSFilterMode: + +enum VSFilterMode +----------------- + + Controls how a filter will be multithreaded, if at all. + + * fmParallel + + Completely parallel execution. + Multiple threads will call a filter's "getframe" function, to fetch several + frames in parallel. + + * fmParallelRequests + + For filters that are serial in nature but can request in advance one or + more frames they need. + A filter's "getframe" function will be called from multiple threads at a + time with activation reason arInitial, but only one thread will call it + with activation reason arAllFramesReady at a time. + + * fmUnordered + + Only one thread can call the filter's "getframe" function at a time. + Useful for filters that modify or examine their internal state to + determine which frames to request. + + While the "getframe" function will only run in one thread at a + time, the calls can happen in any order. For example, it can be + called with reason arInitial for frame 0, then again with reason + arInitial for frame 1, then with reason arAllFramesReady for + frame 0. + + * fmFrameState + + For compatibility with other filtering architectures. DO NOT USE IN NEW FILTERS. + The filter's "getframe" function only ever gets called from one thread at a + time. Unlike fmUnordered, only one frame is processed at a time. + + +.. _VSMediaType: + +enum VSMediaType +---------------- + + Used to indicate the type of a `VSFrame` or `VSNode` object. + + * mtVideo + + * mtAudio + + +.. _VSAudioChannels: + +enum VSAudioChannels +-------------------- + + Audio channel positions as an enum. Mirrors the FFmpeg audio channel constants in older api versions. See the header for all available values. + + * ac\* + + +.. _VSPropertyType: + +enum VSPropertyType +------------------- + + Types of properties that can be stored in a VSMap. + + * ptUnset + + * ptInt + + * ptFloat + + * ptData + + * ptFunction + + * ptVideoNode + + * ptAudioNode + + * ptVideoFrame + + * ptAudioFrame + + +.. _VSMapPropertyError: + +enum VSMapPropertyError +----------------------- + + When a mapGet* function fails, it returns one of these in the *err* + parameter. + + All errors are non-zero. + + * peSuccess + + * peUnset + + The requested key was not found in the map. + + * peType + + The wrong function was used to retrieve the property. E.g. + mapGetInt_\ () was used on a property of type ptFloat. + + * peIndex + + The requested index was out of bounds. + + * peError + + The map has the error state set. + + +.. _VSMapAppendMode: + +enum VSMapAppendMode +--------------------- + + Controls the behaviour of mapSetInt_\ () and friends. + + * maReplace + + All existing values associated with the key will be replaced with + the new value. + + * maAppend + + The new value will be appended to the list of existing values + associated with the key. + + +.. _VSActivationReason: + +enum VSActivationReason +----------------------- + + See VSFilterGetFrame_. + + * arInitial + + * arAllFramesReady + + * arError + + +.. _VSMessageType: + +enum VSMessageType +------------------ + + See addLogHandler_\ (). + + * mtDebug + + * mtInformation + + * mtWarning + + * mtCritical + + * mtFatal + + +.. _VSCoreCreationFlags: + +enum VSCoreCreationFlags +------------------------ + + Options when creating a core. + + * ccfEnableGraphInspection + + Required to use the graph inspection api functions. Increases memory usage due to the extra information stored. + + * ccfDisableAutoLoading + + Don't autoload any user plugins. Core plugins are always loaded. + + * ccfDisableLibraryUnloading + + Don't unload plugin libraries when the core is destroyed. Due to a small amount of memory leaking every load + and unload (windows feature, not my fault) of a library this may help in applications with extreme amount of script reloading. + + +.. _VSPluginConfigFlags: + +enum VSPluginConfigFlags +------------------------ + + Options when loading a plugin. + + * pcModifiable + + Allow functions to be added to the plugin object after the plugin loading phase. Mostly useful for + Avisynth compatibility and other foreign plugin loaders. + + +.. _VSDataTypeHint: + +enum VSDataTypeHint +------------------- + + Since the data type can contain both pure binary data and printable strings the type also contains a hint + for whether or not it is human readable. Generally the unknown type should be very rare and is almost only + created as an artifact of API3 compatibility. + + * dtUnknown + + * dtBinary + + * dtUtf8 + + +.. _VSRequestPattern: + +enum VSRequestPattern +--------------------- + + Describes the upstream frame request pattern of a filter. + + * rpGeneral + + Anything goes. Note that filters that may be requesting beyond the end of a VSNode length in frames (repeating the last frame) should use *rpGeneral* and not any of the other modes. + + * rpNoFrameReuse + + Will only request an input frame at most once if all output frames are requested exactly one time. This includes filters such as Trim, Reverse, SelectEvery. + + * rpStrictSpatial + + Only requests frame N to output frame N. The main difference to *rpNoFrameReuse* is that the requested frame is always fixed and known ahead of time. Filter examples Lut, Expr (conditionally, see *rpGeneral* note) and similar. + + +.. _VSCacheMode: + +enum VSCacheMode +---------------- + + Describes how the output of a node is cached. + + * cmAuto + + Cache is enabled or disabled based on the reported request patterns and number of consumers. + + * cmForceDisable + + Never cache anything. + + * cmForceEnable + + * Always use the cache. + + +Structs +####### + +Most structs are opaque and their contents can only be accessed using functions in the API. + + +.. _VSFrame: + +struct VSFrame +----------------- + + A frame that can hold audio or video data. + + Each row of pixels in a frame is guaranteed to have an alignment of at least 32 + bytes. Two frames with the same width and bytes per sample are guaranteed to have the same stride. + + Audio data is also guaranteed to be at least 32 byte aligned. + + Any data can be attached to a frame, using a VSMap_. + + +.. _VSNode: + +struct VSNode +---------------- + + A reference to a node in the constructed filter graph. Its primary use + is as an argument to other filter or to request frames from. + + +.. _VSCore: + +struct VSCore +------------- + + The core represents one instance of VapourSynth. Every core individually + loads plugins and keeps track of memory. + + +.. _VSPlugin: + +struct VSPlugin +--------------- + + A VapourSynth plugin. There are a few of these built into the core, + and therefore available at all times: the basic filters (identifier + ``com.vapoursynth.std``, namespace ``std``), the resizers (identifier + ``com.vapoursynth.resize``, namespace ``resize``), and the Avisynth + compatibility module, if running in Windows (identifier + ``com.vapoursynth.avisynth``, namespace ``avs``). + + The Function Reference describes how to load VapourSynth and Avisynth + plugins. + + A VSPlugin instance is constructed by the core when loading a plugin + (.so / .dylib / .dll), and the pointer is passed to the plugin's + VapourSynthPluginInit2() function. + + A VapourSynth plugin can export any number of filters. + + Plugins have a few attributes: + + - An identifier, which must be unique among all VapourSynth plugins in + existence, because this is what the core uses to make sure a plugin + only gets loaded once. + + - A namespace, also unique. The filters exported by a plugin end up in + the plugin's namespace. + + - A full name, which is used by the core in a few error messages. + + - The version of the plugin. + + - The VapourSynth API version the plugin requires. + + - A file name. + + Things you can do with a VSPlugin: + + - Enumerate all the filters it exports, using getNextPluginFunction_\ (). + + - Invoke one of its filters, using invoke_\ (). + + - Get its location in the file system, using getPluginPath_\ (). + + All loaded plugins (including built-in) can be enumerated with + getNextPlugin_\ (). + + Once loaded, a plugin only gets unloaded when the VapourSynth core is freed. + + +.. _VSPluginFunction: + +struct VSPluginFunction +----------------------- + + A function belonging to a Vapoursynth plugin. This object primarily exists so + a plugin's name, argument list and return type can be queried by editors. + + One peculiarity is that plugin functions cannot be invoked using a `VSPluginFunction` + pointer but is instead done using invoke_\ () which takes a `VSPlugin` and + the function name as a string. + + +.. _VSFunction: + +struct VSFunction +----------------- + + Holds a reference to a function that may be called. This type primarily exists + so functions can be shared between the scripting layer and plugins in the core. + + +.. _VSMap: + +struct VSMap +------------ + + VSMap is a container that stores (key,value) pairs. The keys are strings + and the values can be (arrays of) integers, floating point numbers, + arrays of bytes, VSNode_, VSFrame_, or VSFunction_. + + The pairs in a VSMap are sorted by key. + + In VapourSynth, VSMaps have several uses: + - storing filters' arguments and return values + + - storing user-defined functions' arguments and return values + + - storing the properties attached to frames + + Only alphanumeric characters and the underscore may be used in keys. + + Creating and destroying a map can be done with createMap_\ () and + freeMap_\ (), respectively. + + A map's contents can be retrieved and modified using a number of functions, + all prefixed with "map". + + A map's contents can be erased with clearMap_\ (). + + +.. _VSLogHandle: + +struct VSLogHandle +------------------ + + Opaque type representing a registered logger. + + +.. _VSFrameContext: + +struct VSFrameContext +--------------------- + + Opaque type representing the current frame request in a filter. + + +.. _VSVideoFormat: + +struct VSVideoFormat +-------------------- + + Describes the format of a clip. + + Use queryVideoFormat_\ () to fill it in with proper error checking. Manually filling out the struct is allowed but discouraged + since illegal combinations of values will cause undefined behavior. + + .. c:member:: int colorFamily + + See VSColorFamily_. + + .. c:member:: int sampleType + + See VSSampleType_. + + .. c:member:: int bitsPerSample + + Number of significant bits. + + .. c:member:: int bytesPerSample + + Number of bytes needed for a sample. This is always a power of 2 and the + smallest possible that can fit the number of bits used per sample. + + .. c:member:: int subSamplingW + .. c:member:: int subSamplingH + + log2 subsampling factor, applied to second and third plane. + Convenient numbers that can be used like so: + + .. code-block:: c + + uv_width = y_width >> subSamplingW; + + .. c:member:: int numPlanes + + Number of planes. + + +.. _VSVideoInfo: + +struct VSVideoInfo +------------------ + + Contains information about a clip. + + .. c:member:: VSVideoFormat format + + Format of the clip. Will have *colorFamily* set to *cfUndefined* if the format can vary. + + .. c:member:: int64_t fpsNum + + Numerator part of the clip's frame rate. It will be 0 if the frame + rate can vary. Should always be a reduced fraction. + + .. c:member:: int64_t fpsDen + + Denominator part of the clip's frame rate. It will be 0 if the frame + rate can vary. Should always be a reduced fraction. + + .. c:member:: int width + + Width of the clip. Both width and height will be 0 if the clip's dimensions can vary. + + .. c:member:: int height + + Height of the clip. Both width and height will be 0 if the clip's dimensions can vary. + + .. c:member:: int numFrames + + Length of the clip. + + +.. _VSAudioFormat: + +struct VSAudioFormat +-------------------- + + Describes the format of a clip. + + Use queryAudioFormat_\ () to fill it in with proper error checking. Manually filling out the struct is allowed but discouraged + since illegal combinations of values will cause undefined behavior. + + .. c:member:: int sampleType + + See VSSampleType_. + + .. c:member:: int bitsPerSample + + Number of significant bits. + + .. c:member:: int bytesPerSample + + Number of bytes needed for a sample. This is always a power of 2 and the + smallest possible that can fit the number of bits used per sample. + + .. c:member:: int numChannels + + Number of audio channels. + + .. c:member:: uint64_t channelLayout + + A bitmask representing the channels present using the constants in 1 left shifted by the constants in VSAudioChannels_. + + +.. _VSAudioInfo: + +struct VSAudioInfo +------------------ + + Contains information about a clip. + + .. c:member:: VSAudioFormat format + + Format of the clip. Unlike video the audio format can never change. + + .. c:member:: int sampleRate + + Sample rate. + + .. c:member:: int64_t numSamples + + Length of the clip in audio samples. + + .. c:member:: int numFrames + + Length of the clip in audio frames. + + +.. _VSCoreInfo: + +struct VSCoreInfo +----------------- + + Contains information about a VSCore_ instance. + + .. c:member:: const char* versionString + + Printable string containing the name of the library, copyright notice, + core and API versions. + + .. c:member:: int core + + Version of the core. + + .. c:member:: int api + + Version of the API. + + .. c:member:: int numThreads + + Number of worker threads. + + .. c:member:: int64_t maxFramebufferSize + + The framebuffer cache will be allowed to grow up to this size (bytes) before memory is aggressively reclaimed. + + .. c:member:: int64_t usedFramebufferSize + + Current size of the framebuffer cache, in bytes. + + +.. _VSFilterDependency: + +struct VSFilterDependency +------------------------- + + Contains information about a VSCore_ instance. + + .. c:member:: VSNode *source + + The node frames are requested from. + + .. c:member:: int requestPattern + + A value from VSRequestPattern_. + + +.. _VSPLUGINAPI: + +struct VSPLUGINAPI +------------------ + + This struct is used to access VapourSynth's API when a plugin is initially loaded. + +---------- + + int getAPIVersion() + + See getAPIVersion_\ () in the struct VSAPI_. + +---------- + + .. _configPlugin: + + int configPlugin(const char \*identifier, const char \*pluginNamespace, const char \*name, int pluginVersion, int apiVersion, int flags, VSPlugin \*plugin) + + Used to provide information about a plugin when loaded. Must be called exactly once from the *VapourSynthPluginInit2* entry point. + It is recommended to use the VS_MAKE_VERSION_ macro when providing the *pluginVersion*. If you don't know the specific *apiVersion* you actually require simply + pass VAPOURSYNTH_API_VERSION_ to match the header version you're compiling against. The *flags* consist of values from VSPluginConfigFlags_ ORed together + but should for most plugins typically be 0. + + Returns non-zero on success. + +---------- + + int registerFunction(const char \*name, const char \*args, const char \*returnType, VSPublicFunction argsFunc, void \*functionData, VSPlugin \*plugin) + + See registerFunction_\ () in the struct VSAPI_. + + +.. _VSAPI: + +struct VSAPI +------------ + + This giant struct is the way to access VapourSynth's public API. + +---------- + + .. _createCore: + + VSCore_ \*createCore(int flags) + + Creates the VapourSynth processing core and returns a pointer to it. It is + possible to create multiple cores but in most cases it shouldn't be needed. + + *flags* + `VSCoreCreationFlags` ORed together if desired. Pass 0 for sane defaults + that should suit most uses. + +---------- + + .. _freeCore: + + void freeCore(VSCore_ \*core) + + Frees a core. Should only be done after all frame requests have completed + and all objects belonging to the core have been released. + +---------- + + .. _setMaxCacheSize: + + int64_t setMaxCacheSize(int64_t bytes, VSCore_ \*core) + + Sets the maximum size of the framebuffer cache. Returns the new maximum + size. + +---------- + + .. _setThreadCount: + + int setThreadCount(int threads, VSCore_ \*core) + + Sets the number of threads used for processing. Pass 0 to automatically detect. + Returns the number of threads that will be used for processing. + +---------- + + .. _getCoreInfo: + + void getCoreInfo(VSCore_ \*core, VSCoreInfo_ \*info) + + Returns information about the VapourSynth core. + +---------- + + .. _getAPIVersion: + + int getAPIVersion() + + Returns the highest VAPOURSYNTH_API_VERSION_ the library support. + +---------- + + .. _logMessage: + + void logMessage(int msgType, const char \*msg, VSCore \*core) + + Send a message through VapourSynth's logging framework. See + addLogHandler_. + + *msgType* + The type of message. One of VSMessageType_. + + If *msgType* is mtFatal, VapourSynth will call abort() after + delivering the message. + + *msg* + The message. + +---------- + + .. _addLogHandler: + + VSLogHandle \*addLogHandler(VSLogHandler handler, VSLogHandlerFree free, void \*userData, VSCore_ \*core) + + Installs a custom handler for the various error messages VapourSynth + emits. The message handler is per VSCore_ instance. Returns a unique handle. + + If no log handler is installed up to a few hundred messages are cached and + will be delivered as soon as a log handler is attached. This behavior exists + mostly so that warnings when auto-loading plugins (default behavior) won't disappear- + + *handler* + typedef void (VS_CC \*VSLogHandler)(int msgType, const char \*msg, void \*userdata) + + Custom message handler. If this is NULL, the default message + handler will be restored. + + *msgType* + The type of message. One of VSMessageType_. + + If *msgType* is mtFatal, VapourSynth will call abort() after the + message handler returns. + + *msg* + The message. + + *free* + typedef void (VS_CC \*VSLogHandlerFree)(void \*userData) + + Called when a handler is removed. + + *userData* + Pointer that gets passed to the message handler. + +---------- + + .. _removeLogHandler: + + int removeLogHandler(VSLogHandle \*handle, VSCore \*core) + + Removes a custom handler. Return non-zero on success and zero if + the handle is invalid. + + *handle* + Handle obtained from addLogHandler_\ (). + +---------- + + .. _newVideoFrame: + + VSFrame_ \*newVideoFrame(const VSVideoFormat_ \*format, int width, int height, const VSFrame_ \*propSrc, VSCore_ \*core) + + Creates a new video frame, optionally copying the properties attached to another + frame. It is a fatal error to pass invalid arguments to this function. + + The new frame contains uninitialised memory. + + *format* + The desired colorspace format. Must not be NULL. + + *width* + + *height* + The desired dimensions of the frame, in pixels. Must be greater than 0 and have a suitable multiple for the subsampling in format. + + *propSrc* + A frame from which properties will be copied. Can be NULL. + + Returns a pointer to the created frame. Ownership of the new frame is + transferred to the caller. + + See also newVideoFrame2_\ (). + +---------- + + .. _newVideoFrame2: + + VSFrame_ \*newVideoFrame2(const VSVideoFormat_ \*format, int width, int height, const VSFrame_ \**planeSrc, const int \*planes, const VSFrame_ \*propSrc, VSCore_ \*core) + + Creates a new video frame from the planes of existing frames, optionally copying + the properties attached to another frame. It is a fatal error to pass invalid arguments to this function. + + *format* + The desired colorspace format. Must not be NULL. + + *width* + + *height* + The desired dimensions of the frame, in pixels. Must be greater than 0 and have a suitable multiple for the subsampling in format. + + *planeSrc* + Array of frames from which planes will be copied. If any elements of + the array are NULL, the corresponding planes in the new frame will + contain uninitialised memory. + + *planes* + Array of plane numbers indicating which plane to copy from the + corresponding source frame. + + *propSrc* + A frame from which properties will be copied. Can be NULL. + + Returns a pointer to the created frame. Ownership of the new frame is + transferred to the caller. + + Example (assume *frameA*, *frameB*, *frameC* are existing frames): + + .. code-block:: c + + const VSFrame * frames[3] = { frameA, frameB, frameC }; + const int planes[3] = { 1, 0, 2 }; + VSFrame * newFrame = vsapi->newVideoFrame2(f, w, h, frames, planes, frameB, core); + + The newFrame's first plane is now a copy of *frameA*'s second plane, + the second plane is a copy of *frameB*'s first plane, + the third plane is a copy of *frameC*'s third plane + and the properties have been copied from *frameB*. + +---------- + + .. _newAudioFrame: + + VSFrame_ \*newAudioFrame(const VSAudioFormat \*format, int numSamples, const VSFrame \*propSrc, VSCore \*core) + + Creates a new audio frame, optionally copying the properties attached to another + frame. It is a fatal error to pass invalid arguments to this function. + + The new frame contains uninitialised memory. + + *format* + The desired audio format. Must not be NULL. + + *numSamples* + The number of samples in the frame. All audio frames apart from the last one returned by a filter must have VS_AUDIO_FRAME_SAMPLES_. + + *propSrc* + A frame from which properties will be copied. Can be NULL. + + Returns a pointer to the created frame. Ownership of the new frame is + transferred to the caller. + + See also newAudioFrame2_\ (). + +---------- + + .. _newAudioFrame2: + + VSFrame_ \*newAudioFrame2(const VSAudioFormat_ \*format, int numSamples, const VSFrame_ \*\*channelSrc, const int \*channels, const VSFrame_ \*propSrc, VSCore \*core) + + Creates a new audio frame, optionally copying the properties attached to another + frame. It is a fatal error to pass invalid arguments to this function. + + The new frame contains uninitialised memory. + + *format* + The desired audio format. Must not be NULL. + + *numSamples* + The number of samples in the frame. All audio frames apart from the last one returned by a filter must have VS_AUDIO_FRAME_SAMPLES_. + + *channelSrc* + Array of frames from which channels will be copied. If any elements of + the array are NULL, the corresponding planes in the new frame will + contain uninitialised memory. + + *channels* + Array of channel numbers indicating which channel to copy from the + corresponding source frame. Note that the number refers to the nth channel + and not a channel name constant. + + *propSrc* + A frame from which properties will be copied. Can be NULL. + + Returns a pointer to the created frame. Ownership of the new frame is + transferred to the caller. + + See also newVideoFrame2_\ (). + +---------- + + .. _freeFrame: + + void freeFrame(const VSFrame_ \*f) + + Decrements the reference count of a frame and deletes it when it reaches 0. + + It is safe to pass NULL. + +---------- + + .. _addFrameRef: + + const VSFrame_ \*addFrameRef(const VSFrame_ \*f) + + Increments the reference count of a frame. Returns *f* as a convenience. + +---------- + + .. _copyFrame: + + VSFrame_ \*copyFrame(const VSFrame_ \*f, VSCore_ \*core) + + Duplicates the frame (not just the reference). As the frame buffer is + shared in a copy-on-write fashion, the frame content is not really + duplicated until a write operation occurs. This is transparent for the user. + + Returns a pointer to the new frame. Ownership is transferred to the caller. + +---------- + + .. _getFramePropertiesRO: + + const VSMap_ \*getFramePropertiesRO(const VSFrame_ \*f) + + Returns a read-only pointer to a frame's properties. The pointer is valid + as long as the frame lives. + +---------- + + .. _getFramePropertiesRW: + + VSMap_ \*getFramePropertiesRW(VSFrame_ \*f) + + Returns a read/write pointer to a frame's properties. The pointer is valid + as long as the frame lives. + +---------- + + .. _getStride: + + ptrdiff_t getStride(const VSFrame_ \*f, int plane) + + Returns the distance in bytes between two consecutive lines of a plane of + a video frame. The stride is always positive. Returns 0 if the requested + *plane* doesn't exist or if it isn't a video frame. + +---------- + + .. _getReadPtr: + + const uint8_t \*getReadPtr(const VSFrame_ \*f, int plane) + + Returns a read-only pointer to a *plane* or channel of a frame. + Returns NULL if an invalid *plane* or channel number is passed. + + .. note:: + Don't assume all three planes of a frame are allocated in one + contiguous chunk (they're not). + +---------- + + .. _getWritePtr: + + uint8_t \*getWritePtr(VSFrame_ \*f, int plane) + + Returns a read-write pointer to a *plane* or channel of a frame. + Returns NULL if an invalid *plane* or channel number is passed. + + .. note:: + Don't assume all three planes of a frame are allocated in one + contiguous chunk (they're not). + +---------- + + .. _getVideoFrameFormat: + + const VSVideoFormat_ \*getVideoFrameFormat(const VSFrame_ \*f) + + Retrieves the format of a video frame. + +---------- + + .. _getAudioFrameFormat: + + const VSAudioFormat_ \*getAudioFrameFormat(const VSFrame_ \*f) + + Retrieves the format of an audio frame. + +---------- + + .. _getFrameType: + + int getFrameType(const VSFrame_ \*f) + + Returns a value from VSMediaType_ to distinguish audio and video frames. + +---------- + + .. _getFrameWidth: + + int getFrameWidth(const VSFrame_ \*f, int plane) + + Returns the width of a *plane* of a given video frame, in pixels. The width + depends on the plane number because of the possible chroma subsampling. Returns 0 + for audio frames. + +---------- + + .. _getFrameHeight: + + int getFrameHeight(const VSFrame_ \*f, int plane) + + Returns the height of a *plane* of a given video frame, in pixels. The height + depends on the plane number because of the possible chroma subsampling. Returns 0 + for audio frames. + +---------- + + .. _getFrameLength: + + int getFrameLength(const VSFrame_ \*f) + + Returns the number of audio samples in a frame. Always returns 1 for video frames. + +---------- + + .. _createVideoFilter: + + void createVideoFilter(VSMap_ \*out, const char \*name, const VSVideoInfo_ \*vi, VSFilterGetFrame_ getFrame, VSFilterFree_ free, int filterMode, const VSFilterDependency_ \*dependencies, int numDeps, void \*instanceData, VSCore_ \*core) + + Creates a new video filter node. + + *out* + Output map for the filter node. + + *name* + Instance name. Please make it the same as the filter's name for easy identification. + + *vi* + The output format of the filter. + + *getFrame* + The filter's "getframe" function. Must not be NULL. + + *free* + The filter's "free" function. Can be NULL. + + *filterMode* + One of VSFilterMode_. Indicates the level of parallelism + supported by the filter. + + *dependencies* + An array of nodes the filter requests frames from and the access pattern. + Used to more efficiently configure caches. + + *numDeps* + Length of the *dependencies* array. + + *instanceData* + A pointer to the private filter data. This pointer will be passed to + the *getFrame* and *free* functions. It should be freed by + the *free* function. + + After this function returns, *out* will contain the new node appended to the + "clip" property, or an error, if something went wrong. + +---------- + + .. _createVideoFilter2: + + VSNode_ \*createVideoFilter2(const char \*name, const VSVideoInfo_ \*vi, VSFilterGetFrame_ getFrame, VSFilterFree_ free, int filterMode, const VSFilterDependency_ \*dependencies, int numDeps, void \*instanceData, VSCore_ \*core) + + Identical to createVideoFilter_ except that the new node is returned + instead of appended to the *out* map. Returns NULL on error. + +---------- + + .. _createAudioFilter: + + void createAudioFilter(VSMap \*out, const char \*name, const VSAudioInfo \*ai, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency_ \*dependencies, int numDeps, void \*instanceData, VSCore \*core) + + Creates a new video filter node. + + *out* + Output map for the filter node. + + *name* + Instance name. Please make it the same as the filter's name for easy identification. + + *ai* + The output format of the filter. + + *getFrame* + The filter's "getframe" function. Must not be NULL. + + *free* + The filter's "free" function. Can be NULL. + + *filterMode* + One of VSFilterMode_. Indicates the level of parallelism + supported by the filter. + + *dependencies* + An array of nodes the filter requests frames from and the access pattern. + Used to more efficiently configure caches. + + *numDeps* + Length of the *dependencies* array. + + *instanceData* + A pointer to the private filter data. This pointer will be passed to + the *getFrame* and *free* functions. It should be freed by + the *free* function. + + After this function returns, *out* will contain the new node appended to the + "clip" property, or an error, if something went wrong. + +---------- + + .. _createAudioFilter2: + + VSNode \*createAudioFilter2(const char \*name, const VSAudioInfo \*ai, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency_ \*dependencies, int numDeps, void \*instanceData, VSCore \*core) + + Identical to createAudioFilter_ except that the new node is returned + instead of appended to the *out* map. Returns NULL on error. + +---------- + + .. _setLinearFilter: + + int setLinearFilter(VSNode_ \*node) + + Must be called immediately after audio or video filter creation. + Returns the upper bound of how many additional frames it is + reasonable to pass to cacheFrame_ when trying to make a request + more linear. + +---------- + + .. _setCacheMode: + + void setCacheMode(VSNode_ \*node, int mode) + + Determines the strategy for frame caching. Pass a VSCacheMode_ constant. + Mostly useful for cache debugging since the auto mode should work well + in just about all cases. Calls to this function may also be silently ignored. + + Resets the cache to default options when called, discarding setCacheOptions_ + changes. + +---------- + + .. _setCacheOptions: + + void setCacheOptions(VSNode_ \*node, int fixedSize, int maxSize, int maxHistorySize) + + Call after setCacheMode_ or the changes will be discarded. Sets internal + details of a node's associated cache. Calls to this function may also + be silently ignored. + + *fixedSize* + Set to non-zero to make the cache always hold *maxSize* frames. + + *maxSize* + The maximum number of frames to cache. Note that this value is automatically + adjusted using an internal algorithm unless *fixedSize* is set. + + *maxHistorySize* + How many frames that have been recently evicted from the cache to keep track off. + Used to determine if growing or shrinking the cache is beneficial. Has no effect + when *fixedSize* is set. + +---------- + + .. _freeNode: + + void freeNode(VSNode_ \*node) + + Decreases the reference count of a node and destroys it once it reaches 0. + + It is safe to pass NULL. + +---------- + + .. _addNodeRef: + + VSNode_ \*addNodeRef(VSNode_ \*node) + + Increment the reference count of a node. Returns the same *node* for convenience. + +---------- + + .. _getNodeType: + + int getNodeType(VSNode_ \*node) + + Returns VSMediaType_. Used to determine if a node is of audio or video type. + +---------- + + .. _getVideoInfo: + + const VSVideoInfo_ \*getVideoInfo(VSNode_ \*node) + + Returns a pointer to the video info associated with a node. The pointer is + valid as long as the node lives. It is undefined behavior to pass a non-video + node. + +---------- + + .. _getAudioInfo: + + const VSAudioInfo_ \*getAudioInfo(VSNode_ \*node) + + Returns a pointer to the audio info associated with a node. The pointer is + valid as long as the node lives. It is undefined behavior to pass a non-audio + node. + +---------- + + .. _getVideoFormatName: + + int getVideoFormatName(const VSVideoFormat \*format, char \*buffer) + + Tries to output a fairly human-readable name of a video format. + + *format* + The input video format. + + *buffer* + Destination buffer. At most 32 bytes including terminating NULL + will be written. + + Returns non-zero on success. + +---------- + + .. _getAudioFormatName: + + int getAudioFormatName(const VSAudioFormat \*format, char \*buffer) + + Tries to output a fairly human-readable name of an audio format. + + *format* + The input audio format. + + *buffer* + Destination buffer. At most 32 bytes including terminating NULL + will be written. + + Returns non-zero on success. + +---------- + + .. _queryVideoFormat: + + int queryVideoFormat(VSVideoFormat_ \*format, int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore_ \*core) + + Fills out a VSVideoInfo_ struct based on the provided arguments. Validates the arguments before filling out *format*. + + *format* + The struct to fill out. + + *colorFamily* + One of VSColorFamily_. + + *sampleType* + One of VSSampleType_. + + *bitsPerSample* + Number of meaningful bits for a single component. The valid range is + 8-32. + + For floating point formats only 16 or 32 bits are allowed. + + *subSamplingW* + log2 of the horizontal chroma subsampling. 0 == no subsampling. The valid range is 0-4. + + *subSamplingH* + log2 of the vertical chroma subsampling. 0 == no subsampling. The valid range is 0-4. + + .. note:: + RGB formats are not allowed to be subsampled in VapourSynth. + + Returns non-zero on success. + +---------- + + .. _queryAudioFormat: + + int queryAudioFormat(VSAudioFormat_ \*format, int sampleType, int bitsPerSample, uint64_t channelLayout, VSCore_ \*core) + + Fills out a VSAudioFormat_ struct based on the provided arguments. Validates the arguments before filling out *format*. + + *format* + The struct to fill out. + + *sampleType* + One of VSSampleType_. + + *bitsPerSample* + Number of meaningful bits for a single component. The valid range is + 8-32. + + For floating point formats only 32 bits are allowed. + + *channelLayout* + A bitmask constructed from bitshifted constants in VSAudioChannels_. For example stereo is expressed as (1 << acFrontLeft) | (1 << acFrontRight). + + Returns non-zero on success. + +---------- + + .. _queryVideoFormatID: + + uint32_t queryVideoFormatID(int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore_ \*core) + + Get the id associated with a video format. Similar to queryVideoFormat_\ () except that it returns a format id instead + of filling out a VSVideoInfo_ struct. + + *colorFamily* + One of VSColorFamily_. + + *sampleType* + One of VSSampleType_. + + *bitsPerSample* + Number of meaningful bits for a single component. The valid range is + 8-32. + + For floating point formats, only 16 or 32 bits are allowed. + + *subSamplingW* + log2 of the horizontal chroma subsampling. 0 == no subsampling. The valid range is 0-4. + + *subSamplingH* + log2 of the vertical chroma subsampling. 0 == no subsampling. The valid range is 0-4. + + .. note:: + RGB formats are not allowed to be subsampled in VapourSynth. + + Returns a valid format id if the provided arguments are valid, on error + 0 is returned. + +---------- + + .. _getVideoFormatByID: + + int getVideoFormatByID(VSVideoFormat_ \*format, uint32_t id, VSCore_ \*core) + + Fills out the VSVideoFormat_ struct passed to *format* based + + *format* + The struct to fill out. + + *id* + The format identifier: one of VSPresetVideoFormat_ or a value gotten from queryVideoFormatID_. + + Returns 0 on failure and non-zero on success. + +---------- + + .. _createMap: + + VSMap_ \*createMap(void) + + Creates a new property map. It must be deallocated later with + freeMap_\ (). + +---------- + + .. _freeMap: + + void freeMap(VSMap_ \*map) + + Frees a map and all the objects it contains. + +---------- + + .. _clearMap: + + void clearMap(VSMap_ \*map) + + Deletes all the keys and their associated values from the map, leaving it + empty. + +---------- + + .. _mapGetError: + + const char \*mapGetError(const VSMap_ \*map) + + Returns a pointer to the error message contained in the map, + or NULL if there is no error set. The pointer is valid until + the next modifying operation on the map. + +---------- + + .. _mapSetError: + + void mapSetError(VSMap_ \*map, const char \*errorMessage) + + Adds an error message to a map. The map is cleared first. The error + message is copied. In this state the map may only be freed, cleared + or queried for the error message. + + For errors encountered in a filter's "getframe" function, use + setFilterError_. + +---------- + + .. _mapNumKeys: + + int mapNumKeys(const VSMap_ \*map) + + Returns the number of keys contained in a property map. + +---------- + + .. _mapGetKey: + + const char \*mapGetKey(const VSMap_ \*map, int index) + + Returns the nth key from a property map. + + Passing an invalid *index* will cause a fatal error. + + The pointer is valid as long as the key exists in the map. + +---------- + + .. _mapDeleteKey: + + int mapDeleteKey(VSMap_ \*map, const char \*key) + + Removes the property with the given key. All values associated with the + key are lost. + + Returns 0 if the key isn't in the map. Otherwise it returns 1. + +---------- + + .. _mapNumElements: + + int mapNumElements(const VSMap_ \*map, const char \*key) + + Returns the number of elements associated with a key in a property map. + Returns -1 if there is no such key in the map. + +---------- + + .. _mapGetType: + + int mapGetType(const VSMap_ \*map, const char \*key) + + Returns a value from VSPropertyType_ representing type + of elements in the given key. If there is no such key in the + map, the returned value is ptUnset. Note that also empty + arrays created with mapSetEmpty_ are typed. + +---------- + + .. _mapSetEmpty: + + int mapSetEmpty(const VSMap_ \*map, const char \*key, int type) + + Creates an empty array of *type* in *key*. Returns non-zero + value on failure due to *key* already existing or having an + invalid name. + +---------- + + .. _mapGetInt: + + int64_t mapGetInt(const VSMap_ \*map, const char \*key, int index, int \*error) + + Retrieves an integer from a specified *key* in a *map*. + + Returns the number on success, or 0 in case of error. + + If the map has an error set (i.e. if mapGetError_\ () returns non-NULL), + VapourSynth will die with a fatal error. + + *index* + Zero-based index of the element. + + Use mapNumElements_\ () to know the total number of elements + associated with a key. + + *error* + One of VSMapPropertyError_, peSuccess on success. + + You may pass NULL here, but then any problems encountered while + retrieving the property will cause VapourSynth to die with a fatal + error. + +---------- + + .. _mapGetIntSaturated: + + int mapGetIntSaturated(const VSMap_ \*map, const char \*key, int index, int \*error) + + Works just like mapGetInt_\ () except that the value returned is also + converted to an integer using saturation. + +---------- + + .. _mapGetIntArray: + + const int64_t \*mapGetIntArray(const VSMap_ \*map, const char \*key, int \*error) + + Retrieves an array of integers from a map. Use this function if there + are a lot of numbers associated with a key, because it is faster than + calling mapGetInt_\ () in a loop. + + Returns a pointer to the first element of the array on success, or NULL + in case of error. Use mapNumElements_\ () to know the total number of + elements associated with a key. + + See mapGetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapSetInt: + + int mapSetInt(VSMap_ \*map, const char \*key, int64_t i, int append) + + Sets an integer to the specified key in a map. + + Multiple values can be associated with one key, but they must all be the + same type. + + *key* + Name of the property. Alphanumeric characters and underscore + may be used. + + *i* + Value to store. + + *append* + One of VSMapAppendMode_. + + Returns 0 on success, or 1 if trying to append to a property with the + wrong type to an existing key. + +---------- + + .. _mapSetIntArray: + + int mapSetIntArray(VSMap_ \*map, const char \*key, const int64_t \*i, int size) + + Adds an array of integers to a map. Use this function if there are a + lot of numbers to add, because it is faster than calling mapSetInt_\ () + in a loop. + + If *map* already contains a property with this *key*, that property will + be overwritten and all old values will be lost. + + *key* + Name of the property. Alphanumeric characters and underscore + may be used. + + *i* + Pointer to the first element of the array to store. + + *size* + Number of integers to read from the array. It can be 0, in which case + no integers are read from the array, and the property will be created + empty. + + Returns 0 on success, or 1 if *size* is negative. + +---------- + + .. _mapGetFloat: + + double mapGetFloat(const VSMap_ \*map, const char \*key, int index, int \*error) + + Retrieves a floating point number from a map. + + Returns the number on success, or 0 in case of error. + + See mapGetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapGetFloatSaturated: + + float mapGetFloatSaturated(const VSMap_ \*map, const char \*key, int index, int \*error) + + Works just like mapGetFloat_\ () except that the value returned is also + converted to a float. + +---------- + + .. _mapGetFloatArray: + + const double \*mapGetFloatArray(const VSMap_ \*map, const char \*key, int \*error) + + Retrieves an array of floating point numbers from a map. Use this function if there + are a lot of numbers associated with a key, because it is faster than + calling mapGetFloat_\ () in a loop. + + Returns a pointer to the first element of the array on success, or NULL + in case of error. Use mapNumElements_\ () to know the total number of + elements associated with a key. + + See mapGetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapSetFloat: + + int mapSetFloat(VSMap_ \*map, const char \*key, double d, int append) + + Sets a float to the specified key in a map. + + See mapSetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapSetFloatArray: + + int mapSetFloatArray(VSMap_ \*map, const char \*key, const double \*d, int size) + + Adds an array of floating point numbers to a map. Use this function if + there are a lot of numbers to add, because it is faster than calling + mapSetFloat_\ () in a loop. + + If *map* already contains a property with this *key*, that property will + be overwritten and all old values will be lost. + + *key* + Name of the property. Alphanumeric characters and underscore + may be used. + + *d* + Pointer to the first element of the array to store. + + *size* + Number of floating point numbers to read from the array. It can be 0, + in which case no numbers are read from the array, and the property + will be created empty. + + Returns 0 on success, or 1 if *size* is negative. + +---------- + + .. _mapGetData: + + const char \*mapGetData(const VSMap_ \*map, const char \*key, int index, int \*error) + + Retrieves arbitrary binary data from a map. Checking mapGetDataTypeHint_\ () + may provide a hint about whether or not the data is human readable. + + Returns a pointer to the data on success, or NULL in case of error. + + The array returned is guaranteed to be NULL-terminated. The NULL + byte is not considered to be part of the array (mapGetDataSize_ + doesn't count it). + + The pointer is valid until the map is destroyed, or until the + corresponding key is removed from the map or altered. + + See mapGetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapGetDataSize: + + int mapGetDataSize(const VSMap_ \*map, const char \*key, int index, int \*error) + + Returns the size in bytes of a property of type ptData (see + VSPropertyType_), or 0 in case of error. The terminating NULL byte + added by mapSetData_\ () is not counted. + + See mapGetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapGetDataTypeHint: + + int mapGetDataTypeHint(const VSMap_ \*map, const char \*key, int index, int \*error) + + Returns the size in bytes of a property of type ptData (see + VSPropertyType_), or 0 in case of error. The terminating NULL byte + added by mapSetData_\ () is not counted. + + See mapGetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapSetData: + + int mapSetData(VSMap \*map, const char \*key, const char \*data, int size, int type, int append) + + Sets binary data to the specified key in a map. + + Multiple values can be associated with one key, but they must all be the + same type. + + *key* + Name of the property. Alphanumeric characters and the underscore + may be used. + + *data* + Value to store. + + This function copies the data, so the pointer should be freed when + no longer needed. A terminating NULL is always added to the copied data + but not included in the total size to make string handling easier. + + *size* + The number of bytes to copy. If this is negative, everything up to + the first NULL byte will be copied. + + *type* + One of VSDataTypeHint_ to hint whether or not it is human readable data. + + *append* + One of VSMapAppendMode_. + + Returns 0 on success, or 1 if trying to append to a property with the + wrong type. + +---------- + + .. _mapGetNode: + + VSNode_ \*mapGetNode(const VSMap_ \*map, const char \*key, int index, int \*error) + + Retrieves a node from a map. + + Returns a pointer to the node on success, or NULL in case of error. + + This function increases the node's reference count, so freeNode_\ () must + be used when the node is no longer needed. + + See mapGetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapSetNode: + + int mapSetNode(VSMap_ \*map, const char \*key, VSNode_ \*node, int append) + + Sets a node to the specified key in a map. + + See mapSetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapConsumeNode: + + int mapConsumeNode(VSMap_ \*map, const char \*key, VSNode_ \*node, int append) + + Sets a node to the specified key in a map and decreases the reference count. + + See mapSetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapGetFrame: + + const VSFrame_ \*propGetFrame(const VSMap_ \*map, const char \*key, int index, int \*error) + + Retrieves a frame from a map. + + Returns a pointer to the frame on success, or NULL in case of error. + + This function increases the frame's reference count, so freeFrame_\ () must + be used when the frame is no longer needed. + + See mapGetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapSetFrame: + + int mapSetFrame(VSMap_ \*map, const char \*key, const VSFrame_ \*f, int append) + + Sets a frame to the specified key in a map. + + See mapSetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapConsumeFrame: + + int mapConsumeFrame(VSMap_ \*map, const char \*key, const VSFrame_ \*f, int append) + + Sets a frame to the specified key in a map and decreases the reference count. + + See mapSetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapGetFunction: + + VSFunctionRef \*mapGetFunc(const VSMap_ \*map, const char \*key, int index, int \*error) + + Retrieves a function from a map. + + Returns a pointer to the function on success, or NULL in case of error. + + This function increases the function's reference count, so freeFunction_\ () must + be used when the function is no longer needed. + + See mapGetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapSetFunction: + + int mapSetFunction(VSMap_ \*map, const char \*key, VSFunction \*func, int append) + + Sets a function object to the specified key in a map. + + See mapSetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _mapConsumeFunction: + + int mapConsumeFunction(VSMap_ \*map, const char \*key, VSFunction \*func, int append) + + Sets a function object to the specified key in a map and decreases the reference count. + + See mapSetInt_\ () for a complete description of the arguments and general behavior. + +---------- + + .. _getPluginByID: + + VSPlugin_ \*getPluginByID(const char \*identifier, VSCore_ \*core) + + Returns a pointer to the plugin with the given identifier, or NULL + if not found. + + *identifier* + Reverse URL that uniquely identifies the plugin. + +---------- + + .. _getPluginByNamespace: + + VSPlugin_ \*getPluginByNamespace(const char \*ns, VSCore_ \*core) + + Returns a pointer to the plugin with the given namespace, or NULL + if not found. + + getPluginByID_ is generally a better option. + + *ns* + Namespace. + +---------- + + .. _getNextPlugin: + + VSPlugin_ \*getNextPlugin(VSPlugin_ \*plugin, VSCore_ \*core) + + Used to enumerate over all currently loaded plugins. The order + is fixed but provides no other guarantees. + + *plugin* + Current plugin. Pass NULL to get the first plugin. + + Returns a pointer to the next plugin in order or NULL if the final + plugin has been reached. + +---------- + + .. _getPluginName: + + const char \*getPluginName(VSPlugin_ \*plugin) + + Returns the name of the plugin that was passed to configPlugin_. + +---------- + + .. _getPluginID: + + const char \*getPluginID(VSPlugin_ \*plugin) + + Returns the identifier of the plugin that was passed to configPlugin_. + +---------- + + .. _getPluginNamespace: + + const char \*getPluginNamespace(VSPlugin_ \*plugin) + + Returns the namespace the plugin currently is loaded in. + +---------- + + .. _getNextPluginFunction: + + VSPluginFunction_ \*getNextPluginFunction(VSPluginFunction_ \*func, VSPlugin \*plugin) + + Used to enumerate over all functions in a plugin. The order + is fixed but provides no other guarantees. + + *func* + Current function. Pass NULL to get the first function. + + *plugin* + The plugin to enumerate functions in. + + Returns a pointer to the next function in order or NULL if the final + function has been reached. + +---------- + + .. _getPluginFunctionByName: + + VSPluginFunction_ \*getPluginFunctionByName(const char \*name, VSPlugin_ \*plugin) + + Get a function belonging to a plugin by its name. + +---------- + + .. _getPluginFunctionName: + + const char \*getPluginFunctionName(VSPluginFunction_ \*func) + + Returns the name of the function that was passed to registerFunction_. + +---------- + + .. _getPluginFunctionArguments: + + const char \*getPluginFunctionArguments(VSPluginFunction_ \*func) + + Returns the argument string of the function that was passed to registerFunction_. + +---------- + + .. _getPluginFunctionReturnType: + + const char \*getPluginFunctionReturnType(VSPluginFunction_ \*func) + + Returns the return type string of the function that was passed to registerFunction_. + +---------- + + .. _getPluginPath: + + const char \*getPluginPath(const VSPlugin_ \*plugin) + + Returns the absolute path to the plugin, including the plugin's file + name. This is the real location of the plugin, i.e. there are no + symbolic links in the path. + + Path elements are always delimited with forward slashes. + + VapourSynth retains ownership of the returned pointer. + +---------- + + .. _getPluginVersion: + + int getPluginVersion(const VSPlugin_ \*plugin) + + Returns the version of the plugin. This is the same as the version number passed to configPlugin_. + +---------- + + .. _invoke: + + VSMap_ \*invoke(VSPlugin_ \*plugin, const char \*name, const VSMap_ \*args) + + Invokes a filter. + + invoke() checks that + the *args* passed to the filter are consistent with the argument list + registered by the plugin that contains the filter, calls the filter's + "create" function, and checks that the filter returns the declared types. + If everything goes smoothly, the filter will be ready to generate + frames after invoke() returns. + + *plugin* + A pointer to the plugin where the filter is located. Must not be NULL. + + See getPluginByID_\ (). + + *name* + Name of the filter to invoke. + + *args* + Arguments for the filter. + + Returns a map containing the filter's return value(s). The caller takes + ownership of the map. Use mapGetError_\ () to check if the filter was invoked + successfully. + + Most filters will either set an error, or one or more clips + with the key "clip". The exception to this are functions, for example + LoadPlugin, which doesn't return any clips for obvious reasons. + +---------- + + .. _createFunction: + + VSFunction_ \*createFunction(VSPublicFunction func, void \*userData, VSFreeFunctionData free, VSCore_ \*core) + + *func* + typedef void (VS_CC \*VSPublicFunction)(const VSMap_ \*in, VSMap_ \*out, void \*userData, VSCore_ \*core, const VSAPI_ \*vsapi) + + User-defined function that may be called in any context. + + *userData* + Pointer passed to *func*. + + *free* + typedef void (VS_CC \*VSFreeFunctionData)(void \*userData) + + Callback tasked with freeing *userData*. Can be NULL. + +---------- + + .. _freeFunction: + + void freeFunction(VSFunction_ \*f) + + Decrements the reference count of a function and deletes it when it reaches 0. + + It is safe to pass NULL. + +---------- + + .. _addFunctionRef: + + VSFunction_ \*addFunctionRef(VSFunction_ \*f) + + Increments the reference count of a function. Returns *f* as a convenience. + +---------- + + .. _callFunction: + + void callFunction(VSFunction_ \*func, const VSMap_ \*in, VSMap_ \*out) + + Calls a function. If the call fails *out* will have an error set. + + *func* + Function to be called. + + *in* + Arguments passed to *func*. + + *out* + Returned values from *func*. + +---------- + + .. _getFrame: + + const VSFrame_ \*getFrame(int n, VSNode_ \*node, char \*errorMsg, int bufSize) + + Fetches a frame synchronously. The frame is available when the function + returns. + + This function is meant for external applications using the core as a + library, or if frame requests are necessary during a filter's + initialization. + + Thread-safe. + + *n* + The frame number. Negative values will cause an error. + + *node* + The node from which the frame is requested. + + *errorMsg* + Pointer to a buffer of *bufSize* bytes to store a possible error + message. Can be NULL if no error message is wanted. + + *bufSize* + Maximum length for the error message, in bytes (including the + trailing '\0'). Can be 0 if no error message is wanted. + + Returns a reference to the generated frame, or NULL in case of failure. + The ownership of the frame is transferred to the caller. + + .. warning:: + Never use inside a filter's "getframe" function. + +---------- + + .. _getFrameAsync: + + void getFrameAsync(int n, VSNode_ \*node, VSFrameDoneCallback callback, void \*userData) + + Requests the generation of a frame. When the frame is ready, + a user-provided function is called. Note that the completion + *callback* will only be called from a single thread at a time. + + This function is meant for applications using VapourSynth as a library. + + Thread-safe. + + *n* + Frame number. Negative values will cause an error. + + *node* + The node from which the frame is requested. + + *callback* + typedef void (VS_CC \*VSFrameDoneCallback)(void \*userData, const VSFrame_ \*f, int n, VSNode_ \*node, const char \*errorMsg) + + Function of the client application called by the core when a requested + frame is ready, after a call to getFrameAsync(). + + If multiple frames were requested, they can be returned in any order. + Client applications must take care of reordering them. + + This function is only ever called from one thread at a time. + + getFrameAsync() may be called from this function to request more + frames. + + *userData* + Pointer to private data from the client application, as passed + previously to getFrameAsync(). + + *f* + Contains a reference to the generated frame, or NULL in case of failure. + The ownership of the frame is transferred to the caller. + + *n* + The frame number. + + *node* + Node the frame belongs to. + + *errorMsg* + String that usually contains an error message if the frame + generation failed. NULL if there is no error. + + *userData* + Pointer passed to the callback. + + .. warning:: + Never use inside a filter's "getframe" function. + +---------- + + .. _getFrameFilter: + + const VSFrame_ \*getFrameFilter(int n, VSNode_ \*node, VSFrameContext_ \*frameCtx) + + Retrieves a frame that was previously requested with + requestFrameFilter_\ (). + + Only use inside a filter's "getframe" function. + + A filter usually calls this function when its activation reason is + arAllFramesReady or arFrameReady. See VSActivationReason_. + + It is safe to retrieve a frame more than once, but each reference + needs to be freed. + + *n* + The frame number. + + *node* + The node from which the frame is retrieved. + + *frameCtx* + The context passed to the filter's "getframe" function. + + Returns a pointer to the requested frame, or NULL if the requested frame + is not available for any reason. The ownership of the frame is + transferred to the caller. + +---------- + + .. _requestFrameFilter: + + void requestFrameFilter(int n, VSNode_ \*node, VSFrameContext_ \*frameCtx) + + Requests a frame from a node and returns immediately. + + Only use inside a filter's "getframe" function. + + A filter usually calls this function when its activation reason is + arInitial. The requested frame can then be retrieved using + getFrameFilter_\ (), when the filter's activation reason is + arAllFramesReady. See VSActivationReason_. + + It is best to request frames in ascending order, i.e. n, n+1, n+2, etc. + + *n* + The frame number. Negative values will cause an error. + + *node* + The node from which the frame is requested. + + *frameCtx* + The context passed to the filter's "getframe" function. + +---------- + + .. _releaseFrameEarly: + + void releaseFrameEarly(VSNode_ \*node, int n, VSFrameContext_ \*frameCtx) + + By default all requested frames are referenced until a filter's frame + request is done. In extreme cases where a filter needs to reduce 20+ + frames into a single output frame it may be beneficial to request + these in batches and incrementally process the data instead. + + Should rarely be needed. + + Only use inside a filter's "getframe" function. + + *node* + The node from which the frame was requested. + + *n* + The frame number. Invalid frame numbers (not cached or negative) will simply be ignored. + + *frameCtx* + The context passed to the filter's "getframe" function. + +---------- + + .. _registerFunction: + + int registerFunction(const char \*name, const char \*args, const char \*returnType, VSPublicFunction argsFunc, void \*functionData, VSPlugin_ \*plugin) + + Function that registers a filter exported by the plugin. A plugin can + export any number of filters. This function may only be called during the plugin + loading phase unless the pcModifiable flag was set by configPlugin_. + + *name* + Filter name. The characters allowed are letters, numbers, and the + underscore. The first character must be a letter. In other words: + ``^[a-zA-Z][a-zA-Z0-9_]*$`` + + Filter names *should be* PascalCase. + + *args* + String containing the filter's list of arguments. + + Arguments are separated by a semicolon. Each argument is made of + several fields separated by a colon. Don't insert additional + whitespace characters, or VapourSynth will die. + + Fields: + The argument name. + The same characters are allowed as for the filter's name. + Argument names *should be* all lowercase and use only letters + and the underscore. + + The type. + "int": int64_t + + "float": double + + "data": const char* + + "anode": const VSNode_\ * (audio type) + + "vnode": const VSNode_\ * (video type) + + "aframe": const VSFrame_\ * (audio type) + + "vframe": const VSFrame_\ * (video type) + + "func": const VSFunctionRef\ * + + It is possible to declare an array by appending "[]" to the type. + + "opt" + If the parameter is optional. + + "empty" + For arrays that are allowed to be empty. + + "any" + Can only be placed last without a semicolon after. Indicates that all remaining arguments that don't match + should also be passed through. + + The following example declares the arguments "blah", "moo", and "asdf":: + + blah:vnode;moo:int[]:opt;asdf:float:opt; + + The following example declares the arguments "blah" and accepts all other arguments no matter the type:: + + blah:vnode;any + + *returnType* + Specifies works similarly to *args* but instead specifies which keys and what type will be returned. Typically this will be:: + + clip:vnode; + + for video filters. It is important to not simply specify "any" for all filters since this information is used for better + auto-completion in many editors. + + *argsFunc* + typedef void (VS_CC \*VSPublicFunction)(const VSMap_ \*in, VSMap_ \*out, void \*userData, VSCore_ \*core, const VSAPI_ \*vsapi) + + User-defined function called by the core to create an instance of the + filter. This function is often named ``fooCreate``. + + In this function, the filter's input parameters should be retrieved + and validated, the filter's private instance data should be + initialised, and createAudioFilter_\ () or createVideoFilter_\ () should be called. This is where + the filter should perform any other initialisation it requires. + + If for some reason you cannot create the filter, you have to free any + created node references using freeNode_\ (), call mapSetError_\ () on + *out*, and return. + + *in* + Input parameter list. + + Use mapGetInt_\ () and friends to retrieve a parameter value. + + The map is guaranteed to exist only until the filter's "init" + function returns. In other words, pointers returned by + mapGetData_\ () will not be usable in the filter's "getframe" and + "free" functions. + + *out* + Output parameter list. createAudioFilter_\ () or createVideoFilter_\ () will add the output + node(s) with the key named "clip", or an error, if something went + wrong. + + *userData* + Pointer that was passed to registerFunction_\ (). + + *functionData* + Pointer to user data that gets passed to *argsFunc* when creating a + filter. Useful to register multiple filters using a single *argsFunc* + function. + + *plugin* + Pointer to the plugin object in the core, as passed to + VapourSynthPluginInit2(). + +---------- + + .. _cacheFrame: + + void cacheFrame(const VSFrame_ \*frame, int n, VSFrameContext_ \*frameCtx) + + Pushes a not requested frame into the cache. This is useful for (source) filters that greatly + benefit from completely linear access and producing all output in linear order. + + This function may only be used in filters that were created with setLinearFilter_. + + Only use inside a filter's "getframe" function. + +---------- + + .. _setFilterError: + + void setFilterError(const char \*errorMessage, VSFrameContext_ \*frameCtx) + + Adds an error message to a frame context, replacing the existing message, + if any. + + This is the way to report errors in a filter's "getframe" function. + Such errors are not necessarily fatal, i.e. the caller can try to + request the same frame again. + +Functions +######### + +.. _getVapourSynthAPI: + +const VSAPI_\* getVapourSynthAPI(int version) + + Returns a pointer to the global VSAPI instance. + + Returns NULL if the requested API version is not supported or if the system + does not meet the minimum requirements to run VapourSynth. It is recommended + to pass VAPOURSYNTH_API_VERSION_. + + +Writing plugins +############### + + +A simple VapourSynth plugin which exports one filter will contain five +functions: an entry point (called ``VapourSynthPluginInit2``), a function tasked +with creating a filter instance (often called ``fooCreate``), an "init" function +(often called ``fooInit``), a "getframe" function (often called ``fooGetframe``), +and a "free" function (often called ``fooFree``). These functions are described +below. + +Another thing a filter requires is an object for storing a filter instance's +private data. This object will usually contain the filter's input nodes (if it +has any) and a VSVideoInfo_ struct describing the video the filter wants to +return. + +The `sdk `_ folder +in the VapourSynth source contains some examples. + +---------- + +.. _VSInitPlugin: + +typedef void (VS_CC \*VSInitPlugin)(VSPlugin_ \*plugin, const VSPLUGINAPI_ \*vspapi) + + A plugin's entry point. It must be called ``VapourSynthPluginInit2``. + This function is called after the core loads the shared library. Its purpose + is to configure the plugin and to register the filters the plugin wants to + export. + + *plugin* + A pointer to the plugin object to be initialized. + + *vspapi* + A pointer to a VSPLUGINAPI_ struct with a subset of the VapourSynth API used for initializing plugins. + The proper way to do things is to call configPlugin_ and then registerFunction_ for each function to export. + +---------- + +.. _VSFilterGetFrame: + +typedef const VSFrame_ \*(VS_CC \*VSFilterGetFrame)(int n, int activationReason, void \*instanceData, void \**frameData, VSFrameContext_ \*frameCtx, VSCore_ \*core, const VSAPI_ \*vsapi) + + A filter's "getframe" function. It is called by the core when it needs + the filter to generate a frame. + + It is possible to allocate local data, persistent during the multiple + calls requesting the output frame. + + In case of error, call setFilterError_\ (), free \*frameData if required, + and return NULL. + + Depending on the VSFilterMode_ set for the filter, multiple output frames + could be requested concurrently. + + It is never called concurrently for the same frame number. + + *n* + Requested frame number. + + *activationReason* + One of VSActivationReason_. + + This function is first called with *activationReason* arInitial. At this + point the function should request the input frames it needs and return + NULL. When one or all of the requested frames are ready, this function + is called again with arAllFramesReady. + The function should only return a frame when called with + *activationReason* arAllFramesReady. + + If a the function is called with arError all processing has to be aborted + and any. + + *instanceData* + The filter's private instance data. + + *frameData* + Optional private data associated with output frame number *n*. + It must be deallocated before the last call for the given frame + (arAllFramesReady or error). + + It points to a void \*[4] array of memory that may be used freely. + See filters like Splice and Trim for examples. + + Return a reference to the output frame number *n* when it is ready, or NULL. + The ownership of the frame is transferred to the caller. + +---------- + +.. _VSFilterFree: + +typedef void (VS_CC \*VSFilterFree)(void \*instanceData, VSCore_ \*core, const VSAPI_ \*vsapi) + + A filter's "free" function. + + This is where the filter should free everything it allocated, + including its instance data. + + *instanceData* + The filter's private instance data. diff --git a/Programs/doc/_sources/api/vshelper4.h.rst.txt b/Programs/doc/_sources/api/vshelper4.h.rst.txt new file mode 100644 index 0000000..ea3456a --- /dev/null +++ b/Programs/doc/_sources/api/vshelper4.h.rst.txt @@ -0,0 +1,272 @@ +VSHelper4.h +=========== + +Table of contents +################# + +Introduction_ + + +Macros_ + VSH_STD_PLUGIN_ID_ + + VSH_RESIZE_PLUGIN_ID_ + + VSH_TEXT_PLUGIN_ID_ + + VS_RESTRICT_ + + `VSH_ALIGNED_MALLOC `_ + + `VSH_ALIGNED_FREE `_ + + VSMIN_ + + VSMAX_ + + +Functions_ + `vsh_aligned_malloc `_ + + `vsh_aligned_free `_ + + isConstantFormat_ + + isSameVideoFormat_ + + isSameVideoPresetFormat_ + + isSameVideoInfo_ + + isSameAudioFormat_ + + isSameAudioInfo_ + + muldivRational_ + + addRational_ + + reduceRational_ + + int64ToIntS_ + + doubleToFloatS_ + + bitblt_ + + areValidDimensions_ + + +Introduction +############ + +This is a collection of helpful macros and functions. Note that all functions (not macros) +are either prefixed with `vsh_` in C mode or placed in the `vsh` namespace for C++. This documentation +will use the C++ names for these function. + + +Macros +###### + +VSH_STD_PLUGIN_ID +----------------- +Macro defined to the internal std plugin id provided for convenience. + + +VSH_RESIZE_PLUGIN_ID +-------------------- +Macro defined to the internal resizer plugin id provided for convenience. + + +VSH_TEXT_PLUGIN_ID +------------------ +Macro defined to the internal std plugin id provided for convenience. + + +VS_RESTRICT +----------- + +Attempts to provide a portable definition of the C99 ``restrict`` keyword, +or its C++ counterpart. + + +.. _vsh_aligned_malloc_c: + +VSH_ALIGNED_MALLOC +------------------ + +VSH_ALIGNED_MALLOC(pptr, size, alignment) + +Expands to _aligned_malloc() in Windows, and posix_memalign() elsewhere. Note that +the arguments are in the style of posix_memalign(). + +*pptr* is a pointer to a pointer. + + +.. _vsh_aligned_free_c: + +VSH_ALIGNED_FREE +---------------- + +VSH_ALIGNED_FREE(ptr) + +Expands to _aligned_free() in Windows, and free() elsewhere. + +*ptr* is a pointer. + + +VSMIN +----- + +VSMIN(a, b) + +Returns the minimum of the two numbers. + + +VSMAX +----- + +VSMAX(a, b) + +Returns the maximum of the two numbers. + + +Functions +######### + +.. _vsh_aligned_malloc_cpp: + +vsh_aligned_malloc +------------------ + +.. cpp:function:: T* vsh::vsh_aligned_malloc(size_t size, size_t alignment) + + A templated aligned malloc for C++. It uses the same functions as the + `VSH_ALIGNED_MALLOC `_ macro but is easier to use. + + +.. _vsh_aligned_free_cpp: + +vsh_aligned_free +---------------- + +.. cpp:function:: void vsh::vsh_aligned_free(void *ptr) + + This simply uses the `VSH_ALIGNED_FREE `_ macro. + + +isConstantFormat +---------------- + +.. cpp:function:: static inline bool vsh::isConstantFormat(const VSVideoInfo *vi) + + Checks if a clip's format and dimensions are known (and therefore constant). + + +isSameVideoFormat +----------------- + +.. cpp:function:: static inline bool vsh::isSameVideoFormat(const VSVideoInfo *v1, const VSVideoInfo *v2) + + Checks if two clips have the same video format. If the format is + unknown in both, it will be considered the same. + + +isSameVideoPresetFormat +----------------------- + +.. cpp:function:: static inline bool vsh::isSameVideoPresetFormat(unsigned presetFormat, const VSVideoFormat *v, VSCore *core, const VSAPI *vsapi) + + Checks if a clip has the same video format as the preset. + + +isSameVideoInfo +--------------- + +.. cpp:function:: static inline bool vsh::isSameVideoInfo(const VSVideoInfo *v1, const VSVideoInfo *v2) + + Checks if two clips have the same video format and dimensions. If the format is + unknown in both, it will be considered the same. This is also true for the + dimensions. Framerate is not taken into consideration when comparing. + + + +isSameAudioFormat +----------------- + +.. cpp:function:: static inline bool vsh::isSameAudioFormat(const VSAudioInfo *v1, const VSAudioInfo *v2) + + Checks if two clips have the same audio format. + + +isSameAudioInfo +--------------- + +.. cpp:function:: static inline bool vsh::isSameAudioInfo(const VSAudioInfo *v1, const VSAudioInfo *v2) + + Checks if two clips have the same audio format and samplerate. + + +muldivRational +-------------- + +.. cpp:function:: static inline void vsh::muldivRational(int64_t *num, int64_t *den, int64_t mul, int64_t div) + + Multiplies two rational numbers and reduces the result, i.e. + *num*\ /\ *den* \* *mul*\ /\ *div*. The result is stored in *num* and *den*. + + The caller must ensure that *div* is not 0. + + +reduceRational +-------------- + +.. cpp:function:: static inline void vsh::reduceRational(int64_t *num, int64_t *den) + + Reduces a rational number. + + +addRational +----------- + +.. cpp:function:: static inline void vsh::addRational(int64_t *num, int64_t *den, int64_t addnum, int64_t addden) + + Adds two rational numbers and reduces the result, i.e. + *num*\ /\ *den* + *addnum*\ /\ *addden*. The result is stored in *num* and *den*. + + +int64ToIntS +----------- + +.. cpp:function:: static inline int vsh::int64ToIntS(int64_t i) + + Converts an int64_t to int with signed saturation. It's useful to silence + warnings when reading integer properties from a VSMap and to avoid unexpected behavior on int overflow. + + +doubleToFloatS +-------------- + +.. cpp:function:: static inline int vsh::doubleToFloatS(double d) + + Converts a double to float. It's useful to silence + warnings when reading double properties from a VSMap and mostly exists to mirror `int64ToIntS`_. + + +bitblt +------ + +.. cpp:function:: static inline void vsh::bitblt(void *dstp, int dst_stride, const void *srcp, int src_stride, size_t row_size, size_t height) + + Copies bytes from one plane to another. Basically, it is memcpy in a loop. + + *row_size* is in bytes. + + +areValidDimensions +------------------ + +.. cpp:function:: static inline bool vsh::areValidDimensions(const VSFormat *fi, int width, int height) + + Checks if the given dimensions are valid for a particular format, with regards + to chroma subsampling. diff --git a/Programs/doc/_sources/api/vsscript4.h.rst.txt b/Programs/doc/_sources/api/vsscript4.h.rst.txt new file mode 100644 index 0000000..76a96ce --- /dev/null +++ b/Programs/doc/_sources/api/vsscript4.h.rst.txt @@ -0,0 +1,292 @@ +VSScript4.h +=========== + +Table of contents +################# + +Introduction_ + + +Structs_ + VSScript_ + + VSScriptAPI_ + + +Functions_ + getVSScriptAPI_ + + getApiVersion_ + + getVSAPI_ + + createScript_ + + getCore_ + + evaluateBuffer_ + + evaluateFile_ + + getError_ + + getExitCode_ + + getVariable_ + + setVariables_ + + getOutputNode_ + + getOutputAlphaNode_ + + getAltOutputMode_ + + freeScript_ + + evalSetWorkingDir_ + + +Introduction +############ + +VSScript provides a convenient wrapper for VapourSynth's scripting interface(s), allowing the evaluation of VapourSynth scripts and retrieval of output clips. + +For reasons unknown, the VSScript library is called ``VSScript`` in Windows and ``vapoursynth-script`` everywhere else. + +At this time, VapourSynth scripts can be written only in Python (version 3). + +Here are a few users of the VSScript library: + + * `vspipe `_ + + * `vsvfw `_ + + * `an example program `_ + + * the video player `mpv `_ + +.. note:: + If libvapoursynth-script is loaded with dlopen(), the RTLD_GLOBAL flag must be used. If not, Python won't be able to import binary modules. This is due to Python's design. + + +Structs +####### + +VSScript +-------- + +A script environment. All evaluation and communication with evaluated scripts happens through a VSScript object. + + +VSScriptAPI +----------- + +This struct is the way to access VSScript's public API. + + +Functions +######### + +getVSScriptAPI +-------------- + +.. c:function:: const VSSCRIPTAPI *getVSScriptAPI(int version) + + Returns a struct containing function pointer for the api. Will return NULL is the specified *version* isn't supported. + + It is recommended to always pass *VSSCRIPT_API_VERSION*. + + +getApiVersion +------------- + +.. c:function:: int getApiVersion() + + Returns the api version provided by vsscript. + + +getVSAPI +-------- + +.. c:function:: const VSAPI *getVSAPI(int version) + + Retrieves the VSAPI struct. Exists mostly as a convenience so the vapoursynth module doesn't have to be explicitly loaded. + + This could return NULL if the VapourSynth library doesn't provide the requested version. + + +createScript +------------ + +.. c:function:: VSScript *createScript(VSCore *core) + + Creates an empty script environment that can be used to evaluate scripts. Passing a pre-created *core* can be usful to have custom core creation flags, log callbacks or plugins pre-loaded. Passing NULL will automatically create a new core with default settings. + + Takes over ownership of the *core* regardless of success or failure. Returns NULL on error. + + +getCore +------- + +.. c:function:: VSCore *getCore(VSScript *handle) + + Retrieves the VapourSynth core that was created in the script environment. If a VapourSynth core has not been created yet, it will be created now, with the default options (see the :doc:`../pythonreference`). + + VSScript retains ownership of the returned core object. + + Returns NULL on error. + + + + +evaluateBuffer +-------------- + +.. c:function:: int evaluateBuffer(VSScript *handle, const char *buffer, const char *scriptFilename) + + Evaluates a script contained in a C string. Can be called multiple times on the same script environment to successively add more processing. + + *handle* + Pointer to a script environment. + + *buffer* + The entire script to evaluate, as a C string. + + *scriptFilename* + A name for the script, which will be displayed in error messages. If this is NULL, the name "" will be used. + + The special ``__file__`` variable will be set to *scriptFilename*'s absolute path if this is not NULL. + + Returns non-zero in case of errors. The error message can be retrieved with getError_\ (). If the script calls *sys.exit(code)* the exit code can be retrieved with getExitCode_\ (). The working directory behavior can be changed by calling evalSetWorkingDir_\ () before this function. + + +evaluateFile +------------ + +.. c:function:: int evaluateFile(VSScript **handle, const char *scriptFilename) + + Evaluates a script contained in a file. This is a convenience function which reads the script from a file for you. It will only read the first 16 MiB which should be enough for everyone. + + Behaves the same as evaluateBuffer\ (). + + +getError +-------- + +.. c:function:: const char *getError(VSScript *handle) + + Returns the error message from a script environment, or NULL, if there is no error. + + It is okay to pass NULL. + + VSScript retains ownership of the pointer and it is only guaranteed to be valid until the next vsscript operation on the *handle*. + + +getExitCode +----------- + +.. c:function:: int getExitCode(VSScript *handle) + + Returns the exit code if the script calls *sys.exit(code)*, or 0, if the script fails for other reasons or calls *sys.exit(0)*. + + It is okay to pass NULL. + + +getVariable +----------- + +.. c:function:: int getVariable(VSScript *handle, const char *name, VSMap *dst) + + Retrieves a variable from the script environment. + + If a VapourSynth core has not been created yet in the script environment, one will be created now, with the default options (see the :doc:`../pythonreference`). + + *name* + Name of the variable to retrieve. + + *dst* + Map where the variable's value will be placed, with the key *name*. + + Returns non-zero on error. + + +setVariables +------------ + +.. c:function:: int vsscript_setVariable(VSScript *handle, const VSMap *vars) + + Sets variables in the script environment. + + The variables are now available to the script. + + If a VapourSynth core has not been created yet in the script environment, one will be created now, with the default options (see the :doc:`../pythonreference`). + + *vars* + Map containing the variables to set. + + Returns non-zero on error. + + +getOutputNode +------------- + +.. c:function:: VSNode *getOutputNode(VSScript *handle, int index) + + Retrieves a node from the script environment. A node in the script must have been marked for output with the requested *index*. + + The returned node has its reference count incremented by one. + + Returns NULL if there is no node at the requested index. + + +getOutputAlphaNode +------------------ + +.. c:function:: VSNode *getOutputAlphaNode(VSScript *handle, int index) + + Retrieves an alpha node from the script environment. A node with associated alpha in the script must have been marked for output with the requested *index*. + + The returned node has its reference count incremented by one. + + Returns NULL if there is no alpha node at the requested index. + + +getAltOutputMode +---------------- + +.. c:function:: int getAltOutputMode(VSScript *handle, int index) + + Retrieves the alternative output mode settings from the script. This value has no fixed meaning but in vspipe and vsvfw it + indicates that alternate output formats should be used when multiple ones are available. It is up to the client application to define the exact meaning or simply disregard it completely. + + Returns 0 if there is no alt output mode set. + + +freeScript +---------- + +.. c:function:: void freeScript(VSScript *handle) + + Frees a script environment. *handle* is no longer usable. + + * Cancels any clips set for output in the script environment. + + * Clears any variables set in the script environment. + + * Clears the error message from the script environment, if there is one. + + * Frees the VapourSynth core used in the script environment, if there is one. + + Since this function frees the VapourSynth core, it must be called only after all frame requests are finished and all objects obtained from the script have been freed (frames, nodes, etc). + + It is safe to pass NULL. + + +evalSetWorkingDir +----------------- + +.. c:function:: void evalSetWorkingDir(VSScript *handle, int setCWD) + + Set whether or not the working directory is temporarily changed to the same + location as the script file when evaluateFile is called. Off by default. diff --git a/Programs/doc/_sources/apireference.rst.txt b/Programs/doc/_sources/apireference.rst.txt new file mode 100644 index 0000000..4e0c7fc --- /dev/null +++ b/Programs/doc/_sources/apireference.rst.txt @@ -0,0 +1,118 @@ +VapourSynth C API Reference +=========================== + +See the example filters in the sdk dir. Reading simplefilters.c, which contains +several built-in functions, can also be very helpful. + +Public Headers +############## + +.. toctree:: + :maxdepth: 1 + :glob: + + api/* + +Common Pitfalls +############### + +There are several minor pitfalls related to the threading and design that have to be taken into consideration. Most of them usually aren't a problem but here's a small checklist of things you have to watch out for sometimes. + +General API +----------- +You may not pass objects (clips, functions and so on) owned by one core as arguments to filters in another core. A manual full deep copy of the data you want to pass on is required. This is generally not a problem since you should never need more than one core per filter graph. + +Plugins +------- +Plugin code may run more multithreaded than it initially appears. *VapourSynthPluginInit* is the only function always guaranteed to not run in parallel. This means that the constructor and destructor of a filter may be run in parallel for several instances. Use proper synchronization if you need to initialize shared data. + +The *GetFrame* function is a bit more complicated so see the reference of the constants. Do however note that the parallelism is per instance. Even if a filter is *fmUnordered* or *fmSerial* other instances may enter *GetFrame* simultaneously. + +There are two common misconseptions about which mode should be used. A simple rule is that *fmSerial* should never be used. And source filters (those returning a frame on *arInitial*) that need locking should use *fmUnordered*. + +Reserved Frame Properties +######################### + +All frames contain a map of key--value pairs. It is recommended that these +properties are named using only a-z, A-Z, 0-9 using CamelCase. There is a +special category of keys starting with _ which have strictly defined meanings +specified below. It is acceptable to not set any of these keys if they are +unknown. It is also a fatal error to set them to a value not specified below. + +int _ChromaLocation + + Chroma sample position in YUV formats. + + 0=left, 1=center, 2=topleft, 3=top, 4=bottomleft, 5=bottom. + +int _ColorRange + + Full or limited range (PC/TV range). Primarily used with YUV formats. + + 0=full range, 1=limited range. + +int _Primaries + + Color primaries as specified in ITU-T H.265 Table E.3. + +int _Matrix + + Matrix coefficients as specified in ITU-T H.265 Table E.5. + +int _Transfer + + Transfer characteristics as specified in ITU-T H.265 Table E.4. + +int _FieldBased + + If the frame is composed of two independent fields (interlaced). + + 0=frame based (progressive), 1=bottom field first, 2=top field first. + +float _AbsoluteTime + + The frame's absolute timestamp in seconds if reported by the source filter. + Should only be set by the source filter and not be modified. Use durations + for all operations that depend on frame length. + +int _DurationNum, int _DurationDen + + The frame's duration in seconds as a rational number. Filters that + modify the framerate should also change these values. + + This fraction should always be normalized. + +bint _Combed + + Whether or not the frame needs postprocessing, usually hinted from field + matching filters. + +int _Field + + If the frame was produced by something like core.std.SeparateFields, + this property signals which field was used to generate this frame. + + 0=from bottom field, 1=from top field. + +string _PictType + + A single character describing the frame type. It uses the common + IPB letters but other letters may also be used for formats with + additional frame types. + +int _SARNum, int _SARDen + + Pixel (sample) aspect ratio as a rational number. + +bint _SceneChangeNext + + If 1, this frame is the last frame of the current scene. The next frame starts a new scene. + +bint _SceneChangePrev + + If 1, this frame starts a new scene. + +frame _Alpha + + A clip's alpha channel can be attached to the clip one frame at a + time using this property. diff --git a/Programs/doc/_sources/applications.rst.txt b/Programs/doc/_sources/applications.rst.txt new file mode 100644 index 0000000..758ef52 --- /dev/null +++ b/Programs/doc/_sources/applications.rst.txt @@ -0,0 +1,31 @@ +Applications and Libraries +========================== + +Applications +############ + +* `D2V Witch `_ -- creates indexes that can be opened by d2vsource +* `Hybrid `_ `(Doom9) `__ -- encoding GUI with VapourSynth support +* `mpv.net `_ -- a media player with VapourSynth built-in +* `SmoothVideo Project `_ -- a plugin/video player component for realtime frame interpolation +* `StaxRip `_ -- encoding GUI with extended VapourSynth scripting support +* `VapourSynth Editor `_ `(Doom9) `__ -- an editor with syntax completion and fast preview support +* `VapourSynth Editor 2 `_ `(Doom9) `__ -- a spiritual successor to VapourSynth Editor +* `VirtualDub2 `_ `(Doom9) `__ -- VirtualDub with added support for high bitdepth colorspaces, useful for previewing +* `vsmkv `_ -- a FUSE-based virtual filesystem for exporting VapourSynth scripts as uncompressed videos in the Matroska (MKV) file format +* `vspreview `_ -- an advanced standalone previewer written in python with too many features to list +* `vspreview-rs `_ `(Doom9) `__ -- minimal VapourSynth script previewer +* `Wobbly `_ `(Doom9) `__ -- IVTC assistant similar to YATTA +* `Yuuno `_ -- incorporates VapourSynth into Jupyter + +Libraries +######### + +* `VapourSynth.nim `_ -- Bindings for the Nim programming language +* `vapoursynth-rs `_ -- VapourSynth Rust wrapper +* `vsxx `_ -- VapourSynth C++ API wrapper + +Tools +##### + +* GitHub Action `install-vapoursynth `_ -- Installs vapoursynth in your GitHub Action. diff --git a/Programs/doc/_sources/functions.rst.txt b/Programs/doc/_sources/functions.rst.txt new file mode 100644 index 0000000..2f796fd --- /dev/null +++ b/Programs/doc/_sources/functions.rst.txt @@ -0,0 +1,38 @@ +Function Reference +================== + +General Functions +################# + +.. toctree:: + :maxdepth: 2 + :glob: + + functions/general/* + +Video Functions +############### + +.. toctree:: + :maxdepth: 2 + :glob: + + functions/video/* + +Text +**** + +.. toctree:: + :maxdepth: 2 + :glob: + + functions/video/text/* + +Audio Functions +############### + +.. toctree:: + :maxdepth: 2 + :glob: + + functions/audio/* diff --git a/Programs/doc/_sources/functions/audio/assumesamplerate.rst.txt b/Programs/doc/_sources/functions/audio/assumesamplerate.rst.txt new file mode 100644 index 0000000..f4fc2da --- /dev/null +++ b/Programs/doc/_sources/functions/audio/assumesamplerate.rst.txt @@ -0,0 +1,5 @@ +AssumeSampleRate +================ + +.. function:: AssumeSampleRate(anode clip[, anode src, int samplerate]) + :module: std diff --git a/Programs/doc/_sources/functions/audio/audiogain.rst.txt b/Programs/doc/_sources/functions/audio/audiogain.rst.txt new file mode 100644 index 0000000..45680f6 --- /dev/null +++ b/Programs/doc/_sources/functions/audio/audiogain.rst.txt @@ -0,0 +1,12 @@ +AudioGain +========= + +.. function:: AudioGain(anode clip, float[] gain) + :module: std + + AudioGain can either change the volume of individual channels + if a separate *gain* for each channel is given or if only a single + *gain* value is supplied it's applied to all channels. + + Negative *gain* values are allowed. Applying a too large gain will + lead to clipping in integer formats. \ No newline at end of file diff --git a/Programs/doc/_sources/functions/audio/audioloop.rst.txt b/Programs/doc/_sources/functions/audio/audioloop.rst.txt new file mode 100644 index 0000000..68ce1d4 --- /dev/null +++ b/Programs/doc/_sources/functions/audio/audioloop.rst.txt @@ -0,0 +1,11 @@ +AudioLoop +========= + +.. function:: AudioLoop(anode clip[, int times=0]) + :module: std + + Returns a clip with the frames or samples repeated over and over again. If *times* is + less than 1 the clip will be repeated until the maximum clip length is + reached, otherwise it will be repeated *times* times. + + In Python, std.AudioLoop can also be invoked :ref:`using the multiplication operator `. diff --git a/Programs/doc/_sources/functions/audio/audiomix.rst.txt b/Programs/doc/_sources/functions/audio/audiomix.rst.txt new file mode 100644 index 0000000..ad02af0 --- /dev/null +++ b/Programs/doc/_sources/functions/audio/audiomix.rst.txt @@ -0,0 +1,38 @@ +AudioMix +======== + +.. function:: AudioMix(anode[] clips, float[] matrix, int[] channels_out) + :module: std + + AudioMix can mix and combine channels from different clips in the most + general way possible. + + Most of the returned clip's properties are implicitly determined from the + first clip given to *clips*. + + The *clips* parameter takes one or more clips with the same format. If the clips + are different lengths they'll be zero extended to that of the longest. + + The argument *matrix* applies the coefficients to each channel of each input clip where + the channels are in the numerical order of their channel constants. For example a stereo clip + will have its channels presented in the order FRONT_LEFT and then FRONT_RIGHT. + + Output channels and order is determined by the *channels_out* array + between input index and output channel happens on the order of lowest output channel + identifier to the highest. + + + + Below are some examples of useful operations. + + Downmix stereo audio to mono:: + + AudioMix(clips=clip, matrix=[0.5, 0.5], channels_out=[vs.FRONT_CENTER]) + + Downmix 5.1 audio:: + + AudioMix(clips=clip, matrix=[1, 0, 0.7071, 0, 0.7071, 0, 0, 1, 0.7071, 0, 0, 0.7071], channels_out=[vs.FRONT_LEFT, vs.FRONT_RIGHT]) + + Copy stereo audio to 5.1 and zero the other channels:: + + AudioMix(clips=c, matrix=[1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], channels_out=[vs.FRONT_LEFT, vs.FRONT_RIGHT, vs.FRONT_CENTER, vs.LOW_FREQUENCY, vs.BACK_LEFT, vs.BACK_RIGHT]) diff --git a/Programs/doc/_sources/functions/audio/audioreverse.rst.txt b/Programs/doc/_sources/functions/audio/audioreverse.rst.txt new file mode 100644 index 0000000..48a49f5 --- /dev/null +++ b/Programs/doc/_sources/functions/audio/audioreverse.rst.txt @@ -0,0 +1,10 @@ +AudioReverse +============ + +.. function:: AudioReverse(anode clip) + :module: std + + Returns a clip with the frame or sample order reversed. For example, a clip with 3 + frames would have the frame order 2, 1, 0. + + In Python, std.AudioReverse can also be invoked by :ref:`slicing a clip `. diff --git a/Programs/doc/_sources/functions/audio/audiosplice.rst.txt b/Programs/doc/_sources/functions/audio/audiosplice.rst.txt new file mode 100644 index 0000000..507a452 --- /dev/null +++ b/Programs/doc/_sources/functions/audio/audiosplice.rst.txt @@ -0,0 +1,12 @@ +AudioSplice +=========== + +.. function:: AudioSplice(anode[] clips) + :module: std + + Returns a clip with all *clips* appended in the given order. + + Splicing clips with different formats or dimensions is + considered an error unless *mismatch* is true. + + In Python, std.AudioSplice can also be invoked :ref:`using the addition operator `. diff --git a/Programs/doc/_sources/functions/audio/audiotrim.rst.txt b/Programs/doc/_sources/functions/audio/audiotrim.rst.txt new file mode 100644 index 0000000..08b867f --- /dev/null +++ b/Programs/doc/_sources/functions/audio/audiotrim.rst.txt @@ -0,0 +1,10 @@ +AudioTrim +========= + +.. function:: AudioTrim(anode clip[, int first=0, int last, int length]) + :module: std + + AudioTrim performs exactly the same operation on audio clips but the unit is + obviously samples instead of frames. + + In Python, std.AudioTrim can also be invoked by :ref:`slicing a clip `. diff --git a/Programs/doc/_sources/functions/audio/blankaudio.rst.txt b/Programs/doc/_sources/functions/audio/blankaudio.rst.txt new file mode 100644 index 0000000..836b079 --- /dev/null +++ b/Programs/doc/_sources/functions/audio/blankaudio.rst.txt @@ -0,0 +1,20 @@ +BlankAudio +========== + +.. function:: BlankAudio([anode clip, int[] channels=[FRONT_LEFT, FRONT_RIGHT], int bits=16, int sampletype=INTEGER, int samplerate=44100, int length=(10*samplerate), bint keep=0]) + :module: std + + Generates a new empty clip. This can be useful to have when editing audio + or for testing. The default is a 10 second long 44.1kHz 16 bit stereo clip. + Instead of specifying every property individually, BlankAudio can also copy + the properties from *clip*. If both an argument such as *sampletype*, and *clip* + are set, then *sampletype* will take precedence. + + The *channels* argument is a list of channel constants. Specifying the same channel twice + is not allowed. + + The possible *sampletype* values are currently INTEGER (0) and FLOAT (1). + + If *keep* is set, a reference to the same frame is returned on every request. + Otherwise a new frame is generated every time. There should usually be no + reason to change this setting. diff --git a/Programs/doc/_sources/functions/audio/setaudiocache.rst.txt b/Programs/doc/_sources/functions/audio/setaudiocache.rst.txt new file mode 100644 index 0000000..475d897 --- /dev/null +++ b/Programs/doc/_sources/functions/audio/setaudiocache.rst.txt @@ -0,0 +1,7 @@ +SetAudioCache +============= + +.. function:: SetAudioCache(anode clip[, int mode, int fixedsize, int maxsize, int historysize]) + :module: std + + see SetVideoCache diff --git a/Programs/doc/_sources/functions/audio/shufflechannels.rst.txt b/Programs/doc/_sources/functions/audio/shufflechannels.rst.txt new file mode 100644 index 0000000..75edd1e --- /dev/null +++ b/Programs/doc/_sources/functions/audio/shufflechannels.rst.txt @@ -0,0 +1,48 @@ +ShuffleChannels +=============== + +.. function:: ShuffleChannels(anode[] clips, int[] channels_in, int[] channels_out) + :module: std + + ShuffleChannels can extract and combine channels from different clips in the most + general way possible. + + Most of the returned clip's properties are implicitly determined from the + first clip given to *clips*. + + The *clips* parameter takes one or more clips with the same format. If the clips + are different lengths they'll be zero extended to that of the longest. + + The argument *channels_in* controls which of the input clips' channels to use and + takes a channel constants as its argument. Specifying a non-existent channel + is an error. If more *channels_in* than *clips* values are specified then the last + clip in the *clips* list is reused as a source. In addition to the channel constant + it's also possible to specify the nth channel by using negative numbers. + + The output channel mapping is determined by *channels_out* and corresponds to the + input channel order. The number of *channels_out* entries must be the same as the + number of *channels_in* entries. Specifying the same output channel twice is an error. + + + + Below are some examples of useful operations. + + Extract the left channel (assuming it exists):: + + ShuffleChannels(clips=clip, channels_in=vs.FRONT_LEFT, channels_out=vs.FRONT_LEFT) + + Swap left and right audio channels in a stereo clip:: + + ShuffleChannels(clips=clip, channels_in=[vs.FRONT_RIGHT, vs.FRONT_LEFT], channels_out=[vs.FRONT_LEFT, vs.FRONT_RIGHT]) + + Swap left and right audio channels in a stereo clip (alternate ordering of arguments):: + + ShuffleChannels(clips=clip, channels_in=[vs.FRONT_LEFT, vs.FRONT_RIGHT], channels_out=[vs.FRONT_RIGHT, vs.FRONT_LEFT]) + + Swap left and right audio channels in a stereo clip (alternate indexing):: + + ShuffleChannels(clips=clip, channels_in=[-2, -1], channels_out=[vs.FRONT_LEFT, vs.FRONT_RIGHT]) + + Merge 2 mono audio clips into a single stereo clip:: + + ShuffleChannels(clips=[clipa, clipb], channels_in=[vs.FRONT_LEFT, vs.FRONT_LEFT], channels_out=[vs.FRONT_LEFT, vs.FRONT_RIGHT]) diff --git a/Programs/doc/_sources/functions/audio/splitchannels.rst.txt b/Programs/doc/_sources/functions/audio/splitchannels.rst.txt new file mode 100644 index 0000000..02b6513 --- /dev/null +++ b/Programs/doc/_sources/functions/audio/splitchannels.rst.txt @@ -0,0 +1,8 @@ +SplitChannels +============= + +.. function:: SplitChannels(anode clip) + :module: std + + SplitChannels returns each audio channel of the input as + a separate clip. diff --git a/Programs/doc/_sources/functions/general/loadallplugins.rst.txt b/Programs/doc/_sources/functions/general/loadallplugins.rst.txt new file mode 100644 index 0000000..6cdd9d3 --- /dev/null +++ b/Programs/doc/_sources/functions/general/loadallplugins.rst.txt @@ -0,0 +1,19 @@ +LoadAllPlugins +============== + +.. function:: LoadAllPlugins(string path) + :module: std + + Loads all native VapourSynth plugins found in the + specified *path*. Plugins that fail to load are + silently skipped. + + Beware of Python's escape character, this will fail:: + + LoadPlugin(path='c:\plugins') + + Correct ways:: + + LoadPlugin(path='c:/plugins') + LoadPlugin(path=r'c:\plugins') + LoadPlugin(path='c:\\plugins\\') diff --git a/Programs/doc/_sources/functions/general/loadplugin.rst.txt b/Programs/doc/_sources/functions/general/loadplugin.rst.txt new file mode 100644 index 0000000..aee85df --- /dev/null +++ b/Programs/doc/_sources/functions/general/loadplugin.rst.txt @@ -0,0 +1,26 @@ +LoadPlugin +========== + +.. function:: LoadPlugin(string path, bint altsearchpath = False) + :module: std + + Load a native VapourSynth plugin. If successful, the loaded plugin's + functions will end up in their own namespace. + + Returns an error if a plugin with the same identifier or namespace already + has been loaded. This is to prevent naming collisions or multiple versions + of the same plugin being loaded at once. + + Plugins are normally loaded with a very specific search order for + dependencies. Setting *altsearchpath* modifies this behavior to also + include dlls in the PATH. + + Beware of Python's escape character, this will fail:: + + LoadPlugin(path='c:\plugins\filter.dll') + + Correct ways:: + + LoadPlugin(path='c:/plugins/filter.dll') + LoadPlugin(path=r'c:\plugins\filter.dll') + LoadPlugin(path='c:\\plugins\\filter.dll') diff --git a/Programs/doc/_sources/functions/general/loadpluginavs.rst.txt b/Programs/doc/_sources/functions/general/loadpluginavs.rst.txt new file mode 100644 index 0000000..578de51 --- /dev/null +++ b/Programs/doc/_sources/functions/general/loadpluginavs.rst.txt @@ -0,0 +1,44 @@ +LoadPlugin (Avisynth Compatibility) +=================================== + +.. function:: LoadPlugin(string path) + :module: avs + + Load an Avisynth 2.5 (32 bit only), 2.6 (32 and 64 bit) or Avisynth+ (32 and 64 bit) plugin. + If successful, the loaded plugin's functions will end up in the avs namespace. Note that + in the case of Avisynth+ there's no way to use the formats combined with alpha or + higher bitdepth packed RGB. Coincidentally there are no plugins that use this in a + meaningful way yet. + + The compatibility module can work with a large number of Avisynth's plugins. + However, the wrapping is not complete, so the following things will cause + problems: + + * The plugin expects YUY2 or RGB32 input. In this case provide input in + either YUV422P8 or RGB24 format pass compatpack=True as an argument + to the Avisynth function. + * The plugin tries to call env->invoke(). + These calls are ignored when it is safe to do so, but otherwise they + will most likely trigger a fatal error. + * Plugins trying to read global variables. + There are no global variables. + + If there are function name collisions functions will have a number appended + to them to make them distinct. For example if three functions are named + *func* then they will be named *func*, *func_2* and *func_3*. This means + that Avisynth functions that have multiple overloads (rare) will give + each overload a different name. + + Note that if you are really insane you can load Avisynth's VirtualDub plugin + loader and use VirtualDub plugins as well. Function overloads are very common + when dealing with VirtualDub. + + Beware of Python's escape character, this will fail:: + + LoadPlugin(path='c:\plugins\filter.dll') + + Correct ways:: + + LoadPlugin(path='c:/plugins/filter.dll') + LoadPlugin(path=r'c:\plugins\filter.dll') + LoadPlugin(path='c:\\plugins\\filter.dll') diff --git a/Programs/doc/_sources/functions/general/setmaxcpu.rst.txt b/Programs/doc/_sources/functions/general/setmaxcpu.rst.txt new file mode 100644 index 0000000..bca78dc --- /dev/null +++ b/Programs/doc/_sources/functions/general/setmaxcpu.rst.txt @@ -0,0 +1,14 @@ +SetMaxCPU +========= + +.. function:: SetMaxCPU(string cpu) + :module: std + + This function is only intended for testing and debugging purposes + and sets the maximum used instruction set for optimized functions. + + Possible values for x86: "avx2", "sse2", "none" + + Other platforms: "none" + + By default all supported cpu features are used. \ No newline at end of file diff --git a/Programs/doc/_sources/functions/video/addborders.rst.txt b/Programs/doc/_sources/functions/video/addborders.rst.txt new file mode 100644 index 0000000..e68816f --- /dev/null +++ b/Programs/doc/_sources/functions/video/addborders.rst.txt @@ -0,0 +1,9 @@ +AddBorders +========== + +.. function:: AddBorders(vnode clip[, int left=0, int right=0, int top=0, int bottom=0, float[] color=]) + :module: std + + Adds borders to frames. The arguments specify the number of pixels to add on + each side. They must obey the subsampling restrictions. + The newly added borders will be set to *color*. diff --git a/Programs/doc/_sources/functions/video/assumefps.rst.txt b/Programs/doc/_sources/functions/video/assumefps.rst.txt new file mode 100644 index 0000000..18b7262 --- /dev/null +++ b/Programs/doc/_sources/functions/video/assumefps.rst.txt @@ -0,0 +1,16 @@ +AssumeFPS +========= + +.. function:: AssumeFPS(vnode clip[, vnode src, int fpsnum, int fpsden=1]) + :module: std + + Returns a clip with the framerate changed. This does not in any way modify + the frames, only their metadata. + + The framerate to assign can either be read from another clip, *src*, or given + as a rational number with *fpsnum* and *fpsden*. + + It is an error to specify both *src* and *fpsnum*. + + AssumeFPS overwrites the frame properties ``_DurationNum`` and + ``_DurationDen`` with the frame duration computed from the new frame rate. diff --git a/Programs/doc/_sources/functions/video/averageframes.rst.txt b/Programs/doc/_sources/functions/video/averageframes.rst.txt new file mode 100644 index 0000000..1aeced8 --- /dev/null +++ b/Programs/doc/_sources/functions/video/averageframes.rst.txt @@ -0,0 +1,21 @@ +AverageFrames +============= + +.. function:: AverageFrames(vnode[] clips, float[] weights[, float scale, bint scenechange, int[] planes]) + :module: std + + AverageFrames has two main modes depending on whether one or multiple *clips* are supplied. + The filter is named AverageFrames since using ones for weights is an easy way to average + many frames together but it can also be seen as a temporal or multiple frame convolution. + + If multiple *clips* are supplied then the frames from each of the *clips* are multiplied by + the respective *weights*, summed together and divided by *scale* before being output. Note + that only integer *weights* and *scale* are allowed for integer input formats. + + If a single *clip* is supplied then an odd number of *weights* are needed and they will instead + be temporally centered on the current frame of the *clip*. The rest works as multiple *clip* mode + with the only difference being that *scenechange* can be set to avoid averaging frames over scene + changes. If this happens then all the weights beyond a scene change are instead applied to the frame + right before it. + + At most 31 *weights* can be supplied. \ No newline at end of file diff --git a/Programs/doc/_sources/functions/video/binarize_binarizemask.rst.txt b/Programs/doc/_sources/functions/video/binarize_binarizemask.rst.txt new file mode 100644 index 0000000..9413324 --- /dev/null +++ b/Programs/doc/_sources/functions/video/binarize_binarizemask.rst.txt @@ -0,0 +1,34 @@ +Binarize/BinarizeMask +===================== + +.. function:: Binarize(vnode clip[, float[] threshold, float[] v0, float[] v1, int[] planes=[0, 1, 2]]) + BinarizeMask(vnode clip[, float[] threshold, float[] v0, float[] v1, int[] planes=[0, 1, 2]]) + :module: std + + Turns every pixel in the image into either *v0*, if it's below + *threshold*, or *v1*, otherwise. The *BinarizeMask* version is intended + for use on mask clips where all planes have the same value range and + only differs in the default values of *v0* and *v1*. + + *clip* + Clip to process. It must have integer sample type and bit depth + between 8 and 16, or float sample type and bit depth of 32. If + there are any frames with other formats, an error will be + returned. + + *threshold* + Defaults to the middle point of range allowed by the format. + Can be specified for each plane individually. + + *v0* + Value given to pixels that are below *threshold*. Can be specified + for each plane individually. Defaults to the lower bound of the format. + + *v1* + Value given to pixels that are greater than or equal to *threshold*. + Defaults to the maximum value allowed by the format. Can be specified + for each plane individually. Defaults to the upper bound of the format. + + *planes* + Specifies which planes will be processed. Any unprocessed planes + will be simply copied. diff --git a/Programs/doc/_sources/functions/video/blankclip.rst.txt b/Programs/doc/_sources/functions/video/blankclip.rst.txt new file mode 100644 index 0000000..f9e3c64 --- /dev/null +++ b/Programs/doc/_sources/functions/video/blankclip.rst.txt @@ -0,0 +1,24 @@ +BlankClip +========= + +.. function:: BlankClip([vnode clip, int width=640, int height=480, int format=vs.RGB24, int length=(10*fpsnum)/fpsden, int fpsnum=24, int fpsden=1, float[] color=, bint keep=0, bint varsize=0, bint varformat=0]) + :module: std + + Generates a new empty clip. This can be useful to have when editing video or + for testing. The default is a 640x480 RGB24 24fps 10 second long black clip. + Instead of specifying every property individually, BlankClip can also copy + the properties from *clip*. If both an argument such as *width*, and *clip* + are set, then *width* will take precedence. + + If *keep* is set, a reference to the same frame is returned on every request. + Otherwise a new frame is generated every time. There should usually be no + reason to change this setting. + + If *varsize* is set, a clip with variable size will be returned. The frames + themselves will still have the size given by the width and height arguments. + + If *varformat* is set, a clip with variable format will be returned. + The frames themselves will have the format given by the format argument. + + It is never an error to use BlankClip. + diff --git a/Programs/doc/_sources/functions/video/boxblur.rst.txt b/Programs/doc/_sources/functions/video/boxblur.rst.txt new file mode 100644 index 0000000..d00a913 --- /dev/null +++ b/Programs/doc/_sources/functions/video/boxblur.rst.txt @@ -0,0 +1,8 @@ +BoxBlur +======= + +.. function:: BoxBlur(vnode clip[, int[] planes, int hradius = 1, int hpasses = 1, int vradius = 1, int vpasses = 1]) + :module: std + + Performs a box blur which is fast even for large radius values. Using multiple *passes* can be used to fairly cheaply + approximate a gaussian blur. A *radius* of 0 means no processing is performed. diff --git a/Programs/doc/_sources/functions/video/cliptoprop.rst.txt b/Programs/doc/_sources/functions/video/cliptoprop.rst.txt new file mode 100644 index 0000000..5549ad1 --- /dev/null +++ b/Programs/doc/_sources/functions/video/cliptoprop.rst.txt @@ -0,0 +1,15 @@ +ClipToProp +========== + +.. function:: ClipToProp(vnode clip, vnode mclip[, string prop='_Alpha']) + :module: std + + Stores each frame of *mclip* as a frame property named *prop* in *clip*. This + is primarily intended to attach mask/alpha clips to another clip so that + editing operations will apply to both. Unlike most other filters the output + length is derived from the second argument named *mclip*. + + If the attached *mclip* does not represent the alpha channel, you should set + *prop* to something else. + + It is the inverse of PropToClip(). diff --git a/Programs/doc/_sources/functions/video/convolution.rst.txt b/Programs/doc/_sources/functions/video/convolution.rst.txt new file mode 100644 index 0000000..ca8925c --- /dev/null +++ b/Programs/doc/_sources/functions/video/convolution.rst.txt @@ -0,0 +1,85 @@ +Convolution +=========== + +.. function:: Convolution(vnode clip, float[] matrix[, float bias=0.0, float divisor=0.0, int[] planes=[0, 1, 2], bint saturate=True, string mode="s"]) + :module: std + + Performs a spatial convolution. + + Here is how a 3x3 convolution is done. Each pixel in the 3x3 + neighbourhood is multiplied by the corresponding coefficient in + *matrix*. The results of the nine multiplications are added together, + then this sum is divided by *divisor*. Next, *bias* is added, and the + result is rounded to the nearest larger integer. If this integer + result is negative and the *saturate* parameter is False, it is + multiplied by -1. Finally, the result is clamped to the format's range + of valid values. + + *clip* + Clip to process. It must have integer sample type and bit depth + between 8 and 16, or float sample type and bit depth of 32. If + there are any frames with other formats, an error will be + returned. + + *matrix* + Coefficients for the convolution. + + When *mode* is "s", this must be an array of 9 or 25 numbers, for + a 3x3 or 5x5 convolution, respectively. + + When *mode* is not "s", this must be an array of 3 to 25 numbers, + with an odd number of elements. + + The values of the coefficients must be between -1023 and 1023 + (inclusive). The coefficients are rounded to integers when + the input is an integer format. + + This is how the elements of *matrix* correspond to the pixels in + a 3x3 neighbourhood:: + + 1 2 3 + 4 5 6 + 7 8 9 + + It's the same principle for the other types of convolutions. The + middle element of *matrix* always corresponds to the center pixel. + + *bias* + Value to add to the final result of the convolution (before clamping + the result to the format's range of valid values). + + *divisor* + Divide the output of the convolution by this value (before adding + *bias*). + + If this parameter is 0.0 (the default), the output of the convolution + will be divided by the sum of the elements of *matrix*, or by 1.0, + if the sum is 0. + + *planes* + Specifies which planes will be processed. Any unprocessed planes + will be simply copied. + + *saturate* + The final result is clamped to the format's range of valid values + (0 .. (2**bitdepth)-1). Therefore, if this parameter is True, + negative values become 0. If this parameter is False, it's instead + the absolute value that is clamped and returned. + + *mode* + Selects the type of convolution. Possible values are "s", for square, + "h" for horizontal, "v" for vertical, and "hv" or "vh" for both + horizontal and vertical. + + How to apply a simple blur equivalent to Avisynth's Blur(1): + + .. code-block:: python + + Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]) + + How to apply a stronger blur equivalent to Avisynth's Blur(1.58): + + .. code-block:: python + + Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1]) + diff --git a/Programs/doc/_sources/functions/video/copyframeprops.rst.txt b/Programs/doc/_sources/functions/video/copyframeprops.rst.txt new file mode 100644 index 0000000..62ac1cf --- /dev/null +++ b/Programs/doc/_sources/functions/video/copyframeprops.rst.txt @@ -0,0 +1,10 @@ +CopyFrameProps +============== + +.. function:: CopyFrameProps(vnode clip, vnode prop_src) + :module: std + + Returns *clip* but with all the frame properties replaced with the + ones from the clip in *prop_src*. Note that if *clip* is longer + than *prop_src* then the last existing frame's properties will be + used instead. diff --git a/Programs/doc/_sources/functions/video/crop_cropabs.rst.txt b/Programs/doc/_sources/functions/video/crop_cropabs.rst.txt new file mode 100644 index 0000000..63d9cec --- /dev/null +++ b/Programs/doc/_sources/functions/video/crop_cropabs.rst.txt @@ -0,0 +1,20 @@ +Crop/CropAbs +=============== + +.. function:: Crop(vnode clip[, int left=0, int right=0, int top=0, int bottom=0]) + CropAbs(vnode clip, int width, int height[, int left=0, int top=0]) + :module: std + + Crops the frames in a clip. + + Crop is the simplest to use of the two. The arguments specify how many + pixels to crop from each side. This function used to be called CropRel + which is still an alias for it. + + CropAbs, on the other hand, is special, because it can accept clips with + variable frame sizes and crop out a fixed size area, thus making it a fixed + size clip. + + Both functions return an error if the whole picture is cropped away, if the + cropped area extends beyond the input or if the subsampling restrictions + aren't met. diff --git a/Programs/doc/_sources/functions/video/deflate_inflate.rst.txt b/Programs/doc/_sources/functions/video/deflate_inflate.rst.txt new file mode 100644 index 0000000..187efbe --- /dev/null +++ b/Programs/doc/_sources/functions/video/deflate_inflate.rst.txt @@ -0,0 +1,44 @@ +Deflate/Inflate +=============== + +.. function:: Deflate(vnode clip[, int[] planes=[0, 1, 2], float threshold]) + :module: std + + Replaces each pixel with the average of the eight pixels in its 3x3 + neighbourhood, but only if that average is less than the center pixel. + + *clip* + Clip to process. It must have integer sample type and bit depth + between 8 and 16, or float sample type and bit depth of 32. If + there are any frames with other formats, an error will be + returned. + + *planes* + Specifies which planes will be processed. Any unprocessed planes + will be simply copied. + + *threshold* + Allows to limit how much pixels are changed. Output pixels will not + become less than ``input - threshold``. The default is no limit. + + +.. function:: Inflate(vnode clip[, int[] planes=[0, 1, 2], int threshold=65535]) + :module: std + + Replaces each pixel with the average of the eight pixels in its 3x3 + neighbourhood, but only if that average is greater than the center + pixel. + + *clip* + Clip to process. It must have integer sample type and bit depth + between 8 and 16, or float sample type and bit depth of 32. If + there are any frames with other formats, an error will be + returned. + + *planes* + Specifies which planes will be processed. Any unprocessed planes + will be simply copied. + + *threshold* + Allows to limit how much pixels are changed. Output pixels will not + become greater than ``input + threshold``. The default is no limit. diff --git a/Programs/doc/_sources/functions/video/deleteframes.rst.txt b/Programs/doc/_sources/functions/video/deleteframes.rst.txt new file mode 100644 index 0000000..0bd003e --- /dev/null +++ b/Programs/doc/_sources/functions/video/deleteframes.rst.txt @@ -0,0 +1,11 @@ +DeleteFrames +============ + +.. function:: DeleteFrames(vnode clip, int[] frames) + :module: std + + Deletes the specified frames. + + All frame numbers apply to the input clip. + + Returns an error if the same frame is deleted twice or if all frames in a clip are deleted. diff --git a/Programs/doc/_sources/functions/video/doubleweave.rst.txt b/Programs/doc/_sources/functions/video/doubleweave.rst.txt new file mode 100644 index 0000000..1194233 --- /dev/null +++ b/Programs/doc/_sources/functions/video/doubleweave.rst.txt @@ -0,0 +1,23 @@ +DoubleWeave +=========== + +.. function:: DoubleWeave(vnode clip[, bint tff]) + :module: std + + Weaves the fields back together from a clip with interleaved fields. + + Since VapourSynth only has a weak notion of field order internally, *tff* + may have to be set. Setting *tff* to true means top fields first and false + means bottom fields first. Note that the ``_Field`` frame property, if present + and in a valid combination, takes precedence over *tff*. + + DoubleWeave's output has the same number of frames as the input. One must + use DoubleWeave together with SelectEvery to undo the effect of + SeparateFields:: + + sep = core.std.SeparateFields(source) + ... + woven = core.std.DoubleWeave(sep) + woven = core.std.SelectEvery(woven, 2, 0) + + The ``_Field`` frame property is deleted and ``_FieldBased`` is set accordingly. diff --git a/Programs/doc/_sources/functions/video/duplicateframes.rst.txt b/Programs/doc/_sources/functions/video/duplicateframes.rst.txt new file mode 100644 index 0000000..fc22747 --- /dev/null +++ b/Programs/doc/_sources/functions/video/duplicateframes.rst.txt @@ -0,0 +1,11 @@ +DuplicateFrames +=============== + +.. function:: DuplicateFrames(vnode clip, int[] frames) + :module: std + + Duplicates the specified frames. + + A frame may be duplicated several times. + + All frame numbers apply to the input clip. diff --git a/Programs/doc/_sources/functions/video/expr.rst.txt b/Programs/doc/_sources/functions/video/expr.rst.txt new file mode 100644 index 0000000..3c2136e --- /dev/null +++ b/Programs/doc/_sources/functions/video/expr.rst.txt @@ -0,0 +1,118 @@ +Expr +==== + +.. function:: Expr(vnode[] clips, string[] expr[, int format]) + :module: std + + Expr evaluates an expression per pixel for up to 26 input *clips*. + The expression, *expr*, is written using reverse polish notation and can be + specified for each plane individually. + The expression given for the previous plane is used if the *expr* array + contains fewer expressions than the input clip has planes. + In practice this means that a single expression will be applied to all planes + by default. + + Specifying an empty string as the expression enables a fast plane copy from + the first specified clip, when possible. If it is not possible due to the + output *format* being incompatible, the plane contents will be undefined. + + Since the expression is evaluated at runtime, there are a few pitfalls. In + order to keep speed up, the input ranges are not normalized to the usual + floating point ranges. Instead they are left as is, meaning that an 8 bit + clip will have values in the 0-255 range and a 10 bit clip will have values + in the 0-1023 range. + Note that floating point clips are even more difficult, as most channels are + stored in the 0-1 range with the exception of U, V, Co and Cg planes, which + are in the -0.5-0.5 range. + If you mix clips with different input formats this must be taken into + consideration. + + When the output format uses integer samples, the result of the expression is + clamped to the [0, 2**bits_per_sample-1] range. + When the output format uses float samples, the result of the expression is + stored without any clamping. + + By default the output *format* is the same as the first input clip's format. + You can override it by setting *format*. The only restriction is that the + output *format* must have the same subsampling as the input *clips* and be + 8..16 bit integer or 32 bit float. 16 bit float is also supported on cpus + with the f16c instructions. + + Logical operators are also a bit special, since everything is done in + floating point arithmetic. + All values greater than 0 are considered true for the purpose of comparisons. + Logical operators return 0.0 for false and 1.0 for true in their operations. + + Since the expression is being evaluated at runtime, there are also the stack + manipulation operators, *swap* and *dup*. The former swaps the topmost and + second topmost values, and the latter duplicates the topmost stack value. + + These operators also have *swapN* and *dupN* forms that allow a value N + steps up in the stack to be swapped or duplicated. The top value of the stack + has index zero meaning that *dup* is equivalent to *dup0* and *swap* is + equivalent to *swap1*. This is because *swapN* always swaps with the topmost + value at index 0. + + Expressions are converted to byte-code or machine-code by an optimizing + compiler and are not guaranteed to evaluate in the order originally written. + The compiler assumes that all input values are finite (i.e neither NaN nor + INF) and that no operator will produce a non-finite value. Such expressions + are invalid. This is especially important for the transcendental operators: + + * exp - expression must not overflow (i.e. x <= 88) + * log - input must be finite and non-negative (i.e. x >= 0 && x <= 3e+38) + * pow - base must be finite and non-negative. Result must not overflow (i.e. x >= 0 && x <= 3e+38; 1e-38 <= result <= 3e+38) + + Clip load operators:: + + x-z, a-w + + The operators taking one argument are:: + + exp log sqrt sin cos abs not dup dupN + + The operators taking two arguments are:: + + + - * / max min pow > < = >= <= and or xor swap swapN + + The operators taking three arguments are:: + + ? + + For example these operations:: + + a b c ? + + d e < + + f abs + + Are equivalent to these operations in C:: + + a ? b : c + + d < e + + abs(f) + + The sin/cos operators are approximated to within 2e-6 absolute error for + inputs with magnitude up to 1e5, and there is no accuracy guarantees for + inputs whose magnitude is larger than 2e5. + + How to average the Y planes of 3 YUV clips and pass through the UV planes + unchanged (assuming same format):: + + std.Expr(clips=[clipa, clipb, clipc], expr=["x y + z + 3 /", "", ""]) + + How to average the Y planes of 3 YUV clips and pass through the UV planes + unchanged (different formats):: + + std.Expr(clips=[clipa16bit, clipb10bit, clipa8bit], + expr=["x y 64 * + z 256 * + 3 /", ""]) + + Setting the output format because the resulting values are illegal in a 10 + bit clip (note that the U and V planes will contain junk since direct copy + isn't possible):: + + std.Expr(clips=[clipa10bit, clipb16bit, clipa8bit], + expr=["x 64 * y + z 256 * + 3 /", ""], format=vs.YUV420P16) diff --git a/Programs/doc/_sources/functions/video/flipvertical_fliphorizontal.rst.txt b/Programs/doc/_sources/functions/video/flipvertical_fliphorizontal.rst.txt new file mode 100644 index 0000000..13fc62e --- /dev/null +++ b/Programs/doc/_sources/functions/video/flipvertical_fliphorizontal.rst.txt @@ -0,0 +1,8 @@ +FlipVertical/FlipHorizontal +=========================== + +.. function:: FlipVertical(vnode clip) + FlipHorizontal(vnode clip) + :module: std + + Flips the *clip* in the vertical or horizontal direction. diff --git a/Programs/doc/_sources/functions/video/frameeval.rst.txt b/Programs/doc/_sources/functions/video/frameeval.rst.txt new file mode 100644 index 0000000..13d90c6 --- /dev/null +++ b/Programs/doc/_sources/functions/video/frameeval.rst.txt @@ -0,0 +1,77 @@ +FrameEval +========= + +.. function:: FrameEval(vnode clip, func eval[, vnode[] prop_src, vnode[] clip_src]) + :module: std + + Allows an arbitrary function to be evaluated every frame. The function gets + the frame number, *n*, as input and should return a clip the output frame can + be requested from. + + The *clip* argument is only used to get the output format from since there is + no reliable automatic way to deduce it. + + When using the argument *prop_src* the function will also have an argument, + *f*, containing the current frames. This is mainly so frame properties can be + accessed and used to make decisions. Note that *f* will only be a list if + more than one *prop_src* clip is provided. + + The *clip_src* argument only exists as a way to hint which clips are referenced in the + *eval* function which can improve caching and graph generation. Its use is encouraged + but not required. + + This function can be used to accomplish the same things as Animate, + ScriptClip and all the other conditional filters in Avisynth. Note that to + modify per frame properties you should use *ModifyFrame*. + + How to animate a BlankClip to fade from white to black. This is the simplest + use case without using the *prop_src* argument:: + + import vapoursynth as vs + import functools + + base_clip = vs.core.std.BlankClip(format=vs.YUV420P8, length=1000, color=[255, 128, 128]) + + def animator(n, clip): + if n > 255: + return clip + else: + return vs.core.std.BlankClip(format=vs.YUV420P8, length=1000, color=[n, 128, 128]) + + animated_clip = vs.core.std.FrameEval(base_clip, functools.partial(animator, clip=base_clip)) + animated_clip.set_output() + + How to perform a simple per frame auto white balance. It shows how to access + calculated frame properties and use them for conditional filtering:: + + import vapoursynth as vs + import functools + import math + + def GrayWorld1Adjust(n, f, clip, core): + small_number = 0.000000001 + red = f[0].props['PlaneStatsAverage'] + green = f[1].props['PlaneStatsAverage'] + blue = f[2].props['PlaneStatsAverage'] + max_rgb = max(red, green, blue) + red_corr = max_rgb/max(red, small_number) + green_corr = max_rgb/max(green, small_number) + blue_corr = max_rgb/max(blue, small_number) + norm = max(blue, math.sqrt(red_corr*red_corr + green_corr*green_corr + blue_corr*blue_corr) / math.sqrt(3), small_number) + r_gain = red_corr/norm + g_gain = green_corr/norm + b_gain = blue_corr/norm + return core.std.Expr(clip, expr=['x ' + repr(r_gain) + ' *', 'x ' + repr(g_gain) + ' *', 'x ' + repr(b_gain) + ' *']) + + def GrayWorld1(clip, matrix_s=None): + rgb_clip = vs.core.resize.Bilinear(clip, format=vs.RGB24) + r_avg = vs.core.std.PlaneStats(rgb_clip, plane=0) + g_avg = vs.core.std.PlaneStats(rgb_clip, plane=1) + b_avg = vs.core.std.PlaneStats(rgb_clip, plane=2) + adjusted_clip = vs.core.std.FrameEval(rgb_clip, functools.partial(GrayWorld1Adjust, clip=rgb_clip, core=vs.core), prop_src=[r_avg, g_avg, b_avg]) + return vs.core.resize.Bilinear(adjusted_clip, format=clip.format.id, matrix_s=matrix_s) + + vs.core.std.LoadPlugin(path='BestSource.dll') + main = vs.core.bs.VideoSource(source='...') + main = GrayWorld1(main) + main.set_output() diff --git a/Programs/doc/_sources/functions/video/freezeframes.rst.txt b/Programs/doc/_sources/functions/video/freezeframes.rst.txt new file mode 100644 index 0000000..944b08f --- /dev/null +++ b/Programs/doc/_sources/functions/video/freezeframes.rst.txt @@ -0,0 +1,18 @@ +FreezeFrames +============ + +.. function:: FreezeFrames(vnode clip, int[] first, int[] last, int[] replacement) + :module: std + + FreezeFrames replaces all the frames in the [*first*,\ *last*] range + (inclusive) with *replacement*. + + A single call to FreezeFrames can freeze any number of ranges:: + + core.std.FreezeFrames(input, first=[0, 100, 231], last=[15, 112, 300], replacement=[8, 50, 2]) + + This replaces [0,15] with 8, [100,112] with 50, and [231,300] with 2 (the + original frame number 2, not frame number 2 after it was replaced with + number 8 by the first range). + + The frame ranges must not overlap. diff --git a/Programs/doc/_sources/functions/video/interleave.rst.txt b/Programs/doc/_sources/functions/video/interleave.rst.txt new file mode 100644 index 0000000..0cb1156 --- /dev/null +++ b/Programs/doc/_sources/functions/video/interleave.rst.txt @@ -0,0 +1,19 @@ +Interleave +========== + +.. function:: Interleave(vnode[] clips[, bint extend=0, bint mismatch=0, bint modify_duration=True]) + :module: std + + Returns a clip with the frames from all *clips* interleaved. For example, + Interleave(clips=[A, B]) will return A.Frame 0, B.Frame 0, A.Frame 1, + B.Frame... + + The *extend* argument controls whether or not all input clips will be treated + as if they have the same length as the longest clip. + + Interleaving clips with different formats or dimensions is considered an + error unless *mismatch* is true. + + If *modify_duration* is set then the output clip's frame rate is the first + input clip's frame rate multiplied by the number of input clips. The frame durations are divided + by the number of input clips. Otherwise the first input clip's frame rate is used. diff --git a/Programs/doc/_sources/functions/video/invert_invertmask.rst.txt b/Programs/doc/_sources/functions/video/invert_invertmask.rst.txt new file mode 100644 index 0000000..6342db8 --- /dev/null +++ b/Programs/doc/_sources/functions/video/invert_invertmask.rst.txt @@ -0,0 +1,21 @@ +Invert/InvertMask +================= + +.. function:: Invert(vnode clip[, int[] planes=[0, 1, 2]]) + InvertMask(vnode clip[, int[] planes=[0, 1, 2]]) + :module: std + + Inverts the pixel values. Specifically, it subtracts the value of the + input pixel from the format's maximum allowed value. The *InvertMask* + version is intended for use on mask clips where all planes have the + same maximum value regardless of the colorspace. + + *clip* + Clip to process. It must have integer sample type and bit depth + between 8 and 16, or float sample type and bit depth of 32. If + there are any frames with other formats, an error will be + returned. + + *planes* + Specifies which planes will be processed. Any unprocessed planes + will be simply copied. diff --git a/Programs/doc/_sources/functions/video/levels.rst.txt b/Programs/doc/_sources/functions/video/levels.rst.txt new file mode 100644 index 0000000..a6a8347 --- /dev/null +++ b/Programs/doc/_sources/functions/video/levels.rst.txt @@ -0,0 +1,39 @@ +Levels +====== + +.. function:: Levels(vnode clip[, float min_in, float max_in, float gamma=1.0, float min_out, float max_out, int[] planes=[0, 1, 2]]) + :module: std + + Adjusts brightness, contrast, and gamma. + + The range [*min_in*, *max_in*] is remapped into [*min_out*, *max_out*]. Note that the + range behavior is unintuitive for YUV float formats since the assumed range will be + 0-1 even for the UV-planes. + + For example, to convert from limited range YUV to full range (8 bit):: + + clip = std.Levels(clip, min_in=16, max_in=235, min_out=0, max_out=255, planes=0) + clip = std.Levels(clip, min_in=16, max_in=240, min_out=0, max_out=255, planes=[1,2]) + + The default value of *max_in* and *max_out* is the format's minimum and maximum + allowed values respectively. Note that all input is clamped to the input range + to prevent out of range output. + + .. warning:: + The default ranges are 0-1 for floating point formats. This may have an undesired + effect on YUV formats. + + *clip* + Clip to process. It must have integer sample type and bit depth + between 8 and 16, or float sample type and bit depth of 32. If + there are any frames with other formats, an error will be + returned. + + *gamma* + Controls the degree of non-linearity of the conversion. Values + greater than 1.0 brighten the output, while values less than 1.0 + darken it. + + *planes* + Specifies which planes will be processed. Any unprocessed planes + will be simply copied. diff --git a/Programs/doc/_sources/functions/video/limiter.rst.txt b/Programs/doc/_sources/functions/video/limiter.rst.txt new file mode 100644 index 0000000..09854d5 --- /dev/null +++ b/Programs/doc/_sources/functions/video/limiter.rst.txt @@ -0,0 +1,23 @@ +Limiter +======= + +.. function:: Limiter(vnode clip[, float[] min, float[] max, int[] planes=[0, 1, 2]]) + :module: std + + Limits the pixel values to the range [*min*, *max*]. + + *clip* + Clip to process. It must have integer sample type and bit depth + between 8 and 16, or float sample type and bit depth of 32. If + there are any frames with other formats, an error will be + returned. + + *min* + Lower bound. Defaults to the lowest allowed value for the input. Can be specified for each plane individually. + + *max* + Upper bound. Defaults to the highest allowed value for the input. Can be specified for each plane individually. + + *planes* + Specifies which planes will be processed. Any unprocessed planes + will be simply copied. diff --git a/Programs/doc/_sources/functions/video/loop.rst.txt b/Programs/doc/_sources/functions/video/loop.rst.txt new file mode 100644 index 0000000..3932250 --- /dev/null +++ b/Programs/doc/_sources/functions/video/loop.rst.txt @@ -0,0 +1,11 @@ +Loop +==== + +.. function:: Loop(vnode clip[, int times=0]) + :module: std + + Returns a clip with the frames or samples repeated over and over again. If *times* is + less than 1 the clip will be repeated until the maximum clip length is + reached, otherwise it will be repeated *times* times. + + In Python, std.Loop can also be invoked :ref:`using the multiplication operator `. diff --git a/Programs/doc/_sources/functions/video/lut.rst.txt b/Programs/doc/_sources/functions/video/lut.rst.txt new file mode 100644 index 0000000..017bdaa --- /dev/null +++ b/Programs/doc/_sources/functions/video/lut.rst.txt @@ -0,0 +1,39 @@ +Lut +=== + +.. function:: Lut(vnode clip[, int[] planes, int[] lut, float[] lutf, func function, int bits, bint floatout]) + :module: std + + Applies a look-up table to the given clip. The lut can be specified as either an array + of 2^bits_per_sample values or given as a *function* having an argument named + *x* to be evaluated. Either *lut*, *lutf* or *function* must be used. The lut will be + applied to the planes listed in *planes* and the other planes will simply be + passed through unchanged. By default all *planes* are processed. + + If *floatout* is set then the output will be floating point instead, and either + *lutf* needs to be set or *function* always needs to return floating point + values. + + How to limit YUV range (by passing an array): + + .. code-block:: python + + luty = [] + for x in range(2**clip.format.bits_per_sample): + luty.append(max(min(x, 235), 16)) + lutuv = [] + for x in range(2**clip.format.bits_per_sample): + lutuv.append(max(min(x, 240), 16)) + ret = Lut(clip=clip, planes=0, lut=luty) + limited_clip = Lut(clip=ret, planes=[1, 2], lut=lutuv) + + How to limit YUV range (using a function): + + .. code-block:: python + + def limity(x): + return max(min(x, 235), 16) + def limituv(x): + return max(min(x, 240), 16) + ret = Lut(clip=clip, planes=0, function=limity) + limited_clip = Lut(clip=ret, planes=[1, 2], function=limituv) diff --git a/Programs/doc/_sources/functions/video/lut2.rst.txt b/Programs/doc/_sources/functions/video/lut2.rst.txt new file mode 100644 index 0000000..459ba81 --- /dev/null +++ b/Programs/doc/_sources/functions/video/lut2.rst.txt @@ -0,0 +1,40 @@ +Lut2 +==== + +.. function:: Lut2(vnode clipa, vnode clipb[, int[] planes, int[] lut, float[] lutf, func function, int bits, bint floatout]) + :module: std + + Applies a look-up table that takes into account the pixel values of two clips. The + *lut* needs to contain 2^(clip1.bits_per_sample + clip2.bits_per_sample) + entries and will be applied to the planes listed in *planes*. Alternatively + a *function* taking *x* and *y* as arguments can be used to make the lut. + The other planes will be passed through unchanged. By default all *planes* + are processed. + + Lut2 also takes an optional bit depth parameter, *bits*, which defaults to + the bit depth of the first input clip, and specifies the bit depth of the + output clip. The user is responsible for understanding the effects of bit + depth conversion, specifically from higher bit depths to lower bit depths, + as no scaling or clamping is applied. + + If *floatout* is set then the output will be floating point instead, and either + *lutf* needs to be set or *function* always needs to return floating point + values. + + How to average 2 clips: + + .. code-block:: python + + lut = [] + for y in range(2 ** clipy.format.bits_per_sample): + for x in range(2 ** clipx.format.bits_per_sample): + lut.append((x + y)//2) + Lut2(clipa=clipa, clipb=clipb, lut=lut) + + How to average 2 clips with a 10-bit output: + + .. code-block:: python + + def f(x, y): + return (x*4 + y)//2 + Lut2(clipa=clipa8bit, clipb=clipb10bit, function=f, bits=10) diff --git a/Programs/doc/_sources/functions/video/makediff.rst.txt b/Programs/doc/_sources/functions/video/makediff.rst.txt new file mode 100644 index 0000000..c8d7f84 --- /dev/null +++ b/Programs/doc/_sources/functions/video/makediff.rst.txt @@ -0,0 +1,15 @@ +MakeDiff +======== + +.. function:: MakeDiff(vnode clipa, vnode clipb[, int[] planes]) + :module: std + + Calculates the difference between *clipa* and *clipb* and clamps the result. + By default all *planes* are processed. This function is usually used together with *MergeDiff*, which can be used to add back the difference. + + Unsharp masking of luma:: + + blur_clip = core.std.Convolution(clip, matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1], planes=[0]) + diff_clip = core.std.MakeDiff(clip, blur_clip, planes=[0]) + sharpened_clip = core.std.MergeDiff(clip, diff_clip, planes=[0]) + diff --git a/Programs/doc/_sources/functions/video/makefulldiff.rst.txt b/Programs/doc/_sources/functions/video/makefulldiff.rst.txt new file mode 100644 index 0000000..c758514 --- /dev/null +++ b/Programs/doc/_sources/functions/video/makefulldiff.rst.txt @@ -0,0 +1,16 @@ +MakeFullDiff +============ + +.. function:: MakeFullDiff(vnode clipa, vnode clipb) + :module: std + + Calculates the difference between *clipa* and *clipb* and outputs a clip with a one higher bitdepth to avoid the clamping or wraparound issues + that would otherwise happen with filters like *MakeDiff* when forming a difference. + This function is usually used together with *MergeFullDiff*, which can be used to add back the difference. + + Unsharp mask:: + + blur_clip = core.std.Convolution(clip, matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]) + diff_clip = core.std.MakeFullDiff(clip, blur_clip) + sharpened_clip = core.std.MergeFullDiff(clip, diff_clip) + diff --git a/Programs/doc/_sources/functions/video/maskedmerge.rst.txt b/Programs/doc/_sources/functions/video/maskedmerge.rst.txt new file mode 100644 index 0000000..5518d91 --- /dev/null +++ b/Programs/doc/_sources/functions/video/maskedmerge.rst.txt @@ -0,0 +1,35 @@ +MaskedMerge +=========== + +.. function:: MaskedMerge(vnode clipa, vnode clipb, vnode mask[, int[] planes, bint first_plane=0, bint premultiplied=0]) + :module: std + + MaskedMerge merges *clipa* with *clipb* using the per pixel weights in the *mask*, + where 0 means that *clipa* is returned unchanged. + The *mask* clip is assumed to be full range for all planes and in the + 0-1 interval for float formats regardless of the colorspace. + If *mask* is a grayscale clip or if *first_plane* is true, the mask's first + plane will be used as the mask for merging all planes. The mask will be + bilinearly resized if necessary. + + If *premultiplied* is set the blending is performed as if *clipb* has been pre-multiplied + with alpha. In pre-multiplied mode it is an error to try to merge two frames with + mismatched full and limited range since it will most likely cause horrible unintended + color shifts. In the other mode it's just a very, very bad idea. + + By default all planes will be + processed, but it is also possible to specify a list of the *planes* to merge + in the output. The unprocessed planes will be copied from the first clip. + + *clipa* and *clipb* must have the same dimensions and format, and the *mask* must be the + same format as the clips or the grayscale equivalent. + + How to apply a mask to the first plane:: + + MaskedMerge(clipa=A, clipb=B, mask=Mask, planes=0) + + How to apply the first plane of a mask to the second and third plane:: + + MaskedMerge(clipa=A, clipb=B, mask=Mask, planes=[1, 2], first_plane=True) + + The frame properties are copied from *clipa*. diff --git a/Programs/doc/_sources/functions/video/median.rst.txt b/Programs/doc/_sources/functions/video/median.rst.txt new file mode 100644 index 0000000..aa51798 --- /dev/null +++ b/Programs/doc/_sources/functions/video/median.rst.txt @@ -0,0 +1,19 @@ +Median +====== + +.. function:: Median(vnode clip[, int[] planes=[0, 1, 2]]) + :module: std + + Replaces each pixel with the median of the nine pixels in its 3x3 + neighbourhood. In other words, the nine pixels are sorted from lowest + to highest, and the middle value is picked. + + *clip* + Clip to process. It must have integer sample type and bit depth + between 8 and 16, or float sample type and bit depth of 32. If + there are any frames with other formats, an error will be + returned. + + *planes* + Specifies which planes will be processed. Any unprocessed planes + will be simply copied. diff --git a/Programs/doc/_sources/functions/video/merge.rst.txt b/Programs/doc/_sources/functions/video/merge.rst.txt new file mode 100644 index 0000000..876ae88 --- /dev/null +++ b/Programs/doc/_sources/functions/video/merge.rst.txt @@ -0,0 +1,29 @@ +Merge +===== + +.. function:: Merge(vnode clipa, vnode clipb[, float[] weight = 0.5]) + :module: std + + Merges *clipa* and *clipb* using the specified *weight* for each plane. The default + is to use a 0.5 *weight* for all planes. A zero *weight* means that *clipa* + is returned unchanged and 1 means that *clipb* is returned unchanged. If a + single *weight* is specified, it will be used for all planes. If two weights + are given then the second value will be used for the third plane as well. + + Values outside the 0-1 range are considered to be an error. Specifying more + weights than planes in the clips is also an error. The clips must have the + same dimensions and format. + + How to merge luma:: + + Merge(clipa=A, clipb=B, weight=[1, 0]) + + How to merge chroma:: + + Merge(clipa=A, clipb=B, weight=[0, 1]) + + The average of two clips:: + + Merge(clipa=A, clipb=B) + + The frame properties are copied from *clipa*. diff --git a/Programs/doc/_sources/functions/video/mergediff.rst.txt b/Programs/doc/_sources/functions/video/mergediff.rst.txt new file mode 100644 index 0000000..abe12be --- /dev/null +++ b/Programs/doc/_sources/functions/video/mergediff.rst.txt @@ -0,0 +1,15 @@ +MergeDiff +========= + +.. function:: MergeDiff(vnode clipa, vnode clipb[, int[] planes]) + :module: std + + Merges back the difference in *clipb* to *clipa* and clamps the result. + By default all *planes* are processed. This function is usually used together with *MakeDiff*, which is normally used to calculate the difference. + + Unsharp masking of luma:: + + blur_clip = core.std.Convolution(clip, matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1], planes=[0]) + diff_clip = core.std.MakeDiff(clip, blur_clip, planes=[0]) + sharpened_clip = core.std.MergeDiff(clip, diff_clip, planes=[0]) + diff --git a/Programs/doc/_sources/functions/video/mergefulldiff.rst.txt b/Programs/doc/_sources/functions/video/mergefulldiff.rst.txt new file mode 100644 index 0000000..8590333 --- /dev/null +++ b/Programs/doc/_sources/functions/video/mergefulldiff.rst.txt @@ -0,0 +1,15 @@ +MergeFullDiff +============= + +.. function:: MergeFullDiff(vnode clipa, vnode clipb) + :module: std + + Merges back the difference in *clipb* to *clipa*. Note that the bitdepth of *clipb* has to be one higher than that of *clip*. + This function is usually used together with *MakeFullDiff*, which is normally used to calculate the difference. + + Unsharp mask:: + + blur_clip = core.std.Convolution(clip, matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]) + diff_clip = core.std.MakeFullDiff(clip, blur_clip) + sharpened_clip = core.std.MergeFullDiff(clip, diff_clip) + diff --git a/Programs/doc/_sources/functions/video/minimum_maximum.rst.txt b/Programs/doc/_sources/functions/video/minimum_maximum.rst.txt new file mode 100644 index 0000000..fa96496 --- /dev/null +++ b/Programs/doc/_sources/functions/video/minimum_maximum.rst.txt @@ -0,0 +1,69 @@ +Minimum/Maximum +=============== + +.. function:: Minimum(vnode clip[, int[] planes=[0, 1, 2], float threshold, bint[] coordinates=[1, 1, 1, 1, 1, 1, 1, 1]]) + :module: std + + Replaces each pixel with the smallest value in its 3x3 neighbourhood. + This operation is also known as erosion. + + *clip* + Clip to process. It must have integer sample type and bit depth + between 8 and 16, or float sample type and bit depth of 32. If + there are any frames with other formats, an error will be + returned. + + *planes* + Specifies which planes will be processed. Any unprocessed planes + will be simply copied. + + *threshold* + Allows to limit how much pixels are changed. Output pixels will not + become less than ``input - threshold``. The default is no limit. + + *coordinates* + Specifies which pixels from the 3x3 neighbourhood are considered. + If an element of this array is 0, the corresponding pixel is not + considered when finding the minimum value. This must contain exactly + 8 numbers. + + Here is how each number corresponds to a pixel in the 3x3 + neighbourhood:: + + 1 2 3 + 4 5 + 6 7 8 + + +.. function:: Maximum(vnode clip[, int[] planes=[0, 1, 2], float threshold, bint[] coordinates=[1, 1, 1, 1, 1, 1, 1, 1]]) + :module: std + + Replaces each pixel with the largest value in its 3x3 neighbourhood. + This operation is also known as dilation. + + *clip* + Clip to process. It must have integer sample type and bit depth + between 8 and 16, or float sample type and bit depth of 32. If + there are any frames with other formats, an error will be + returned. + + *planes* + Specifies which planes will be processed. Any unprocessed planes + will be simply copied. + + *threshold* + Allows to limit how much pixels are changed. Output pixels will not + become less than ``input - threshold``. The default is no limit. + + *coordinates* + Specifies which pixels from the 3x3 neighbourhood are considered. + If an element of this array is 0, the corresponding pixel is not + considered when finding the maximum value. This must contain exactly + 8 numbers. + + Here is how each number corresponds to a pixel in the 3x3 + neighbourhood:: + + 1 2 3 + 4 5 + 6 7 8 diff --git a/Programs/doc/_sources/functions/video/modifyframe.rst.txt b/Programs/doc/_sources/functions/video/modifyframe.rst.txt new file mode 100644 index 0000000..e2a0040 --- /dev/null +++ b/Programs/doc/_sources/functions/video/modifyframe.rst.txt @@ -0,0 +1,49 @@ +ModifyFrame +=========== + +.. function:: ModifyFrame(vnode clip, clip[] clips, func selector) + :module: std + + The *selector* function is called for every single frame and can modify the + properties of one of the frames gotten from *clips*. The additional *clips*' + properties should only be read and not modified because only one modified + frame can be returned. + + You must first copy the input frame to make it modifiable. Any frame may be + returned as long as it has the same format as the *clip*. + Failure to do so will produce an error. If for conditional reasons you do not + need to modify the current frame's properties, you can simply pass it through. + The selector function is passed *n*, the current frame number, and *f*, which + is a frame or a list of frames if there is more than one clip specified. + + If you do not need to modify frame properties but only read them, you should + probably be using *FrameEval* instead. + + How to set the property FrameNumber to the current frame number:: + + def set_frame_number(n, f): + fout = f.copy() + fout.props['FrameNumber'] = n + return fout + ... + ModifyFrame(clip=clip, clips=clip, selector=set_frame_number) + + How to remove a property:: + + def remove_property(n, f): + fout = f.copy() + del fout.props['FrameNumber'] + return fout + ... + ModifyFrame(clip=clip, clips=clip, selector=remove_property) + + An example of how to copy certain properties from one clip to another + (clip1 and clip2 have the same format):: + + def transfer_property(n, f): + fout = f[1].copy() + fout.props['FrameNumber'] = f[0].props['FrameNumber'] + fout.props['_Combed'] = f[0].props['_Combed'] + return fout + ... + ModifyFrame(clip=clip1, clips=[clip1, clip2], selector=transfer_property) diff --git a/Programs/doc/_sources/functions/video/pemverifier.rst.txt b/Programs/doc/_sources/functions/video/pemverifier.rst.txt new file mode 100644 index 0000000..f71a369 --- /dev/null +++ b/Programs/doc/_sources/functions/video/pemverifier.rst.txt @@ -0,0 +1,14 @@ +PEMVerifier +=========== + +.. function:: PEMVerifier(vnode clip[, float[] upper, float[] lower]) + :module: std + + The *PEMVerifier* is used to check for out-of-bounds pixel values during filter + development. It is a public function so badly coded filters won't go + unnoticed. + + If no values are set, then *upper* and *lower* default to the max and min values + allowed in the current format. If an out of bounds value is + encountered a frame error is set and the coordinates of the first bad pixel + are included in the error message. diff --git a/Programs/doc/_sources/functions/video/planestats.rst.txt b/Programs/doc/_sources/functions/video/planestats.rst.txt new file mode 100644 index 0000000..ccdf247 --- /dev/null +++ b/Programs/doc/_sources/functions/video/planestats.rst.txt @@ -0,0 +1,15 @@ +PlaneStats +========== + +.. function:: PlaneStats(vnode clipa[, vnode clipb, int plane=0, string prop='PlaneStats']) + :module: std + + This function calculates the min, max and average normalized value of all + the pixels in the specified *plane* and stores the values in the frame properties + named *prop*\ Min, *prop*\ Max and *prop*\ Average. + + If *clipb* is supplied, the absolute normalized difference between the two clips + will be stored in *prop*\ Diff as well. + + The normalization means that the average and the diff will always be floats + between 0 and 1, no matter what the input format is. diff --git a/Programs/doc/_sources/functions/video/premultiply.rst.txt b/Programs/doc/_sources/functions/video/premultiply.rst.txt new file mode 100644 index 0000000..bcbe1ab --- /dev/null +++ b/Programs/doc/_sources/functions/video/premultiply.rst.txt @@ -0,0 +1,14 @@ +PreMultiply +=========== + +.. function:: PreMultiply(vnode clip, vnode alpha) + :module: std + + PreMultiply simply multiplies *clip* and *alpha* in order to make it more suitable for + later operations. This will yield much better results when resizing and a clip with an + alpha channel and :doc:`MaskedMerge ` can use it as input. The *alpha* clip + must be the grayscale format equivalent of *clip*. + + Note that limited range pre-multiplied contents excludes the offset. For example with + 8 bit input 60 luma and 128 alpha would be calculated as ((60 - 16) * 128)/255 + 16 + and not (60 * 128)/255. \ No newline at end of file diff --git a/Programs/doc/_sources/functions/video/prewitt_sobel.rst.txt b/Programs/doc/_sources/functions/video/prewitt_sobel.rst.txt new file mode 100644 index 0000000..0a25513 --- /dev/null +++ b/Programs/doc/_sources/functions/video/prewitt_sobel.rst.txt @@ -0,0 +1,26 @@ +Prewitt/Sobel +=================== + +.. function:: Prewitt(vnode clip[, int[] planes=[0, 1, 2], float scale=1]) + :module: std + + Creates an edge mask using the Prewitt operator. + +.. function:: Sobel(vnode clip[, int[] planes=[0, 1, 2], float scale=1]) + :module: std + + Creates an edge mask using the Sobel operator. + + *clip* + Clip to process. It must have integer sample type and bit depth + between 8 and 16, or float sample type and bit depth of 32. If + there are any frames with other formats, an error will be + returned. + + *planes* + Specifies which planes will be processed. Any unprocessed planes + will be simply copied. + + *scale* + Multiply all pixels by scale before outputting. This can be used to + increase or decrease the intensity of edges in the output. diff --git a/Programs/doc/_sources/functions/video/proptoclip.rst.txt b/Programs/doc/_sources/functions/video/proptoclip.rst.txt new file mode 100644 index 0000000..701e8d1 --- /dev/null +++ b/Programs/doc/_sources/functions/video/proptoclip.rst.txt @@ -0,0 +1,12 @@ +PropToClip +========== + +.. function:: PropToClip(vnode clip[, string prop='_Alpha']) + :module: std + + Extracts a clip from the frames attached to the frame property *prop* in + *clip*. + This function is mainly used to extract a mask/alpha clip that was stored in + another one. + + It is the inverse of ClipToProp(). diff --git a/Programs/doc/_sources/functions/video/removeframeprops.rst.txt b/Programs/doc/_sources/functions/video/removeframeprops.rst.txt new file mode 100644 index 0000000..c315aed --- /dev/null +++ b/Programs/doc/_sources/functions/video/removeframeprops.rst.txt @@ -0,0 +1,9 @@ +RemoveFrameProps +================ + +.. function:: RemoveFrameProps(vnode clip[, string props[]]) + :module: std + + Returns *clip* but with all the frame properties named in + *props* removed. If *props* is unset them all frame properties + are removed. diff --git a/Programs/doc/_sources/functions/video/resize.rst.txt b/Programs/doc/_sources/functions/video/resize.rst.txt new file mode 100644 index 0000000..8e5e413 --- /dev/null +++ b/Programs/doc/_sources/functions/video/resize.rst.txt @@ -0,0 +1,286 @@ +Resize +====== + +.. function:: Bilinear(vnode clip[, int width, int height, int format, enum matrix, enum transfer, enum primaries, enum range, enum chromaloc, enum matrix_in, enum transfer_in, enum primaries_in, enum range_in, enum chromaloc_in, float filter_param_a, float filter_param_b, string resample_filter_uv, float filter_param_a_uv, float filter_param_b_uv, string dither_type="none", string cpu_type, float src_left, float src_top, float src_width, float src_height, float nominal_luminance]) + Bicubic(vnode clip[, ...]) + Point(vnode clip[, ...]) + Lanczos(vnode clip[, ...]) + Spline16(vnode clip[, ...]) + Spline36(vnode clip[, ...]) + Spline64(vnode clip[, ...]) + Bob(vnode clip, string filter="bicubic", bint tff[, ...]) + :module: resize + + In VapourSynth the resizers have several functions. In addition to scaling, + they also do colorspace conversions and conversions to and from the compat + formats. Resize converts a clip of known or unknown format to another clip + of known or unknown format, changing only the parameters specified by the + user. The resize filters can handle varying size and format input clips + and turn them into constant format clips. + + If you do not know which resizer to choose, then try Bicubic. It usually + makes a good neutral default. + + *Bob* can be used as a rudimentary deinterlacer. + + Arguments denoted as type *enum* may be specified by numerical index (see + ITU-T H.265 Annex E.3) or by name. Enums specified by name have their + argument name suffixed with "_s". For example, a destination matrix of + BT 709 can be specified either with ``matrix=1`` or with ``matrix_s="709"``. + + Note that *matrix* is not an optional argument when converting to YUV. + Also note that if no matrix is specified in an input YUV frame's properties + then *matrix_in* also needs to be set. + + The function will return an error if the subsampling restrictions aren't + followed. + + If you get an error like:: + + Resize error 3074: no path between colorspaces (2/2/2 => 1/1/1). + May need to specify additional colorspace parameters. + + It usually means the matrix/transfer/primaries are unknown and you have to + specify the input colorspace parameters yourself. Note: 2 means "unspecified" + according to the ITU-T recommendation. + + Resizing is performed per-field for interlaced images, as indicated by the + *_FieldBased* frame property. Source filters may sometimes mark progressive + video as interlaced, which can result in sub-optimal resampling quality + unless *_FieldBased* is cleared. + + *clip*: + + Accepts all kinds of input. + + *width*, *height*: + + Output image dimensions. + + *filter*: + + Scaling method for deinterlacing. See *resample_filter_uv* for accepted values. + + *tff*: + + Field order for deinterlacing. Used when the *_FieldBased* property is not set. + + *format*: + + Output format id. + + *matrix*, *transfer*, *primaries*: + + Output colorspace specification. If not provided, the corresponding attributes from + the input clip will be selected, except for YCoCg and RGB color families, where the + corresponding matrix is set by default. + + *range*: + + Output pixel range. For integer formats, this allows selection of the legal code + values. Even when set, out of range values (BTB/WTW) may be generated. If the input + format is of a different color family, the default range is studio/limited for YUV + and full-range for RGB. + + *chromaloc*: + + Output chroma location. For subsampled formats, specifies the chroma location. If + the input format is 4:4:4 or RGB and the output is subsampled, the default location + is left-aligned, as per MPEG. Possible chroma locations (ITU-T H.265 Figure E.1): + *left*, *center*, *top_left*, *top*, *bottom_left*, *bottom* + + *matrix_in*, *transfer_in*, *primaries_in*, *range_in*, *chromaloc_in*: + + Input colorspace/format specification. If the corresponding frame property is set + to a value other than unspecified, the frame property is used instead of this parameter. + Default values are set for certain color families. See the equivalent output arguments + for more information. + + *filter_param_a*, *filter_param_b*: + + Parameters for the scaler used for RGB and Y-channel. For the bicubic filter, + filter_param_a/b represent the "b" and "c" parameters. For the lanczos filter, + filter_param_a represents the number of taps. + + *resample_filter_uv*: + + Scaling method for UV channels. It defaults to the same as for the Y-channel. The + following values can be used with *resample_filter_uv*: *point*, *bilinear*, *bicubic*, + *spline16*, *spline36*, *lanczos*. + + *filter_param_a_uv*, *filter_param_b_uv*: + + Parameters for the scaler used for UV channels. + + *dither_type*: + + Dithering method. Dithering is used only for conversions resulting in an integer + format. The following dithering methods are available: *none*, *ordered*, *random*, + *error_diffusion*. + + *cpu_type*: + + Only used for testing. + + *src_left*, *src_top*, *src_width*, *src_height*: + + Used to select the source region of the input to use. Can also be used to shift the image. + Defaults to the whole image. + + *nominal_luminance*: + + Determines the physical brightness of the value 1.0. The unit is in cd/m^2. + + To convert to YV12:: + + Bicubic(clip=clip, format=vs.YUV420P8, matrix_s="709") + + To resize and convert YUV with color information frame properties to planar RGB:: + + Bicubic(clip=clip, width=1920, height=1080, format=vs.RGB24) + + To resize and convert YUV without color information frame properties to planar RGB:: + + Bicubic(clip=clip, width=1920, height=1080, format=vs.RGB24, matrix_in_s="709") + + The following tables list values of selected colorspace enumerations and + their abbreviated names. (Numerical value in parentheses.) For all possible values, + see ITU-T H.265. + + Matrix coefficients (ITU-T H.265 Table E.5):: + + rgb (0) Identity + The identity matrix. + Typically used for GBR (often referred to as RGB); + however, may also be used for YZX (often referred to as + XYZ); + 709 (1) KR = 0.2126; KB = 0.0722 + ITU-R Rec. BT.709-5 + unspec (2) Unspecified + Image characteristics are unknown or are determined by the + application. + fcc (4) + 470bg (5) KR = 0.299; KB = 0.114 + ITU-R Rec. BT.470-6 System B, G (historical) + (functionally the same as the value 6 (170m)) + 170m (6) KR = 0.299; KB = 0.114 + SMPTE 170M (2004) + (functionally the same as the value 5 (470bg)) + 240m (7) SMPTE 240M + ycgco (8) YCgCo + 2020ncl (9) KR = 0.2627; KB = 0.0593 + Rec. ITU-R BT.2020 non-constant luminance system + 2020cl (10) KR = 0.2627; KB = 0.0593 + Rec. ITU-R BT.2020 constant luminance system + chromancl (12) Chromaticity derived non-constant luminance system + chromacl (13) Chromaticity derived constant luminance system + ictcp (14) ICtCp + + Transfer characteristics (ITU-T H.265 Table E.4):: + + 709 (1) V = a * Lc0.45 - ( a - 1 ) for 1 >= Lc >= b + V = 4.500 * Lc for b > Lc >= 0 + Rec. ITU-R BT.709-5 + (functionally the same as the values 6 (601), + 14 (2020_10) and 15 (2020_12)) + unspec (2) Unspecified + Image characteristics are unknown or are determined by the + application. + 470m (4) ITU-R Rec. BT.470-6 System M + 470bg (5) ITU-R Rec. BT.470-6 System B, G (historical) + 601 (6) V = a * Lc0.45 - ( a - 1 ) for 1 >= Lc >= b + V = 4.500 * Lc for b > Lc >= 0 + Rec. ITU-R BT.601-6 525 or 625 + (functionally the same as the values 1 (709), + 14 (2020_10) and 15 (2020_12)) + 240m (7) SMPTE 240M + linear (8) V = Lc for all values of Lc + Linear transfer characteristics + log100 (9) Log 1:100 contrast + log316 (10) Log 1:316 contrast + xvycc (11) IEC 61966-2-4 + srgb (13) IEC 61966-2-1 + 2020_10 (14) V = a * Lc0.45 - ( a - 1 ) for 1 >= Lc >= b + V = 4.500 * Lc for b > Lc >= 0 + Rec. ITU-R BT.2020 + (functionally the same as the values 1 (709), + 6 (601) and 15 (2020_12)) + 2020_12 (15) V = a * Lc0.45 - ( a - 1 ) for 1 >= Lc >= b + V = 4.500 * Lc for b > Lc >= 0 + Rec. ITU-R BT.2020 + (functionally the same as the values 1 (709), + 6 (601) and 14 (2020_10)) + st2084 (16) SMPTE ST 2084 + std-b67 (18) ARIB std-b67 + + Color primaries (ITU-T H.265 Table E.3):: + + 709 (1) primary x y + green 0.300 0.600 + blue 0.150 0.060 + red 0.640 0.330 + white D65 0.3127 0.3290 + Rec. ITU-R BT.709-5 + unspec (2) Unspecified + Image characteristics are unknown or are determined by the + application. + 470m (4) ITU-R Rec. BT.470-6 System M + 470bg (5) ITU-R Rec. BT.470-6 System B, G (historical) + 170m (6) primary x y + green 0.310 0.595 + blue 0.155 0.070 + red 0.630 0.340 + white D65 0.3127 0.3290 + SMPTE 170M (2004) + (functionally the same as the value 7 (240m)) + 240m (7) primary x y + green 0.310 0.595 + blue 0.155 0.070 + red 0.630 0.340 + white D65 0.3127 0.3290 + SMPTE 240M (1999) + (functionally the same as the value 6 (170m)) + film (8) + 2020 (9) primary x y + green 0.170 0.797 + blue 0.131 0.046 + red 0.708 0.292 + white D65 0.3127 0.3290 + Rec. ITU-R BT.2020 + st428 (10) Commonly known as xyz + xyz (10) Alias for st428 + st431-2 (11) DCI-P3 with traditional white point + st432-1 (12) DCI-P3 + jedec-p22 (22) E.B.U. STANDARD FOR CHROMATICITY TOLERANCES FOR STUDIO MONITORS (3213-E) + Also known as JEDEC P22 + + Pixel range (ITU-T H.265 Eq E-4 to E-15):: + + limited (0) Studio (TV) legal range, 16-235 in 8 bits. + Y = Clip1Y( Round( ( 1 << ( BitDepthY - 8 ) ) * + ( 219 * E'Y + 16 ) ) ) + Cb = Clip1C( Round( ( 1 << ( BitDepthC - 8 ) ) * + ( 224 * E'PB + 128 ) ) ) + Cr = Clip1C( Round( ( 1 << ( BitDepthC - 8 ) ) * + ( 224 * E'PR + 128 ) ) ) + + R = Clip1Y( ( 1 << ( BitDepthY - 8 ) ) * + ( 219 * E'R + 16 ) ) + G = Clip1Y( ( 1 << ( BitDepthY - 8 ) ) * + ( 219 * E'G + 16 ) ) + B = Clip1Y( ( 1 << ( BitDepthY - 8 ) ) * + ( 219 * E'B + 16 ) ) + full (1) Full (PC) dynamic range, 0-255 in 8 bits. + Y = Clip1Y( Round( ( ( 1 << BitDepthY ) - 1 ) * E'Y ) ) + Cb = Clip1C( Round( ( ( 1 << BitDepthC ) - 1 ) * E'PB + + ( 1 << ( BitDepthC - 1 ) ) ) ) + Cr = Clip1C( Round( ( ( 1 << BitDepthC ) - 1 ) * E'PR + + ( 1 << ( BitDepthC - 1 ) ) ) ) + + R = Clip1Y( ( ( 1 << BitDepthY ) - 1 ) * E'R ) + G = Clip1Y( ( ( 1 << BitDepthY ) - 1 ) * E'G ) + B = Clip1Y( ( ( 1 << BitDepthY ) - 1 ) * E'B ) + + + + diff --git a/Programs/doc/_sources/functions/video/reverse.rst.txt b/Programs/doc/_sources/functions/video/reverse.rst.txt new file mode 100644 index 0000000..4f8c249 --- /dev/null +++ b/Programs/doc/_sources/functions/video/reverse.rst.txt @@ -0,0 +1,10 @@ +Reverse +======= + +.. function:: Reverse(vnode clip) + :module: std + + Returns a clip with the frame or sample order reversed. For example, a clip with 3 + frames would have the frame order 2, 1, 0. + + In Python, std.Reverse can also be invoked by :ref:`slicing a clip `. diff --git a/Programs/doc/_sources/functions/video/selectevery.rst.txt b/Programs/doc/_sources/functions/video/selectevery.rst.txt new file mode 100644 index 0000000..b520337 --- /dev/null +++ b/Programs/doc/_sources/functions/video/selectevery.rst.txt @@ -0,0 +1,31 @@ +SelectEvery +=========== + +.. function:: SelectEvery(vnode clip, int cycle, int[] offsets[, bint modify_duration=True]) + :module: std + + Returns a clip with only some of the frames in every *cycle* selected. The + *offsets* given must be between 0 and *cycle* - 1. + + Below are some examples of useful operations. + + Return even numbered frames, starting with 0:: + + SelectEvery(clip=clip, cycle=2, offsets=0) + + Return odd numbered frames, starting with 1:: + + SelectEvery(clip=clip, cycle=2, offsets=1) + + Fixed pattern 1 in 5 decimation, first frame in every cycle removed:: + + SelectEvery(clip=clip, cycle=5, offsets=[1, 2, 3, 4]) + + Duplicate every fourth frame:: + + SelectEvery(clip=clip, cycle=4, offsets=[0, 1, 2, 3, 3]) + + In Python, std.SelectEvery can also be invoked by :ref:`slicing a clip `. + + If *modify_duration* is set the clip's frame rate is multiplied by the number + of offsets and divided by *cycle*. The frame durations are adjusted in the same manner. diff --git a/Programs/doc/_sources/functions/video/separatefields.rst.txt b/Programs/doc/_sources/functions/video/separatefields.rst.txt new file mode 100644 index 0000000..189427b --- /dev/null +++ b/Programs/doc/_sources/functions/video/separatefields.rst.txt @@ -0,0 +1,20 @@ +SeparateFields +============== + +.. function:: SeparateFields(vnode clip[, bint tff, bint modify_duration=True]) + :module: std + + Returns a clip with the fields separated and interleaved. + + The *tff* argument only has an effect when the field order isn't set for a frame. + Setting *tff* to true means top field first and false means bottom field + first. + + If *modify_duration* is set then the output clip's frame rate is double that of the input clip. + The frame durations will also be halved. + + The ``_FieldBased`` frame property is deleted. The ``_Field`` frame + property is added. + + If no field order is specified in ``_FieldBased`` or *tff* an error + will be returned. diff --git a/Programs/doc/_sources/functions/video/setfieldbased.rst.txt b/Programs/doc/_sources/functions/video/setfieldbased.rst.txt new file mode 100644 index 0000000..09834b1 --- /dev/null +++ b/Programs/doc/_sources/functions/video/setfieldbased.rst.txt @@ -0,0 +1,25 @@ +SetFieldBased +============= + +.. function:: SetFieldBased(vnode clip, int value) + :module: std + + This is a convenience function. See *SetFrameProps* if you want to + set other properties. + + SetFieldBased sets ``_FieldBased`` to *value* and deletes + the ``_Field`` frame property. The possible values are: + + 0 = Frame Based + + 1 = Bottom Field First + + 2 = Top Field First + + For example, if you have source material that's progressive but has + been encoded as interlaced you can set it to be treated as frame based + (not interlaced) to improve resizing quality:: + + clip = core.bs.VideoSource("rule6.mkv") + clip = core.std.SetFieldBased(clip, 0) + clip = clip.resize.Bilinear(clip, width=320, height=240) diff --git a/Programs/doc/_sources/functions/video/setframeprop.rst.txt b/Programs/doc/_sources/functions/video/setframeprop.rst.txt new file mode 100644 index 0000000..7200d60 --- /dev/null +++ b/Programs/doc/_sources/functions/video/setframeprop.rst.txt @@ -0,0 +1,20 @@ +SetFrameProp +============ + +.. function:: SetFrameProp(vnode clip, string prop[, int[] intval, float[] floatval, string[] data]) + :module: std + + Adds a frame property to every frame in *clip*. + + If there is already a property with the name *prop* in the frames, + it will be overwritten. + + The type of the property added depends on which of the *intval*, + *floatval*, or *data* parameters is used. + + The *data* parameter can only be used to add NULL-terminated strings, + not arbitrary binary data. + + For example, to set the field order to top field first:: + + clip = c.std.SetFrameProp(clip, prop="_FieldBased", intval=2) diff --git a/Programs/doc/_sources/functions/video/setframeprops.rst.txt b/Programs/doc/_sources/functions/video/setframeprops.rst.txt new file mode 100644 index 0000000..e5e9116 --- /dev/null +++ b/Programs/doc/_sources/functions/video/setframeprops.rst.txt @@ -0,0 +1,13 @@ +SetFrameProps +============= + +.. function:: SetFrameProps(vnode clip, ...) + :module: std + + Adds the specified values as a frame property of every frame + in *clip*. If a frame property with the same key already exists + it will be replaced. + + For example, to set the field order to top field first:: + + clip = c.std.SetFrameProps(clip, _FieldBased=2) diff --git a/Programs/doc/_sources/functions/video/setvideocache.rst.txt b/Programs/doc/_sources/functions/video/setvideocache.rst.txt new file mode 100644 index 0000000..4edcf46 --- /dev/null +++ b/Programs/doc/_sources/functions/video/setvideocache.rst.txt @@ -0,0 +1,27 @@ +SetVideoCache +============= + +.. function:: SetVideoCache(vnode clip[, int mode, int fixedsize, int maxsize, int historysize]) + :module: std + + Every filter node has a cache associated with it that + may or may not be enabled depending on the dependencies + and request patterns. This function allows all automatic + behavior to be overridden. + + The *mode* option has 3 possible options where 0 always + disables caching, 1 always enables the cache and -1 + uses the automatically calculated settings. Note that + setting *mode* to -1 will reset the other values to + their defaults as well. + + The other options are fairly self-explanatory where + setting *fixedsize* prevents the cache from over time + altering its *maxsize* based on request history. The + final *historysize* argument controls how many previous + and no longer cached requests should be considered when + adjusting *maxsize*, generally this value should not + be touched at all. + + Note that setting *mode* will reset all other options + to their defaults. \ No newline at end of file diff --git a/Programs/doc/_sources/functions/video/shuffleplanes.rst.txt b/Programs/doc/_sources/functions/video/shuffleplanes.rst.txt new file mode 100644 index 0000000..d50c06e --- /dev/null +++ b/Programs/doc/_sources/functions/video/shuffleplanes.rst.txt @@ -0,0 +1,48 @@ +ShufflePlanes +============= + +.. function:: ShufflePlanes(vnode[] clips, int[] planes, int colorfamily) + :module: std + + ShufflePlanes can extract and combine planes from different clips in the most + general way possible. + This is both good and bad, as there are almost no error checks. + + Most of the returned clip's properties are implicitly determined from the + first clip given to *clips*. + + The *clips* parameter takes between one and three clips for color families + with three planes. In this case clips=[A] is equivalent to clips=[A, A, A] + and clips=[A, B] is equivalent to clips=[A, B, B]. For the GRAY color + family, which has one plane, it takes exactly one clip. + + The argument *planes* controls which of the input clips' planes to use. + Zero indexed. The first number refers to the first input clip, the second + number to the second clip, the third number to the third clip. + + The only thing that needs to be specified is *colorfamily*, which controls which + color family (YUV, RGB, GRAY) the output clip will be. + Properties such as subsampling are determined from the relative size of the + given planes to combine. + + ShufflePlanes accepts clips with variable format and dimensions only when + extracting a single plane. + + Below are some examples of useful operations. + + Extract plane with index X. X=0 will mean luma in a YUV clip and R in an RGB + clip. Likewise 1 will return the U and G channels, respectively:: + + ShufflePlanes(clips=clip, planes=X, colorfamily=vs.GRAY) + + Swap U and V in a YUV clip:: + + ShufflePlanes(clips=clip, planes=[0, 2, 1], colorfamily=vs.YUV) + + Merge 3 grayscale clips into a YUV clip:: + + ShufflePlanes(clips=[Yclip, Uclip, Vclip], planes=[0, 0, 0], colorfamily=vs.YUV) + + Cast a YUV clip to RGB:: + + ShufflePlanes(clips=[YUVclip], planes=[0, 1, 2], colorfamily=vs.RGB) diff --git a/Programs/doc/_sources/functions/video/splice.rst.txt b/Programs/doc/_sources/functions/video/splice.rst.txt new file mode 100644 index 0000000..df7e020 --- /dev/null +++ b/Programs/doc/_sources/functions/video/splice.rst.txt @@ -0,0 +1,12 @@ +Splice +====== + +.. function:: Splice(vnode[] clips[, bint mismatch=0]) + :module: std + + Returns a clip with all *clips* appended in the given order. + + Splicing clips with different formats or dimensions is + considered an error unless *mismatch* is true. + + In Python, std.Splice can also be invoked :ref:`using the addition operator `. diff --git a/Programs/doc/_sources/functions/video/splitplanes.rst.txt b/Programs/doc/_sources/functions/video/splitplanes.rst.txt new file mode 100644 index 0000000..049d7b4 --- /dev/null +++ b/Programs/doc/_sources/functions/video/splitplanes.rst.txt @@ -0,0 +1,8 @@ +SplitPlanes +=========== + +.. function:: SplitPlanes(vnode clip) + :module: std + + SplitPlanes returns each plane of the input as + separate clips. diff --git a/Programs/doc/_sources/functions/video/stackvertical_stackhorizontal.rst.txt b/Programs/doc/_sources/functions/video/stackvertical_stackhorizontal.rst.txt new file mode 100644 index 0000000..cdd7f5f --- /dev/null +++ b/Programs/doc/_sources/functions/video/stackvertical_stackhorizontal.rst.txt @@ -0,0 +1,12 @@ +StackVertical/StackHorizontal +============================= + +.. function:: StackVertical(vnode[] clips) + StackHorizontal(vnode[] clips) + :module: std + + Stacks all given *clips* together. The same format is a requirement. For + StackVertical all clips also need to be the same width and for + StackHorizontal all clips need to be the same height. + + The frame properties are copied from the first clip. diff --git a/Programs/doc/_sources/functions/video/text/clipinfo.rst.txt b/Programs/doc/_sources/functions/video/text/clipinfo.rst.txt new file mode 100644 index 0000000..ab2a767 --- /dev/null +++ b/Programs/doc/_sources/functions/video/text/clipinfo.rst.txt @@ -0,0 +1,9 @@ +ClipInfo +======== + +.. function:: ClipInfo(vnode clip[, int alignment=7, int scale=1]]) + :module: text + + Prints information about the *clip*, such as the format and framerate. + + This is a convenience function for *Text*. diff --git a/Programs/doc/_sources/functions/video/text/coreinfo.rst.txt b/Programs/doc/_sources/functions/video/text/coreinfo.rst.txt new file mode 100644 index 0000000..18eb56c --- /dev/null +++ b/Programs/doc/_sources/functions/video/text/coreinfo.rst.txt @@ -0,0 +1,10 @@ +CoreInfo +======== + +.. function:: CoreInfo([vnode clip=std.BlankClip(), int alignment=7, int scale=1]) + :module: text + + Prints information about the VapourSynth core, such as version and memory + use. If no *clip* is supplied, a default blank one is used. + + This is a convenience function for *Text*. diff --git a/Programs/doc/_sources/functions/video/text/framenum.rst.txt b/Programs/doc/_sources/functions/video/text/framenum.rst.txt new file mode 100644 index 0000000..cb48463 --- /dev/null +++ b/Programs/doc/_sources/functions/video/text/framenum.rst.txt @@ -0,0 +1,9 @@ +FrameNum +======== + +.. function:: FrameNum(vnode clip[, int alignment=7, int scale=1]) + :module: text + + Prints the current frame number. + + This is a convenience function for *Text*. diff --git a/Programs/doc/_sources/functions/video/text/frameprops.rst.txt b/Programs/doc/_sources/functions/video/text/frameprops.rst.txt new file mode 100644 index 0000000..2a2a8e2 --- /dev/null +++ b/Programs/doc/_sources/functions/video/text/frameprops.rst.txt @@ -0,0 +1,10 @@ +FrameProps +========== + +.. function:: FrameProps(vnode clip[, string props=[], int alignment=7, int scale=1]) + :module: text + + Prints all properties attached to the frames, or if the *props* array is + given only those properties. + + This is a convenience function for *Text*. diff --git a/Programs/doc/_sources/functions/video/text/text.rst.txt b/Programs/doc/_sources/functions/video/text/text.rst.txt new file mode 100644 index 0000000..2722425 --- /dev/null +++ b/Programs/doc/_sources/functions/video/text/text.rst.txt @@ -0,0 +1,23 @@ +Text +==== + +.. function:: Text(vnode clip, string text[, int alignment=7, int scale=1]) + :module: text + + Text is a simple text printing filter. It doesn't use any external libraries + for drawing the text. It uses a built-in bitmap font: the not-bold, 8×16 + version of Terminus. The font was not modified, only converted from PCF to an + array of bytes. + + The font covers Windows-1252, which is a superset of ISO-8859-1 (aka latin1). + Unprintable characters get turned into underscores. Long lines get wrapped in + a dumb way. Lines that end up too low to fit in the frame are silently + dropped. + + The *alignment* parameter takes a number from 1 to 9, corresponding to the + positions of the keys on a numpad. + + The *scale* parameter sets an integer scaling factor for the bitmap font. + + *ClipInfo*, *CoreInfo*, *FrameNum*, and *FrameProps* are convenience functions + based on *Text*. diff --git a/Programs/doc/_sources/functions/video/transpose.rst.txt b/Programs/doc/_sources/functions/video/transpose.rst.txt new file mode 100644 index 0000000..c03f042 --- /dev/null +++ b/Programs/doc/_sources/functions/video/transpose.rst.txt @@ -0,0 +1,18 @@ +Transpose +========= + +.. function:: Transpose(vnode clip) + :module: std + + Flips the contents of the frames in the same way as a matrix transpose would + do. Combine it with FlipVertical or FlipHorizontal to synthesize a left or + right rotation. Calling Transpose twice in a row is the same as doing nothing + (but slower). + + Here is a picture to illustrate what Transpose does:: + + 0 5 55 + 0 1 1 2 3 1 8 89 + 5 8 13 21 34 => 1 13 144 + 55 89 144 233 377 2 21 233 + 3 34 377 diff --git a/Programs/doc/_sources/functions/video/trim.rst.txt b/Programs/doc/_sources/functions/video/trim.rst.txt new file mode 100644 index 0000000..5b6dfaa --- /dev/null +++ b/Programs/doc/_sources/functions/video/trim.rst.txt @@ -0,0 +1,17 @@ +Trim +==== + +.. function:: Trim(vnode clip[, int first=0, int last, int length]) + :module: std + + Trim returns a clip with only the frames between the arguments *first* and + *last*, or a clip of *length* frames, starting at *first*. + Trim is inclusive so Trim(clip, first=3, last=3) will return one frame. If + neither *last* nor *length* is specified, no frames are removed from the end + of the clip. + + Specifying both *last* and *length* is considered to be an error. + Likewise is calling Trim in a way that returns no frames, as 0 frame clips are + not allowed in VapourSynth. + + In Python, std.Trim can also be invoked by :ref:`slicing a clip `. diff --git a/Programs/doc/_sources/functions/video/turn180.rst.txt b/Programs/doc/_sources/functions/video/turn180.rst.txt new file mode 100644 index 0000000..11d7780 --- /dev/null +++ b/Programs/doc/_sources/functions/video/turn180.rst.txt @@ -0,0 +1,7 @@ +Turn180 +======= + +.. function:: Turn180(vnode clip) + :module: std + + Turns the frames in a clip 180 degrees (to the left, not to the right). diff --git a/Programs/doc/_sources/gettingstarted.rst.txt b/Programs/doc/_sources/gettingstarted.rst.txt new file mode 100644 index 0000000..e5f77d1 --- /dev/null +++ b/Programs/doc/_sources/gettingstarted.rst.txt @@ -0,0 +1,78 @@ +Getting Started +=============== + +So you managed to install VapourSynth. Now what? + +If you don't know the basics of Python, you may want to check out a +`tutorial `_. + +You can "play around" in the python interpreter if you want, but that's not how +most scripts are created. + +Example Script +############## + +It all starts with a *.vpy* script. +Here's a sample script to be inspired by, it assumes that `BestSource `_ +is installed and :doc:`auto-loaded `. + +.. code-block:: python + + from vapoursynth import core # Get an instance of the core + clip = core.bs.VideoSource(source='filename.mkv') # Load a video track in mkv file + clip = core.std.FlipHorizontal(clip) # Flip the video clip in the horizontal direction + clip.set_output() # Set the video clip to be accessible for output + +Audio is also supported, use `BestSource `_ to load your audio file. + +.. code-block:: python + + from vapoursynth import core # Get an instance of the core + clip = core.bs.AudioSource(source='filename.mkv') # Load an audio track in mkv file + clip = core.std.AudioGain(clip,gain=2.0) # Gain all channels 2x + clip.set_output() # Set the audio clip to be accessible for output + +You can combine 2 operations in one script. + +.. code-block:: python + + from vapoursynth import core + video = core.bs.VideoSource(source='filename.mkv') + audio = core.bs.AudioSource(source='filename.mkv') + video = core.std.FlipHorizontal(video) + audio = core.std.AudioGain(audio,gain=2.0) + video.set_output(index=0) + audio.set_output(index=1) + +Remember that most VapourSynth objects have a quite nice string representation +in Python, so if you want to know more about an instance just call ``print()``. + +Preview +####### + +It's possible to directly open the script in `VapourSynth Editor `_ +or `VirtualDub FilterMod `_ for previewing. + +Output with VSPipe +################## + +VSPipe is very useful to pipe the output to various applications, for example x264 and flac for encoding. + +Here are some examples of command lines that automatically pass on most video and audio attributes. + +For x264:: + + vspipe -c y4m script.vpy - | x264 --demuxer y4m - --output encoded.264 + +For flac:: + + vspipe -c wav script.vpy - | flac - -o encoded.flac + +For FFmpeg:: + + vspipe -c y4m script.vpy - | ffmpeg -i - encoded.mkv + +For mpv:: + + vspipe -c y4m script.vpy - | mpv - + vspipe -c wav script.vpy - | mpv - diff --git a/Programs/doc/_sources/index.rst.txt b/Programs/doc/_sources/index.rst.txt new file mode 100644 index 0000000..b2cb328 --- /dev/null +++ b/Programs/doc/_sources/index.rst.txt @@ -0,0 +1,23 @@ +Welcome to `VapourSynth `_’s documentation! +======================================================================== + +Contents: + +.. toctree:: + :maxdepth: 3 + + introduction + installation + gettingstarted + pythonreference + functions + output + applications + apireference + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` diff --git a/Programs/doc/_sources/installation.rst.txt b/Programs/doc/_sources/installation.rst.txt new file mode 100644 index 0000000..cb14225 --- /dev/null +++ b/Programs/doc/_sources/installation.rst.txt @@ -0,0 +1,341 @@ +Installation +============ + +Basic Program +############# + +The installation contains two main steps: + +1. Install VapourSynth core library. +2. Install the Python wrapper of VapourSynth. + +After you completed the second step, you can test it by opening a Python command line +and type this:: + + from vapoursynth import core + print(core.version()) + +After pressing return at the final line, you should see the version printed along with a +few other lines describing the options used when instantiating the Core object. +In fact, these lines should be the same as the output result of ``vspipe --version``. + +Windows Installation +******************** + +Prerequisites +------------- + +First download and install the prerequisites: + * `Python 3.11.x `_ or Python 3.8.x -- 32 or 64 bit version depending on which version of VapourSynth you want to install + +Note that VapourSynth and Python have to be matched so both are either installed +for all users or for only for the current user. + +Also note that per user installs will not install the required Visual Studio +2019 runtimes. + +Installation +------------ + +Simply run the `VapourSynth installer `_. +It should automatically detect and install everything, including the Python wrapper. + +If the tests mentioned at the beginning fails, there may be a bug in the installer or there are +old copies of vapoursynth.pyd and vapoursynth.dll lying around. + +Windows Installation (Portable) +******************************* + +First download and decompress the prerequisites: + * `Python 3.11.x `_ or Python 3.8.x -- 32 or 64 bit embeddable version + +Simply decompress the `portable VapourSynth archive `_ +into the Python dir and overwrite all existing files.Run ``vs-detect-python.bat`` +to configure it for the current Python version. Done. + +You can also use the VapourSynth Editor by decompressing it into the same directory. + +OS X Installation +***************** + +First download and install the prerequisites: + * Xcode -- Available from the AppStore + * `Homebrew `_ -- A package manager + +Simply run these commands in a terminal and wait for them to complete:: + + brew install vapoursynth + +Linux installation +****************** + +Several distributions have VapourSynth packages. Note that those packages are usually OUT OF DATE. + +Debian +------ +The VapourSynth packages are provided by `deb-multimedia repository `_. +You need to add the repository first following the guide on the official website. + +Fedora, CentOS and RHEL +----------------------- +For Fedora, the VapourSynth packages can be downloaded from official repository directly. +For CentOS and RHEL, you should install EPEL (Extra Packages for Enterprise Linux) repository first. + +Gentoo +------ +There is an `unofficial Portage tree `_ with all VapourSynth related ebuilds. +Check the Github link for more information and instructions. + +Arch Linux +---------- +`VapourSynth-related packages `_ are provided by the Community repository. + +Nix and NixOS +------------- +``vapoursynth`` is available on nixpkgs, either via ``nixpkgs#vapoursynth`` or via ``nixpkgs#python3Packages.vapoursynth`` (currently on unstable only). +Be aware that the derivation is broken on MacOS. + +VapourSynth releases are not backported to the current stable branch. +To get the newest version use the unstable branch. + +Windows Compilation +******************* + +Preparing the Build Environment on Windows +------------------------------------------ + +Default install paths are assumed in all projects and scripts, be prepared to adjust many things if you changed them + +Required languages and applications: + +* Needs `Visual Studio 2019 `_ +* It also needs both `32bit `_ and `64bit `_ Python 3.8.x and 3.11.x (the msvc project assumes that you installed python for all users.) +* `InnoSetup `_ is needed to create the installer (default installation path assumed) +* `7-zip `_ is needed to compress the portable version (default installation path assumed) + +Preparing the C++ Project +------------------------- + +* Clone VapourSynth +* Clone VSRepo into the VapourSynth dir (``git clone https://github.com/vapoursynth/vsrepo``) +* Clone zimg into the VapourSynth dir (``git clone https://github.com/sekrit-twc/zimg.git --recurse-submodules``) +* Clone avs+ into the VapourSynth dir (``git clone https://github.com/AviSynth/AviSynthPlus.git``) +* Clone libp2p into the VapourSynth dir (``git clone https://github.com/sekrit-twc/libp2p.git``) +* Compile 32 and 64 bit releases using the VapourSynth solution + +Preparing the Python Project +---------------------------- + +* Run ``py -3.11 -m pip install -r python-requirements.txt`` for 64bit. +* Run ``py -3.8 -m pip install -r python-requirements.txt`` for 64bit. +* Run ``cython_build.bat`` to compile the Python modules +* Run ``docs_build.bat`` to compile the documentation + +Distribution +------------ + +All the above steps are necessary to create the installer + +You also need 7z.exe and 7z.dll from `7-zip `_ +Both need to be placed in the "installer" dir. + +You'll also have to grab the file ``pfm-192-vapoursynth-win.exe`` +which is only available from installations/portable releases. + +Run ``make_portable.bat`` and ``make_installers.bat`` to package things. + +.. note:: Note that the Avisynth side of AVFS won't work properly in debug builds (memory allocation and exceptions across module boundaries trolololol) + +Linux and OS X Compilation +************************** + +These are the requirements: + * Autoconf, Automake, and Libtool, probably recent versions + + * pkg-config + + * GCC 4.8 or newer, or Clang + + * `zimg `_ + + * Python 3 + + * Cython 0.28 or later installed in your Python 3 environment + + * Sphinx for the documentation (optional) + +Note: **any version of Python 3 will do.** A specific version is only +required when using the official Windows binaries. + +Required packages (OS X) +------------------------ + +First download and install the prerequisites: + * Xcode -- Available from the AppStore + * `Homebrew `_ -- A package manager + +Installation of the required packages is very easy. Simply run these +commands in a terminal and wait for them to complete:: + + brew install python3 ffmpeg libass zimg imagemagick + pip3 install cython + +If you've already installed all the required packages and instead want +to update them, simply run:: + + brew update && brew upgrade + pip3 install --upgrade cython + +Compilation +----------- + +If you haven't checked out the source code before, use git to do so:: + + git clone https://github.com/vapoursynth/vapoursynth.git + +Or if you already have a copy of the source, update it with:: + + git pull + +Enter the VapourSynth directory and run these commands to compile and install:: + + ./autogen.sh + ./configure + make + make install + +Depending on your operating system's configuration, VapourSynth may not +work out of the box with the default prefix of /usr/local. Two errors +may pop up when running ``vspipe --version``: + +* "vspipe: error while loading shared libraries: libvapoursynth-script.so.0: + cannot open shared object file: No such file or directory" + + This is caused by the non-standard location of libvapoursynth-script.so.0. + Your dynamic loader is not configured to look in /usr/local/lib. One + way to work around this error is to use the LD_LIBRARY_PATH environment + variable:: + + $ LD_LIBRARY_PATH=/usr/local/lib vspipe --version + +* "Failed to initialize VapourSynth environment" + + This is caused by the non-standard location of the Python module, + vapoursynth.so. Your Python is not configured to look in + /usr/local/lib/python3.x/site-packages. One way to work around this + error is to use the PYTHONPATH environment variable:: + + $ PYTHONPATH=/usr/local/lib/python3.x/site-packages vspipe --version + + Replace "x" with the correct number. + + +The documentation can be built using its own Makefile:: + + $ make -C doc/ html + +The documentation can be installed using the standard program ``cp``. + +Plugins and Scripts +################### + +If you're looking for plugins and scripts then one of the most complete lists +available can be found at `vsdb.top `_. + +Installing with VSRepo +********************** + +On windows you can use the included vsrepo.py to install and upgrade plugins and scripts. + +Simply run ``vsrepo.py install `` to install them. + +If you need a list of known plugins and scripts you can run ``vsrepo.py available`` or visit `vsdb.top `_. + +For more reference, visit `vsrepo's repository `_ + +Installing Manually +******************* + +You can put your plugin (``.dll``) and script (``.py``) to where you think it is convenient. + +For plugins, you can use ``std.LoadPlugin`` function to load it. there is also a plugin autoloading mechanism to save your time, see blow. + +For scripts, you should add a relative path to ``python._pth``, then you can import it in your script. + +Plugin Autoloading +****************** + +VapourSynth automatically loads all the native plugins located in certain +folders. Autoloading works just like manual loading, with the exception +that any errors encountered while loading a plugin are silently ignored. + +.. note:: + + Avoid autoloading from folders that other applications might also + use, such as /usr/lib or /usr/local/lib in a Linux system. Several + users reported crashes when VapourSynth attempted to load some + random libraries (\*cough\*wxgtk\*cough\*). + +Windows +------- + +Windows has in total 3 different autoloading directories: user plugins, core plugins and global plugins. They are searched in that order. +User plugins are always loaded first so that the current user can always decide which exact version of a plugin is used. Core plugins follow. +Global plugins are placed last to prevent them from overriding any of the included plugins by accident. + +The searched paths are: + +#. **\\VapourSynth\\plugins32 or **\\VapourSynth\\plugins64 +#. **\\core\\plugins +#. **\\plugins + +Note that the per user path is not created by default. +On modern Windows versions the *AppData* directory is located in **\\AppData\\Roaming by default. + +Shortcuts to the global autoload directory are located in the start menu. + +Avisynth plugins are never autoloaded. Support for this may be added in the future. + +User plugins should never be put into the *core\\plugins* directory. + +Windows Portable +---------------- + +The searched paths are: + +#. **\\vapoursynth32\\coreplugins or **\\vapoursynth64\\coreplugins +#. **\\vapoursynth32\\plugins or **\\vapoursynth64\\plugins + +User plugins should never be put into the *coreplugins* directory. + +Linux +----- + +Autoloading can be configured using the file +$XDG_CONFIG_HOME/vapoursynth/vapoursynth.conf, +or $HOME/.config/vapoursynth/vapoursynth.conf if XDG_CONFIG_HOME is not +defined. + +To provide your own path to the config file, you can use $VAPOURSYNTH_CONF_PATH. + +Two configuration options may be used: **UserPluginDir**, empty by default, +and **SystemPluginDir**, whose default value is set at compile time to +``$libdir/vapoursynth``, or to the location passed to the ``--with-plugindir`` +argument to ``configure``. + +UserPluginDir is tried first, then SystemPluginDir. + +Example vapoursynth.conf:: + + UserPluginDir=/home/asdf/vapoursynth/plugins + SystemPluginDir=/special/non/default/location + + +OS X +---- + +Autoloading can be configured using the file +$HOME/Library/Application Support/VapourSynth/vapoursynth.conf. Everything else is +the same as in Linux. + +Like on linux, you can use $VAPOURSYNTH_CONF_PATH to provide your own configuration. diff --git a/Programs/doc/_sources/introduction.rst.txt b/Programs/doc/_sources/introduction.rst.txt new file mode 100644 index 0000000..45245e1 --- /dev/null +++ b/Programs/doc/_sources/introduction.rst.txt @@ -0,0 +1,36 @@ +Introduction +============ + +VapourSynth is an application for video manipulation. Or a plugin. Or a library. +It's hard to tell because it has a core library written in C++ and a Python +module to allow video scripts to be created. It came to be when I started +thinking about alternative designs for Avisynth and most of it was written +over a 3 month period. + +The software has been heavily inspired by `Avisynth `_ +and aims to be a 21st century rewrite, taking advantage of the advancements +computers have made since the late 90s. +The main features compared to Avisynth are: + + * Multithreaded - Frame level multithreading that scales well + * Generalized Colorspaces - New colorspaces can be specified at runtime + * Per Frame Properties - Additional metadata can be attached to frames + * Python Based - The scripting part is implemented as a Python module so you + don't have to learn a special language + * Support for video with format changes - Some video just can't stick to one + format or frame size. VapourSynth can handle any kind of change + * Compatible with a large number of already existing Avisynth plugins + +About the author +################ + +Fredrik Mellbin majored in electrical engineering with a focus on image analysis +and processing with medical applications. He has previously worked with digital +electronics and likes to plan his own software projects in his spare time. +When he one day found himself out of work he needed something to do between +sending out job applications and waiting for a reply. The natural choice for +the author was to try to improve Avisynth, the software that once made him +interested in video editing. VapourSynth is the result of all that time waiting. + +Feel free to contact me at fredrik.mellbin that round thingy with an a gmail.com +if you need help to port a filter or want to sponsor the development. diff --git a/Programs/doc/_sources/output.rst.txt b/Programs/doc/_sources/output.rst.txt new file mode 100644 index 0000000..7bd71cc --- /dev/null +++ b/Programs/doc/_sources/output.rst.txt @@ -0,0 +1,125 @@ +Output +====== + +VSPipe +###### + +Synopsis +******** + +**vspipe** + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

VapourSynth4.h

+
+

Table of contents

+

Introduction

+
+
Macros

VS_CC

+

VS_EXTERNAL_API

+

VAPOURSYNTH_API_MAJOR

+

VAPOURSYNTH_API_MINOR

+

VAPOURSYNTH_API_VERSION

+

VS_AUDIO_FRAME_SAMPLES

+

VS_MAKE_VERSION

+
+
Enums

VSColorFamily

+

VSSampleType

+

VSPresetVideoFormat

+

VSFilterMode

+

VSMediaType

+

VSAudioChannels

+

VSPropertyType

+

VSMapPropertyError

+

VSMapAppendMode

+

VSActivationReason

+

VSMessageType

+

VSCoreCreationFlags

+

VSPluginConfigFlags

+

VSDataTypeHint

+

VSRequestPattern

+

VSCacheMode

+
+
Structs

VSFrame

+

VSNode

+

VSCore

+

VSPlugin

+

VSPluginFunction

+

VSFunction

+

VSMap

+

VSLogHandle

+

VSFrameContext

+

VSVideoFormat

+

VSVideoInfo

+

VSAudioFormat

+

VSAudioInfo

+

VSCoreInfo

+

VSFilterDependency

+

VSPLUGINAPI

+

VSAPI

+
+
+
+
+
Functions

getVapourSynthAPI

+
+
Writing plugins

VSInitPlugin

+

VSFilterGetFrame

+

VSFilterFree

+
+
+
+
+

Introduction

+

This is VapourSynth’s main header file. Plugins and applications that use +the library must include it.

+

VapourSynth’s public API is all C.

+
+
+

Macros

+

VapourSynth4.h defines some preprocessor macros that make the programmer’s life +easier. The relevant ones are described below.

+
+

VS_CC

+

The VS_CC macro expands to the calling convention used by VapourSynth. +All functions meant to be called by VapourSynth must use this macro (a +filter’s “init”, “getframe”, “free” functions, etc).

+

Example:

+
static void VS_CC fooInit(...) { ... }
+
+
+
+
+

VS_EXTERNAL_API

+

The VS_EXTERNAL_API macro expands to the platform-specific magic required +for functions exported by shared libraries. It also takes care of adding +extern "C" when needed, and VS_CC.

+

This macro must be used for a plugin’s entry point, like so:

+
VS_EXTERNAL_API(void) VapourSynthPluginInit2(...) { ... }
+
+
+
+
+

VAPOURSYNTH_API_MAJOR

+

Major API version.

+
+
+

VAPOURSYNTH_API_MINOR

+

Minor API version. It is bumped when new functions are added to VSAPI or core behavior is noticeably changed.

+
+
+

VAPOURSYNTH_API_VERSION

+

API version. The high 16 bits are VAPOURSYNTH_API_MAJOR, the low 16 +bits are VAPOURSYNTH_API_MINOR.

+
+
+

VS_AUDIO_FRAME_SAMPLES

+

The number of audio samples in an audio frame. It is a static number to make it possible to calculate which audio frames are needed to retrieve specific samples.

+
+
+

VS_MAKE_VERSION

+

Used to create version numbers. The first argument is the major version and second is the minor.

+
+
+
+

Enums

+
+

enum VSColorFamily

+
+
    +
  • cfUndefined

  • +
  • cfGray

  • +
  • cfRGB

  • +
  • cfYUV

  • +
+
+
+
+

enum VSSampleType

+
+
    +
  • stInteger

  • +
  • stFloat

  • +
+
+
+
+

enum VSPresetVideoFormat

+
+

The presets suffixed with H and S have floating point sample type. +The H and S suffixes stand for half precision and single precision, +respectively. All formats are planar. See the header for all currently +defined video format presets.

+
    +
  • pf*

  • +
+
+
+
+

enum VSFilterMode

+
+

Controls how a filter will be multithreaded, if at all.

+
    +
  • fmParallel

    +

    Completely parallel execution. +Multiple threads will call a filter’s “getframe” function, to fetch several +frames in parallel.

    +
  • +
  • fmParallelRequests

    +

    For filters that are serial in nature but can request in advance one or +more frames they need. +A filter’s “getframe” function will be called from multiple threads at a +time with activation reason arInitial, but only one thread will call it +with activation reason arAllFramesReady at a time.

    +
  • +
  • fmUnordered

    +

    Only one thread can call the filter’s “getframe” function at a time. +Useful for filters that modify or examine their internal state to +determine which frames to request.

    +

    While the “getframe” function will only run in one thread at a +time, the calls can happen in any order. For example, it can be +called with reason arInitial for frame 0, then again with reason +arInitial for frame 1, then with reason arAllFramesReady for +frame 0.

    +
  • +
  • fmFrameState

    +

    For compatibility with other filtering architectures. DO NOT USE IN NEW FILTERS. +The filter’s “getframe” function only ever gets called from one thread at a +time. Unlike fmUnordered, only one frame is processed at a time.

    +
  • +
+
+
+
+

enum VSMediaType

+
+

Used to indicate the type of a VSFrame or VSNode object.

+
    +
  • mtVideo

  • +
  • mtAudio

  • +
+
+
+
+

enum VSAudioChannels

+
+

Audio channel positions as an enum. Mirrors the FFmpeg audio channel constants in older api versions. See the header for all available values.

+
    +
  • ac*

  • +
+
+
+
+

enum VSPropertyType

+
+

Types of properties that can be stored in a VSMap.

+
    +
  • ptUnset

  • +
  • ptInt

  • +
  • ptFloat

  • +
  • ptData

  • +
  • ptFunction

  • +
  • ptVideoNode

  • +
  • ptAudioNode

  • +
  • ptVideoFrame

  • +
  • ptAudioFrame

  • +
+
+
+
+

enum VSMapPropertyError

+
+

When a mapGet* function fails, it returns one of these in the err +parameter.

+

All errors are non-zero.

+
    +
  • peSuccess

  • +
  • peUnset

    +

    The requested key was not found in the map.

    +
  • +
  • peType

    +

    The wrong function was used to retrieve the property. E.g. +mapGetInt() was used on a property of type ptFloat.

    +
  • +
  • peIndex

    +

    The requested index was out of bounds.

    +
  • +
  • peError

    +

    The map has the error state set.

    +
  • +
+
+
+
+

enum VSMapAppendMode

+
+

Controls the behaviour of mapSetInt() and friends.

+
    +
  • maReplace

    +

    All existing values associated with the key will be replaced with +the new value.

    +
  • +
  • maAppend

    +

    The new value will be appended to the list of existing values +associated with the key.

    +
  • +
+
+
+
+

enum VSActivationReason

+
+

See VSFilterGetFrame.

+
    +
  • arInitial

  • +
  • arAllFramesReady

  • +
  • arError

  • +
+
+
+
+

enum VSMessageType

+
+

See addLogHandler().

+
    +
  • mtDebug

  • +
  • mtInformation

  • +
  • mtWarning

  • +
  • mtCritical

  • +
  • mtFatal

  • +
+
+
+
+

enum VSCoreCreationFlags

+
+

Options when creating a core.

+
    +
  • ccfEnableGraphInspection

    +
    +

    Required to use the graph inspection api functions. Increases memory usage due to the extra information stored.

    +
    +
  • +
  • ccfDisableAutoLoading

    +
    +

    Don’t autoload any user plugins. Core plugins are always loaded.

    +
    +
  • +
  • ccfDisableLibraryUnloading

    +
    +

    Don’t unload plugin libraries when the core is destroyed. Due to a small amount of memory leaking every load +and unload (windows feature, not my fault) of a library this may help in applications with extreme amount of script reloading.

    +
    +
  • +
+
+
+
+

enum VSPluginConfigFlags

+
+

Options when loading a plugin.

+
    +
  • pcModifiable

    +
    +

    Allow functions to be added to the plugin object after the plugin loading phase. Mostly useful for +Avisynth compatibility and other foreign plugin loaders.

    +
    +
  • +
+
+
+
+

enum VSDataTypeHint

+
+

Since the data type can contain both pure binary data and printable strings the type also contains a hint +for whether or not it is human readable. Generally the unknown type should be very rare and is almost only +created as an artifact of API3 compatibility.

+
    +
  • dtUnknown

  • +
  • dtBinary

  • +
  • dtUtf8

  • +
+
+
+
+

enum VSRequestPattern

+
+

Describes the upstream frame request pattern of a filter.

+
    +
  • rpGeneral

    +
    +

    Anything goes. Note that filters that may be requesting beyond the end of a VSNode length in frames (repeating the last frame) should use rpGeneral and not any of the other modes.

    +
    +
  • +
  • rpNoFrameReuse

    +

    Will only request an input frame at most once if all output frames are requested exactly one time. This includes filters such as Trim, Reverse, SelectEvery.

    +
  • +
  • rpStrictSpatial

    +

    Only requests frame N to output frame N. The main difference to rpNoFrameReuse is that the requested frame is always fixed and known ahead of time. Filter examples Lut, Expr (conditionally, see rpGeneral note) and similar.

    +
  • +
+
+
+
+

enum VSCacheMode

+
+

Describes how the output of a node is cached.

+
    +
  • cmAuto

    +
    +

    Cache is enabled or disabled based on the reported request patterns and number of consumers.

    +
    +
  • +
  • cmForceDisable

    +
    +

    Never cache anything.

    +
    +
  • +
  • cmForceEnable

    +
    +
      +
    • Always use the cache.

    • +
    +
    +
  • +
+
+
+
+
+

Structs

+

Most structs are opaque and their contents can only be accessed using functions in the API.

+
+

struct VSFrame

+
+

A frame that can hold audio or video data.

+

Each row of pixels in a frame is guaranteed to have an alignment of at least 32 +bytes. Two frames with the same width and bytes per sample are guaranteed to have the same stride.

+

Audio data is also guaranteed to be at least 32 byte aligned.

+

Any data can be attached to a frame, using a VSMap.

+
+
+
+

struct VSNode

+
+

A reference to a node in the constructed filter graph. Its primary use +is as an argument to other filter or to request frames from.

+
+
+
+

struct VSCore

+
+

The core represents one instance of VapourSynth. Every core individually +loads plugins and keeps track of memory.

+
+
+
+

struct VSPlugin

+
+

A VapourSynth plugin. There are a few of these built into the core, +and therefore available at all times: the basic filters (identifier +com.vapoursynth.std, namespace std), the resizers (identifier +com.vapoursynth.resize, namespace resize), and the Avisynth +compatibility module, if running in Windows (identifier +com.vapoursynth.avisynth, namespace avs).

+

The Function Reference describes how to load VapourSynth and Avisynth +plugins.

+

A VSPlugin instance is constructed by the core when loading a plugin +(.so / .dylib / .dll), and the pointer is passed to the plugin’s +VapourSynthPluginInit2() function.

+

A VapourSynth plugin can export any number of filters.

+

Plugins have a few attributes:

+
+
    +
  • An identifier, which must be unique among all VapourSynth plugins in +existence, because this is what the core uses to make sure a plugin +only gets loaded once.

  • +
  • A namespace, also unique. The filters exported by a plugin end up in +the plugin’s namespace.

  • +
  • A full name, which is used by the core in a few error messages.

  • +
  • The version of the plugin.

  • +
  • The VapourSynth API version the plugin requires.

  • +
  • A file name.

  • +
+
+

Things you can do with a VSPlugin:

+
+
+
+

All loaded plugins (including built-in) can be enumerated with +getNextPlugin().

+

Once loaded, a plugin only gets unloaded when the VapourSynth core is freed.

+
+
+
+

struct VSPluginFunction

+
+

A function belonging to a Vapoursynth plugin. This object primarily exists so +a plugin’s name, argument list and return type can be queried by editors.

+

One peculiarity is that plugin functions cannot be invoked using a VSPluginFunction +pointer but is instead done using invoke() which takes a VSPlugin and +the function name as a string.

+
+
+
+

struct VSFunction

+
+

Holds a reference to a function that may be called. This type primarily exists +so functions can be shared between the scripting layer and plugins in the core.

+
+
+
+

struct VSMap

+
+

VSMap is a container that stores (key,value) pairs. The keys are strings +and the values can be (arrays of) integers, floating point numbers, +arrays of bytes, VSNode, VSFrame, or VSFunction.

+

The pairs in a VSMap are sorted by key.

+
+
In VapourSynth, VSMaps have several uses:
    +
  • storing filters’ arguments and return values

  • +
  • storing user-defined functions’ arguments and return values

  • +
  • storing the properties attached to frames

  • +
+
+
+

Only alphanumeric characters and the underscore may be used in keys.

+

Creating and destroying a map can be done with createMap() and +freeMap(), respectively.

+

A map’s contents can be retrieved and modified using a number of functions, +all prefixed with “map”.

+

A map’s contents can be erased with clearMap().

+
+
+
+

struct VSLogHandle

+
+

Opaque type representing a registered logger.

+
+
+
+

struct VSFrameContext

+
+

Opaque type representing the current frame request in a filter.

+
+
+
+

struct VSVideoFormat

+
+

Describes the format of a clip.

+

Use queryVideoFormat() to fill it in with proper error checking. Manually filling out the struct is allowed but discouraged +since illegal combinations of values will cause undefined behavior.

+
+
+int colorFamily
+

See VSColorFamily.

+
+ +
+
+int sampleType
+

See VSSampleType.

+
+ +
+
+int bitsPerSample
+

Number of significant bits.

+
+ +
+
+int bytesPerSample
+

Number of bytes needed for a sample. This is always a power of 2 and the +smallest possible that can fit the number of bits used per sample.

+
+ +
+
+int subSamplingW
+
+ +
+
+int subSamplingH
+

log2 subsampling factor, applied to second and third plane. +Convenient numbers that can be used like so:

+
uv_width = y_width >> subSamplingW;
+
+
+
+ +
+
+int numPlanes
+

Number of planes.

+
+ +
+
+
+

struct VSVideoInfo

+
+

Contains information about a clip.

+
+
+VSVideoFormat format
+

Format of the clip. Will have colorFamily set to cfUndefined if the format can vary.

+
+ +
+
+int64_t fpsNum
+

Numerator part of the clip’s frame rate. It will be 0 if the frame +rate can vary. Should always be a reduced fraction.

+
+ +
+
+int64_t fpsDen
+

Denominator part of the clip’s frame rate. It will be 0 if the frame +rate can vary. Should always be a reduced fraction.

+
+ +
+
+int width
+

Width of the clip. Both width and height will be 0 if the clip’s dimensions can vary.

+
+ +
+
+int height
+

Height of the clip. Both width and height will be 0 if the clip’s dimensions can vary.

+
+ +
+
+int numFrames
+

Length of the clip.

+
+ +
+
+
+

struct VSAudioFormat

+
+

Describes the format of a clip.

+

Use queryAudioFormat() to fill it in with proper error checking. Manually filling out the struct is allowed but discouraged +since illegal combinations of values will cause undefined behavior.

+
+
+int sampleType
+

See VSSampleType.

+
+ +
+
+int bitsPerSample
+

Number of significant bits.

+
+ +
+
+int bytesPerSample
+

Number of bytes needed for a sample. This is always a power of 2 and the +smallest possible that can fit the number of bits used per sample.

+
+ +
+
+int numChannels
+

Number of audio channels.

+
+ +
+
+uint64_t channelLayout
+

A bitmask representing the channels present using the constants in 1 left shifted by the constants in VSAudioChannels.

+
+ +
+
+
+

struct VSAudioInfo

+
+

Contains information about a clip.

+
+
+VSAudioFormat format
+

Format of the clip. Unlike video the audio format can never change.

+
+ +
+
+int sampleRate
+

Sample rate.

+
+ +
+
+int64_t numSamples
+

Length of the clip in audio samples.

+
+ +
+
+int numFrames
+

Length of the clip in audio frames.

+
+ +
+
+
+

struct VSCoreInfo

+
+

Contains information about a VSCore instance.

+
+
+const char *versionString
+

Printable string containing the name of the library, copyright notice, +core and API versions.

+
+ +
+
+int core
+

Version of the core.

+
+ +
+
+int api
+

Version of the API.

+
+ +
+
+int numThreads
+

Number of worker threads.

+
+ +
+
+int64_t maxFramebufferSize
+

The framebuffer cache will be allowed to grow up to this size (bytes) before memory is aggressively reclaimed.

+
+ +
+
+int64_t usedFramebufferSize
+

Current size of the framebuffer cache, in bytes.

+
+ +
+
+
+

struct VSFilterDependency

+
+

Contains information about a VSCore instance.

+
+
+VSNode *source
+

The node frames are requested from.

+
+ +
+
+int requestPattern
+

A value from VSRequestPattern.

+
+ +
+
+
+

struct VSPLUGINAPI

+
+

This struct is used to access VapourSynth’s API when a plugin is initially loaded.

+
+
+
+

int getAPIVersion()

+
+

See getAPIVersion() in the struct VSAPI.

+
+
+
+
+

int configPlugin(const char *identifier, const char *pluginNamespace, const char *name, int pluginVersion, int apiVersion, int flags, VSPlugin *plugin)

+
+

Used to provide information about a plugin when loaded. Must be called exactly once from the VapourSynthPluginInit2 entry point. +It is recommended to use the VS_MAKE_VERSION macro when providing the pluginVersion. If you don’t know the specific apiVersion you actually require simply +pass VAPOURSYNTH_API_VERSION to match the header version you’re compiling against. The flags consist of values from VSPluginConfigFlags ORed together +but should for most plugins typically be 0.

+

Returns non-zero on success.

+
+
+
+
+

int registerFunction(const char *name, const char *args, const char *returnType, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin)

+
+

See registerFunction() in the struct VSAPI.

+
+
+
+
+

struct VSAPI

+
+

This giant struct is the way to access VapourSynth’s public API.

+
+
+
+

VSCore *createCore(int flags)

+
+

Creates the VapourSynth processing core and returns a pointer to it. It is +possible to create multiple cores but in most cases it shouldn’t be needed.

+
+
flags

VSCoreCreationFlags ORed together if desired. Pass 0 for sane defaults +that should suit most uses.

+
+
+
+
+
+
+

void freeCore(VSCore *core)

+
+

Frees a core. Should only be done after all frame requests have completed +and all objects belonging to the core have been released.

+
+
+
+
+

int64_t setMaxCacheSize(int64_t bytes, VSCore *core)

+
+

Sets the maximum size of the framebuffer cache. Returns the new maximum +size.

+
+
+
+
+

int setThreadCount(int threads, VSCore *core)

+
+

Sets the number of threads used for processing. Pass 0 to automatically detect. +Returns the number of threads that will be used for processing.

+
+
+
+
+

void getCoreInfo(VSCore *core, VSCoreInfo *info)

+
+

Returns information about the VapourSynth core.

+
+
+
+
+

int getAPIVersion()

+
+

Returns the highest VAPOURSYNTH_API_VERSION the library support.

+
+
+
+
+

void logMessage(int msgType, const char *msg, VSCore *core)

+
+

Send a message through VapourSynth’s logging framework. See +addLogHandler.

+
+
msgType

The type of message. One of VSMessageType.

+

If msgType is mtFatal, VapourSynth will call abort() after +delivering the message.

+
+
msg

The message.

+
+
+
+
+
+
+

VSLogHandle *addLogHandler(VSLogHandler handler, VSLogHandlerFree free, void *userData, VSCore *core)

+
+

Installs a custom handler for the various error messages VapourSynth +emits. The message handler is per VSCore instance. Returns a unique handle.

+

If no log handler is installed up to a few hundred messages are cached and +will be delivered as soon as a log handler is attached. This behavior exists +mostly so that warnings when auto-loading plugins (default behavior) won’t disappear-

+
+
handler

typedef void (VS_CC *VSLogHandler)(int msgType, const char *msg, void *userdata)

+

Custom message handler. If this is NULL, the default message +handler will be restored.

+
+
msgType

The type of message. One of VSMessageType.

+

If msgType is mtFatal, VapourSynth will call abort() after the +message handler returns.

+
+
msg

The message.

+
+
+
+
free

typedef void (VS_CC *VSLogHandlerFree)(void *userData)

+

Called when a handler is removed.

+
+
userData

Pointer that gets passed to the message handler.

+
+
+
+
+
+
+

int removeLogHandler(VSLogHandle *handle, VSCore *core)

+
+

Removes a custom handler. Return non-zero on success and zero if +the handle is invalid.

+
+
handle

Handle obtained from addLogHandler().

+
+
+
+
+
+
+

VSFrame *newVideoFrame(const VSVideoFormat *format, int width, int height, const VSFrame *propSrc, VSCore *core)

+
+

Creates a new video frame, optionally copying the properties attached to another +frame. It is a fatal error to pass invalid arguments to this function.

+

The new frame contains uninitialised memory.

+
+
format

The desired colorspace format. Must not be NULL.

+
+
+

width

+
+
height

The desired dimensions of the frame, in pixels. Must be greater than 0 and have a suitable multiple for the subsampling in format.

+
+
propSrc

A frame from which properties will be copied. Can be NULL.

+
+
+

Returns a pointer to the created frame. Ownership of the new frame is +transferred to the caller.

+

See also newVideoFrame2().

+
+
+
+
+

VSFrame *newVideoFrame2(const VSVideoFormat *format, int width, int height, const VSFrame **planeSrc, const int *planes, const VSFrame *propSrc, VSCore *core)

+
+

Creates a new video frame from the planes of existing frames, optionally copying +the properties attached to another frame. It is a fatal error to pass invalid arguments to this function.

+
+
format

The desired colorspace format. Must not be NULL.

+
+
+

width

+
+
height

The desired dimensions of the frame, in pixels. Must be greater than 0 and have a suitable multiple for the subsampling in format.

+
+
planeSrc

Array of frames from which planes will be copied. If any elements of +the array are NULL, the corresponding planes in the new frame will +contain uninitialised memory.

+
+
planes

Array of plane numbers indicating which plane to copy from the +corresponding source frame.

+
+
propSrc

A frame from which properties will be copied. Can be NULL.

+
+
+

Returns a pointer to the created frame. Ownership of the new frame is +transferred to the caller.

+

Example (assume frameA, frameB, frameC are existing frames):

+
const VSFrame * frames[3] = { frameA, frameB, frameC };
+const int planes[3] = { 1, 0, 2 };
+VSFrame * newFrame = vsapi->newVideoFrame2(f, w, h, frames, planes, frameB, core);
+
+
+

The newFrame’s first plane is now a copy of frameA’s second plane, +the second plane is a copy of frameB’s first plane, +the third plane is a copy of frameC’s third plane +and the properties have been copied from frameB.

+
+
+
+
+

VSFrame *newAudioFrame(const VSAudioFormat *format, int numSamples, const VSFrame *propSrc, VSCore *core)

+
+

Creates a new audio frame, optionally copying the properties attached to another +frame. It is a fatal error to pass invalid arguments to this function.

+

The new frame contains uninitialised memory.

+
+
format

The desired audio format. Must not be NULL.

+
+
numSamples

The number of samples in the frame. All audio frames apart from the last one returned by a filter must have VS_AUDIO_FRAME_SAMPLES.

+
+
propSrc

A frame from which properties will be copied. Can be NULL.

+
+
+

Returns a pointer to the created frame. Ownership of the new frame is +transferred to the caller.

+

See also newAudioFrame2().

+
+
+
+
+

VSFrame *newAudioFrame2(const VSAudioFormat *format, int numSamples, const VSFrame **channelSrc, const int *channels, const VSFrame *propSrc, VSCore *core)

+
+

Creates a new audio frame, optionally copying the properties attached to another +frame. It is a fatal error to pass invalid arguments to this function.

+

The new frame contains uninitialised memory.

+
+
format

The desired audio format. Must not be NULL.

+
+
numSamples

The number of samples in the frame. All audio frames apart from the last one returned by a filter must have VS_AUDIO_FRAME_SAMPLES.

+
+
channelSrc

Array of frames from which channels will be copied. If any elements of +the array are NULL, the corresponding planes in the new frame will +contain uninitialised memory.

+
+
channels

Array of channel numbers indicating which channel to copy from the +corresponding source frame. Note that the number refers to the nth channel +and not a channel name constant.

+
+
propSrc

A frame from which properties will be copied. Can be NULL.

+
+
+

Returns a pointer to the created frame. Ownership of the new frame is +transferred to the caller.

+

See also newVideoFrame2().

+
+
+
+
+

void freeFrame(const VSFrame *f)

+
+

Decrements the reference count of a frame and deletes it when it reaches 0.

+

It is safe to pass NULL.

+
+
+
+
+

const VSFrame *addFrameRef(const VSFrame *f)

+
+

Increments the reference count of a frame. Returns f as a convenience.

+
+
+
+
+

VSFrame *copyFrame(const VSFrame *f, VSCore *core)

+
+

Duplicates the frame (not just the reference). As the frame buffer is +shared in a copy-on-write fashion, the frame content is not really +duplicated until a write operation occurs. This is transparent for the user.

+

Returns a pointer to the new frame. Ownership is transferred to the caller.

+
+
+
+
+

const VSMap *getFramePropertiesRO(const VSFrame *f)

+
+

Returns a read-only pointer to a frame’s properties. The pointer is valid +as long as the frame lives.

+
+
+
+
+

VSMap *getFramePropertiesRW(VSFrame *f)

+
+

Returns a read/write pointer to a frame’s properties. The pointer is valid +as long as the frame lives.

+
+
+
+
+

ptrdiff_t getStride(const VSFrame *f, int plane)

+
+

Returns the distance in bytes between two consecutive lines of a plane of +a video frame. The stride is always positive. Returns 0 if the requested +plane doesn’t exist or if it isn’t a video frame.

+
+
+
+
+

const uint8_t *getReadPtr(const VSFrame *f, int plane)

+
+

Returns a read-only pointer to a plane or channel of a frame. +Returns NULL if an invalid plane or channel number is passed.

+
+

Note

+

Don’t assume all three planes of a frame are allocated in one +contiguous chunk (they’re not).

+
+
+
+
+
+

uint8_t *getWritePtr(VSFrame *f, int plane)

+
+

Returns a read-write pointer to a plane or channel of a frame. +Returns NULL if an invalid plane or channel number is passed.

+
+

Note

+

Don’t assume all three planes of a frame are allocated in one +contiguous chunk (they’re not).

+
+
+
+
+
+

const VSVideoFormat *getVideoFrameFormat(const VSFrame *f)

+
+

Retrieves the format of a video frame.

+
+
+
+
+

const VSAudioFormat *getAudioFrameFormat(const VSFrame *f)

+
+

Retrieves the format of an audio frame.

+
+
+
+
+

int getFrameType(const VSFrame *f)

+
+

Returns a value from VSMediaType to distinguish audio and video frames.

+
+
+
+
+

int getFrameWidth(const VSFrame *f, int plane)

+
+

Returns the width of a plane of a given video frame, in pixels. The width +depends on the plane number because of the possible chroma subsampling. Returns 0 +for audio frames.

+
+
+
+
+

int getFrameHeight(const VSFrame *f, int plane)

+
+

Returns the height of a plane of a given video frame, in pixels. The height +depends on the plane number because of the possible chroma subsampling. Returns 0 +for audio frames.

+
+
+
+
+

int getFrameLength(const VSFrame *f)

+
+

Returns the number of audio samples in a frame. Always returns 1 for video frames.

+
+
+
+
+

void createVideoFilter(VSMap *out, const char *name, const VSVideoInfo *vi, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core)

+
+

Creates a new video filter node.

+
+
out

Output map for the filter node.

+
+
name

Instance name. Please make it the same as the filter’s name for easy identification.

+
+
vi

The output format of the filter.

+
+
getFrame

The filter’s “getframe” function. Must not be NULL.

+
+
free

The filter’s “free” function. Can be NULL.

+
+
filterMode

One of VSFilterMode. Indicates the level of parallelism +supported by the filter.

+
+
dependencies

An array of nodes the filter requests frames from and the access pattern. +Used to more efficiently configure caches.

+
+
numDeps

Length of the dependencies array.

+
+
instanceData

A pointer to the private filter data. This pointer will be passed to +the getFrame and free functions. It should be freed by +the free function.

+
+
+

After this function returns, out will contain the new node appended to the +“clip” property, or an error, if something went wrong.

+
+
+
+
+

VSNode *createVideoFilter2(const char *name, const VSVideoInfo *vi, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core)

+
+

Identical to createVideoFilter except that the new node is returned +instead of appended to the out map. Returns NULL on error.

+
+
+
+
+

void createAudioFilter(VSMap *out, const char *name, const VSAudioInfo *ai, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core)

+
+

Creates a new video filter node.

+
+
out

Output map for the filter node.

+
+
name

Instance name. Please make it the same as the filter’s name for easy identification.

+
+
ai

The output format of the filter.

+
+
getFrame

The filter’s “getframe” function. Must not be NULL.

+
+
free

The filter’s “free” function. Can be NULL.

+
+
filterMode

One of VSFilterMode. Indicates the level of parallelism +supported by the filter.

+
+
dependencies

An array of nodes the filter requests frames from and the access pattern. +Used to more efficiently configure caches.

+
+
numDeps

Length of the dependencies array.

+
+
instanceData

A pointer to the private filter data. This pointer will be passed to +the getFrame and free functions. It should be freed by +the free function.

+
+
+

After this function returns, out will contain the new node appended to the +“clip” property, or an error, if something went wrong.

+
+
+
+
+

VSNode *createAudioFilter2(const char *name, const VSAudioInfo *ai, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core)

+
+

Identical to createAudioFilter except that the new node is returned +instead of appended to the out map. Returns NULL on error.

+
+
+
+
+

int setLinearFilter(VSNode *node)

+
+

Must be called immediately after audio or video filter creation. +Returns the upper bound of how many additional frames it is +reasonable to pass to cacheFrame when trying to make a request +more linear.

+
+
+
+
+

void setCacheMode(VSNode *node, int mode)

+
+

Determines the strategy for frame caching. Pass a VSCacheMode constant. +Mostly useful for cache debugging since the auto mode should work well +in just about all cases. Calls to this function may also be silently ignored.

+

Resets the cache to default options when called, discarding setCacheOptions +changes.

+
+
+
+
+

void setCacheOptions(VSNode *node, int fixedSize, int maxSize, int maxHistorySize)

+
+

Call after setCacheMode or the changes will be discarded. Sets internal +details of a node’s associated cache. Calls to this function may also +be silently ignored.

+
+
fixedSize

Set to non-zero to make the cache always hold maxSize frames.

+
+
maxSize

The maximum number of frames to cache. Note that this value is automatically +adjusted using an internal algorithm unless fixedSize is set.

+
+
maxHistorySize

How many frames that have been recently evicted from the cache to keep track off. +Used to determine if growing or shrinking the cache is beneficial. Has no effect +when fixedSize is set.

+
+
+
+
+
+
+

void freeNode(VSNode *node)

+
+

Decreases the reference count of a node and destroys it once it reaches 0.

+

It is safe to pass NULL.

+
+
+
+
+

VSNode *addNodeRef(VSNode *node)

+
+

Increment the reference count of a node. Returns the same node for convenience.

+
+
+
+
+

int getNodeType(VSNode *node)

+
+

Returns VSMediaType. Used to determine if a node is of audio or video type.

+
+
+
+
+

const VSVideoInfo *getVideoInfo(VSNode *node)

+
+

Returns a pointer to the video info associated with a node. The pointer is +valid as long as the node lives. It is undefined behavior to pass a non-video +node.

+
+
+
+
+

const VSAudioInfo *getAudioInfo(VSNode *node)

+
+

Returns a pointer to the audio info associated with a node. The pointer is +valid as long as the node lives. It is undefined behavior to pass a non-audio +node.

+
+
+
+
+

int getVideoFormatName(const VSVideoFormat *format, char *buffer)

+
+

Tries to output a fairly human-readable name of a video format.

+
+
format

The input video format.

+
+
buffer

Destination buffer. At most 32 bytes including terminating NULL +will be written.

+
+
+

Returns non-zero on success.

+
+
+
+
+

int getAudioFormatName(const VSAudioFormat *format, char *buffer)

+
+

Tries to output a fairly human-readable name of an audio format.

+
+
format

The input audio format.

+
+
buffer

Destination buffer. At most 32 bytes including terminating NULL +will be written.

+
+
+

Returns non-zero on success.

+
+
+
+
+

int queryVideoFormat(VSVideoFormat *format, int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core)

+
+

Fills out a VSVideoInfo struct based on the provided arguments. Validates the arguments before filling out format.

+
+
format

The struct to fill out.

+
+
colorFamily

One of VSColorFamily.

+
+
sampleType

One of VSSampleType.

+
+
bitsPerSample

Number of meaningful bits for a single component. The valid range is +8-32.

+

For floating point formats only 16 or 32 bits are allowed.

+
+
subSamplingW

log2 of the horizontal chroma subsampling. 0 == no subsampling. The valid range is 0-4.

+
+
subSamplingH

log2 of the vertical chroma subsampling. 0 == no subsampling. The valid range is 0-4.

+
+

Note

+

RGB formats are not allowed to be subsampled in VapourSynth.

+
+
+
+

Returns non-zero on success.

+
+
+
+
+

int queryAudioFormat(VSAudioFormat *format, int sampleType, int bitsPerSample, uint64_t channelLayout, VSCore *core)

+
+

Fills out a VSAudioFormat struct based on the provided arguments. Validates the arguments before filling out format.

+
+
format

The struct to fill out.

+
+
sampleType

One of VSSampleType.

+
+
bitsPerSample

Number of meaningful bits for a single component. The valid range is +8-32.

+

For floating point formats only 32 bits are allowed.

+
+
channelLayout

A bitmask constructed from bitshifted constants in VSAudioChannels. For example stereo is expressed as (1 << acFrontLeft) | (1 << acFrontRight).

+
+
+

Returns non-zero on success.

+
+
+
+
+

uint32_t queryVideoFormatID(int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core)

+
+

Get the id associated with a video format. Similar to queryVideoFormat() except that it returns a format id instead +of filling out a VSVideoInfo struct.

+
+
colorFamily

One of VSColorFamily.

+
+
sampleType

One of VSSampleType.

+
+
bitsPerSample

Number of meaningful bits for a single component. The valid range is +8-32.

+

For floating point formats, only 16 or 32 bits are allowed.

+
+
subSamplingW

log2 of the horizontal chroma subsampling. 0 == no subsampling. The valid range is 0-4.

+
+
subSamplingH

log2 of the vertical chroma subsampling. 0 == no subsampling. The valid range is 0-4.

+
+

Note

+

RGB formats are not allowed to be subsampled in VapourSynth.

+
+
+
+

Returns a valid format id if the provided arguments are valid, on error +0 is returned.

+
+
+
+
+

int getVideoFormatByID(VSVideoFormat *format, uint32_t id, VSCore *core)

+
+

Fills out the VSVideoFormat struct passed to format based

+
+
format

The struct to fill out.

+
+
id

The format identifier: one of VSPresetVideoFormat or a value gotten from queryVideoFormatID.

+
+
+

Returns 0 on failure and non-zero on success.

+
+
+
+
+

VSMap *createMap(void)

+
+

Creates a new property map. It must be deallocated later with +freeMap().

+
+
+
+
+

void freeMap(VSMap *map)

+
+

Frees a map and all the objects it contains.

+
+
+
+
+

void clearMap(VSMap *map)

+
+

Deletes all the keys and their associated values from the map, leaving it +empty.

+
+
+
+
+

const char *mapGetError(const VSMap *map)

+
+

Returns a pointer to the error message contained in the map, +or NULL if there is no error set. The pointer is valid until +the next modifying operation on the map.

+
+
+
+
+

void mapSetError(VSMap *map, const char *errorMessage)

+
+

Adds an error message to a map. The map is cleared first. The error +message is copied. In this state the map may only be freed, cleared +or queried for the error message.

+

For errors encountered in a filter’s “getframe” function, use +setFilterError.

+
+
+
+
+

int mapNumKeys(const VSMap *map)

+
+

Returns the number of keys contained in a property map.

+
+
+
+
+

const char *mapGetKey(const VSMap *map, int index)

+
+

Returns the nth key from a property map.

+

Passing an invalid index will cause a fatal error.

+

The pointer is valid as long as the key exists in the map.

+
+
+
+
+

int mapDeleteKey(VSMap *map, const char *key)

+
+

Removes the property with the given key. All values associated with the +key are lost.

+

Returns 0 if the key isn’t in the map. Otherwise it returns 1.

+
+
+
+
+

int mapNumElements(const VSMap *map, const char *key)

+
+

Returns the number of elements associated with a key in a property map. +Returns -1 if there is no such key in the map.

+
+
+
+
+

int mapGetType(const VSMap *map, const char *key)

+
+

Returns a value from VSPropertyType representing type +of elements in the given key. If there is no such key in the +map, the returned value is ptUnset. Note that also empty +arrays created with mapSetEmpty are typed.

+
+
+
+
+

int mapSetEmpty(const VSMap *map, const char *key, int type)

+
+

Creates an empty array of type in key. Returns non-zero +value on failure due to key already existing or having an +invalid name.

+
+
+
+
+

int64_t mapGetInt(const VSMap *map, const char *key, int index, int *error)

+
+

Retrieves an integer from a specified key in a map.

+

Returns the number on success, or 0 in case of error.

+

If the map has an error set (i.e. if mapGetError() returns non-NULL), +VapourSynth will die with a fatal error.

+
+
index

Zero-based index of the element.

+

Use mapNumElements() to know the total number of elements +associated with a key.

+
+
error

One of VSMapPropertyError, peSuccess on success.

+

You may pass NULL here, but then any problems encountered while +retrieving the property will cause VapourSynth to die with a fatal +error.

+
+
+
+
+
+
+

int mapGetIntSaturated(const VSMap *map, const char *key, int index, int *error)

+
+

Works just like mapGetInt() except that the value returned is also +converted to an integer using saturation.

+
+
+
+
+

const int64_t *mapGetIntArray(const VSMap *map, const char *key, int *error)

+
+

Retrieves an array of integers from a map. Use this function if there +are a lot of numbers associated with a key, because it is faster than +calling mapGetInt() in a loop.

+

Returns a pointer to the first element of the array on success, or NULL +in case of error. Use mapNumElements() to know the total number of +elements associated with a key.

+

See mapGetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

int mapSetInt(VSMap *map, const char *key, int64_t i, int append)

+
+

Sets an integer to the specified key in a map.

+

Multiple values can be associated with one key, but they must all be the +same type.

+
+
key

Name of the property. Alphanumeric characters and underscore +may be used.

+
+
i

Value to store.

+
+
append

One of VSMapAppendMode.

+
+
+

Returns 0 on success, or 1 if trying to append to a property with the +wrong type to an existing key.

+
+
+
+
+

int mapSetIntArray(VSMap *map, const char *key, const int64_t *i, int size)

+
+

Adds an array of integers to a map. Use this function if there are a +lot of numbers to add, because it is faster than calling mapSetInt() +in a loop.

+

If map already contains a property with this key, that property will +be overwritten and all old values will be lost.

+
+
key

Name of the property. Alphanumeric characters and underscore +may be used.

+
+
i

Pointer to the first element of the array to store.

+
+
size

Number of integers to read from the array. It can be 0, in which case +no integers are read from the array, and the property will be created +empty.

+
+
+

Returns 0 on success, or 1 if size is negative.

+
+
+
+
+

double mapGetFloat(const VSMap *map, const char *key, int index, int *error)

+
+

Retrieves a floating point number from a map.

+

Returns the number on success, or 0 in case of error.

+

See mapGetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

float mapGetFloatSaturated(const VSMap *map, const char *key, int index, int *error)

+
+

Works just like mapGetFloat() except that the value returned is also +converted to a float.

+
+
+
+
+

const double *mapGetFloatArray(const VSMap *map, const char *key, int *error)

+
+

Retrieves an array of floating point numbers from a map. Use this function if there +are a lot of numbers associated with a key, because it is faster than +calling mapGetFloat() in a loop.

+

Returns a pointer to the first element of the array on success, or NULL +in case of error. Use mapNumElements() to know the total number of +elements associated with a key.

+

See mapGetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

int mapSetFloat(VSMap *map, const char *key, double d, int append)

+
+

Sets a float to the specified key in a map.

+

See mapSetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

int mapSetFloatArray(VSMap *map, const char *key, const double *d, int size)

+
+

Adds an array of floating point numbers to a map. Use this function if +there are a lot of numbers to add, because it is faster than calling +mapSetFloat() in a loop.

+

If map already contains a property with this key, that property will +be overwritten and all old values will be lost.

+
+
key

Name of the property. Alphanumeric characters and underscore +may be used.

+
+
d

Pointer to the first element of the array to store.

+
+
size

Number of floating point numbers to read from the array. It can be 0, +in which case no numbers are read from the array, and the property +will be created empty.

+
+
+

Returns 0 on success, or 1 if size is negative.

+
+
+
+
+

const char *mapGetData(const VSMap *map, const char *key, int index, int *error)

+
+

Retrieves arbitrary binary data from a map. Checking mapGetDataTypeHint() +may provide a hint about whether or not the data is human readable.

+

Returns a pointer to the data on success, or NULL in case of error.

+

The array returned is guaranteed to be NULL-terminated. The NULL +byte is not considered to be part of the array (mapGetDataSize +doesn’t count it).

+

The pointer is valid until the map is destroyed, or until the +corresponding key is removed from the map or altered.

+

See mapGetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

int mapGetDataSize(const VSMap *map, const char *key, int index, int *error)

+
+

Returns the size in bytes of a property of type ptData (see +VSPropertyType), or 0 in case of error. The terminating NULL byte +added by mapSetData() is not counted.

+

See mapGetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

int mapGetDataTypeHint(const VSMap *map, const char *key, int index, int *error)

+
+

Returns the size in bytes of a property of type ptData (see +VSPropertyType), or 0 in case of error. The terminating NULL byte +added by mapSetData() is not counted.

+

See mapGetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

int mapSetData(VSMap *map, const char *key, const char *data, int size, int type, int append)

+
+

Sets binary data to the specified key in a map.

+

Multiple values can be associated with one key, but they must all be the +same type.

+
+
key

Name of the property. Alphanumeric characters and the underscore +may be used.

+
+
data

Value to store.

+

This function copies the data, so the pointer should be freed when +no longer needed. A terminating NULL is always added to the copied data +but not included in the total size to make string handling easier.

+
+
size

The number of bytes to copy. If this is negative, everything up to +the first NULL byte will be copied.

+
+
type

One of VSDataTypeHint to hint whether or not it is human readable data.

+
+
append

One of VSMapAppendMode.

+
+
+

Returns 0 on success, or 1 if trying to append to a property with the +wrong type.

+
+
+
+
+

VSNode *mapGetNode(const VSMap *map, const char *key, int index, int *error)

+
+

Retrieves a node from a map.

+

Returns a pointer to the node on success, or NULL in case of error.

+

This function increases the node’s reference count, so freeNode() must +be used when the node is no longer needed.

+

See mapGetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

int mapSetNode(VSMap *map, const char *key, VSNode *node, int append)

+
+

Sets a node to the specified key in a map.

+

See mapSetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

int mapConsumeNode(VSMap *map, const char *key, VSNode *node, int append)

+
+

Sets a node to the specified key in a map and decreases the reference count.

+

See mapSetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

const VSFrame *propGetFrame(const VSMap *map, const char *key, int index, int *error)

+
+

Retrieves a frame from a map.

+

Returns a pointer to the frame on success, or NULL in case of error.

+

This function increases the frame’s reference count, so freeFrame() must +be used when the frame is no longer needed.

+

See mapGetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

int mapSetFrame(VSMap *map, const char *key, const VSFrame *f, int append)

+
+

Sets a frame to the specified key in a map.

+

See mapSetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

int mapConsumeFrame(VSMap *map, const char *key, const VSFrame *f, int append)

+
+

Sets a frame to the specified key in a map and decreases the reference count.

+

See mapSetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

VSFunctionRef *mapGetFunc(const VSMap *map, const char *key, int index, int *error)

+
+

Retrieves a function from a map.

+

Returns a pointer to the function on success, or NULL in case of error.

+

This function increases the function’s reference count, so freeFunction() must +be used when the function is no longer needed.

+

See mapGetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

int mapSetFunction(VSMap *map, const char *key, VSFunction *func, int append)

+
+

Sets a function object to the specified key in a map.

+

See mapSetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

int mapConsumeFunction(VSMap *map, const char *key, VSFunction *func, int append)

+
+

Sets a function object to the specified key in a map and decreases the reference count.

+

See mapSetInt() for a complete description of the arguments and general behavior.

+
+
+
+
+

VSPlugin *getPluginByID(const char *identifier, VSCore *core)

+
+

Returns a pointer to the plugin with the given identifier, or NULL +if not found.

+
+
identifier

Reverse URL that uniquely identifies the plugin.

+
+
+
+
+
+
+

VSPlugin *getPluginByNamespace(const char *ns, VSCore *core)

+
+

Returns a pointer to the plugin with the given namespace, or NULL +if not found.

+

getPluginByID is generally a better option.

+
+
ns

Namespace.

+
+
+
+
+
+
+

VSPlugin *getNextPlugin(VSPlugin *plugin, VSCore *core)

+
+

Used to enumerate over all currently loaded plugins. The order +is fixed but provides no other guarantees.

+
+
plugin

Current plugin. Pass NULL to get the first plugin.

+
+
+

Returns a pointer to the next plugin in order or NULL if the final +plugin has been reached.

+
+
+
+
+

const char *getPluginName(VSPlugin *plugin)

+
+

Returns the name of the plugin that was passed to configPlugin.

+
+
+
+
+

const char *getPluginID(VSPlugin *plugin)

+
+

Returns the identifier of the plugin that was passed to configPlugin.

+
+
+
+
+

const char *getPluginNamespace(VSPlugin *plugin)

+
+

Returns the namespace the plugin currently is loaded in.

+
+
+
+
+

VSPluginFunction *getNextPluginFunction(VSPluginFunction *func, VSPlugin *plugin)

+
+

Used to enumerate over all functions in a plugin. The order +is fixed but provides no other guarantees.

+
+
func

Current function. Pass NULL to get the first function.

+
+
plugin

The plugin to enumerate functions in.

+
+
+

Returns a pointer to the next function in order or NULL if the final +function has been reached.

+
+
+
+
+

VSPluginFunction *getPluginFunctionByName(const char *name, VSPlugin *plugin)

+
+

Get a function belonging to a plugin by its name.

+
+
+
+
+

const char *getPluginFunctionName(VSPluginFunction *func)

+
+

Returns the name of the function that was passed to registerFunction.

+
+
+
+
+

const char *getPluginFunctionArguments(VSPluginFunction *func)

+
+

Returns the argument string of the function that was passed to registerFunction.

+
+
+
+
+

const char *getPluginFunctionReturnType(VSPluginFunction *func)

+
+

Returns the return type string of the function that was passed to registerFunction.

+
+
+
+
+

const char *getPluginPath(const VSPlugin *plugin)

+
+

Returns the absolute path to the plugin, including the plugin’s file +name. This is the real location of the plugin, i.e. there are no +symbolic links in the path.

+

Path elements are always delimited with forward slashes.

+

VapourSynth retains ownership of the returned pointer.

+
+
+
+
+

int getPluginVersion(const VSPlugin *plugin)

+
+

Returns the version of the plugin. This is the same as the version number passed to configPlugin.

+
+
+
+
+

VSMap *invoke(VSPlugin *plugin, const char *name, const VSMap *args)

+
+

Invokes a filter.

+

invoke() checks that +the args passed to the filter are consistent with the argument list +registered by the plugin that contains the filter, calls the filter’s +“create” function, and checks that the filter returns the declared types. +If everything goes smoothly, the filter will be ready to generate +frames after invoke() returns.

+
+
plugin

A pointer to the plugin where the filter is located. Must not be NULL.

+

See getPluginByID().

+
+
name

Name of the filter to invoke.

+
+
args

Arguments for the filter.

+
+
+

Returns a map containing the filter’s return value(s). The caller takes +ownership of the map. Use mapGetError() to check if the filter was invoked +successfully.

+

Most filters will either set an error, or one or more clips +with the key “clip”. The exception to this are functions, for example +LoadPlugin, which doesn’t return any clips for obvious reasons.

+
+
+
+
+

VSFunction *createFunction(VSPublicFunction func, void *userData, VSFreeFunctionData free, VSCore *core)

+
+
+
func

typedef void (VS_CC *VSPublicFunction)(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi)

+

User-defined function that may be called in any context.

+
+
userData

Pointer passed to func.

+
+
free

typedef void (VS_CC *VSFreeFunctionData)(void *userData)

+

Callback tasked with freeing userData. Can be NULL.

+
+
+
+
+
+
+

void freeFunction(VSFunction *f)

+
+

Decrements the reference count of a function and deletes it when it reaches 0.

+

It is safe to pass NULL.

+
+
+
+
+

VSFunction *addFunctionRef(VSFunction *f)

+
+

Increments the reference count of a function. Returns f as a convenience.

+
+
+
+
+

void callFunction(VSFunction *func, const VSMap *in, VSMap *out)

+
+

Calls a function. If the call fails out will have an error set.

+
+
func

Function to be called.

+
+
in

Arguments passed to func.

+
+
out

Returned values from func.

+
+
+
+
+
+
+

const VSFrame *getFrame(int n, VSNode *node, char *errorMsg, int bufSize)

+
+

Fetches a frame synchronously. The frame is available when the function +returns.

+

This function is meant for external applications using the core as a +library, or if frame requests are necessary during a filter’s +initialization.

+

Thread-safe.

+
+
n

The frame number. Negative values will cause an error.

+
+
node

The node from which the frame is requested.

+
+
errorMsg

Pointer to a buffer of bufSize bytes to store a possible error +message. Can be NULL if no error message is wanted.

+
+
bufSize

Maximum length for the error message, in bytes (including the +trailing ‘0’). Can be 0 if no error message is wanted.

+
+
+

Returns a reference to the generated frame, or NULL in case of failure. +The ownership of the frame is transferred to the caller.

+
+

Warning

+

Never use inside a filter’s “getframe” function.

+
+
+
+
+
+

void getFrameAsync(int n, VSNode *node, VSFrameDoneCallback callback, void *userData)

+
+

Requests the generation of a frame. When the frame is ready, +a user-provided function is called. Note that the completion +callback will only be called from a single thread at a time.

+

This function is meant for applications using VapourSynth as a library.

+

Thread-safe.

+
+
n

Frame number. Negative values will cause an error.

+
+
node

The node from which the frame is requested.

+
+
callback

typedef void (VS_CC *VSFrameDoneCallback)(void *userData, const VSFrame *f, int n, VSNode *node, const char *errorMsg)

+

Function of the client application called by the core when a requested +frame is ready, after a call to getFrameAsync().

+

If multiple frames were requested, they can be returned in any order. +Client applications must take care of reordering them.

+

This function is only ever called from one thread at a time.

+

getFrameAsync() may be called from this function to request more +frames.

+
+
userData

Pointer to private data from the client application, as passed +previously to getFrameAsync().

+
+
f

Contains a reference to the generated frame, or NULL in case of failure. +The ownership of the frame is transferred to the caller.

+
+
n

The frame number.

+
+
node

Node the frame belongs to.

+
+
errorMsg

String that usually contains an error message if the frame +generation failed. NULL if there is no error.

+
+
+
+
userData

Pointer passed to the callback.

+
+
+
+

Warning

+

Never use inside a filter’s “getframe” function.

+
+
+
+
+
+

const VSFrame *getFrameFilter(int n, VSNode *node, VSFrameContext *frameCtx)

+
+

Retrieves a frame that was previously requested with +requestFrameFilter().

+

Only use inside a filter’s “getframe” function.

+

A filter usually calls this function when its activation reason is +arAllFramesReady or arFrameReady. See VSActivationReason.

+

It is safe to retrieve a frame more than once, but each reference +needs to be freed.

+
+
n

The frame number.

+
+
node

The node from which the frame is retrieved.

+
+
frameCtx

The context passed to the filter’s “getframe” function.

+
+
+

Returns a pointer to the requested frame, or NULL if the requested frame +is not available for any reason. The ownership of the frame is +transferred to the caller.

+
+
+
+
+

void requestFrameFilter(int n, VSNode *node, VSFrameContext *frameCtx)

+
+

Requests a frame from a node and returns immediately.

+

Only use inside a filter’s “getframe” function.

+

A filter usually calls this function when its activation reason is +arInitial. The requested frame can then be retrieved using +getFrameFilter(), when the filter’s activation reason is +arAllFramesReady. See VSActivationReason.

+

It is best to request frames in ascending order, i.e. n, n+1, n+2, etc.

+
+
n

The frame number. Negative values will cause an error.

+
+
node

The node from which the frame is requested.

+
+
frameCtx

The context passed to the filter’s “getframe” function.

+
+
+
+
+
+
+

void releaseFrameEarly(VSNode *node, int n, VSFrameContext *frameCtx)

+
+

By default all requested frames are referenced until a filter’s frame +request is done. In extreme cases where a filter needs to reduce 20+ +frames into a single output frame it may be beneficial to request +these in batches and incrementally process the data instead.

+

Should rarely be needed.

+

Only use inside a filter’s “getframe” function.

+
+
node

The node from which the frame was requested.

+
+
n

The frame number. Invalid frame numbers (not cached or negative) will simply be ignored.

+
+
frameCtx

The context passed to the filter’s “getframe” function.

+
+
+
+
+
+
+

int registerFunction(const char *name, const char *args, const char *returnType, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin)

+
+

Function that registers a filter exported by the plugin. A plugin can +export any number of filters. This function may only be called during the plugin +loading phase unless the pcModifiable flag was set by configPlugin.

+
+
name

Filter name. The characters allowed are letters, numbers, and the +underscore. The first character must be a letter. In other words: +^[a-zA-Z][a-zA-Z0-9_]*$

+

Filter names should be PascalCase.

+
+
args

String containing the filter’s list of arguments.

+

Arguments are separated by a semicolon. Each argument is made of +several fields separated by a colon. Don’t insert additional +whitespace characters, or VapourSynth will die.

+
+
Fields:
+
The argument name.

The same characters are allowed as for the filter’s name. +Argument names should be all lowercase and use only letters +and the underscore.

+
+
The type.

“int”: int64_t

+

“float”: double

+

“data”: const char*

+

“anode”: const VSNode* (audio type)

+

“vnode”: const VSNode* (video type)

+

“aframe”: const VSFrame* (audio type)

+

“vframe”: const VSFrame* (video type)

+

“func”: const VSFunctionRef*

+

It is possible to declare an array by appending “[]” to the type.

+
+
“opt”

If the parameter is optional.

+
+
“empty”

For arrays that are allowed to be empty.

+
+
“any”

Can only be placed last without a semicolon after. Indicates that all remaining arguments that don’t match +should also be passed through.

+
+
+
+
+

The following example declares the arguments “blah”, “moo”, and “asdf”:

+
blah:vnode;moo:int[]:opt;asdf:float:opt;
+
+
+

The following example declares the arguments “blah” and accepts all other arguments no matter the type:

+
blah:vnode;any
+
+
+
+
returnType

Specifies works similarly to args but instead specifies which keys and what type will be returned. Typically this will be:

+
clip:vnode;
+
+
+

for video filters. It is important to not simply specify “any” for all filters since this information is used for better +auto-completion in many editors.

+
+
argsFunc

typedef void (VS_CC *VSPublicFunction)(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi)

+

User-defined function called by the core to create an instance of the +filter. This function is often named fooCreate.

+

In this function, the filter’s input parameters should be retrieved +and validated, the filter’s private instance data should be +initialised, and createAudioFilter() or createVideoFilter() should be called. This is where +the filter should perform any other initialisation it requires.

+

If for some reason you cannot create the filter, you have to free any +created node references using freeNode(), call mapSetError() on +out, and return.

+
+
in

Input parameter list.

+

Use mapGetInt() and friends to retrieve a parameter value.

+

The map is guaranteed to exist only until the filter’s “init” +function returns. In other words, pointers returned by +mapGetData() will not be usable in the filter’s “getframe” and +“free” functions.

+
+
out

Output parameter list. createAudioFilter() or createVideoFilter() will add the output +node(s) with the key named “clip”, or an error, if something went +wrong.

+
+
userData

Pointer that was passed to registerFunction().

+
+
+
+
functionData

Pointer to user data that gets passed to argsFunc when creating a +filter. Useful to register multiple filters using a single argsFunc +function.

+
+
plugin

Pointer to the plugin object in the core, as passed to +VapourSynthPluginInit2().

+
+
+
+
+
+
+

void cacheFrame(const VSFrame *frame, int n, VSFrameContext *frameCtx)

+
+

Pushes a not requested frame into the cache. This is useful for (source) filters that greatly +benefit from completely linear access and producing all output in linear order.

+

This function may only be used in filters that were created with setLinearFilter.

+

Only use inside a filter’s “getframe” function.

+
+
+
+
+

void setFilterError(const char *errorMessage, VSFrameContext *frameCtx)

+
+

Adds an error message to a frame context, replacing the existing message, +if any.

+

This is the way to report errors in a filter’s “getframe” function. +Such errors are not necessarily fatal, i.e. the caller can try to +request the same frame again.

+
+
+
+
+
+

Functions

+

const VSAPI* getVapourSynthAPI(int version)

+
+

Returns a pointer to the global VSAPI instance.

+

Returns NULL if the requested API version is not supported or if the system +does not meet the minimum requirements to run VapourSynth. It is recommended +to pass VAPOURSYNTH_API_VERSION.

+
+
+
+

Writing plugins

+

A simple VapourSynth plugin which exports one filter will contain five +functions: an entry point (called VapourSynthPluginInit2), a function tasked +with creating a filter instance (often called fooCreate), an “init” function +(often called fooInit), a “getframe” function (often called fooGetframe), +and a “free” function (often called fooFree). These functions are described +below.

+

Another thing a filter requires is an object for storing a filter instance’s +private data. This object will usually contain the filter’s input nodes (if it +has any) and a VSVideoInfo struct describing the video the filter wants to +return.

+

The sdk folder +in the VapourSynth source contains some examples.

+
+

typedef void (VS_CC *VSInitPlugin)(VSPlugin *plugin, const VSPLUGINAPI *vspapi)

+
+

A plugin’s entry point. It must be called VapourSynthPluginInit2. +This function is called after the core loads the shared library. Its purpose +is to configure the plugin and to register the filters the plugin wants to +export.

+
+
plugin

A pointer to the plugin object to be initialized.

+
+
vspapi

A pointer to a VSPLUGINAPI struct with a subset of the VapourSynth API used for initializing plugins. +The proper way to do things is to call configPlugin and then registerFunction for each function to export.

+
+
+
+
+

typedef const VSFrame *(VS_CC *VSFilterGetFrame)(int n, int activationReason, void *instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi)

+
+

A filter’s “getframe” function. It is called by the core when it needs +the filter to generate a frame.

+

It is possible to allocate local data, persistent during the multiple +calls requesting the output frame.

+

In case of error, call setFilterError(), free *frameData if required, +and return NULL.

+

Depending on the VSFilterMode set for the filter, multiple output frames +could be requested concurrently.

+

It is never called concurrently for the same frame number.

+
+
n

Requested frame number.

+
+
activationReason

One of VSActivationReason.

+

This function is first called with activationReason arInitial. At this +point the function should request the input frames it needs and return +NULL. When one or all of the requested frames are ready, this function +is called again with arAllFramesReady. +The function should only return a frame when called with +activationReason arAllFramesReady.

+

If a the function is called with arError all processing has to be aborted +and any.

+
+
instanceData

The filter’s private instance data.

+
+
frameData

Optional private data associated with output frame number n. +It must be deallocated before the last call for the given frame +(arAllFramesReady or error).

+

It points to a void *[4] array of memory that may be used freely. +See filters like Splice and Trim for examples.

+
+
+

Return a reference to the output frame number n when it is ready, or NULL. +The ownership of the frame is transferred to the caller.

+
+
+

typedef void (VS_CC *VSFilterFree)(void *instanceData, VSCore *core, const VSAPI *vsapi)

+
+

A filter’s “free” function.

+

This is where the filter should free everything it allocated, +including its instance data.

+
+
instanceData

The filter’s private instance data.

+
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/api/vshelper4.h.html b/Programs/doc/api/vshelper4.h.html new file mode 100644 index 0000000..01a9805 --- /dev/null +++ b/Programs/doc/api/vshelper4.h.html @@ -0,0 +1,365 @@ + + + + + + + VSHelper4.h — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

VSHelper4.h

+
+

Table of contents

+

Introduction

+
+
Macros

VSH_STD_PLUGIN_ID

+

VSH_RESIZE_PLUGIN_ID

+

VSH_TEXT_PLUGIN_ID

+

VS_RESTRICT

+

VSH_ALIGNED_MALLOC

+

VSH_ALIGNED_FREE

+

VSMIN

+

VSMAX

+
+
Functions

vsh_aligned_malloc

+

vsh_aligned_free

+

isConstantFormat

+

isSameVideoFormat

+

isSameVideoPresetFormat

+

isSameVideoInfo

+

isSameAudioFormat

+

isSameAudioInfo

+

muldivRational

+

addRational

+

reduceRational

+

int64ToIntS

+

doubleToFloatS

+

bitblt

+

areValidDimensions

+
+
+
+
+

Introduction

+

This is a collection of helpful macros and functions. Note that all functions (not macros) +are either prefixed with vsh_ in C mode or placed in the vsh namespace for C++. This documentation +will use the C++ names for these function.

+
+
+

Macros

+
+

VSH_STD_PLUGIN_ID

+

Macro defined to the internal std plugin id provided for convenience.

+
+
+

VSH_RESIZE_PLUGIN_ID

+

Macro defined to the internal resizer plugin id provided for convenience.

+
+
+

VSH_TEXT_PLUGIN_ID

+

Macro defined to the internal std plugin id provided for convenience.

+
+
+

VS_RESTRICT

+

Attempts to provide a portable definition of the C99 restrict keyword, +or its C++ counterpart.

+
+
+

VSH_ALIGNED_MALLOC

+

VSH_ALIGNED_MALLOC(pptr, size, alignment)

+

Expands to _aligned_malloc() in Windows, and posix_memalign() elsewhere. Note that +the arguments are in the style of posix_memalign().

+

pptr is a pointer to a pointer.

+
+
+

VSH_ALIGNED_FREE

+

VSH_ALIGNED_FREE(ptr)

+

Expands to _aligned_free() in Windows, and free() elsewhere.

+

ptr is a pointer.

+
+
+

VSMIN

+

VSMIN(a, b)

+

Returns the minimum of the two numbers.

+
+
+

VSMAX

+

VSMAX(a, b)

+

Returns the maximum of the two numbers.

+
+
+
+

Functions

+
+

vsh_aligned_malloc

+
+
+T *vsh::vsh_aligned_malloc(size_t size, size_t alignment)
+

A templated aligned malloc for C++. It uses the same functions as the +VSH_ALIGNED_MALLOC macro but is easier to use.

+
+ +
+
+

vsh_aligned_free

+
+
+void vsh::vsh_aligned_free(void *ptr)
+

This simply uses the VSH_ALIGNED_FREE macro.

+
+ +
+
+

isConstantFormat

+
+
+static inline bool vsh::isConstantFormat(const VSVideoInfo *vi)
+

Checks if a clip’s format and dimensions are known (and therefore constant).

+
+ +
+
+

isSameVideoFormat

+
+
+static inline bool vsh::isSameVideoFormat(const VSVideoInfo *v1, const VSVideoInfo *v2)
+

Checks if two clips have the same video format. If the format is +unknown in both, it will be considered the same.

+
+ +
+
+

isSameVideoPresetFormat

+
+
+static inline bool vsh::isSameVideoPresetFormat(unsigned presetFormat, const VSVideoFormat *v, VSCore *core, const VSAPI *vsapi)
+

Checks if a clip has the same video format as the preset.

+
+ +
+
+

isSameVideoInfo

+
+
+static inline bool vsh::isSameVideoInfo(const VSVideoInfo *v1, const VSVideoInfo *v2)
+

Checks if two clips have the same video format and dimensions. If the format is +unknown in both, it will be considered the same. This is also true for the +dimensions. Framerate is not taken into consideration when comparing.

+
+ +
+
+

isSameAudioFormat

+
+
+static inline bool vsh::isSameAudioFormat(const VSAudioInfo *v1, const VSAudioInfo *v2)
+

Checks if two clips have the same audio format.

+
+ +
+
+

isSameAudioInfo

+
+
+static inline bool vsh::isSameAudioInfo(const VSAudioInfo *v1, const VSAudioInfo *v2)
+

Checks if two clips have the same audio format and samplerate.

+
+ +
+
+

muldivRational

+
+
+static inline void vsh::muldivRational(int64_t *num, int64_t *den, int64_t mul, int64_t div)
+

Multiplies two rational numbers and reduces the result, i.e. +num/den * mul/div. The result is stored in num and den.

+

The caller must ensure that div is not 0.

+
+ +
+
+

reduceRational

+
+
+static inline void vsh::reduceRational(int64_t *num, int64_t *den)
+

Reduces a rational number.

+
+ +
+
+

addRational

+
+
+static inline void vsh::addRational(int64_t *num, int64_t *den, int64_t addnum, int64_t addden)
+

Adds two rational numbers and reduces the result, i.e. +num/den + addnum/addden. The result is stored in num and den.

+
+ +
+
+

int64ToIntS

+
+
+static inline int vsh::int64ToIntS(int64_t i)
+

Converts an int64_t to int with signed saturation. It’s useful to silence +warnings when reading integer properties from a VSMap and to avoid unexpected behavior on int overflow.

+
+ +
+
+

doubleToFloatS

+
+
+static inline int vsh::doubleToFloatS(double d)
+

Converts a double to float. It’s useful to silence +warnings when reading double properties from a VSMap and mostly exists to mirror int64ToIntS.

+
+ +
+
+

bitblt

+
+
+static inline void vsh::bitblt(void *dstp, int dst_stride, const void *srcp, int src_stride, size_t row_size, size_t height)
+

Copies bytes from one plane to another. Basically, it is memcpy in a loop.

+

row_size is in bytes.

+
+ +
+
+

areValidDimensions

+
+
+static inline bool vsh::areValidDimensions(const VSFormat *fi, int width, int height)
+

Checks if the given dimensions are valid for a particular format, with regards +to chroma subsampling.

+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/api/vsscript4.h.html b/Programs/doc/api/vsscript4.h.html new file mode 100644 index 0000000..7abae53 --- /dev/null +++ b/Programs/doc/api/vsscript4.h.html @@ -0,0 +1,386 @@ + + + + + + + VSScript4.h — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

VSScript4.h

+
+

Table of contents

+

Introduction

+
+
Structs

VSScript

+

VSScriptAPI

+
+
Functions

getVSScriptAPI

+

getApiVersion

+

getVSAPI

+

createScript

+

getCore

+

evaluateBuffer

+

evaluateFile

+

getError

+

getExitCode

+

getVariable

+

setVariables

+

getOutputNode

+

getOutputAlphaNode

+

getAltOutputMode

+

freeScript

+

evalSetWorkingDir

+
+
+
+
+

Introduction

+

VSScript provides a convenient wrapper for VapourSynth’s scripting interface(s), allowing the evaluation of VapourSynth scripts and retrieval of output clips.

+

For reasons unknown, the VSScript library is called VSScript in Windows and vapoursynth-script everywhere else.

+

At this time, VapourSynth scripts can be written only in Python (version 3).

+

Here are a few users of the VSScript library:

+
+
+
+
+

Note

+

If libvapoursynth-script is loaded with dlopen(), the RTLD_GLOBAL flag must be used. If not, Python won’t be able to import binary modules. This is due to Python’s design.

+
+
+
+

Structs

+
+

VSScript

+

A script environment. All evaluation and communication with evaluated scripts happens through a VSScript object.

+
+
+

VSScriptAPI

+

This struct is the way to access VSScript’s public API.

+
+
+
+

Functions

+
+

getVSScriptAPI

+
+
+const VSSCRIPTAPI *getVSScriptAPI(int version)
+

Returns a struct containing function pointer for the api. Will return NULL is the specified version isn’t supported.

+

It is recommended to always pass VSSCRIPT_API_VERSION.

+
+ +
+
+

getApiVersion

+
+
+int getApiVersion()
+

Returns the api version provided by vsscript.

+
+ +
+
+

getVSAPI

+
+
+const VSAPI *getVSAPI(int version)
+

Retrieves the VSAPI struct. Exists mostly as a convenience so the vapoursynth module doesn’t have to be explicitly loaded.

+

This could return NULL if the VapourSynth library doesn’t provide the requested version.

+
+ +
+
+

createScript

+
+
+VSScript *createScript(VSCore *core)
+

Creates an empty script environment that can be used to evaluate scripts. Passing a pre-created core can be usful to have custom core creation flags, log callbacks or plugins pre-loaded. Passing NULL will automatically create a new core with default settings.

+

Takes over ownership of the core regardless of success or failure. Returns NULL on error.

+
+ +
+
+

getCore

+
+
+VSCore *getCore(VSScript *handle)
+

Retrieves the VapourSynth core that was created in the script environment. If a VapourSynth core has not been created yet, it will be created now, with the default options (see the Python Reference).

+

VSScript retains ownership of the returned core object.

+

Returns NULL on error.

+
+ +
+
+

evaluateBuffer

+
+
+int evaluateBuffer(VSScript *handle, const char *buffer, const char *scriptFilename)
+

Evaluates a script contained in a C string. Can be called multiple times on the same script environment to successively add more processing.

+
+
handle

Pointer to a script environment.

+
+
buffer

The entire script to evaluate, as a C string.

+
+
scriptFilename

A name for the script, which will be displayed in error messages. If this is NULL, the name “<string>” will be used.

+

The special __file__ variable will be set to scriptFilename’s absolute path if this is not NULL.

+
+
+

Returns non-zero in case of errors. The error message can be retrieved with getError(). If the script calls sys.exit(code) the exit code can be retrieved with getExitCode(). The working directory behavior can be changed by calling evalSetWorkingDir() before this function.

+
+ +
+
+

evaluateFile

+
+
+int evaluateFile(VSScript **handle, const char *scriptFilename)
+

Evaluates a script contained in a file. This is a convenience function which reads the script from a file for you. It will only read the first 16 MiB which should be enough for everyone.

+

Behaves the same as evaluateBuffer().

+
+ +
+
+

getError

+
+
+const char *getError(VSScript *handle)
+

Returns the error message from a script environment, or NULL, if there is no error.

+

It is okay to pass NULL.

+

VSScript retains ownership of the pointer and it is only guaranteed to be valid until the next vsscript operation on the handle.

+
+ +
+
+

getExitCode

+
+
+int getExitCode(VSScript *handle)
+

Returns the exit code if the script calls sys.exit(code), or 0, if the script fails for other reasons or calls sys.exit(0).

+

It is okay to pass NULL.

+
+ +
+
+

getVariable

+
+
+int getVariable(VSScript *handle, const char *name, VSMap *dst)
+

Retrieves a variable from the script environment.

+

If a VapourSynth core has not been created yet in the script environment, one will be created now, with the default options (see the Python Reference).

+
+
name

Name of the variable to retrieve.

+
+
dst

Map where the variable’s value will be placed, with the key name.

+
+
+

Returns non-zero on error.

+
+ +
+
+

setVariables

+
+
+int vsscript_setVariable(VSScript *handle, const VSMap *vars)
+

Sets variables in the script environment.

+

The variables are now available to the script.

+

If a VapourSynth core has not been created yet in the script environment, one will be created now, with the default options (see the Python Reference).

+
+
vars

Map containing the variables to set.

+
+
+

Returns non-zero on error.

+
+ +
+
+

getOutputNode

+
+
+VSNode *getOutputNode(VSScript *handle, int index)
+

Retrieves a node from the script environment. A node in the script must have been marked for output with the requested index.

+

The returned node has its reference count incremented by one.

+

Returns NULL if there is no node at the requested index.

+
+ +
+
+

getOutputAlphaNode

+
+
+VSNode *getOutputAlphaNode(VSScript *handle, int index)
+

Retrieves an alpha node from the script environment. A node with associated alpha in the script must have been marked for output with the requested index.

+

The returned node has its reference count incremented by one.

+

Returns NULL if there is no alpha node at the requested index.

+
+ +
+
+

getAltOutputMode

+
+
+int getAltOutputMode(VSScript *handle, int index)
+

Retrieves the alternative output mode settings from the script. This value has no fixed meaning but in vspipe and vsvfw it +indicates that alternate output formats should be used when multiple ones are available. It is up to the client application to define the exact meaning or simply disregard it completely.

+

Returns 0 if there is no alt output mode set.

+
+ +
+
+

freeScript

+
+
+void freeScript(VSScript *handle)
+

Frees a script environment. handle is no longer usable.

+
    +
  • Cancels any clips set for output in the script environment.

  • +
  • Clears any variables set in the script environment.

  • +
  • Clears the error message from the script environment, if there is one.

  • +
  • Frees the VapourSynth core used in the script environment, if there is one.

  • +
+

Since this function frees the VapourSynth core, it must be called only after all frame requests are finished and all objects obtained from the script have been freed (frames, nodes, etc).

+

It is safe to pass NULL.

+
+ +
+
+

evalSetWorkingDir

+
+
+void evalSetWorkingDir(VSScript *handle, int setCWD)
+

Set whether or not the working directory is temporarily changed to the same +location as the script file when evaluateFile is called. Off by default.

+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/apireference.html b/Programs/doc/apireference.html new file mode 100644 index 0000000..c7ae4cb --- /dev/null +++ b/Programs/doc/apireference.html @@ -0,0 +1,240 @@ + + + + + + + VapourSynth C API Reference — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

VapourSynth C API Reference

+

See the example filters in the sdk dir. Reading simplefilters.c, which contains +several built-in functions, can also be very helpful.

+
+

Public Headers

+ +
+
+

Common Pitfalls

+

There are several minor pitfalls related to the threading and design that have to be taken into consideration. Most of them usually aren’t a problem but here’s a small checklist of things you have to watch out for sometimes.

+
+

General API

+

You may not pass objects (clips, functions and so on) owned by one core as arguments to filters in another core. A manual full deep copy of the data you want to pass on is required. This is generally not a problem since you should never need more than one core per filter graph.

+
+
+

Plugins

+

Plugin code may run more multithreaded than it initially appears. VapourSynthPluginInit is the only function always guaranteed to not run in parallel. This means that the constructor and destructor of a filter may be run in parallel for several instances. Use proper synchronization if you need to initialize shared data.

+

The GetFrame function is a bit more complicated so see the reference of the constants. Do however note that the parallelism is per instance. Even if a filter is fmUnordered or fmSerial other instances may enter GetFrame simultaneously.

+

There are two common misconseptions about which mode should be used. A simple rule is that fmSerial should never be used. And source filters (those returning a frame on arInitial) that need locking should use fmUnordered.

+
+
+
+

Reserved Frame Properties

+

All frames contain a map of key–value pairs. It is recommended that these +properties are named using only a-z, A-Z, 0-9 using CamelCase. There is a +special category of keys starting with _ which have strictly defined meanings +specified below. It is acceptable to not set any of these keys if they are +unknown. It is also a fatal error to set them to a value not specified below.

+

int _ChromaLocation

+
+

Chroma sample position in YUV formats.

+

0=left, 1=center, 2=topleft, 3=top, 4=bottomleft, 5=bottom.

+
+

int _ColorRange

+
+

Full or limited range (PC/TV range). Primarily used with YUV formats.

+

0=full range, 1=limited range.

+
+

int _Primaries

+
+

Color primaries as specified in ITU-T H.265 Table E.3.

+
+

int _Matrix

+
+

Matrix coefficients as specified in ITU-T H.265 Table E.5.

+
+

int _Transfer

+
+

Transfer characteristics as specified in ITU-T H.265 Table E.4.

+
+

int _FieldBased

+
+

If the frame is composed of two independent fields (interlaced).

+

0=frame based (progressive), 1=bottom field first, 2=top field first.

+
+

float _AbsoluteTime

+
+

The frame’s absolute timestamp in seconds if reported by the source filter. +Should only be set by the source filter and not be modified. Use durations +for all operations that depend on frame length.

+
+

int _DurationNum, int _DurationDen

+
+

The frame’s duration in seconds as a rational number. Filters that +modify the framerate should also change these values.

+

This fraction should always be normalized.

+
+

bint _Combed

+
+

Whether or not the frame needs postprocessing, usually hinted from field +matching filters.

+
+

int _Field

+
+

If the frame was produced by something like core.std.SeparateFields, +this property signals which field was used to generate this frame.

+

0=from bottom field, 1=from top field.

+
+

string _PictType

+
+

A single character describing the frame type. It uses the common +IPB letters but other letters may also be used for formats with +additional frame types.

+
+

int _SARNum, int _SARDen

+
+

Pixel (sample) aspect ratio as a rational number.

+
+

bint _SceneChangeNext

+
+

If 1, this frame is the last frame of the current scene. The next frame starts a new scene.

+
+

bint _SceneChangePrev

+
+

If 1, this frame starts a new scene.

+
+

frame _Alpha

+
+

A clip’s alpha channel can be attached to the clip one frame at a +time using this property.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/applications.html b/Programs/doc/applications.html new file mode 100644 index 0000000..9d8c10e --- /dev/null +++ b/Programs/doc/applications.html @@ -0,0 +1,156 @@ + + + + + + + Applications and Libraries — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Applications and Libraries

+
+

Applications

+
    +
  • D2V Witch – creates indexes that can be opened by d2vsource

  • +
  • Hybrid (Doom9) – encoding GUI with VapourSynth support

  • +
  • mpv.net – a media player with VapourSynth built-in

  • +
  • SmoothVideo Project – a plugin/video player component for realtime frame interpolation

  • +
  • StaxRip – encoding GUI with extended VapourSynth scripting support

  • +
  • VapourSynth Editor (Doom9) – an editor with syntax completion and fast preview support

  • +
  • VapourSynth Editor 2 (Doom9) – a spiritual successor to VapourSynth Editor

  • +
  • VirtualDub2 (Doom9) – VirtualDub with added support for high bitdepth colorspaces, useful for previewing

  • +
  • vsmkv – a FUSE-based virtual filesystem for exporting VapourSynth scripts as uncompressed videos in the Matroska (MKV) file format

  • +
  • vspreview – an advanced standalone previewer written in python with too many features to list

  • +
  • vspreview-rs (Doom9) – minimal VapourSynth script previewer

  • +
  • Wobbly (Doom9) – IVTC assistant similar to YATTA

  • +
  • Yuuno – incorporates VapourSynth into Jupyter

  • +
+
+
+

Libraries

+ +
+
+

Tools

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions.html b/Programs/doc/functions.html new file mode 100644 index 0000000..aabf06e --- /dev/null +++ b/Programs/doc/functions.html @@ -0,0 +1,551 @@ + + + + + + + Function Reference — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Function Reference

+
+

General Functions

+ +
+
+

Video Functions

+
+ +
+
+

Text

+ +
+
+
+

Audio Functions

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/audio/assumesamplerate.html b/Programs/doc/functions/audio/assumesamplerate.html new file mode 100644 index 0000000..0c7dac4 --- /dev/null +++ b/Programs/doc/functions/audio/assumesamplerate.html @@ -0,0 +1,146 @@ + + + + + + + AssumeSampleRate — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AssumeSampleRate

+
+
+std.AssumeSampleRate(anode clip[, anode src, int samplerate])
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/audio/audiogain.html b/Programs/doc/functions/audio/audiogain.html new file mode 100644 index 0000000..4683eb4 --- /dev/null +++ b/Programs/doc/functions/audio/audiogain.html @@ -0,0 +1,151 @@ + + + + + + + AudioGain — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AudioGain

+
+
+std.AudioGain(anode clip, float[] gain)
+

AudioGain can either change the volume of individual channels +if a separate gain for each channel is given or if only a single +gain value is supplied it’s applied to all channels.

+

Negative gain values are allowed. Applying a too large gain will +lead to clipping in integer formats.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/audio/audioloop.html b/Programs/doc/functions/audio/audioloop.html new file mode 100644 index 0000000..8c03fca --- /dev/null +++ b/Programs/doc/functions/audio/audioloop.html @@ -0,0 +1,150 @@ + + + + + + + AudioLoop — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AudioLoop

+
+
+std.AudioLoop(anode clip[, int times=0])
+

Returns a clip with the frames or samples repeated over and over again. If times is +less than 1 the clip will be repeated until the maximum clip length is +reached, otherwise it will be repeated times times.

+

In Python, std.AudioLoop can also be invoked using the multiplication operator.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/audio/audiomix.html b/Programs/doc/functions/audio/audiomix.html new file mode 100644 index 0000000..5457b74 --- /dev/null +++ b/Programs/doc/functions/audio/audiomix.html @@ -0,0 +1,171 @@ + + + + + + + AudioMix — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AudioMix

+
+
+std.AudioMix(anode[] clips, float[] matrix, int[] channels_out)
+

AudioMix can mix and combine channels from different clips in the most +general way possible.

+

Most of the returned clip’s properties are implicitly determined from the +first clip given to clips.

+

The clips parameter takes one or more clips with the same format. If the clips +are different lengths they’ll be zero extended to that of the longest.

+

The argument matrix applies the coefficients to each channel of each input clip where +the channels are in the numerical order of their channel constants. For example a stereo clip +will have its channels presented in the order FRONT_LEFT and then FRONT_RIGHT.

+

Output channels and order is determined by the channels_out array +between input index and output channel happens on the order of lowest output channel +identifier to the highest.

+

Below are some examples of useful operations.

+

Downmix stereo audio to mono:

+
AudioMix(clips=clip, matrix=[0.5, 0.5], channels_out=[vs.FRONT_CENTER])
+
+
+

Downmix 5.1 audio:

+
AudioMix(clips=clip, matrix=[1, 0, 0.7071, 0, 0.7071, 0, 0, 1, 0.7071, 0, 0, 0.7071], channels_out=[vs.FRONT_LEFT, vs.FRONT_RIGHT])
+
+
+

Copy stereo audio to 5.1 and zero the other channels:

+
AudioMix(clips=c, matrix=[1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], channels_out=[vs.FRONT_LEFT, vs.FRONT_RIGHT, vs.FRONT_CENTER, vs.LOW_FREQUENCY, vs.BACK_LEFT, vs.BACK_RIGHT])
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/audio/audioreverse.html b/Programs/doc/functions/audio/audioreverse.html new file mode 100644 index 0000000..2702cb8 --- /dev/null +++ b/Programs/doc/functions/audio/audioreverse.html @@ -0,0 +1,149 @@ + + + + + + + AudioReverse — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AudioReverse

+
+
+std.AudioReverse(anode clip)
+

Returns a clip with the frame or sample order reversed. For example, a clip with 3 +frames would have the frame order 2, 1, 0.

+

In Python, std.AudioReverse can also be invoked by slicing a clip.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/audio/audiosplice.html b/Programs/doc/functions/audio/audiosplice.html new file mode 100644 index 0000000..f6f8abe --- /dev/null +++ b/Programs/doc/functions/audio/audiosplice.html @@ -0,0 +1,150 @@ + + + + + + + AudioSplice — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AudioSplice

+
+
+std.AudioSplice(anode[] clips)
+

Returns a clip with all clips appended in the given order.

+

Splicing clips with different formats or dimensions is +considered an error unless mismatch is true.

+

In Python, std.AudioSplice can also be invoked using the addition operator.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/audio/audiotrim.html b/Programs/doc/functions/audio/audiotrim.html new file mode 100644 index 0000000..3ca0c2b --- /dev/null +++ b/Programs/doc/functions/audio/audiotrim.html @@ -0,0 +1,149 @@ + + + + + + + AudioTrim — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AudioTrim

+
+
+std.AudioTrim(anode clip[, int first=0, int last, int length])
+

AudioTrim performs exactly the same operation on audio clips but the unit is +obviously samples instead of frames.

+

In Python, std.AudioTrim can also be invoked by slicing a clip.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/audio/blankaudio.html b/Programs/doc/functions/audio/blankaudio.html new file mode 100644 index 0000000..c0e4c62 --- /dev/null +++ b/Programs/doc/functions/audio/blankaudio.html @@ -0,0 +1,157 @@ + + + + + + + BlankAudio — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BlankAudio

+
+
+std.BlankAudio([anode clip, int[] channels=[FRONT_LEFT, FRONT_RIGHT], int bits=16, int sampletype=INTEGER, int samplerate=44100, int length=(10*samplerate), bint keep=0])
+

Generates a new empty clip. This can be useful to have when editing audio +or for testing. The default is a 10 second long 44.1kHz 16 bit stereo clip. +Instead of specifying every property individually, BlankAudio can also copy +the properties from clip. If both an argument such as sampletype, and clip +are set, then sampletype will take precedence.

+

The channels argument is a list of channel constants. Specifying the same channel twice +is not allowed.

+

The possible sampletype values are currently INTEGER (0) and FLOAT (1).

+

If keep is set, a reference to the same frame is returned on every request. +Otherwise a new frame is generated every time. There should usually be no +reason to change this setting.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/audio/setaudiocache.html b/Programs/doc/functions/audio/setaudiocache.html new file mode 100644 index 0000000..476c039 --- /dev/null +++ b/Programs/doc/functions/audio/setaudiocache.html @@ -0,0 +1,147 @@ + + + + + + + SetAudioCache — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

SetAudioCache

+
+
+std.SetAudioCache(anode clip[, int mode, int fixedsize, int maxsize, int historysize])
+

see SetVideoCache

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/audio/shufflechannels.html b/Programs/doc/functions/audio/shufflechannels.html new file mode 100644 index 0000000..2f53bf4 --- /dev/null +++ b/Programs/doc/functions/audio/shufflechannels.html @@ -0,0 +1,181 @@ + + + + + + + ShuffleChannels — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ShuffleChannels

+
+
+std.ShuffleChannels(anode[] clips, int[] channels_in, int[] channels_out)
+

ShuffleChannels can extract and combine channels from different clips in the most +general way possible.

+

Most of the returned clip’s properties are implicitly determined from the +first clip given to clips.

+

The clips parameter takes one or more clips with the same format. If the clips +are different lengths they’ll be zero extended to that of the longest.

+

The argument channels_in controls which of the input clips’ channels to use and +takes a channel constants as its argument. Specifying a non-existent channel +is an error. If more channels_in than clips values are specified then the last +clip in the clips list is reused as a source. In addition to the channel constant +it’s also possible to specify the nth channel by using negative numbers.

+

The output channel mapping is determined by channels_out and corresponds to the +input channel order. The number of channels_out entries must be the same as the +number of channels_in entries. Specifying the same output channel twice is an error.

+

Below are some examples of useful operations.

+

Extract the left channel (assuming it exists):

+
ShuffleChannels(clips=clip, channels_in=vs.FRONT_LEFT, channels_out=vs.FRONT_LEFT)
+
+
+

Swap left and right audio channels in a stereo clip:

+
ShuffleChannels(clips=clip, channels_in=[vs.FRONT_RIGHT, vs.FRONT_LEFT], channels_out=[vs.FRONT_LEFT, vs.FRONT_RIGHT])
+
+
+

Swap left and right audio channels in a stereo clip (alternate ordering of arguments):

+
ShuffleChannels(clips=clip, channels_in=[vs.FRONT_LEFT, vs.FRONT_RIGHT], channels_out=[vs.FRONT_RIGHT, vs.FRONT_LEFT])
+
+
+

Swap left and right audio channels in a stereo clip (alternate indexing):

+
ShuffleChannels(clips=clip, channels_in=[-2, -1], channels_out=[vs.FRONT_LEFT, vs.FRONT_RIGHT])
+
+
+

Merge 2 mono audio clips into a single stereo clip:

+
ShuffleChannels(clips=[clipa, clipb], channels_in=[vs.FRONT_LEFT, vs.FRONT_LEFT], channels_out=[vs.FRONT_LEFT, vs.FRONT_RIGHT])
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/audio/splitchannels.html b/Programs/doc/functions/audio/splitchannels.html new file mode 100644 index 0000000..1ef737a --- /dev/null +++ b/Programs/doc/functions/audio/splitchannels.html @@ -0,0 +1,148 @@ + + + + + + + SplitChannels — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

SplitChannels

+
+
+std.SplitChannels(anode clip)
+

SplitChannels returns each audio channel of the input as +a separate clip.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/general/loadallplugins.html b/Programs/doc/functions/general/loadallplugins.html new file mode 100644 index 0000000..06ca792 --- /dev/null +++ b/Programs/doc/functions/general/loadallplugins.html @@ -0,0 +1,152 @@ + + + + + + + LoadAllPlugins — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

LoadAllPlugins

+
+
+std.LoadAllPlugins(string path)
+

Loads all native VapourSynth plugins found in the +specified path. Plugins that fail to load are +silently skipped.

+

Beware of Python’s escape character, this will fail:

+
LoadPlugin(path='c:\plugins')
+
+
+

Correct ways:

+
LoadPlugin(path='c:/plugins')
+LoadPlugin(path=r'c:\plugins')
+LoadPlugin(path='c:\\plugins\\')
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/general/loadplugin.html b/Programs/doc/functions/general/loadplugin.html new file mode 100644 index 0000000..6cba183 --- /dev/null +++ b/Programs/doc/functions/general/loadplugin.html @@ -0,0 +1,157 @@ + + + + + + + LoadPlugin — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

LoadPlugin

+
+
+std.LoadPlugin(string path, bint altsearchpath = False)
+

Load a native VapourSynth plugin. If successful, the loaded plugin’s +functions will end up in their own namespace.

+

Returns an error if a plugin with the same identifier or namespace already +has been loaded. This is to prevent naming collisions or multiple versions +of the same plugin being loaded at once.

+

Plugins are normally loaded with a very specific search order for +dependencies. Setting altsearchpath modifies this behavior to also +include dlls in the PATH.

+

Beware of Python’s escape character, this will fail:

+
LoadPlugin(path='c:\plugins\filter.dll')
+
+
+

Correct ways:

+
LoadPlugin(path='c:/plugins/filter.dll')
+LoadPlugin(path=r'c:\plugins\filter.dll')
+LoadPlugin(path='c:\\plugins\\filter.dll')
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/general/loadpluginavs.html b/Programs/doc/functions/general/loadpluginavs.html new file mode 100644 index 0000000..6fb4a80 --- /dev/null +++ b/Programs/doc/functions/general/loadpluginavs.html @@ -0,0 +1,177 @@ + + + + + + + LoadPlugin (Avisynth Compatibility) — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

LoadPlugin (Avisynth Compatibility)

+
+
+avs.LoadPlugin(string path)
+

Load an Avisynth 2.5 (32 bit only), 2.6 (32 and 64 bit) or Avisynth+ (32 and 64 bit) plugin. +If successful, the loaded plugin’s functions will end up in the avs namespace. Note that +in the case of Avisynth+ there’s no way to use the formats combined with alpha or +higher bitdepth packed RGB. Coincidentally there are no plugins that use this in a +meaningful way yet.

+

The compatibility module can work with a large number of Avisynth’s plugins. +However, the wrapping is not complete, so the following things will cause +problems:

+
+
    +
  • The plugin expects YUY2 or RGB32 input. In this case provide input in +either YUV422P8 or RGB24 format pass compatpack=True as an argument +to the Avisynth function.

  • +
  • The plugin tries to call env->invoke(). +These calls are ignored when it is safe to do so, but otherwise they +will most likely trigger a fatal error.

  • +
  • Plugins trying to read global variables. +There are no global variables.

  • +
+
+

If there are function name collisions functions will have a number appended +to them to make them distinct. For example if three functions are named +func then they will be named func, func_2 and func_3. This means +that Avisynth functions that have multiple overloads (rare) will give +each overload a different name.

+

Note that if you are really insane you can load Avisynth’s VirtualDub plugin +loader and use VirtualDub plugins as well. Function overloads are very common +when dealing with VirtualDub.

+

Beware of Python’s escape character, this will fail:

+
LoadPlugin(path='c:\plugins\filter.dll')
+
+
+

Correct ways:

+
LoadPlugin(path='c:/plugins/filter.dll')
+LoadPlugin(path=r'c:\plugins\filter.dll')
+LoadPlugin(path='c:\\plugins\\filter.dll')
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/general/setmaxcpu.html b/Programs/doc/functions/general/setmaxcpu.html new file mode 100644 index 0000000..af9d550 --- /dev/null +++ b/Programs/doc/functions/general/setmaxcpu.html @@ -0,0 +1,144 @@ + + + + + + + SetMaxCPU — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

SetMaxCPU

+
+
+std.SetMaxCPU(string cpu)
+

This function is only intended for testing and debugging purposes +and sets the maximum used instruction set for optimized functions.

+

Possible values for x86: “avx2”, “sse2”, “none”

+

Other platforms: “none”

+

By default all supported cpu features are used.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/addborders.html b/Programs/doc/functions/video/addborders.html new file mode 100644 index 0000000..0d711f2 --- /dev/null +++ b/Programs/doc/functions/video/addborders.html @@ -0,0 +1,194 @@ + + + + + + + AddBorders — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AddBorders

+
+
+std.AddBorders(vnode clip[, int left=0, int right=0, int top=0, int bottom=0, float[] color=<black>])
+

Adds borders to frames. The arguments specify the number of pixels to add on +each side. They must obey the subsampling restrictions. +The newly added borders will be set to color.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/assumefps.html b/Programs/doc/functions/video/assumefps.html new file mode 100644 index 0000000..5f42340 --- /dev/null +++ b/Programs/doc/functions/video/assumefps.html @@ -0,0 +1,198 @@ + + + + + + + AssumeFPS — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AssumeFPS

+
+
+std.AssumeFPS(vnode clip[, vnode src, int fpsnum, int fpsden=1])
+

Returns a clip with the framerate changed. This does not in any way modify +the frames, only their metadata.

+

The framerate to assign can either be read from another clip, src, or given +as a rational number with fpsnum and fpsden.

+

It is an error to specify both src and fpsnum.

+

AssumeFPS overwrites the frame properties _DurationNum and +_DurationDen with the frame duration computed from the new frame rate.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/averageframes.html b/Programs/doc/functions/video/averageframes.html new file mode 100644 index 0000000..da06bfe --- /dev/null +++ b/Programs/doc/functions/video/averageframes.html @@ -0,0 +1,203 @@ + + + + + + + AverageFrames — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

AverageFrames

+
+
+std.AverageFrames(vnode[] clips, float[] weights[, float scale, bint scenechange, int[] planes])
+

AverageFrames has two main modes depending on whether one or multiple clips are supplied. +The filter is named AverageFrames since using ones for weights is an easy way to average +many frames together but it can also be seen as a temporal or multiple frame convolution.

+

If multiple clips are supplied then the frames from each of the clips are multiplied by +the respective weights, summed together and divided by scale before being output. Note +that only integer weights and scale are allowed for integer input formats.

+

If a single clip is supplied then an odd number of weights are needed and they will instead +be temporally centered on the current frame of the clip. The rest works as multiple clip mode +with the only difference being that scenechange can be set to avoid averaging frames over scene +changes. If this happens then all the weights beyond a scene change are instead applied to the frame +right before it.

+

At most 31 weights can be supplied.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/binarize_binarizemask.html b/Programs/doc/functions/video/binarize_binarizemask.html new file mode 100644 index 0000000..5f1d12b --- /dev/null +++ b/Programs/doc/functions/video/binarize_binarizemask.html @@ -0,0 +1,218 @@ + + + + + + + Binarize/BinarizeMask — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Binarize/BinarizeMask

+
+
+std.Binarize(vnode clip[, float[] threshold, float[] v0, float[] v1, int[] planes=[0, 1, 2]])
+
+std.BinarizeMask(vnode clip[, float[] threshold, float[] v0, float[] v1, int[] planes=[0, 1, 2]])
+

Turns every pixel in the image into either v0, if it’s below +threshold, or v1, otherwise. The BinarizeMask version is intended +for use on mask clips where all planes have the same value range and +only differs in the default values of v0 and v1.

+
+
clip

Clip to process. It must have integer sample type and bit depth +between 8 and 16, or float sample type and bit depth of 32. If +there are any frames with other formats, an error will be +returned.

+
+
threshold

Defaults to the middle point of range allowed by the format. +Can be specified for each plane individually.

+
+
v0

Value given to pixels that are below threshold. Can be specified +for each plane individually. Defaults to the lower bound of the format.

+
+
v1

Value given to pixels that are greater than or equal to threshold. +Defaults to the maximum value allowed by the format. Can be specified +for each plane individually. Defaults to the upper bound of the format.

+
+
planes

Specifies which planes will be processed. Any unprocessed planes +will be simply copied.

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/blankclip.html b/Programs/doc/functions/video/blankclip.html new file mode 100644 index 0000000..a30f882 --- /dev/null +++ b/Programs/doc/functions/video/blankclip.html @@ -0,0 +1,204 @@ + + + + + + + BlankClip — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BlankClip

+
+
+std.BlankClip([vnode clip, int width=640, int height=480, int format=vs.RGB24, int length=(10*fpsnum)/fpsden, int fpsnum=24, int fpsden=1, float[] color=<black>, bint keep=0, bint varsize=0, bint varformat=0])
+

Generates a new empty clip. This can be useful to have when editing video or +for testing. The default is a 640x480 RGB24 24fps 10 second long black clip. +Instead of specifying every property individually, BlankClip can also copy +the properties from clip. If both an argument such as width, and clip +are set, then width will take precedence.

+

If keep is set, a reference to the same frame is returned on every request. +Otherwise a new frame is generated every time. There should usually be no +reason to change this setting.

+

If varsize is set, a clip with variable size will be returned. The frames +themselves will still have the size given by the width and height arguments.

+

If varformat is set, a clip with variable format will be returned. +The frames themselves will have the format given by the format argument.

+

It is never an error to use BlankClip.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/boxblur.html b/Programs/doc/functions/video/boxblur.html new file mode 100644 index 0000000..faaf411 --- /dev/null +++ b/Programs/doc/functions/video/boxblur.html @@ -0,0 +1,193 @@ + + + + + + + BoxBlur — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

BoxBlur

+
+
+std.BoxBlur(vnode clip[, int[] planes, int hradius = 1, int hpasses = 1, int vradius = 1, int vpasses = 1])
+

Performs a box blur which is fast even for large radius values. Using multiple passes can be used to fairly cheaply +approximate a gaussian blur. A radius of 0 means no processing is performed.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/cliptoprop.html b/Programs/doc/functions/video/cliptoprop.html new file mode 100644 index 0000000..05952cb --- /dev/null +++ b/Programs/doc/functions/video/cliptoprop.html @@ -0,0 +1,198 @@ + + + + + + + ClipToProp — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ClipToProp

+
+
+std.ClipToProp(vnode clip, vnode mclip[, string prop='_Alpha'])
+

Stores each frame of mclip as a frame property named prop in clip. This +is primarily intended to attach mask/alpha clips to another clip so that +editing operations will apply to both. Unlike most other filters the output +length is derived from the second argument named mclip.

+

If the attached mclip does not represent the alpha channel, you should set +prop to something else.

+

It is the inverse of PropToClip().

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/convolution.html b/Programs/doc/functions/video/convolution.html new file mode 100644 index 0000000..d38fe68 --- /dev/null +++ b/Programs/doc/functions/video/convolution.html @@ -0,0 +1,254 @@ + + + + + + + Convolution — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Convolution

+
+
+std.Convolution(vnode clip, float[] matrix[, float bias=0.0, float divisor=0.0, int[] planes=[0, 1, 2], bint saturate=True, string mode="s"])
+

Performs a spatial convolution.

+

Here is how a 3x3 convolution is done. Each pixel in the 3x3 +neighbourhood is multiplied by the corresponding coefficient in +matrix. The results of the nine multiplications are added together, +then this sum is divided by divisor. Next, bias is added, and the +result is rounded to the nearest larger integer. If this integer +result is negative and the saturate parameter is False, it is +multiplied by -1. Finally, the result is clamped to the format’s range +of valid values.

+
+
clip

Clip to process. It must have integer sample type and bit depth +between 8 and 16, or float sample type and bit depth of 32. If +there are any frames with other formats, an error will be +returned.

+
+
matrix

Coefficients for the convolution.

+

When mode is “s”, this must be an array of 9 or 25 numbers, for +a 3x3 or 5x5 convolution, respectively.

+

When mode is not “s”, this must be an array of 3 to 25 numbers, +with an odd number of elements.

+

The values of the coefficients must be between -1023 and 1023 +(inclusive). The coefficients are rounded to integers when +the input is an integer format.

+

This is how the elements of matrix correspond to the pixels in +a 3x3 neighbourhood:

+
1 2 3
+4 5 6
+7 8 9
+
+
+

It’s the same principle for the other types of convolutions. The +middle element of matrix always corresponds to the center pixel.

+
+
bias

Value to add to the final result of the convolution (before clamping +the result to the format’s range of valid values).

+
+
divisor

Divide the output of the convolution by this value (before adding +bias).

+

If this parameter is 0.0 (the default), the output of the convolution +will be divided by the sum of the elements of matrix, or by 1.0, +if the sum is 0.

+
+
planes

Specifies which planes will be processed. Any unprocessed planes +will be simply copied.

+
+
saturate

The final result is clamped to the format’s range of valid values +(0 .. (2**bitdepth)-1). Therefore, if this parameter is True, +negative values become 0. If this parameter is False, it’s instead +the absolute value that is clamped and returned.

+
+
mode

Selects the type of convolution. Possible values are “s”, for square, +“h” for horizontal, “v” for vertical, and “hv” or “vh” for both +horizontal and vertical.

+
+
+

How to apply a simple blur equivalent to Avisynth’s Blur(1):

+
Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1])
+
+
+

How to apply a stronger blur equivalent to Avisynth’s Blur(1.58):

+
Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1])
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/copyframeprops.html b/Programs/doc/functions/video/copyframeprops.html new file mode 100644 index 0000000..3394be5 --- /dev/null +++ b/Programs/doc/functions/video/copyframeprops.html @@ -0,0 +1,195 @@ + + + + + + + CopyFrameProps — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CopyFrameProps

+
+
+std.CopyFrameProps(vnode clip, vnode prop_src)
+

Returns clip but with all the frame properties replaced with the +ones from the clip in prop_src. Note that if clip is longer +than prop_src then the last existing frame’s properties will be +used instead.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/crop_cropabs.html b/Programs/doc/functions/video/crop_cropabs.html new file mode 100644 index 0000000..b2811e2 --- /dev/null +++ b/Programs/doc/functions/video/crop_cropabs.html @@ -0,0 +1,204 @@ + + + + + + + Crop/CropAbs — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Crop/CropAbs

+
+
+std.Crop(vnode clip[, int left=0, int right=0, int top=0, int bottom=0])
+
+std.CropAbs(vnode clip, int width, int height[, int left=0, int top=0])
+

Crops the frames in a clip.

+

Crop is the simplest to use of the two. The arguments specify how many +pixels to crop from each side. This function used to be called CropRel +which is still an alias for it.

+

CropAbs, on the other hand, is special, because it can accept clips with +variable frame sizes and crop out a fixed size area, thus making it a fixed +size clip.

+

Both functions return an error if the whole picture is cropped away, if the +cropped area extends beyond the input or if the subsampling restrictions +aren’t met.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/deflate_inflate.html b/Programs/doc/functions/video/deflate_inflate.html new file mode 100644 index 0000000..6f960bb --- /dev/null +++ b/Programs/doc/functions/video/deflate_inflate.html @@ -0,0 +1,228 @@ + + + + + + + Deflate/Inflate — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Deflate/Inflate

+
+
+std.Deflate(vnode clip[, int[] planes=[0, 1, 2], float threshold])
+

Replaces each pixel with the average of the eight pixels in its 3x3 +neighbourhood, but only if that average is less than the center pixel.

+
+
clip

Clip to process. It must have integer sample type and bit depth +between 8 and 16, or float sample type and bit depth of 32. If +there are any frames with other formats, an error will be +returned.

+
+
planes

Specifies which planes will be processed. Any unprocessed planes +will be simply copied.

+
+
threshold

Allows to limit how much pixels are changed. Output pixels will not +become less than input - threshold. The default is no limit.

+
+
+
+ +
+
+std.Inflate(vnode clip[, int[] planes=[0, 1, 2], int threshold=65535])
+

Replaces each pixel with the average of the eight pixels in its 3x3 +neighbourhood, but only if that average is greater than the center +pixel.

+
+
clip

Clip to process. It must have integer sample type and bit depth +between 8 and 16, or float sample type and bit depth of 32. If +there are any frames with other formats, an error will be +returned.

+
+
planes

Specifies which planes will be processed. Any unprocessed planes +will be simply copied.

+
+
threshold

Allows to limit how much pixels are changed. Output pixels will not +become greater than input + threshold. The default is no limit.

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/deleteframes.html b/Programs/doc/functions/video/deleteframes.html new file mode 100644 index 0000000..72f3066 --- /dev/null +++ b/Programs/doc/functions/video/deleteframes.html @@ -0,0 +1,194 @@ + + + + + + + DeleteFrames — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

DeleteFrames

+
+
+std.DeleteFrames(vnode clip, int[] frames)
+

Deletes the specified frames.

+

All frame numbers apply to the input clip.

+

Returns an error if the same frame is deleted twice or if all frames in a clip are deleted.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/doubleweave.html b/Programs/doc/functions/video/doubleweave.html new file mode 100644 index 0000000..1af70d4 --- /dev/null +++ b/Programs/doc/functions/video/doubleweave.html @@ -0,0 +1,206 @@ + + + + + + + DoubleWeave — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

DoubleWeave

+
+
+std.DoubleWeave(vnode clip[, bint tff])
+

Weaves the fields back together from a clip with interleaved fields.

+

Since VapourSynth only has a weak notion of field order internally, tff +may have to be set. Setting tff to true means top fields first and false +means bottom fields first. Note that the _Field frame property, if present +and in a valid combination, takes precedence over tff.

+

DoubleWeave’s output has the same number of frames as the input. One must +use DoubleWeave together with SelectEvery to undo the effect of +SeparateFields:

+
sep = core.std.SeparateFields(source)
+...
+woven = core.std.DoubleWeave(sep)
+woven = core.std.SelectEvery(woven, 2, 0)
+
+
+

The _Field frame property is deleted and _FieldBased is set accordingly.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/duplicateframes.html b/Programs/doc/functions/video/duplicateframes.html new file mode 100644 index 0000000..ef08c0f --- /dev/null +++ b/Programs/doc/functions/video/duplicateframes.html @@ -0,0 +1,194 @@ + + + + + + + DuplicateFrames — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/expr.html b/Programs/doc/functions/video/expr.html new file mode 100644 index 0000000..3059d31 --- /dev/null +++ b/Programs/doc/functions/video/expr.html @@ -0,0 +1,295 @@ + + + + + + + Expr — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Expr

+
+
+std.Expr(vnode[] clips, string[] expr[, int format])
+

Expr evaluates an expression per pixel for up to 26 input clips. +The expression, expr, is written using reverse polish notation and can be +specified for each plane individually. +The expression given for the previous plane is used if the expr array +contains fewer expressions than the input clip has planes. +In practice this means that a single expression will be applied to all planes +by default.

+

Specifying an empty string as the expression enables a fast plane copy from +the first specified clip, when possible. If it is not possible due to the +output format being incompatible, the plane contents will be undefined.

+

Since the expression is evaluated at runtime, there are a few pitfalls. In +order to keep speed up, the input ranges are not normalized to the usual +floating point ranges. Instead they are left as is, meaning that an 8 bit +clip will have values in the 0-255 range and a 10 bit clip will have values +in the 0-1023 range. +Note that floating point clips are even more difficult, as most channels are +stored in the 0-1 range with the exception of U, V, Co and Cg planes, which +are in the -0.5-0.5 range. +If you mix clips with different input formats this must be taken into +consideration.

+

When the output format uses integer samples, the result of the expression is +clamped to the [0, 2**bits_per_sample-1] range. +When the output format uses float samples, the result of the expression is +stored without any clamping.

+

By default the output format is the same as the first input clip’s format. +You can override it by setting format. The only restriction is that the +output format must have the same subsampling as the input clips and be +8..16 bit integer or 32 bit float. 16 bit float is also supported on cpus +with the f16c instructions.

+

Logical operators are also a bit special, since everything is done in +floating point arithmetic. +All values greater than 0 are considered true for the purpose of comparisons. +Logical operators return 0.0 for false and 1.0 for true in their operations.

+

Since the expression is being evaluated at runtime, there are also the stack +manipulation operators, swap and dup. The former swaps the topmost and +second topmost values, and the latter duplicates the topmost stack value.

+

These operators also have swapN and dupN forms that allow a value N +steps up in the stack to be swapped or duplicated. The top value of the stack +has index zero meaning that dup is equivalent to dup0 and swap is +equivalent to swap1. This is because swapN always swaps with the topmost +value at index 0.

+

Expressions are converted to byte-code or machine-code by an optimizing +compiler and are not guaranteed to evaluate in the order originally written. +The compiler assumes that all input values are finite (i.e neither NaN nor +INF) and that no operator will produce a non-finite value. Such expressions +are invalid. This is especially important for the transcendental operators:

+
    +
  • exp - expression must not overflow (i.e. x <= 88)

  • +
  • log - input must be finite and non-negative (i.e. x >= 0 && x <= 3e+38)

  • +
  • pow - base must be finite and non-negative. Result must not overflow (i.e. x >= 0 && x <= 3e+38; 1e-38 <= result <= 3e+38)

  • +
+

Clip load operators:

+
x-z, a-w
+
+
+

The operators taking one argument are:

+
exp log sqrt sin cos abs not dup dupN
+
+
+

The operators taking two arguments are:

+
+ - * / max min pow > < = >= <= and or xor swap swapN
+
+
+

The operators taking three arguments are:

+
?
+
+
+

For example these operations:

+
a b c ?
+
+d e <
+
+f abs
+
+
+

Are equivalent to these operations in C:

+
a ? b : c
+
+d < e
+
+abs(f)
+
+
+

The sin/cos operators are approximated to within 2e-6 absolute error for +inputs with magnitude up to 1e5, and there is no accuracy guarantees for +inputs whose magnitude is larger than 2e5.

+

How to average the Y planes of 3 YUV clips and pass through the UV planes +unchanged (assuming same format):

+
std.Expr(clips=[clipa, clipb, clipc], expr=["x y + z + 3 /", "", ""])
+
+
+

How to average the Y planes of 3 YUV clips and pass through the UV planes +unchanged (different formats):

+
std.Expr(clips=[clipa16bit, clipb10bit, clipa8bit],
+   expr=["x y 64 * + z 256 * + 3 /", ""])
+
+
+

Setting the output format because the resulting values are illegal in a 10 +bit clip (note that the U and V planes will contain junk since direct copy +isn’t possible):

+
std.Expr(clips=[clipa10bit, clipb16bit, clipa8bit],
+   expr=["x 64 * y + z 256 * + 3 /", ""], format=vs.YUV420P16)
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/flipvertical_fliphorizontal.html b/Programs/doc/functions/video/flipvertical_fliphorizontal.html new file mode 100644 index 0000000..67633f0 --- /dev/null +++ b/Programs/doc/functions/video/flipvertical_fliphorizontal.html @@ -0,0 +1,195 @@ + + + + + + + FlipVertical/FlipHorizontal — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/frameeval.html b/Programs/doc/functions/video/frameeval.html new file mode 100644 index 0000000..f76c5d7 --- /dev/null +++ b/Programs/doc/functions/video/frameeval.html @@ -0,0 +1,258 @@ + + + + + + + FrameEval — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

FrameEval

+
+
+std.FrameEval(vnode clip, func eval[, vnode[] prop_src, vnode[] clip_src])
+

Allows an arbitrary function to be evaluated every frame. The function gets +the frame number, n, as input and should return a clip the output frame can +be requested from.

+

The clip argument is only used to get the output format from since there is +no reliable automatic way to deduce it.

+

When using the argument prop_src the function will also have an argument, +f, containing the current frames. This is mainly so frame properties can be +accessed and used to make decisions. Note that f will only be a list if +more than one prop_src clip is provided.

+

The clip_src argument only exists as a way to hint which clips are referenced in the +eval function which can improve caching and graph generation. Its use is encouraged +but not required.

+

This function can be used to accomplish the same things as Animate, +ScriptClip and all the other conditional filters in Avisynth. Note that to +modify per frame properties you should use ModifyFrame.

+

How to animate a BlankClip to fade from white to black. This is the simplest +use case without using the prop_src argument:

+
import vapoursynth as vs
+import functools
+
+base_clip = vs.core.std.BlankClip(format=vs.YUV420P8, length=1000, color=[255, 128, 128])
+
+def animator(n, clip):
+   if n > 255:
+      return clip
+   else:
+      return vs.core.std.BlankClip(format=vs.YUV420P8, length=1000, color=[n, 128, 128])
+
+animated_clip = vs.core.std.FrameEval(base_clip, functools.partial(animator, clip=base_clip))
+animated_clip.set_output()
+
+
+

How to perform a simple per frame auto white balance. It shows how to access +calculated frame properties and use them for conditional filtering:

+
import vapoursynth as vs
+import functools
+import math
+
+def GrayWorld1Adjust(n, f, clip, core):
+   small_number = 0.000000001
+   red   = f[0].props['PlaneStatsAverage']
+   green = f[1].props['PlaneStatsAverage']
+   blue  = f[2].props['PlaneStatsAverage']
+   max_rgb = max(red, green, blue)
+   red_corr   = max_rgb/max(red, small_number)
+   green_corr = max_rgb/max(green, small_number)
+   blue_corr  = max_rgb/max(blue, small_number)
+   norm = max(blue, math.sqrt(red_corr*red_corr + green_corr*green_corr + blue_corr*blue_corr) / math.sqrt(3), small_number)
+   r_gain = red_corr/norm
+   g_gain = green_corr/norm
+   b_gain = blue_corr/norm
+   return core.std.Expr(clip, expr=['x ' + repr(r_gain) + ' *', 'x ' + repr(g_gain) + ' *', 'x ' + repr(b_gain) + ' *'])
+
+def GrayWorld1(clip, matrix_s=None):
+   rgb_clip = vs.core.resize.Bilinear(clip, format=vs.RGB24)
+   r_avg = vs.core.std.PlaneStats(rgb_clip, plane=0)
+   g_avg = vs.core.std.PlaneStats(rgb_clip, plane=1)
+   b_avg = vs.core.std.PlaneStats(rgb_clip, plane=2)
+   adjusted_clip = vs.core.std.FrameEval(rgb_clip, functools.partial(GrayWorld1Adjust, clip=rgb_clip, core=vs.core), prop_src=[r_avg, g_avg, b_avg])
+   return vs.core.resize.Bilinear(adjusted_clip, format=clip.format.id, matrix_s=matrix_s)
+
+vs.core.std.LoadPlugin(path='BestSource.dll')
+main = vs.core.bs.VideoSource(source='...')
+main = GrayWorld1(main)
+main.set_output()
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/freezeframes.html b/Programs/doc/functions/video/freezeframes.html new file mode 100644 index 0000000..13cc0d0 --- /dev/null +++ b/Programs/doc/functions/video/freezeframes.html @@ -0,0 +1,201 @@ + + + + + + + FreezeFrames — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

FreezeFrames

+
+
+std.FreezeFrames(vnode clip, int[] first, int[] last, int[] replacement)
+

FreezeFrames replaces all the frames in the [first,last] range +(inclusive) with replacement.

+

A single call to FreezeFrames can freeze any number of ranges:

+
core.std.FreezeFrames(input, first=[0, 100, 231], last=[15, 112, 300], replacement=[8, 50, 2])
+
+
+

This replaces [0,15] with 8, [100,112] with 50, and [231,300] with 2 (the +original frame number 2, not frame number 2 after it was replaced with +number 8 by the first range).

+

The frame ranges must not overlap.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/interleave.html b/Programs/doc/functions/video/interleave.html new file mode 100644 index 0000000..3cc84fe --- /dev/null +++ b/Programs/doc/functions/video/interleave.html @@ -0,0 +1,201 @@ + + + + + + + Interleave — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Interleave

+
+
+std.Interleave(vnode[] clips[, bint extend=0, bint mismatch=0, bint modify_duration=True])
+

Returns a clip with the frames from all clips interleaved. For example, +Interleave(clips=[A, B]) will return A.Frame 0, B.Frame 0, A.Frame 1, +B.Frame…

+

The extend argument controls whether or not all input clips will be treated +as if they have the same length as the longest clip.

+

Interleaving clips with different formats or dimensions is considered an +error unless mismatch is true.

+

If modify_duration is set then the output clip’s frame rate is the first +input clip’s frame rate multiplied by the number of input clips. The frame durations are divided +by the number of input clips. Otherwise the first input clip’s frame rate is used.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/invert_invertmask.html b/Programs/doc/functions/video/invert_invertmask.html new file mode 100644 index 0000000..8c98a74 --- /dev/null +++ b/Programs/doc/functions/video/invert_invertmask.html @@ -0,0 +1,208 @@ + + + + + + + Invert/InvertMask — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Invert/InvertMask

+
+
+std.Invert(vnode clip[, int[] planes=[0, 1, 2]])
+
+std.InvertMask(vnode clip[, int[] planes=[0, 1, 2]])
+

Inverts the pixel values. Specifically, it subtracts the value of the +input pixel from the format’s maximum allowed value. The InvertMask +version is intended for use on mask clips where all planes have the +same maximum value regardless of the colorspace.

+
+
clip

Clip to process. It must have integer sample type and bit depth +between 8 and 16, or float sample type and bit depth of 32. If +there are any frames with other formats, an error will be +returned.

+
+
planes

Specifies which planes will be processed. Any unprocessed planes +will be simply copied.

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/levels.html b/Programs/doc/functions/video/levels.html new file mode 100644 index 0000000..e2f336c --- /dev/null +++ b/Programs/doc/functions/video/levels.html @@ -0,0 +1,224 @@ + + + + + + + Levels — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Levels

+
+
+std.Levels(vnode clip[, float min_in, float max_in, float gamma=1.0, float min_out, float max_out, int[] planes=[0, 1, 2]])
+

Adjusts brightness, contrast, and gamma.

+

The range [min_in, max_in] is remapped into [min_out, max_out]. Note that the +range behavior is unintuitive for YUV float formats since the assumed range will be +0-1 even for the UV-planes.

+

For example, to convert from limited range YUV to full range (8 bit):

+
clip = std.Levels(clip, min_in=16, max_in=235, min_out=0, max_out=255, planes=0)
+clip = std.Levels(clip, min_in=16, max_in=240, min_out=0, max_out=255, planes=[1,2])
+
+
+

The default value of max_in and max_out is the format’s minimum and maximum +allowed values respectively. Note that all input is clamped to the input range +to prevent out of range output.

+
+

Warning

+
+
The default ranges are 0-1 for floating point formats. This may have an undesired

effect on YUV formats.

+
+
+
+
+
clip

Clip to process. It must have integer sample type and bit depth +between 8 and 16, or float sample type and bit depth of 32. If +there are any frames with other formats, an error will be +returned.

+
+
gamma

Controls the degree of non-linearity of the conversion. Values +greater than 1.0 brighten the output, while values less than 1.0 +darken it.

+
+
planes

Specifies which planes will be processed. Any unprocessed planes +will be simply copied.

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/limiter.html b/Programs/doc/functions/video/limiter.html new file mode 100644 index 0000000..73f4886 --- /dev/null +++ b/Programs/doc/functions/video/limiter.html @@ -0,0 +1,206 @@ + + + + + + + Limiter — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Limiter

+
+
+std.Limiter(vnode clip[, float[] min, float[] max, int[] planes=[0, 1, 2]])
+

Limits the pixel values to the range [min, max].

+
+
clip

Clip to process. It must have integer sample type and bit depth +between 8 and 16, or float sample type and bit depth of 32. If +there are any frames with other formats, an error will be +returned.

+
+
min

Lower bound. Defaults to the lowest allowed value for the input. Can be specified for each plane individually.

+
+
max

Upper bound. Defaults to the highest allowed value for the input. Can be specified for each plane individually.

+
+
planes

Specifies which planes will be processed. Any unprocessed planes +will be simply copied.

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/loop.html b/Programs/doc/functions/video/loop.html new file mode 100644 index 0000000..60f4a5b --- /dev/null +++ b/Programs/doc/functions/video/loop.html @@ -0,0 +1,195 @@ + + + + + + + Loop — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Loop

+
+
+std.Loop(vnode clip[, int times=0])
+

Returns a clip with the frames or samples repeated over and over again. If times is +less than 1 the clip will be repeated until the maximum clip length is +reached, otherwise it will be repeated times times.

+

In Python, std.Loop can also be invoked using the multiplication operator.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/lut.html b/Programs/doc/functions/video/lut.html new file mode 100644 index 0000000..f762ec8 --- /dev/null +++ b/Programs/doc/functions/video/lut.html @@ -0,0 +1,219 @@ + + + + + + + Lut — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Lut

+
+
+std.Lut(vnode clip[, int[] planes, int[] lut, float[] lutf, func function, int bits, bint floatout])
+

Applies a look-up table to the given clip. The lut can be specified as either an array +of 2^bits_per_sample values or given as a function having an argument named +x to be evaluated. Either lut, lutf or function must be used. The lut will be +applied to the planes listed in planes and the other planes will simply be +passed through unchanged. By default all planes are processed.

+

If floatout is set then the output will be floating point instead, and either +lutf needs to be set or function always needs to return floating point +values.

+

How to limit YUV range (by passing an array):

+
luty = []
+for x in range(2**clip.format.bits_per_sample):
+   luty.append(max(min(x, 235), 16))
+lutuv = []
+for x in range(2**clip.format.bits_per_sample):
+   lutuv.append(max(min(x, 240), 16))
+ret = Lut(clip=clip, planes=0, lut=luty)
+limited_clip = Lut(clip=ret, planes=[1, 2], lut=lutuv)
+
+
+

How to limit YUV range (using a function):

+
def limity(x):
+   return max(min(x, 235), 16)
+def limituv(x):
+   return max(min(x, 240), 16)
+ret = Lut(clip=clip, planes=0, function=limity)
+limited_clip = Lut(clip=ret, planes=[1, 2], function=limituv)
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/lut2.html b/Programs/doc/functions/video/lut2.html new file mode 100644 index 0000000..bd21a03 --- /dev/null +++ b/Programs/doc/functions/video/lut2.html @@ -0,0 +1,219 @@ + + + + + + + Lut2 — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Lut2

+
+
+std.Lut2(vnode clipa, vnode clipb[, int[] planes, int[] lut, float[] lutf, func function, int bits, bint floatout])
+

Applies a look-up table that takes into account the pixel values of two clips. The +lut needs to contain 2^(clip1.bits_per_sample + clip2.bits_per_sample) +entries and will be applied to the planes listed in planes. Alternatively +a function taking x and y as arguments can be used to make the lut. +The other planes will be passed through unchanged. By default all planes +are processed.

+

Lut2 also takes an optional bit depth parameter, bits, which defaults to +the bit depth of the first input clip, and specifies the bit depth of the +output clip. The user is responsible for understanding the effects of bit +depth conversion, specifically from higher bit depths to lower bit depths, +as no scaling or clamping is applied.

+

If floatout is set then the output will be floating point instead, and either +lutf needs to be set or function always needs to return floating point +values.

+

How to average 2 clips:

+
lut = []
+for y in range(2 ** clipy.format.bits_per_sample):
+   for x in range(2 ** clipx.format.bits_per_sample):
+      lut.append((x + y)//2)
+Lut2(clipa=clipa, clipb=clipb, lut=lut)
+
+
+

How to average 2 clips with a 10-bit output:

+
def f(x, y):
+   return (x*4 + y)//2
+Lut2(clipa=clipa8bit, clipb=clipb10bit, function=f, bits=10)
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/makediff.html b/Programs/doc/functions/video/makediff.html new file mode 100644 index 0000000..c23c622 --- /dev/null +++ b/Programs/doc/functions/video/makediff.html @@ -0,0 +1,199 @@ + + + + + + + MakeDiff — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MakeDiff

+
+
+std.MakeDiff(vnode clipa, vnode clipb[, int[] planes])
+

Calculates the difference between clipa and clipb and clamps the result. +By default all planes are processed. This function is usually used together with MergeDiff, which can be used to add back the difference.

+

Unsharp masking of luma:

+
blur_clip = core.std.Convolution(clip, matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1], planes=[0])
+diff_clip = core.std.MakeDiff(clip, blur_clip, planes=[0])
+sharpened_clip = core.std.MergeDiff(clip, diff_clip, planes=[0])
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/makefulldiff.html b/Programs/doc/functions/video/makefulldiff.html new file mode 100644 index 0000000..c5ed2e4 --- /dev/null +++ b/Programs/doc/functions/video/makefulldiff.html @@ -0,0 +1,200 @@ + + + + + + + MakeFullDiff — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MakeFullDiff

+
+
+std.MakeFullDiff(vnode clipa, vnode clipb)
+

Calculates the difference between clipa and clipb and outputs a clip with a one higher bitdepth to avoid the clamping or wraparound issues +that would otherwise happen with filters like MakeDiff when forming a difference. +This function is usually used together with MergeFullDiff, which can be used to add back the difference.

+

Unsharp mask:

+
blur_clip = core.std.Convolution(clip, matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1])
+diff_clip = core.std.MakeFullDiff(clip, blur_clip)
+sharpened_clip = core.std.MergeFullDiff(clip, diff_clip)
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/maskedmerge.html b/Programs/doc/functions/video/maskedmerge.html new file mode 100644 index 0000000..2a4dee5 --- /dev/null +++ b/Programs/doc/functions/video/maskedmerge.html @@ -0,0 +1,216 @@ + + + + + + + MaskedMerge — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MaskedMerge

+
+
+std.MaskedMerge(vnode clipa, vnode clipb, vnode mask[, int[] planes, bint first_plane=0, bint premultiplied=0])
+

MaskedMerge merges clipa with clipb using the per pixel weights in the mask, +where 0 means that clipa is returned unchanged. +The mask clip is assumed to be full range for all planes and in the +0-1 interval for float formats regardless of the colorspace. +If mask is a grayscale clip or if first_plane is true, the mask’s first +plane will be used as the mask for merging all planes. The mask will be +bilinearly resized if necessary.

+

If premultiplied is set the blending is performed as if clipb has been pre-multiplied +with alpha. In pre-multiplied mode it is an error to try to merge two frames with +mismatched full and limited range since it will most likely cause horrible unintended +color shifts. In the other mode it’s just a very, very bad idea.

+

By default all planes will be +processed, but it is also possible to specify a list of the planes to merge +in the output. The unprocessed planes will be copied from the first clip.

+

clipa and clipb must have the same dimensions and format, and the mask must be the +same format as the clips or the grayscale equivalent.

+

How to apply a mask to the first plane:

+
MaskedMerge(clipa=A, clipb=B, mask=Mask, planes=0)
+
+
+

How to apply the first plane of a mask to the second and third plane:

+
MaskedMerge(clipa=A, clipb=B, mask=Mask, planes=[1, 2], first_plane=True)
+
+
+

The frame properties are copied from clipa.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/median.html b/Programs/doc/functions/video/median.html new file mode 100644 index 0000000..fee3f85 --- /dev/null +++ b/Programs/doc/functions/video/median.html @@ -0,0 +1,204 @@ + + + + + + + Median — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Median

+
+
+std.Median(vnode clip[, int[] planes=[0, 1, 2]])
+

Replaces each pixel with the median of the nine pixels in its 3x3 +neighbourhood. In other words, the nine pixels are sorted from lowest +to highest, and the middle value is picked.

+
+
clip

Clip to process. It must have integer sample type and bit depth +between 8 and 16, or float sample type and bit depth of 32. If +there are any frames with other formats, an error will be +returned.

+
+
planes

Specifies which planes will be processed. Any unprocessed planes +will be simply copied.

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/merge.html b/Programs/doc/functions/video/merge.html new file mode 100644 index 0000000..9312c4d --- /dev/null +++ b/Programs/doc/functions/video/merge.html @@ -0,0 +1,212 @@ + + + + + + + Merge — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Merge

+
+
+std.Merge(vnode clipa, vnode clipb[, float[] weight = 0.5])
+

Merges clipa and clipb using the specified weight for each plane. The default +is to use a 0.5 weight for all planes. A zero weight means that clipa +is returned unchanged and 1 means that clipb is returned unchanged. If a +single weight is specified, it will be used for all planes. If two weights +are given then the second value will be used for the third plane as well.

+

Values outside the 0-1 range are considered to be an error. Specifying more +weights than planes in the clips is also an error. The clips must have the +same dimensions and format.

+

How to merge luma:

+
Merge(clipa=A, clipb=B, weight=[1, 0])
+
+
+

How to merge chroma:

+
Merge(clipa=A, clipb=B, weight=[0, 1])
+
+
+

The average of two clips:

+
Merge(clipa=A, clipb=B)
+
+
+

The frame properties are copied from clipa.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/mergediff.html b/Programs/doc/functions/video/mergediff.html new file mode 100644 index 0000000..4db8930 --- /dev/null +++ b/Programs/doc/functions/video/mergediff.html @@ -0,0 +1,199 @@ + + + + + + + MergeDiff — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MergeDiff

+
+
+std.MergeDiff(vnode clipa, vnode clipb[, int[] planes])
+

Merges back the difference in clipb to clipa and clamps the result. +By default all planes are processed. This function is usually used together with MakeDiff, which is normally used to calculate the difference.

+

Unsharp masking of luma:

+
blur_clip = core.std.Convolution(clip, matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1], planes=[0])
+diff_clip = core.std.MakeDiff(clip, blur_clip, planes=[0])
+sharpened_clip = core.std.MergeDiff(clip, diff_clip, planes=[0])
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/mergefulldiff.html b/Programs/doc/functions/video/mergefulldiff.html new file mode 100644 index 0000000..a4dc258 --- /dev/null +++ b/Programs/doc/functions/video/mergefulldiff.html @@ -0,0 +1,199 @@ + + + + + + + MergeFullDiff — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MergeFullDiff

+
+
+std.MergeFullDiff(vnode clipa, vnode clipb)
+

Merges back the difference in clipb to clipa. Note that the bitdepth of clipb has to be one higher than that of clip. +This function is usually used together with MakeFullDiff, which is normally used to calculate the difference.

+

Unsharp mask:

+
blur_clip = core.std.Convolution(clip, matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1])
+diff_clip = core.std.MakeFullDiff(clip, blur_clip)
+sharpened_clip = core.std.MergeFullDiff(clip, diff_clip)
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/minimum_maximum.html b/Programs/doc/functions/video/minimum_maximum.html new file mode 100644 index 0000000..7b1e930 --- /dev/null +++ b/Programs/doc/functions/video/minimum_maximum.html @@ -0,0 +1,251 @@ + + + + + + + Minimum/Maximum — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Minimum/Maximum

+
+
+std.Minimum(vnode clip[, int[] planes=[0, 1, 2], float threshold, bint[] coordinates=[1, 1, 1, 1, 1, 1, 1, 1]])
+

Replaces each pixel with the smallest value in its 3x3 neighbourhood. +This operation is also known as erosion.

+
+
clip

Clip to process. It must have integer sample type and bit depth +between 8 and 16, or float sample type and bit depth of 32. If +there are any frames with other formats, an error will be +returned.

+
+
planes

Specifies which planes will be processed. Any unprocessed planes +will be simply copied.

+
+
threshold

Allows to limit how much pixels are changed. Output pixels will not +become less than input - threshold. The default is no limit.

+
+
coordinates

Specifies which pixels from the 3x3 neighbourhood are considered. +If an element of this array is 0, the corresponding pixel is not +considered when finding the minimum value. This must contain exactly +8 numbers.

+

Here is how each number corresponds to a pixel in the 3x3 +neighbourhood:

+
1 2 3
+4   5
+6 7 8
+
+
+
+
+
+ +
+
+std.Maximum(vnode clip[, int[] planes=[0, 1, 2], float threshold, bint[] coordinates=[1, 1, 1, 1, 1, 1, 1, 1]])
+

Replaces each pixel with the largest value in its 3x3 neighbourhood. +This operation is also known as dilation.

+
+
clip

Clip to process. It must have integer sample type and bit depth +between 8 and 16, or float sample type and bit depth of 32. If +there are any frames with other formats, an error will be +returned.

+
+
planes

Specifies which planes will be processed. Any unprocessed planes +will be simply copied.

+
+
threshold

Allows to limit how much pixels are changed. Output pixels will not +become less than input - threshold. The default is no limit.

+
+
coordinates

Specifies which pixels from the 3x3 neighbourhood are considered. +If an element of this array is 0, the corresponding pixel is not +considered when finding the maximum value. This must contain exactly +8 numbers.

+

Here is how each number corresponds to a pixel in the 3x3 +neighbourhood:

+
1 2 3
+4   5
+6 7 8
+
+
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/modifyframe.html b/Programs/doc/functions/video/modifyframe.html new file mode 100644 index 0000000..8471acc --- /dev/null +++ b/Programs/doc/functions/video/modifyframe.html @@ -0,0 +1,232 @@ + + + + + + + ModifyFrame — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ModifyFrame

+
+
+std.ModifyFrame(vnode clip, clip[] clips, func selector)
+

The selector function is called for every single frame and can modify the +properties of one of the frames gotten from clips. The additional clips’ +properties should only be read and not modified because only one modified +frame can be returned.

+

You must first copy the input frame to make it modifiable. Any frame may be +returned as long as it has the same format as the clip. +Failure to do so will produce an error. If for conditional reasons you do not +need to modify the current frame’s properties, you can simply pass it through. +The selector function is passed n, the current frame number, and f, which +is a frame or a list of frames if there is more than one clip specified.

+

If you do not need to modify frame properties but only read them, you should +probably be using FrameEval instead.

+

How to set the property FrameNumber to the current frame number:

+
def set_frame_number(n, f):
+   fout = f.copy()
+   fout.props['FrameNumber'] = n
+   return fout
+...
+ModifyFrame(clip=clip, clips=clip, selector=set_frame_number)
+
+
+

How to remove a property:

+
def remove_property(n, f):
+   fout = f.copy()
+   del fout.props['FrameNumber']
+   return fout
+...
+ModifyFrame(clip=clip, clips=clip, selector=remove_property)
+
+
+

An example of how to copy certain properties from one clip to another +(clip1 and clip2 have the same format):

+
def transfer_property(n, f):
+   fout = f[1].copy()
+   fout.props['FrameNumber'] = f[0].props['FrameNumber']
+   fout.props['_Combed'] = f[0].props['_Combed']
+   return fout
+...
+ModifyFrame(clip=clip1, clips=[clip1, clip2], selector=transfer_property)
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/pemverifier.html b/Programs/doc/functions/video/pemverifier.html new file mode 100644 index 0000000..f333f66 --- /dev/null +++ b/Programs/doc/functions/video/pemverifier.html @@ -0,0 +1,198 @@ + + + + + + + PEMVerifier — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

PEMVerifier

+
+
+std.PEMVerifier(vnode clip[, float[] upper, float[] lower])
+

The PEMVerifier is used to check for out-of-bounds pixel values during filter +development. It is a public function so badly coded filters won’t go +unnoticed.

+

If no values are set, then upper and lower default to the max and min values +allowed in the current format. If an out of bounds value is +encountered a frame error is set and the coordinates of the first bad pixel +are included in the error message.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/planestats.html b/Programs/doc/functions/video/planestats.html new file mode 100644 index 0000000..3a18eaa --- /dev/null +++ b/Programs/doc/functions/video/planestats.html @@ -0,0 +1,198 @@ + + + + + + + PlaneStats — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

PlaneStats

+
+
+std.PlaneStats(vnode clipa[, vnode clipb, int plane=0, string prop='PlaneStats'])
+

This function calculates the min, max and average normalized value of all +the pixels in the specified plane and stores the values in the frame properties +named propMin, propMax and propAverage.

+

If clipb is supplied, the absolute normalized difference between the two clips +will be stored in propDiff as well.

+

The normalization means that the average and the diff will always be floats +between 0 and 1, no matter what the input format is.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/premultiply.html b/Programs/doc/functions/video/premultiply.html new file mode 100644 index 0000000..f72bc10 --- /dev/null +++ b/Programs/doc/functions/video/premultiply.html @@ -0,0 +1,198 @@ + + + + + + + PreMultiply — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

PreMultiply

+
+
+std.PreMultiply(vnode clip, vnode alpha)
+

PreMultiply simply multiplies clip and alpha in order to make it more suitable for +later operations. This will yield much better results when resizing and a clip with an +alpha channel and MaskedMerge can use it as input. The alpha clip +must be the grayscale format equivalent of clip.

+

Note that limited range pre-multiplied contents excludes the offset. For example with +8 bit input 60 luma and 128 alpha would be calculated as ((60 - 16) * 128)/255 + 16 +and not (60 * 128)/255.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/prewitt_sobel.html b/Programs/doc/functions/video/prewitt_sobel.html new file mode 100644 index 0000000..b56d810 --- /dev/null +++ b/Programs/doc/functions/video/prewitt_sobel.html @@ -0,0 +1,212 @@ + + + + + + + Prewitt/Sobel — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Prewitt/Sobel

+
+
+std.Prewitt(vnode clip[, int[] planes=[0, 1, 2], float scale=1])
+

Creates an edge mask using the Prewitt operator.

+
+ +
+
+std.Sobel(vnode clip[, int[] planes=[0, 1, 2], float scale=1])
+

Creates an edge mask using the Sobel operator.

+
+
clip

Clip to process. It must have integer sample type and bit depth +between 8 and 16, or float sample type and bit depth of 32. If +there are any frames with other formats, an error will be +returned.

+
+
planes

Specifies which planes will be processed. Any unprocessed planes +will be simply copied.

+
+
scale

Multiply all pixels by scale before outputting. This can be used to +increase or decrease the intensity of edges in the output.

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/proptoclip.html b/Programs/doc/functions/video/proptoclip.html new file mode 100644 index 0000000..369849d --- /dev/null +++ b/Programs/doc/functions/video/proptoclip.html @@ -0,0 +1,196 @@ + + + + + + + PropToClip — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

PropToClip

+
+
+std.PropToClip(vnode clip[, string prop='_Alpha'])
+

Extracts a clip from the frames attached to the frame property prop in +clip. +This function is mainly used to extract a mask/alpha clip that was stored in +another one.

+

It is the inverse of ClipToProp().

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/removeframeprops.html b/Programs/doc/functions/video/removeframeprops.html new file mode 100644 index 0000000..c4baa86 --- /dev/null +++ b/Programs/doc/functions/video/removeframeprops.html @@ -0,0 +1,194 @@ + + + + + + + RemoveFrameProps — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

RemoveFrameProps

+
+
+std.RemoveFrameProps(vnode clip[, string props[]])
+

Returns clip but with all the frame properties named in +props removed. If props is unset them all frame properties +are removed.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/resize.html b/Programs/doc/functions/video/resize.html new file mode 100644 index 0000000..85ba18c --- /dev/null +++ b/Programs/doc/functions/video/resize.html @@ -0,0 +1,475 @@ + + + + + + + Resize — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Resize

+
+
+resize.Bilinear(vnode clip[, int width, int height, int format, enum matrix, enum transfer, enum primaries, enum range, enum chromaloc, enum matrix_in, enum transfer_in, enum primaries_in, enum range_in, enum chromaloc_in, float filter_param_a, float filter_param_b, string resample_filter_uv, float filter_param_a_uv, float filter_param_b_uv, string dither_type="none", string cpu_type, float src_left, float src_top, float src_width, float src_height, float nominal_luminance])
+
+resize.Bicubic(vnode clip[, ...])
+
+resize.Point(vnode clip[, ...])
+
+resize.Lanczos(vnode clip[, ...])
+
+resize.Spline16(vnode clip[, ...])
+
+resize.Spline36(vnode clip[, ...])
+
+resize.Spline64(vnode clip[, ...])
+
+resize.Bob(vnode clip, string filter="bicubic", bint tff[, ...])
+

In VapourSynth the resizers have several functions. In addition to scaling, +they also do colorspace conversions and conversions to and from the compat +formats. Resize converts a clip of known or unknown format to another clip +of known or unknown format, changing only the parameters specified by the +user. The resize filters can handle varying size and format input clips +and turn them into constant format clips.

+

If you do not know which resizer to choose, then try Bicubic. It usually +makes a good neutral default.

+

Bob can be used as a rudimentary deinterlacer.

+

Arguments denoted as type enum may be specified by numerical index (see +ITU-T H.265 Annex E.3) or by name. Enums specified by name have their +argument name suffixed with “_s”. For example, a destination matrix of +BT 709 can be specified either with matrix=1 or with matrix_s="709".

+

Note that matrix is not an optional argument when converting to YUV. +Also note that if no matrix is specified in an input YUV frame’s properties +then matrix_in also needs to be set.

+

The function will return an error if the subsampling restrictions aren’t +followed.

+

If you get an error like:

+
Resize error 3074: no path between colorspaces (2/2/2 => 1/1/1).
+May need to specify additional colorspace parameters.
+
+
+

It usually means the matrix/transfer/primaries are unknown and you have to +specify the input colorspace parameters yourself. Note: 2 means “unspecified” +according to the ITU-T recommendation.

+

Resizing is performed per-field for interlaced images, as indicated by the +_FieldBased frame property. Source filters may sometimes mark progressive +video as interlaced, which can result in sub-optimal resampling quality +unless _FieldBased is cleared.

+

clip:

+
+

Accepts all kinds of input.

+
+

width, height:

+
+

Output image dimensions.

+
+

filter:

+
+

Scaling method for deinterlacing. See resample_filter_uv for accepted values.

+
+

tff:

+
+

Field order for deinterlacing. Used when the _FieldBased property is not set.

+
+

format:

+
+

Output format id.

+
+

matrix, transfer, primaries:

+
+

Output colorspace specification. If not provided, the corresponding attributes from +the input clip will be selected, except for YCoCg and RGB color families, where the +corresponding matrix is set by default.

+
+

range:

+
+

Output pixel range. For integer formats, this allows selection of the legal code +values. Even when set, out of range values (BTB/WTW) may be generated. If the input +format is of a different color family, the default range is studio/limited for YUV +and full-range for RGB.

+
+

chromaloc:

+
+

Output chroma location. For subsampled formats, specifies the chroma location. If +the input format is 4:4:4 or RGB and the output is subsampled, the default location +is left-aligned, as per MPEG. Possible chroma locations (ITU-T H.265 Figure E.1): +left, center, top_left, top, bottom_left, bottom

+
+

matrix_in, transfer_in, primaries_in, range_in, chromaloc_in:

+
+

Input colorspace/format specification. If the corresponding frame property is set +to a value other than unspecified, the frame property is used instead of this parameter. +Default values are set for certain color families. See the equivalent output arguments +for more information.

+
+

filter_param_a, filter_param_b:

+
+

Parameters for the scaler used for RGB and Y-channel. For the bicubic filter, +filter_param_a/b represent the “b” and “c” parameters. For the lanczos filter, +filter_param_a represents the number of taps.

+
+

resample_filter_uv:

+
+

Scaling method for UV channels. It defaults to the same as for the Y-channel. The +following values can be used with resample_filter_uv: point, bilinear, bicubic, +spline16, spline36, lanczos.

+
+

filter_param_a_uv, filter_param_b_uv:

+
+

Parameters for the scaler used for UV channels.

+
+

dither_type:

+
+

Dithering method. Dithering is used only for conversions resulting in an integer +format. The following dithering methods are available: none, ordered, random, +error_diffusion.

+
+

cpu_type:

+
+

Only used for testing.

+
+

src_left, src_top, src_width, src_height:

+
+

Used to select the source region of the input to use. Can also be used to shift the image. +Defaults to the whole image.

+
+

nominal_luminance:

+
+

Determines the physical brightness of the value 1.0. The unit is in cd/m^2.

+
+

To convert to YV12:

+
Bicubic(clip=clip, format=vs.YUV420P8, matrix_s="709")
+
+
+

To resize and convert YUV with color information frame properties to planar RGB:

+
Bicubic(clip=clip, width=1920, height=1080, format=vs.RGB24)
+
+
+

To resize and convert YUV without color information frame properties to planar RGB:

+
Bicubic(clip=clip, width=1920, height=1080, format=vs.RGB24, matrix_in_s="709")
+
+
+

The following tables list values of selected colorspace enumerations and +their abbreviated names. (Numerical value in parentheses.) For all possible values, +see ITU-T H.265.

+
+

Matrix coefficients (ITU-T H.265 Table E.5):

+
rgb (0)        Identity
+               The identity matrix.
+               Typically used for GBR (often referred to as RGB);
+               however, may also be used for YZX (often referred to as
+               XYZ);
+709 (1)        KR = 0.2126; KB = 0.0722
+               ITU-R Rec. BT.709-5
+unspec (2)     Unspecified
+               Image characteristics are unknown or are determined by the
+               application.
+fcc (4)
+470bg (5)      KR = 0.299; KB = 0.114
+               ITU-R Rec. BT.470-6 System B, G (historical)
+               (functionally the same as the value 6 (170m))
+170m (6)       KR = 0.299; KB = 0.114
+               SMPTE 170M (2004)
+               (functionally the same as the value 5 (470bg))
+240m (7)       SMPTE 240M
+ycgco (8)      YCgCo
+2020ncl (9)    KR = 0.2627; KB = 0.0593
+               Rec. ITU-R BT.2020 non-constant luminance system
+2020cl (10)    KR = 0.2627; KB = 0.0593
+               Rec. ITU-R BT.2020 constant luminance system
+chromancl (12) Chromaticity derived non-constant luminance system
+chromacl (13)  Chromaticity derived constant luminance system
+ictcp (14)     ICtCp
+
+
+

Transfer characteristics (ITU-T H.265 Table E.4):

+
709 (1)        V = a * Lc0.45 - ( a - 1 ) for 1 >= Lc >= b
+               V = 4.500 * Lc for b > Lc >= 0
+               Rec. ITU-R BT.709-5
+               (functionally the same as the values 6 (601),
+               14 (2020_10) and 15 (2020_12))
+unspec (2)     Unspecified
+               Image characteristics are unknown or are determined by the
+               application.
+470m (4)       ITU-R Rec. BT.470-6 System M
+470bg (5)      ITU-R Rec. BT.470-6 System B, G (historical)
+601 (6)        V = a * Lc0.45 - ( a - 1 ) for 1 >= Lc >= b
+               V = 4.500 * Lc for b > Lc >= 0
+               Rec. ITU-R BT.601-6 525 or 625
+               (functionally the same as the values 1 (709),
+               14 (2020_10) and 15 (2020_12))
+240m (7)       SMPTE 240M
+linear (8)     V = Lc for all values of Lc
+               Linear transfer characteristics
+log100 (9)     Log 1:100 contrast
+log316 (10)    Log 1:316 contrast
+xvycc (11)     IEC 61966-2-4
+srgb (13)      IEC 61966-2-1
+2020_10 (14)   V = a * Lc0.45 - ( a - 1 ) for 1 >= Lc >= b
+               V = 4.500 * Lc for b > Lc >= 0
+               Rec. ITU-R BT.2020
+               (functionally the same as the values 1 (709),
+               6 (601) and 15 (2020_12))
+2020_12 (15)   V = a * Lc0.45 - ( a - 1 ) for 1 >= Lc >= b
+               V = 4.500 * Lc for b > Lc >= 0
+               Rec. ITU-R BT.2020
+               (functionally the same as the values 1 (709),
+               6 (601) and 14 (2020_10))
+st2084 (16)    SMPTE ST 2084
+std-b67 (18)   ARIB std-b67
+
+
+

Color primaries (ITU-T H.265 Table E.3):

+
709 (1)        primary x y
+               green 0.300 0.600
+               blue 0.150 0.060
+               red 0.640 0.330
+               white D65 0.3127 0.3290
+               Rec. ITU-R BT.709-5
+unspec (2)     Unspecified
+               Image characteristics are unknown or are determined by the
+               application.
+470m (4)       ITU-R Rec. BT.470-6 System M
+470bg (5)      ITU-R Rec. BT.470-6 System B, G (historical)
+170m (6)       primary x y
+               green 0.310 0.595
+               blue 0.155 0.070
+               red 0.630 0.340
+               white D65 0.3127 0.3290
+               SMPTE 170M (2004)
+               (functionally the same as the value 7 (240m))
+240m (7)       primary x y
+               green 0.310 0.595
+               blue 0.155 0.070
+               red 0.630 0.340
+               white D65 0.3127 0.3290
+               SMPTE 240M (1999)
+               (functionally the same as the value 6 (170m))
+film (8)
+2020 (9)       primary x y
+               green 0.170 0.797
+               blue 0.131 0.046
+               red 0.708 0.292
+               white D65 0.3127 0.3290
+               Rec. ITU-R BT.2020
+st428 (10)     Commonly known as xyz
+xyz (10)       Alias for st428
+st431-2 (11)   DCI-P3 with traditional white point
+st432-1 (12)   DCI-P3
+jedec-p22 (22) E.B.U. STANDARD FOR CHROMATICITY TOLERANCES FOR STUDIO MONITORS (3213-E)
+               Also known as JEDEC P22
+
+
+

Pixel range (ITU-T H.265 Eq E-4 to E-15):

+
limited (0) Studio (TV) legal range, 16-235 in 8 bits.
+            Y = Clip1Y( Round( ( 1 << ( BitDepthY - 8 ) ) *
+                                      ( 219 * E'Y + 16 ) ) )
+            Cb = Clip1C( Round( ( 1 << ( BitDepthC - 8 ) ) *
+                                       ( 224 * E'PB + 128 ) ) )
+            Cr = Clip1C( Round( ( 1 << ( BitDepthC - 8 ) ) *
+                                       ( 224 * E'PR + 128 ) ) )
+
+            R = Clip1Y( ( 1 << ( BitDepthY - 8 ) ) *
+                               ( 219 * E'R + 16 ) )
+            G = Clip1Y( ( 1 << ( BitDepthY - 8 ) ) *
+                               ( 219 * E'G + 16 ) )
+            B = Clip1Y( ( 1 << ( BitDepthY - 8 ) ) *
+                               ( 219 * E'B + 16 ) )
+full (1)    Full (PC) dynamic range, 0-255 in 8 bits.
+            Y = Clip1Y( Round( ( ( 1 << BitDepthY ) - 1 ) * E'Y ) )
+            Cb = Clip1C( Round( ( ( 1 << BitDepthC ) - 1 ) * E'PB +
+                                  ( 1 << ( BitDepthC - 1 ) ) ) )
+            Cr = Clip1C( Round( ( ( 1 << BitDepthC ) - 1 ) * E'PR +
+                                  ( 1 << ( BitDepthC - 1 ) ) ) )
+
+            R = Clip1Y( ( ( 1 << BitDepthY ) - 1 ) * E'R )
+            G = Clip1Y( ( ( 1 << BitDepthY ) - 1 ) * E'G )
+            B = Clip1Y( ( ( 1 << BitDepthY ) - 1 ) * E'B )
+
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/reverse.html b/Programs/doc/functions/video/reverse.html new file mode 100644 index 0000000..70f9449 --- /dev/null +++ b/Programs/doc/functions/video/reverse.html @@ -0,0 +1,194 @@ + + + + + + + Reverse — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Reverse

+
+
+std.Reverse(vnode clip)
+

Returns a clip with the frame or sample order reversed. For example, a clip with 3 +frames would have the frame order 2, 1, 0.

+

In Python, std.Reverse can also be invoked by slicing a clip.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/selectevery.html b/Programs/doc/functions/video/selectevery.html new file mode 100644 index 0000000..09a5f68 --- /dev/null +++ b/Programs/doc/functions/video/selectevery.html @@ -0,0 +1,213 @@ + + + + + + + SelectEvery — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

SelectEvery

+
+
+std.SelectEvery(vnode clip, int cycle, int[] offsets[, bint modify_duration=True])
+

Returns a clip with only some of the frames in every cycle selected. The +offsets given must be between 0 and cycle - 1.

+

Below are some examples of useful operations.

+

Return even numbered frames, starting with 0:

+
SelectEvery(clip=clip, cycle=2, offsets=0)
+
+
+

Return odd numbered frames, starting with 1:

+
SelectEvery(clip=clip, cycle=2, offsets=1)
+
+
+

Fixed pattern 1 in 5 decimation, first frame in every cycle removed:

+
SelectEvery(clip=clip, cycle=5, offsets=[1, 2, 3, 4])
+
+
+

Duplicate every fourth frame:

+
SelectEvery(clip=clip, cycle=4, offsets=[0, 1, 2, 3, 3])
+
+
+

In Python, std.SelectEvery can also be invoked by slicing a clip.

+

If modify_duration is set the clip’s frame rate is multiplied by the number +of offsets and divided by cycle. The frame durations are adjusted in the same manner.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/separatefields.html b/Programs/doc/functions/video/separatefields.html new file mode 100644 index 0000000..c950470 --- /dev/null +++ b/Programs/doc/functions/video/separatefields.html @@ -0,0 +1,201 @@ + + + + + + + SeparateFields — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

SeparateFields

+
+
+std.SeparateFields(vnode clip[, bint tff, bint modify_duration=True])
+

Returns a clip with the fields separated and interleaved.

+

The tff argument only has an effect when the field order isn’t set for a frame. +Setting tff to true means top field first and false means bottom field +first.

+

If modify_duration is set then the output clip’s frame rate is double that of the input clip. +The frame durations will also be halved.

+

The _FieldBased frame property is deleted. The _Field frame +property is added.

+

If no field order is specified in _FieldBased or tff an error +will be returned.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/setfieldbased.html b/Programs/doc/functions/video/setfieldbased.html new file mode 100644 index 0000000..902c496 --- /dev/null +++ b/Programs/doc/functions/video/setfieldbased.html @@ -0,0 +1,208 @@ + + + + + + + SetFieldBased — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

SetFieldBased

+
+
+std.SetFieldBased(vnode clip, int value)
+

This is a convenience function. See SetFrameProps if you want to +set other properties.

+

SetFieldBased sets _FieldBased to value and deletes +the _Field frame property. The possible values are:

+
+

0 = Frame Based

+

1 = Bottom Field First

+

2 = Top Field First

+
+

For example, if you have source material that’s progressive but has +been encoded as interlaced you can set it to be treated as frame based +(not interlaced) to improve resizing quality:

+
clip = core.bs.VideoSource("rule6.mkv")
+clip = core.std.SetFieldBased(clip, 0)
+clip = clip.resize.Bilinear(clip, width=320, height=240)
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/setframeprop.html b/Programs/doc/functions/video/setframeprop.html new file mode 100644 index 0000000..1d34cb5 --- /dev/null +++ b/Programs/doc/functions/video/setframeprop.html @@ -0,0 +1,202 @@ + + + + + + + SetFrameProp — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

SetFrameProp

+
+
+std.SetFrameProp(vnode clip, string prop[, int[] intval, float[] floatval, string[] data])
+

Adds a frame property to every frame in clip.

+

If there is already a property with the name prop in the frames, +it will be overwritten.

+

The type of the property added depends on which of the intval, +floatval, or data parameters is used.

+

The data parameter can only be used to add NULL-terminated strings, +not arbitrary binary data.

+

For example, to set the field order to top field first:

+
clip = c.std.SetFrameProp(clip, prop="_FieldBased", intval=2)
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/setframeprops.html b/Programs/doc/functions/video/setframeprops.html new file mode 100644 index 0000000..531ca8b --- /dev/null +++ b/Programs/doc/functions/video/setframeprops.html @@ -0,0 +1,198 @@ + + + + + + + SetFrameProps — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

SetFrameProps

+
+
+std.SetFrameProps(vnode clip, ...)
+

Adds the specified values as a frame property of every frame +in clip. If a frame property with the same key already exists +it will be replaced.

+

For example, to set the field order to top field first:

+
clip = c.std.SetFrameProps(clip, _FieldBased=2)
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/setvideocache.html b/Programs/doc/functions/video/setvideocache.html new file mode 100644 index 0000000..02130cc --- /dev/null +++ b/Programs/doc/functions/video/setvideocache.html @@ -0,0 +1,209 @@ + + + + + + + SetVideoCache — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

SetVideoCache

+
+
+std.SetVideoCache(vnode clip[, int mode, int fixedsize, int maxsize, int historysize])
+

Every filter node has a cache associated with it that +may or may not be enabled depending on the dependencies +and request patterns. This function allows all automatic +behavior to be overridden.

+

The mode option has 3 possible options where 0 always +disables caching, 1 always enables the cache and -1 +uses the automatically calculated settings. Note that +setting mode to -1 will reset the other values to +their defaults as well.

+

The other options are fairly self-explanatory where +setting fixedsize prevents the cache from over time +altering its maxsize based on request history. The +final historysize argument controls how many previous +and no longer cached requests should be considered when +adjusting maxsize, generally this value should not +be touched at all.

+

Note that setting mode will reset all other options +to their defaults.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/shuffleplanes.html b/Programs/doc/functions/video/shuffleplanes.html new file mode 100644 index 0000000..a2bf89c --- /dev/null +++ b/Programs/doc/functions/video/shuffleplanes.html @@ -0,0 +1,227 @@ + + + + + + + ShufflePlanes — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ShufflePlanes

+
+
+std.ShufflePlanes(vnode[] clips, int[] planes, int colorfamily)
+

ShufflePlanes can extract and combine planes from different clips in the most +general way possible. +This is both good and bad, as there are almost no error checks.

+

Most of the returned clip’s properties are implicitly determined from the +first clip given to clips.

+

The clips parameter takes between one and three clips for color families +with three planes. In this case clips=[A] is equivalent to clips=[A, A, A] +and clips=[A, B] is equivalent to clips=[A, B, B]. For the GRAY color +family, which has one plane, it takes exactly one clip.

+

The argument planes controls which of the input clips’ planes to use. +Zero indexed. The first number refers to the first input clip, the second +number to the second clip, the third number to the third clip.

+

The only thing that needs to be specified is colorfamily, which controls which +color family (YUV, RGB, GRAY) the output clip will be. +Properties such as subsampling are determined from the relative size of the +given planes to combine.

+

ShufflePlanes accepts clips with variable format and dimensions only when +extracting a single plane.

+

Below are some examples of useful operations.

+

Extract plane with index X. X=0 will mean luma in a YUV clip and R in an RGB +clip. Likewise 1 will return the U and G channels, respectively:

+
ShufflePlanes(clips=clip, planes=X, colorfamily=vs.GRAY)
+
+
+

Swap U and V in a YUV clip:

+
ShufflePlanes(clips=clip, planes=[0, 2, 1], colorfamily=vs.YUV)
+
+
+

Merge 3 grayscale clips into a YUV clip:

+
ShufflePlanes(clips=[Yclip, Uclip, Vclip], planes=[0, 0, 0], colorfamily=vs.YUV)
+
+
+

Cast a YUV clip to RGB:

+
ShufflePlanes(clips=[YUVclip], planes=[0, 1, 2], colorfamily=vs.RGB)
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/splice.html b/Programs/doc/functions/video/splice.html new file mode 100644 index 0000000..41d3a89 --- /dev/null +++ b/Programs/doc/functions/video/splice.html @@ -0,0 +1,195 @@ + + + + + + + Splice — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Splice

+
+
+std.Splice(vnode[] clips[, bint mismatch=0])
+

Returns a clip with all clips appended in the given order.

+

Splicing clips with different formats or dimensions is +considered an error unless mismatch is true.

+

In Python, std.Splice can also be invoked using the addition operator.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/splitplanes.html b/Programs/doc/functions/video/splitplanes.html new file mode 100644 index 0000000..aa5bd07 --- /dev/null +++ b/Programs/doc/functions/video/splitplanes.html @@ -0,0 +1,193 @@ + + + + + + + SplitPlanes — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/stackvertical_stackhorizontal.html b/Programs/doc/functions/video/stackvertical_stackhorizontal.html new file mode 100644 index 0000000..55519e4 --- /dev/null +++ b/Programs/doc/functions/video/stackvertical_stackhorizontal.html @@ -0,0 +1,198 @@ + + + + + + + StackVertical/StackHorizontal — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

StackVertical/StackHorizontal

+
+
+std.StackVertical(vnode[] clips)
+
+std.StackHorizontal(vnode[] clips)
+

Stacks all given clips together. The same format is a requirement. For +StackVertical all clips also need to be the same width and for +StackHorizontal all clips need to be the same height.

+

The frame properties are copied from the first clip.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/text/clipinfo.html b/Programs/doc/functions/video/text/clipinfo.html new file mode 100644 index 0000000..90e46fa --- /dev/null +++ b/Programs/doc/functions/video/text/clipinfo.html @@ -0,0 +1,197 @@ + + + + + + + ClipInfo — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ClipInfo

+
+
+text.ClipInfo(vnode clip[, int alignment=7, int scale=1]])
+

Prints information about the clip, such as the format and framerate.

+

This is a convenience function for Text.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/text/coreinfo.html b/Programs/doc/functions/video/text/coreinfo.html new file mode 100644 index 0000000..c16b227 --- /dev/null +++ b/Programs/doc/functions/video/text/coreinfo.html @@ -0,0 +1,198 @@ + + + + + + + CoreInfo — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CoreInfo

+
+
+text.CoreInfo([vnode clip=std.BlankClip(), int alignment=7, int scale=1])
+

Prints information about the VapourSynth core, such as version and memory +use. If no clip is supplied, a default blank one is used.

+

This is a convenience function for Text.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/text/framenum.html b/Programs/doc/functions/video/text/framenum.html new file mode 100644 index 0000000..18b518e --- /dev/null +++ b/Programs/doc/functions/video/text/framenum.html @@ -0,0 +1,197 @@ + + + + + + + FrameNum — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/text/frameprops.html b/Programs/doc/functions/video/text/frameprops.html new file mode 100644 index 0000000..6d1bfc7 --- /dev/null +++ b/Programs/doc/functions/video/text/frameprops.html @@ -0,0 +1,198 @@ + + + + + + + FrameProps — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

FrameProps

+
+
+text.FrameProps(vnode clip[, string props=[], int alignment=7, int scale=1])
+

Prints all properties attached to the frames, or if the props array is +given only those properties.

+

This is a convenience function for Text.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/text/text.html b/Programs/doc/functions/video/text/text.html new file mode 100644 index 0000000..b3a6640 --- /dev/null +++ b/Programs/doc/functions/video/text/text.html @@ -0,0 +1,208 @@ + + + + + + + Text — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Text

+
+
+text.Text(vnode clip, string text[, int alignment=7, int scale=1])
+

Text is a simple text printing filter. It doesn’t use any external libraries +for drawing the text. It uses a built-in bitmap font: the not-bold, 8×16 +version of Terminus. The font was not modified, only converted from PCF to an +array of bytes.

+

The font covers Windows-1252, which is a superset of ISO-8859-1 (aka latin1). +Unprintable characters get turned into underscores. Long lines get wrapped in +a dumb way. Lines that end up too low to fit in the frame are silently +dropped.

+

The alignment parameter takes a number from 1 to 9, corresponding to the +positions of the keys on a numpad.

+

The scale parameter sets an integer scaling factor for the bitmap font.

+

ClipInfo, CoreInfo, FrameNum, and FrameProps are convenience functions +based on Text.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/transpose.html b/Programs/doc/functions/video/transpose.html new file mode 100644 index 0000000..0818873 --- /dev/null +++ b/Programs/doc/functions/video/transpose.html @@ -0,0 +1,203 @@ + + + + + + + Transpose — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Transpose

+
+
+std.Transpose(vnode clip)
+

Flips the contents of the frames in the same way as a matrix transpose would +do. Combine it with FlipVertical or FlipHorizontal to synthesize a left or +right rotation. Calling Transpose twice in a row is the same as doing nothing +(but slower).

+

Here is a picture to illustrate what Transpose does:

+
                          0   5  55
+ 0   1   1   2   3        1   8  89
+ 5   8  13  21  34   =>   1  13 144
+55  89 144 233 377        2  21 233
+                          3  34 377
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/trim.html b/Programs/doc/functions/video/trim.html new file mode 100644 index 0000000..90eee99 --- /dev/null +++ b/Programs/doc/functions/video/trim.html @@ -0,0 +1,200 @@ + + + + + + + Trim — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Trim

+
+
+std.Trim(vnode clip[, int first=0, int last, int length])
+

Trim returns a clip with only the frames between the arguments first and +last, or a clip of length frames, starting at first. +Trim is inclusive so Trim(clip, first=3, last=3) will return one frame. If +neither last nor length is specified, no frames are removed from the end +of the clip.

+

Specifying both last and length is considered to be an error. +Likewise is calling Trim in a way that returns no frames, as 0 frame clips are +not allowed in VapourSynth.

+

In Python, std.Trim can also be invoked by slicing a clip.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/functions/video/turn180.html b/Programs/doc/functions/video/turn180.html new file mode 100644 index 0000000..ef5ca9f --- /dev/null +++ b/Programs/doc/functions/video/turn180.html @@ -0,0 +1,192 @@ + + + + + + + Turn180 — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Programs/doc/genindex.html b/Programs/doc/genindex.html new file mode 100644 index 0000000..c2e9ce2 --- /dev/null +++ b/Programs/doc/genindex.html @@ -0,0 +1,990 @@ + + + + + + Index — VapourSynth R64 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Index

+ +
+ _ + | A + | B + | C + | D + | E + | F + | G + | H + | I + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + +
+

_

+ + +
+ +

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

Q

+ + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ + + +
+
+
+ +
+ +
+

© Copyright 2012-2023, Fredrik Mellbin.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/gettingstarted.html b/Programs/doc/gettingstarted.html new file mode 100644 index 0000000..dd37121 --- /dev/null +++ b/Programs/doc/gettingstarted.html @@ -0,0 +1,187 @@ + + + + + + + Getting Started — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Getting Started

+

So you managed to install VapourSynth. Now what?

+

If you don’t know the basics of Python, you may want to check out a +tutorial.

+

You can “play around” in the python interpreter if you want, but that’s not how +most scripts are created.

+
+

Example Script

+

It all starts with a .vpy script. +Here’s a sample script to be inspired by, it assumes that BestSource +is installed and auto-loaded.

+
from vapoursynth import core                     # Get an instance of the core
+clip = core.bs.VideoSource(source='filename.mkv')  # Load a video track in mkv file
+clip = core.std.FlipHorizontal(clip)             # Flip the video clip in the horizontal direction
+clip.set_output()                                # Set the video clip to be accessible for output
+
+
+

Audio is also supported, use BestSource to load your audio file.

+
from vapoursynth import core                     # Get an instance of the core
+clip = core.bs.AudioSource(source='filename.mkv')    # Load an audio track in mkv file
+clip = core.std.AudioGain(clip,gain=2.0)         # Gain all channels 2x
+clip.set_output()                                # Set the audio clip to be accessible for output
+
+
+

You can combine 2 operations in one script.

+
from vapoursynth import core
+video = core.bs.VideoSource(source='filename.mkv')
+audio = core.bs.AudioSource(source='filename.mkv')
+video = core.std.FlipHorizontal(video)
+audio = core.std.AudioGain(audio,gain=2.0)
+video.set_output(index=0)
+audio.set_output(index=1)
+
+
+

Remember that most VapourSynth objects have a quite nice string representation +in Python, so if you want to know more about an instance just call print().

+
+
+

Preview

+

It’s possible to directly open the script in VapourSynth Editor +or VirtualDub FilterMod for previewing.

+
+
+

Output with VSPipe

+

VSPipe is very useful to pipe the output to various applications, for example x264 and flac for encoding.

+

Here are some examples of command lines that automatically pass on most video and audio attributes.

+

For x264:

+
vspipe -c y4m script.vpy - | x264 --demuxer y4m - --output encoded.264
+
+
+

For flac:

+
vspipe -c wav script.vpy - | flac - -o encoded.flac
+
+
+

For FFmpeg:

+
vspipe -c y4m script.vpy - | ffmpeg -i - encoded.mkv
+
+
+

For mpv:

+
vspipe -c y4m script.vpy - | mpv -
+vspipe -c wav script.vpy - | mpv -
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/index.html b/Programs/doc/index.html new file mode 100644 index 0000000..7f25471 --- /dev/null +++ b/Programs/doc/index.html @@ -0,0 +1,324 @@ + + + + + + + Welcome to VapourSynth’s documentation! — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Welcome to VapourSynth’s documentation!

+

Contents:

+
+ +
+
+
+

Indices and tables

+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/installation.html b/Programs/doc/installation.html new file mode 100644 index 0000000..5d5b7d1 --- /dev/null +++ b/Programs/doc/installation.html @@ -0,0 +1,476 @@ + + + + + + + Installation — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Installation

+
+

Basic Program

+

The installation contains two main steps:

+
    +
  1. Install VapourSynth core library.

  2. +
  3. Install the Python wrapper of VapourSynth.

  4. +
+

After you completed the second step, you can test it by opening a Python command line +and type this:

+
from vapoursynth import core
+print(core.version())
+
+
+

After pressing return at the final line, you should see the version printed along with a +few other lines describing the options used when instantiating the Core object. +In fact, these lines should be the same as the output result of vspipe --version.

+
+

Windows Installation

+
+

Prerequisites

+
+
First download and install the prerequisites:
    +
  • Python 3.11.x or Python 3.8.x – 32 or 64 bit version depending on which version of VapourSynth you want to install

  • +
+
+
+

Note that VapourSynth and Python have to be matched so both are either installed +for all users or for only for the current user.

+

Also note that per user installs will not install the required Visual Studio +2019 runtimes.

+
+
+

Installation

+

Simply run the VapourSynth installer. +It should automatically detect and install everything, including the Python wrapper.

+

If the tests mentioned at the beginning fails, there may be a bug in the installer or there are +old copies of vapoursynth.pyd and vapoursynth.dll lying around.

+
+
+
+

Windows Installation (Portable)

+
+
First download and decompress the prerequisites:
    +
  • Python 3.11.x or Python 3.8.x – 32 or 64 bit embeddable version

  • +
+
+
+

Simply decompress the portable VapourSynth archive +into the Python dir and overwrite all existing files.Run vs-detect-python.bat +to configure it for the current Python version. Done.

+

You can also use the VapourSynth Editor by decompressing it into the same directory.

+
+
+

OS X Installation

+
+
First download and install the prerequisites:
    +
  • Xcode – Available from the AppStore

  • +
  • Homebrew – A package manager

  • +
+
+
+

Simply run these commands in a terminal and wait for them to complete:

+
brew install vapoursynth
+
+
+
+
+

Linux installation

+

Several distributions have VapourSynth packages. Note that those packages are usually OUT OF DATE.

+
+

Debian

+

The VapourSynth packages are provided by deb-multimedia repository. +You need to add the repository first following the guide on the official website.

+
+
+

Fedora, CentOS and RHEL

+

For Fedora, the VapourSynth packages can be downloaded from official repository directly. +For CentOS and RHEL, you should install EPEL (Extra Packages for Enterprise Linux) repository first.

+
+
+

Gentoo

+

There is an unofficial Portage tree with all VapourSynth related ebuilds. +Check the Github link for more information and instructions.

+
+
+

Arch Linux

+

VapourSynth-related packages are provided by the Community repository.

+
+
+

Nix and NixOS

+

vapoursynth is available on nixpkgs, either via nixpkgs#vapoursynth or via nixpkgs#python3Packages.vapoursynth (currently on unstable only). +Be aware that the derivation is broken on MacOS.

+

VapourSynth releases are not backported to the current stable branch. +To get the newest version use the unstable branch.

+
+
+
+

Windows Compilation

+
+

Preparing the Build Environment on Windows

+

Default install paths are assumed in all projects and scripts, be prepared to adjust many things if you changed them

+

Required languages and applications:

+
    +
  • Needs Visual Studio 2019

  • +
  • It also needs both 32bit and 64bit Python 3.8.x and 3.11.x (the msvc project assumes that you installed python for all users.)

  • +
  • InnoSetup is needed to create the installer (default installation path assumed)

  • +
  • 7-zip is needed to compress the portable version (default installation path assumed)

  • +
+
+
+

Preparing the C++ Project

+
    +
  • Clone VapourSynth

  • +
  • Clone VSRepo into the VapourSynth dir (git clone https://github.com/vapoursynth/vsrepo)

  • +
  • Clone zimg into the VapourSynth dir (git clone https://github.com/sekrit-twc/zimg.git --recurse-submodules)

  • +
  • Clone avs+ into the VapourSynth dir (git clone https://github.com/AviSynth/AviSynthPlus.git)

  • +
  • Clone libp2p into the VapourSynth dir (git clone https://github.com/sekrit-twc/libp2p.git)

  • +
  • Compile 32 and 64 bit releases using the VapourSynth solution

  • +
+
+
+

Preparing the Python Project

+
    +
  • Run py -3.11 -m pip install -r python-requirements.txt for 64bit.

  • +
  • Run py -3.8 -m pip install -r python-requirements.txt for 64bit.

  • +
  • Run cython_build.bat to compile the Python modules

  • +
  • Run docs_build.bat to compile the documentation

  • +
+
+
+

Distribution

+

All the above steps are necessary to create the installer

+

You also need 7z.exe and 7z.dll from 7-zip +Both need to be placed in the “installer” dir.

+

You’ll also have to grab the file pfm-192-vapoursynth-win.exe +which is only available from installations/portable releases.

+

Run make_portable.bat and make_installers.bat to package things.

+
+

Note

+

Note that the Avisynth side of AVFS won’t work properly in debug builds (memory allocation and exceptions across module boundaries trolololol)

+
+
+
+
+

Linux and OS X Compilation

+
+
These are the requirements:
    +
  • Autoconf, Automake, and Libtool, probably recent versions

  • +
  • pkg-config

  • +
  • GCC 4.8 or newer, or Clang

  • +
  • zimg

  • +
  • Python 3

  • +
  • Cython 0.28 or later installed in your Python 3 environment

  • +
  • Sphinx for the documentation (optional)

  • +
+
+
+

Note: any version of Python 3 will do. A specific version is only +required when using the official Windows binaries.

+
+

Required packages (OS X)

+
+
First download and install the prerequisites:
    +
  • Xcode – Available from the AppStore

  • +
  • Homebrew – A package manager

  • +
+
+
+

Installation of the required packages is very easy. Simply run these +commands in a terminal and wait for them to complete:

+
brew install python3 ffmpeg libass zimg imagemagick
+pip3 install cython
+
+
+

If you’ve already installed all the required packages and instead want +to update them, simply run:

+
brew update && brew upgrade
+pip3 install --upgrade cython
+
+
+
+
+

Compilation

+

If you haven’t checked out the source code before, use git to do so:

+
git clone https://github.com/vapoursynth/vapoursynth.git
+
+
+

Or if you already have a copy of the source, update it with:

+
git pull
+
+
+

Enter the VapourSynth directory and run these commands to compile and install:

+
./autogen.sh
+./configure
+make
+make install
+
+
+

Depending on your operating system’s configuration, VapourSynth may not +work out of the box with the default prefix of /usr/local. Two errors +may pop up when running vspipe --version:

+
    +
  • “vspipe: error while loading shared libraries: libvapoursynth-script.so.0: +cannot open shared object file: No such file or directory”

    +

    This is caused by the non-standard location of libvapoursynth-script.so.0. +Your dynamic loader is not configured to look in /usr/local/lib. One +way to work around this error is to use the LD_LIBRARY_PATH environment +variable:

    +
    $ LD_LIBRARY_PATH=/usr/local/lib vspipe --version
    +
    +
    +
  • +
  • “Failed to initialize VapourSynth environment”

    +

    This is caused by the non-standard location of the Python module, +vapoursynth.so. Your Python is not configured to look in +/usr/local/lib/python3.x/site-packages. One way to work around this +error is to use the PYTHONPATH environment variable:

    +
    $ PYTHONPATH=/usr/local/lib/python3.x/site-packages vspipe --version
    +
    +
    +

    Replace “x” with the correct number.

    +
  • +
+

The documentation can be built using its own Makefile:

+
$ make -C doc/ html
+
+
+

The documentation can be installed using the standard program cp.

+
+
+
+
+

Plugins and Scripts

+

If you’re looking for plugins and scripts then one of the most complete lists +available can be found at vsdb.top.

+
+

Installing with VSRepo

+

On windows you can use the included vsrepo.py to install and upgrade plugins and scripts.

+

Simply run vsrepo.py install <namespace or identifier> to install them.

+

If you need a list of known plugins and scripts you can run vsrepo.py available or visit vsdb.top.

+

For more reference, visit vsrepo’s repository

+
+
+

Installing Manually

+

You can put your plugin (.dll) and script (.py) to where you think it is convenient.

+

For plugins, you can use std.LoadPlugin function to load it. there is also a plugin autoloading mechanism to save your time, see blow.

+

For scripts, you should add a relative path to python<your_python_version>._pth, then you can import it in your script.

+
+
+

Plugin Autoloading

+

VapourSynth automatically loads all the native plugins located in certain +folders. Autoloading works just like manual loading, with the exception +that any errors encountered while loading a plugin are silently ignored.

+
+

Note

+

Avoid autoloading from folders that other applications might also +use, such as /usr/lib or /usr/local/lib in a Linux system. Several +users reported crashes when VapourSynth attempted to load some +random libraries (*cough*wxgtk*cough*).

+
+
+

Windows

+

Windows has in total 3 different autoloading directories: user plugins, core plugins and global plugins. They are searched in that order. +User plugins are always loaded first so that the current user can always decide which exact version of a plugin is used. Core plugins follow. +Global plugins are placed last to prevent them from overriding any of the included plugins by accident.

+

The searched paths are:

+
    +
  1. <AppData>\VapourSynth\plugins32 or <AppData>\VapourSynth\plugins64

  2. +
  3. <VapourSynth path>\core\plugins

  4. +
  5. <VapourSynth path>\plugins

  6. +
+

Note that the per user path is not created by default. +On modern Windows versions the AppData directory is located in <user>\AppData\Roaming by default.

+

Shortcuts to the global autoload directory are located in the start menu.

+

Avisynth plugins are never autoloaded. Support for this may be added in the future.

+

User plugins should never be put into the core\plugins directory.

+
+
+

Windows Portable

+

The searched paths are:

+
    +
  1. <VapourSynth.dll path>\vapoursynth32\coreplugins or <VapourSynth.dll path>\vapoursynth64\coreplugins

  2. +
  3. <VapourSynth.dll path>\vapoursynth32\plugins or <VapourSynth.dll path>\vapoursynth64\plugins

  4. +
+

User plugins should never be put into the coreplugins directory.

+
+
+

Linux

+

Autoloading can be configured using the file +$XDG_CONFIG_HOME/vapoursynth/vapoursynth.conf, +or $HOME/.config/vapoursynth/vapoursynth.conf if XDG_CONFIG_HOME is not +defined.

+

To provide your own path to the config file, you can use $VAPOURSYNTH_CONF_PATH.

+

Two configuration options may be used: UserPluginDir, empty by default, +and SystemPluginDir, whose default value is set at compile time to +$libdir/vapoursynth, or to the location passed to the --with-plugindir +argument to configure.

+

UserPluginDir is tried first, then SystemPluginDir.

+

Example vapoursynth.conf:

+
UserPluginDir=/home/asdf/vapoursynth/plugins
+SystemPluginDir=/special/non/default/location
+
+
+
+
+

OS X

+

Autoloading can be configured using the file +$HOME/Library/Application Support/VapourSynth/vapoursynth.conf. Everything else is +the same as in Linux.

+

Like on linux, you can use $VAPOURSYNTH_CONF_PATH to provide your own configuration.

+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/introduction.html b/Programs/doc/introduction.html new file mode 100644 index 0000000..cb6b68a --- /dev/null +++ b/Programs/doc/introduction.html @@ -0,0 +1,155 @@ + + + + + + + Introduction — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Introduction

+

VapourSynth is an application for video manipulation. Or a plugin. Or a library. +It’s hard to tell because it has a core library written in C++ and a Python +module to allow video scripts to be created. It came to be when I started +thinking about alternative designs for Avisynth and most of it was written +over a 3 month period.

+

The software has been heavily inspired by Avisynth +and aims to be a 21st century rewrite, taking advantage of the advancements +computers have made since the late 90s. +The main features compared to Avisynth are:

+
+
    +
  • Multithreaded - Frame level multithreading that scales well

  • +
  • Generalized Colorspaces - New colorspaces can be specified at runtime

  • +
  • Per Frame Properties - Additional metadata can be attached to frames

  • +
  • Python Based - The scripting part is implemented as a Python module so you +don’t have to learn a special language

  • +
  • Support for video with format changes - Some video just can’t stick to one +format or frame size. VapourSynth can handle any kind of change

  • +
  • Compatible with a large number of already existing Avisynth plugins

  • +
+
+
+

About the author

+

Fredrik Mellbin majored in electrical engineering with a focus on image analysis +and processing with medical applications. He has previously worked with digital +electronics and likes to plan his own software projects in his spare time. +When he one day found himself out of work he needed something to do between +sending out job applications and waiting for a reply. The natural choice for +the author was to try to improve Avisynth, the software that once made him +interested in video editing. VapourSynth is the result of all that time waiting.

+

Feel free to contact me at fredrik.mellbin that round thingy with an a gmail.com +if you need help to port a filter or want to sponsor the development.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/objects.inv b/Programs/doc/objects.inv new file mode 100644 index 0000000..3efae63 Binary files /dev/null and b/Programs/doc/objects.inv differ diff --git a/Programs/doc/output.html b/Programs/doc/output.html new file mode 100644 index 0000000..820c6ba --- /dev/null +++ b/Programs/doc/output.html @@ -0,0 +1,227 @@ + + + + + + + Output — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Output

+
+

VSPipe

+
+

Synopsis

+

vspipe <script> <outfile> [options]

+

vspipe’s main purpose is to evaluate VapourSynth scripts and output the +frames to a file.

+

If outfile is a hyphen (-), vspipe will write to the standard output.

+

If outfile is a dot (.), vspipe will do everything as usual, except it +will not write the video frames anywhere.

+
+
+

Options

+
+
-a, --arg key=value

Argument to pass to the script environment, it a key with this name and value (str typed) will be set in the globals dict

+
+
-s, --start N

Set output frame range (first frame)

+
+
-e, --end N

Set output frame range (last frame)

+
+
-o, --outputindex N

Select output index

+
+
-r, --requests N

Set number of concurrent frame requests

+
+
-c, --container <y4m/wav/w64>

Add headers for the specified format to the output

+
+
-t, --timecodes FILE

Write timecodes v2 file

+
+
-p, --progress

Print progress to stderr

+
+
--filter-time

Records the time spent in each filter and prints it out at the end of processing.

+
+
-i, --info

Show video info and exit

+
+
-g, --graph <simple/full>

Print output node filter graph in dot format to outfile and exit

+
+
-v, --version

Show version info and exit

+
+
+
+
+

Examples

+
+
Show script info:

vspipe --info script.vpy -

+
+
Write to stdout:

vspipe [options] script.vpy -

+
+
Request all frames but don’t output them:

vspipe [options] script.vpy .

+
+
Write frames 5-100 to file:

vspipe --start 5 --end 100 script.vpy output.raw

+
+
Pipe to x264 and write timecodes file:

vspipe script.vpy - --y4m --timecodes timecodes.txt | x264 --demuxer y4m -o script.mkv -

+
+
Pass values to a script:

vspipe --arg deinterlace=yes --arg "message=fluffy kittens" script.vpy output.raw

+
+
+
+
+
+

AVFS

+

AV FileSystem is based on AVFS and shares most of its +source code and functionality. This package has several uses. It can easily make +a script file openable by any application, as it appears like a real, +uncompressed avi file. It can also be used to bridge the 32/64 bit gap, since a +plain file can always be read.

+

To use it simply run avfs in the core32 or core64 directories with the script name as argument. +This will create a virtual file in C:\\Volumes.

+

The alt_output argument of set_output is respected and can be used to get additional compatibility +with professional applications.

+
+

Avisynth Support

+

Note that this AVFS version is also compatible with Avisynth 2.6 and Avisynth+. When using Avisynth+ +higher bitdepth output is also supported. The easiest way to obtain a recent version is to extract +avfs.exe from the portable VapourSynth archives.

+
+
+
+

VFW

+

On windows, you can output video to VFW based programs.

+

If you install VapourSynth by installer, the VSVFW.dll is registered already

+

Else, you could register it manually, use register file below or use theChaosCoder’s batch.

+
Windows Registry Editor Version 5.00
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{58F74CA0-BD0E-4664-A49B-8D10E6F0C131}]
+@="VapourSynth"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{58F74CA0-BD0E-4664-A49B-8D10E6F0C131}\InProcServer32]
+@="<your VSVFW.dll directory>\\VSVFW.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AVIFile\Extensions\VPY]
+@="{58F74CA0-BD0E-4664-A49B-8D10E6F0C131}"
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/pythonreference.html b/Programs/doc/pythonreference.html new file mode 100644 index 0000000..50db49d --- /dev/null +++ b/Programs/doc/pythonreference.html @@ -0,0 +1,1694 @@ + + + + + + + Python Reference — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Python Reference

+

VapourSynth is separated into a core library and a Python module. This section +explains how the core library is exposed through Python and some of the +special things unique to Python scripting, such as slicing and output.

+
+

Note

+

Any script executed through the vsscript api (that means vspipe, avfs, vsvfw or +other API users) will have __name__ set to “__vapoursynth__” unlike normal Python +scripts where it usually is “__main__”.

+
+
+

VapourSynth Structure

+

Most operations in the VapourSynth library are performed through the singleton +core object. This core may load plugins, which all end up in their own unit, +or namespace, so to say, to avoid naming conflicts in the contained functions. +For this reason you call a plugin function with core.unit.Function().

+

All arguments to functions have names that are lowercase and all function names +are CamelCase. Unit names are also lowercase and usually short. This is good to +remember as a general rule.

+
+
+

Grammar

+
+

Slicing and Other Syntactic Sugar

+

The VideoNode and AudioNode class (always called “clip” in practice) supports the full +range of indexing and slicing operations in Python. If you do perform a slicing +operation on a clip, you will get a new clip back with the desired frames. +Here are a few examples.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Operation

Description

Equivalent

clip = clip[5]

Make a single frame clip containing frame number 5

clip = clip[5:11]

Make a clip containing frames 5 to 10 [1]

clip = core.std.Trim(clip, first=5, last=10)

+

clip = core.std.AudioTrim(clip, first=5, last=10)

+

clip = clip[::2]

Select even numbered frames

clip = core.std.SelectEvery(clip, cycle=2, offsets=0)

clip = clip[1::2]

Select odd numbered frames

clip = core.std.SelectEvery(clip, cycle=2, offsets=1)

clip = clip[::-1]

Reverses a clip

clip = core.std.Reverse(clip)

+

clip = core.std.AudioReverse(clip)

+

clip = clip1 + clip2

The addition operator can be used to splice clips together

clip = core.std.Splice([clip1, clip2], mismatch=False)

+

clip = core.std.AudioSplice([clip1, clip2])

+

clip = clip * 10

The multiplication operator can be used to loop a clip [2]

clip = core.std.Loop(clip, times=10)

+

clip = core.std.AudioLoop(clip, times=10)

+
+ +

Filters can be chained with a dot:

+
clip = clip.std.Trim(first=100, last=2000).std.FlipVertical()
+
+
+

Which is quivalent to:

+
clip = core.std.FlipVertical(core.std.Trim(clip, first=100, last=2000))
+
+
+
+
+

Python Keywords as Filter Arguments

+

If a filter’s argument happens to be a Python keyword, you may append +an underscore to the argument’s name when invoking the filter. The Python +module will strip one trailing underscore (if present) from all filter arguments before +passing them to the filters.

+
clip = core.plugin.Filter(clip, lambda_=1)
+
+
+

Another way to deal with such arguments is to place them in a dictionary:

+
kwargs = { "lambda": 1 }
+clip = core.plugin.Filter(clip, **kwargs)
+
+
+

VapourSynth will also support the PEP8 convention of using a single trailing +underscore to prevent collisions with python keywords.

+
+
+

Windows File Paths

+

If you have a string containing backslashes, you must either prefix the +string with “r”, or duplicate every single backslash. The reason is +that the backslash is an escape character in Python.

+

Use os.path.normcase(path) +to fix Incorrect path string.

+

Correct example:

+
"B:/VapourSynth/VapourSynth.dll"
+"B:\\VapourSynth\\VapourSynth.dll"
+r"B:\VapourSynth\VapourSynth.dll"
+
+
+
+
+

Output

+

The normal way of specifying the clip(s) to output is to call +clip.set_output(). All standard VapourSynth components only use output +index 0, except for vspipe where it’s configurable but defaults to 0. +There are also other variables that can be set to control how a format is +output. For example, setting alt_output=1 changes the packing of the +YUV422P10 format to one that is common in professional software (like Adobe +products). Note that currently alt_output modes only has an effect with +YUV420P8 (I420, IYUV), YUV422P8 (YUY2, UYVY) and YUV422P10 (v210).

+

An example on how to get v210 output:

+
some_clip = core.resize.Bicubic(clip, format=vs.YUV422P10)
+some_clip.set_output(alt_output=1)
+
+
+

An example on how to get UYVY output:

+
some_clip = core.resize.Bicubic(clip, format=vs.YUV422P8)
+some_clip.set_output(alt_output=2)
+
+
+
+
+

Raw Access to Frame Data

+

The VideoFrame and AudioFrame classes contains one picture/audio chunk and all the metadata +associated with it. It is possible to access the raw data using either +get_read_ptr(plane) or get_write_ptr(plane) and get_stride(plane) with ctypes.

+

A more Python friendly wrapping is also available where each plane/channel can be accessed +as a Python array using frame[plane/channel].

+

To get a frame simply call get_frame(n) on a clip. Should you desire to get +all frames in a clip, use this code:

+
for frame in clip.frames():
+    # Do stuff with your frame
+    pass
+
+
+
+
+
+

Classes and Functions

+
+
+core
+

Gets the singleton Core object. If it is the first time the function is called, +the Core will be instantiated with the default options. This is the preferred +way to reference the core.

+
+ +
+
+get_outputs()
+

Return a read-only mapping of all outputs registered on the current node.

+

The mapping will automatically update when a new output is registered.

+
+ +
+
+get_output([index = 0])
+

Get a previously set output node. Throws an error if the index hasn’t been +set. Will return a VideoOutputTuple containing alpha and the alt_output setting for video output and an AudioNode for audio.

+
+ +
+
+clear_output([index = 0])
+

Clears a clip previously set for output.

+
+ +
+
+clear_outputs()
+

Clears all clips set for output in the current environment.

+
+ +
+
+construct_signature(signature[, injected=None])
+

Creates a inspect.Signature object for the given registration signature.

+

If injected is not None, the default of the first argument of the signature will be replaced with the value supplied with injected.

+
+ +
+
+register_on_destroy(callback)
+

Registers a callback that is called when the script is being finalized. +This allows you to release resources at the end of a script.

+

A callback must be registered with every script that is run, +even if the code is being reused in multiple script runs.

+

No new callbacks can be registered when the script is already being finalized.

+
+ +
+
+unregister_on_destroy(callback)
+

Unregisters a previously added callback.

+
+ +
+
+class Core
+

The Core class uses a singleton pattern. Use the core attribute to obtain an +instance. All loaded plugins are exposed as attributes of the core object. +These attributes in turn hold the functions contained in the plugin. +Use plugins() to obtain a full list of all currently loaded plugins +you may call this way.

+
+
+num_threads
+

The number of concurrent threads used by the core. Can be set to change the number. Setting to a value less than one makes it default to the number of hardware threads.

+
+ +
+
+max_cache_size
+

Set the upper framebuffer cache size after which memory is aggressively +freed. The value is in megabytes.

+
+ +
+
+plugins()
+

Containing all loaded plugins.

+
+ +
+
+get_video_format(id)
+

Retrieve a Format object corresponding to the specified id. Returns None if the id is invalid.

+
+ +
+
+query_video_format(color_family, sample_type, bits_per_sample, subsampling_w, subsampling_h)
+

Retrieve a Format object corresponding to the format information, Invalid formats throw an exception.

+
+ +
+
+create_video_frame(format, width, height)
+

Creates a new frame with uninitialized planes with the given dimensions and format. +This function is safe to call within a frame callback.

+
+ +
+
+add_log_handler(handler_func)
+

Installs a custom handler for the various error messages VapourSynth emits. +The message handler is currently global, i.e. per process, not per VSCore instance. +Returns a LogHandle object. +handler_func is a callback function of the form func(MessageType, message).

+
+ +
+
+remove_log_handler(handle)
+

Removes a custom handler.

+
+ +
+
+log_message(message_type, message)
+

Send a message through VapourSynth’s logging framework.

+
+ +
+
+version()
+

Returns version information as a string.

+
+ +
+
+version_number()
+

Returns the core version as a number.

+
+

Note

+

If you are writing a library, you should use vapoursynth.__version__ or vapoursynth.__api_version__ instead.

+
+
+ +
+
+rule6()
+

Illegal behavior detection.

+
+ +
+ +
+
+class Local
+

Internally, there can be more than one core. This is usually the case in previewer-applications. +Use this class to store variables that depend on the currently active core.

+
l = Local()
+l.test = 1
+
+
+
+ +
+
+class VideoNode
+

Represents a video clip. The class itself supports indexing and slicing to +perform trim, reverse and selectevery operations. Several operators are also +defined for the VideoNode class: addition appends clips and multiplication +repeats them. Note that slicing and indexing always return a new VideoNode +object and not a VideoFrame.

+
+
+format
+

A Format object describing the frame data. If the format can change +between frames, this value is None.

+
+ +
+
+width
+

The width of the video. This value will be 0 if the width and height can +change between frames.

+
+ +
+
+height
+

The height of the video. This value will be 0 if the width and height can +change between frames.

+
+ +
+
+num_frames
+

The number of frames in the clip.

+
+ +
+
+fps
+

The framerate represented as a Fraction. It is 0/1 when the clip has a variable +framerate.

+
+
+numerator
+

The numerator of the framerate. If the clip has variable framerate, the value will be 0.

+
+ +
+
+denominator
+

The denominator of the framerate. If the clip has variable framerate, the value will be 0.

+
+ +
+ +
+
+fps_num
+

Deprecated, use fps.numerator instead

+
+ +
+
+fps_den
+

Deprecated, use fps.denominator instead

+
+ +
+
+flags
+

Special flags set for this clip. This attribute should normally be +ignored.

+
+ +
+
+get_frame(n)
+

Returns a VideoFrame from position n.

+
+ +
+
+get_frame_async(n)
+

Returns a concurrent.futures.Future-object which result will be a VideoFrame instance or sets the +exception thrown when rendering the frame.

+

The future will always be in the running or completed state

+
+ +
+
+get_frame_async(n, cb: callable)
+

Renders a frame in another thread. When the frame is rendered, it will either call cb(Frame, None) on success +or cb(None, Exception) if something fails.

+

Added: R58

+
+ +
+
+set_output(index=0, alpha=None, alt_output=0)
+

Set the clip to be accessible for output. This is the standard way to +specify which clip(s) to output. All VapourSynth tools (vsvfw, vsfs, +vspipe) use the clip in index 0. It’s possible to specify an additional +containing the alpha to output at the same time. Currently only vspipe +takes alpha into consideration when outputting. +The alt_output argument is for optional alternate output modes. Currently +it controls the FOURCCs used for VFW-style output with certain formats.

+
+ +
+
+output(fileobj[, y4m = False, prefetch = 0, progress_update = None, backlog=-1])
+

Write the whole clip to the specified file handle. It is possible to pipe to stdout by specifying sys.stdout as the file. +YUV4MPEG2 headers will be added when y4m is true. +The current progress can be reported by passing a callback function of the form func(current_frame, total_frames) to progress_update. +The prefetch argument is only for debugging purposes and should never need to be changed. +The backlog argument is only for debugging purposes and should never need to be changed.

+
+ +
+
+frames([prefetch=None, backlog=None, close=False])
+

Returns a generator iterator of all VideoFrames in the clip. It will render multiple frames concurrently.

+

The prefetch argument defines how many frames are rendered concurrently. Is only there for debugging purposes and should never need to be changed. +The backlog argument defines how many unconsumed frames (including those that did not finish rendering yet) vapoursynth buffers at most before it stops rendering additional frames. This argument is there to limit the memory this function uses storing frames. +The close argument determines if the frame should be closed after each iteration step. It defaults to false to remain backward compatible.

+
+ +
+
+is_inspectable(version=None)
+

Returns a truthy value if you can use the node inspection API with a given version. +The python inspection-api is versioned, as the underlying API is unstable at the time of writing. +The version number will be incremented every time the python API changes. +There will be no attempt to maintain backwards compatibility as long as the API is marked as unstable.

+

This method may never return a truthy value.

+

This is the only stable function in the current inspection api-implementation.

+
+

Note

+

Be aware that introspection features must be enabled manually by the backing environment. Standalone Python-Scripts, +not running inside vspipe or other editors, have introspection enabled automatically.

+
+
+

Warning

+

The graph-inspection-api is unstable. Omitting the version-argument will therefore always return +None.

+
+

The current version of the unstable python graph-inspection API is 0.

+

Added: R58

+
+
Parameters:
+

version – If None, it will use the version number of the last stable API.

+
+
+
+ +
+ +
+
+class VideoOutputTuple
+

This class is returned by get_output if the output is video.

+
+
+clip
+

A VideoNode-instance containing the color planes.

+
+ +
+
+alpha
+

A VideoNode-instance containing the alpha planes.

+
+ +
+
+alt_output
+

An integer with the alternate output mode to be used. May be ignored if no meaningful mapping exists.

+
+ +
+ +
+
+class VideoFrame
+
+

This class represents a video frame and all metadata attached to it.

+
+
+
+format
+

A Format object describing the frame data.

+
+ +
+
+width
+

The width of the frame.

+
+ +
+
+height
+

The height of the frame.

+
+ +
+
+readonly
+

If readonly is True, the frame data and properties cannot be modified.

+
+ +
+
+props
+

This attribute holds all the frame’s properties as a dict. They are also mapped as sub-attributes for +compatibility with older scripts. For more information, see: +API Reference +Note: This includes the data for matrix, transfer and primaries. (_Matrix, +_Transfer, _Primaries) See Resize for more information.

+
+ +
+
+copy()
+

Returns a writable copy of the frame.

+
+ +
+
+close()
+

Forcefully releases the frame. Once freed, the you cannot call any function on the frame, nor use the associated +FrameProps.

+

To make sure you don’t forget to close the frame, the frame is now a context-manager that automatically calls +this method for you:

+
with core.std.BlankClip().get_frame(0) as f:
+    print(f.props)
+
+
+
+ +
+
+closed
+

Tells you if the frame has been closed. It will be False if the close()-method has not been called yet.

+
+ +
+
+get_read_ptr(plane)
+

Returns a pointer to the raw frame data. The data may not be modified. +Note that this is a thin wrapper for the underlying +C-api and as such calls to get_write_ptr, including the ones made internally by other functions in the Python bindings, +may invalidate any pointers previously gotten to the frame with +get_read_ptr when called.

+
+ +
+
+get_write_ptr(plane)
+

Returns a pointer to the raw frame data. It may be modified using ctypes +or some other similar python package. Note that this is a thin wrapper for the underlying +C-api and as such calls to get_write_ptr, including the ones made internally by other functions in the Python bindings, +may invalidate any pointers previously gotten to the frame with +get_read_ptr when called.

+
+ +
+
+get_stride(plane)
+

Returns the stride between lines in a plane.

+
+ +
+
+readchunks()
+

This method is usually used to dump the contents of a VideoFrame to disk. +The returned generator yields contiguous chunks of the VideoFrame memory.

+
with open('output.raw', 'wb') as file:
+   with vs.core.std.BlankClip(color=[25, 50, 60]).get_frame(0) as f:
+      for chunk in f.readchunks():
+         file.write(chunk)
+
+
+
+

Note

+

Usually, the frame contents will be held in a contiguous array, +and this method will yield n_planes of data chunks each holding the entire plane. +Don’t, however, take this for granted, as it can’t be the case, +and you will iterate over lines of plane data instead, which are assured to be contiguous.

+

If you want to safely read the whole plane, use frame[plane_idx] to get the plane memoryview.

+
+
+ +
+ +
+
+class VideoFormat
+

This class represents all information needed to describe a frame format. It +holds the general color type, subsampling, number of planes and so on. +The names map directly to the C API so consult it for more detailed +information.

+
+
+id
+

A unique id identifying the format.

+
+ +
+
+name
+

A human readable name of the format.

+
+ +
+
+color_family
+

Which group of colorspaces the format describes.

+
+ +
+
+sample_type
+

If the format is integer or floating point based.

+
+ +
+
+bits_per_sample
+

How many bits are used to store one sample in one plane.

+
+ +
+
+bytes_per_sample
+

The actual storage is padded up to 2^n bytes for efficiency.

+
+ +
+
+subsampling_w
+

The subsampling for the second and third plane in the horizontal +direction.

+
+ +
+
+subsampling_h
+

The subsampling for the second and third plane in the vertical direction.

+
+ +
+
+num_planes
+

The number of planes the format has.

+
+ +
+
+replace(core=None, **kwargs)
+

Returns a new format with the given modifications.

+

The only supported attributes that can be replaced are color_family, +sample_type, bits_per_sample, subsampling_w, subsampling_h.

+

The optional core-parameter defines on which core the new format +should be registered. This is usually not needed and defaults +to the core of the current environment.

+
+ +
+ +
+
+class AudioNode
+

Represents an audio clip. The class itself supports indexing and slicing to +perform trim, reverse and selectevery operations. Several operators are also +defined for the AudioNode class: addition appends clips and multiplication +repeats them. Note that slicing and indexing always return a new AudioNode +object and not a AudioFrame.

+
+
+sample_type
+

If the format is integer or floating point based.

+
+ +
+
+bits_per_sample
+

How many bits are used to store one sample in one plane.

+
+ +
+
+bytes_per_sample
+

The actual storage is padded up to 2^n bytes for efficiency.

+
+ +
+
+channel_layout
+

A mask of used channels.

+
+ +
+
+num_channels
+

The number of channels the format has.

+
+ +
+
+sample_rate
+

Playback sample rate.

+
+ +
+
+get_frame(n)
+

Returns an AudioFrame from position n.

+
+ +
+
+get_frame_async(n)
+

Returns a concurrent.futures.Future-object which result will be an AudioFrame instance or sets the +exception thrown when rendering the frame.

+

The future will always be in the running or completed state

+
+ +
+
+set_output(index=0)
+

Set the clip to be accessible for output.

+
+ +
+
+frames([prefetch=None, backlog=None])
+

Returns a generator iterator of all AudioFrames in the clip. It will render multiple frames concurrently.

+

The prefetch argument defines how many frames are rendered concurrently. Is only there for debugging purposes and should never need to be changed. +The backlog argument defines how many unconsumed frames (including those that did not finish rendering yet) vapoursynth buffers at most before it stops rendering additional frames. This argument is there to limit the memory this function uses storing frames.

+
+ +
+
+is_inspectable(version=None)
+

Returns a truthy value if you can use the node inspection API with a given version. +The python inspection-api is versioned, as the underlying API is unstable at the time of writing. +The version number will be incremented every time the python API changes. +There will be no attempt to maintain backwards compatibility as long as the API is marked as unstable.

+

This method may never return a truthy value.

+

This is the only stable function in the current inspection api-implementation.

+
+

Note

+

Be aware that introspection features must be enabled manually by the backing environment. Standalone Python-Scripts, +not running inside vspipe or other editors, have introspection enabled automatically.

+
+
+

Warning

+

The graph-inspection-api is unstable. Omitting the version-argument will therefore always return +None.

+
+

The current version of the unstable python graph-inspection API is 0.

+

Added: R58

+
+
Parameters:
+

version – If None, it will use the version number of the last stable API.

+
+
+
+ +
+ +
+
+class AudioFrame
+
+

This class represents an audio frame and all metadata attached to it.

+
+
+
+sample_type
+

If the format is integer or floating point based.

+
+ +
+
+bits_per_sample
+

How many bits are used to store one sample in one plane.

+
+ +
+
+bytes_per_sample
+

The actual storage is padded up to 2^n bytes for efficiency.

+
+ +
+
+channel_layout
+

A mask of used channels.

+
+ +
+
+num_channels
+

The number of channels the format has.

+
+ +
+
+readonly
+

If readonly is True, the frame data and properties cannot be modified.

+
+ +
+
+props
+

This attribute holds all the frame’s properties as a dict. Note that audio frame properties are fairly +non-sensical as a concept for audio due to an arbitrary number of samples being lumped together and rarely used.

+
+ +
+
+copy()
+

Returns a writable copy of the frame.

+
+ +
+
+get_read_ptr(plane)
+

Returns a pointer to the raw frame data. The data may not be modified.

+
+ +
+
+get_write_ptr(plane)
+

Returns a pointer to the raw frame data. It may be modified using ctypes +or some other similar python package.

+
+ +
+
+get_stride(plane)
+

Returns the stride between lines in a plane.

+
+ +
+ +
+
+class Plugin
+

Plugin is a class that represents a loaded plugin and its namespace.

+
+
+namespace
+

The namespace of the plugin.

+
+ +
+
+name
+

The name string of the plugin.

+
+ +
+
+identifier
+
+ +
+
+functions()
+

Containing all the functions in the plugin, You can access it by calling core.<namespace>.functions().

+
+ +
+ +
+
+class Function
+

Function is a simple wrapper class for a function provided by a VapourSynth plugin. +Its main purpose is to be called and nothing else.

+
+
+name
+

The function name. Identical to the string used to register the function.

+
+ +
+
+plugin
+

The Plugin object the function belongs to.

+
+ +
+
+signature
+

Raw function signature string. Identical to the string used to register the function.

+
+ +
+
+return_signature
+

Raw function signature string. Identical to the return type string used register the function.

+
+ +
+ +
+
+class Environment
+

This class represents an environment.

+

Some editors allow multiple vapoursynth-scripts to run in the same process, each of them comes with a different Core-instance and +their own set of outputs. Each core-instance with their associated outputs represent their own environment.

+

At any given time, only one environment can be active (in the same context). This class allows introspection about +environments and allows to switch to them at will.

+
env = get_current_environment()
+# sometime later
+with env.use():
+  # Do stuff inside this env.
+
+
+
+
+is_single()
+

Returns True if the script is _not_ running inside a vsscript-Environment. +If it is running inside a vsscript-Environment, it returns False.

+
+ +
+
+env_id
+

Return -1 if the script is not running inside a vsscript-Environment. +Otherwise, it will return the current environment-id.

+
+ +
+
+single
+

See is_single()

+
+ +
+
+alive
+

Has the environment been destroyed by the underlying application?

+
+ +
+
+copy()
+

Creates a copy of the environment-object.

+

Added: R51

+
+ +
+
+use()
+

Returns a context-manager that enables the given environment in the block enclosed in the with-statement and restores the environment to the one +defined before the with-block has been encountered.

+
env = get_current_environment()
+with env.use():
+    with env.use():
+        pass
+
+
+

Added: R51

+
+ +
+ +
+
+get_current_environment()
+

Returns an Environment-object representing the environment the script is currently running in. It will raise an error if we are currently not inside any +script-environment while vsscript is being used.

+

This function is intended for Python-based editors using vsscript.

+

Added: R51

+
+ +
+
+class EnvironmentPolicy
+

This class is intended for subclassing by custom Script-Runners and Editors. +Normal users don’t need this class. Most methods implemented here have corresponding APIs in other parts of this module.

+

An instance of this class controls which environment is activated in the current context. +The exact meaning of “context” is defined by the concrete EnvironmentPolicy. A environment is represented by a EnvironmentData-object.

+

To use this class, first create a subclass and then use register_policy() to get VapourSynth to use your policy. This must happen before vapoursynth is first +used. VapourSynth will automatically register an internal policy if it needs one. The subclass must be weak-referenciable!

+

Once the method on_policy_registered() has been called, the policy is responsible for creating and managing environments.

+

Special considerations have been made to ensure the functions of class cannot be abused. You cannot retrieve the current running policy yourself. +The additional API exposed by “on_policy_registered” is only valid if the policy has been registered. +Once the policy is unregistered, all calls to the additional API will fail with a RuntimeError.

+

Added: R51

+
+
+on_policy_registered(special_api)
+

This method is called when the policy has successfully been registered. It proivdes additional internal methods that are hidden as they are useless and or harmful +unless you implement your own policy.

+
+
Parameters:
+

special_api – This is a EnvironmentPolicyAPI-object that exposes additional API

+
+
+
+ +
+
+on_policy_cleared()
+

This method is called once the python-process exits or when unregister_policy is called by the environment-policy. This allows the policy to free the resources +used by the policy.

+
+ +
+
+get_current_environment()
+

This method is called by the module to detect which environment is currently running in the current context. If None is returned, it means that no environment is currently active.

+
+
Returns:
+

An EnvironmentData-object representing the currently active environment in the current context.

+
+
+
+ +
+
+set_environment(environment)
+

This method is called by the module to change the currently active environment. If None is passed to this function the policy may switch to another environment of its choosing.

+

Note: The function is responsible to check whether or not the environment is alive. If a dead environment is passed, it should act like None has been passed instead of the dead environment but must never error.

+
+
Parameters:
+

environment – The EnvironmentData to enable in the current context.

+
+
Returns:
+

The environment that was enabled previously.

+
+
+
+ +
+
+is_alive(environment)
+

Is the current environment still active and managed by the policy.

+

The default implementation checks if EnvironmentPolicyAPI.destroy_environment has been called on the environment.

+
+ +
+ +
+
+class EnvironmentPolicyAPI
+

This class is intended to be used by custom Script-Runners and Editors. An instance of this class exposes an additional API. +The methods are bound to a specific EnvironmentPolicy-instance and will only work if the policy is currently registered.

+

Added: R51

+
+
+wrap_environment(environment)
+

Creates a new Environment-object bound to the passed environment-id.

+
+

Warning

+

This function does not check if the id corresponds to a live environment as the caller is expected to know which environments are active.

+
+
+ +
+
+create_environment(flags=0)
+

Returns a Environment that is used by the wrapper for context sensitive data used by VapourSynth. +For example it holds the currently active core object as well as the currently registered outputs.

+
+ +
+
+set_logger(environment, callback)
+

This function sets the logger for the given environment.

+

This logger is a callback function that accepts two parameters: Level, which is an instance of vs.MessageType and a string containing the log message.

+
+ +
+
+destroy_environment(environment)
+

Marks an environment as destroyed. Older environment-policy implementations that don’t use this function still work.

+

Either EnvironmentPolicy.is_alive must be overridden or this method be used to mark the environment as destroyed.

+

Added: R52

+
+ +
+
+unregister_policy()
+

Unregisters the policy it is bound to and allows another policy to be registered.

+
+ +
+
+get_vapoursynth_api(version)
+

Exposes getVapoursynthAPI to python. Returns a ctypes.c_void_p.

+

Access to this function is provisional and might be removed if it is abused too much.

+

Added: R62

+
+ +
+
+get_core_ptr(environment)
+

Returns a ctypes.c_void_p pointing to the Core*-object that powers the environment.

+

Access to this function is provisional and might be removed if it is abused too much.

+

Added: R62

+
+ +
+ +
+
+register_policy(policy)
+

This function is intended for use by custom Script-Runners and Editors. It installs your custom EnvironmentPolicy. This function only works if no other policy has been +installed.

+

If no policy is installed, the first environment-sensitive call will automatically register an internal policy.

+

Added: R50

+
+

Note

+

This must be done before VapourSynth is used in any way. Here is a non-exhaustive list that automatically register a policy:

+ +
+
+ +
+
+_try_enable_introspection(version=None)
+

Tries to enable introspection. Returns true if it succeeds.

+
+
Parameters:
+

version – If not passed it will use the newest stable introspection-api.

+
+
+

Added: R58

+
+ +
+
+has_policy()
+

This function is intended for subclassing by custom Script-Runners and Editors. This function checks if a EnvironmentPolicy has been installed.

+

Added: R50

+
+ +
+
+class EnvironmentData
+

Internal class that stores the context sensitive data that VapourSynth needs. It is an opaque object whose attributes you cannot access directly.

+

A normal user has no way of getting an instance of this object. You can only encounter EnvironmentData-objects if you work with EnvironmentPolicies.

+

This object is weak-referenciable meaning you can get a callback if the environment-data object is actually being freed (i.e. no other object holds an instance +to the environment data.)

+

Added: R50

+
+ +
+
+class Func
+

Func is a simple wrapper class for VapourSynth VSFunc objects. +Its main purpose is to be called and manage reference counting.

+
+ +
+
+exception Error
+

The standard exception class. This exception is thrown on most errors +encountered in VapourSynth.

+
+ +
+
+

Constants

+
+

Video

+
+

Color Family

+

The color family constants describe groups of formats and the basic way their +color information is stored. You should be familiar with all of them apart from +maybe YCOCG and COMPAT. The latter is a special junk category for non-planar +formats. These are the declared constants in the module:

+
UNDEFINED
+RGB
+YUV
+GRAY
+
+
+
+
+

Format

+

Format constants exactly describe a format. All common and even more uncommon +formats have handy constants predefined so in practice no one should really +need to register one of their own. These values are mostly used by the resizers +to specify which format to convert to. The naming system is quite simple. First +the color family, then the subsampling (only YUV has it) and after that how many +bits per sample in one plane. The exception to this rule is RGB, which has the +bits for all 3 planes added together. The long list of values:

+
NONE
+GRAY8
+GRAY9
+GRAY10
+GRAY12
+GRAY14
+GRAY16
+GRAY32
+GRAYH
+GRAYS
+YUV420P8
+YUV422P8
+YUV444P8
+YUV410P8
+YUV411P8
+YUV440P8
+YUV420P9
+YUV422P9
+YUV444P9
+YUV420P10
+YUV422P10
+YUV444P10
+YUV420P12
+YUV422P12
+YUV444P12
+YUV420P14
+YUV422P14
+YUV444P14
+YUV420P16
+YUV422P16
+YUV444P16
+YUV444PH
+YUV444PS
+RGB24
+RGB27
+RGB30
+RGB36
+RGB42
+RGB48
+RGBH
+RGBS
+
+
+
+
+

Chroma Location

+
CHROMA_LEFT
+CHROMA_CENTER
+CHROMA_TOP_LEFT
+CHROMA_TOP
+CHROMA_BOTTOM_LEFT
+CHROMA_BOTTOM
+
+
+
+
+

Field Based

+
FIELD_PROGRESSIVE
+FIELD_TOP
+FIELD_BOTTOM
+
+
+
+
+

Color Range

+
RANGE_FULL
+RANGE_LIMITED
+
+
+
+
+

Matrix Coefficients

+
MATRIX_RGB
+MATRIX_BT709
+MATRIX_UNSPECIFIED
+MATRIX_FCC
+MATRIX_BT470_BG
+MATRIX_ST170_M
+MATRIX_ST240_M
+MATRIX_YCGCO
+MATRIX_BT2020_NCL
+MATRIX_BT2020_CL
+MATRIX_CHROMATICITY_DERIVED_NCL
+MATRIX_CHROMATICITY_DERIVED_CL
+MATRIX_ICTCP
+
+
+
+
+

TransferCharacteristics

+
TRANSFER_BT709
+TRANSFER_UNSPECIFIED
+TRANSFER_BT470_M
+TRANSFER_BT470_BG
+TRANSFER_BT601
+TRANSFER_ST240_M
+TRANSFER_LINEAR
+TRANSFER_LOG_100
+TRANSFER_LOG_316
+TRANSFER_IEC_61966_2_4
+TRANSFER_IEC_61966_2_1
+TRANSFER_BT2020_10
+TRANSFER_BT2020_12
+TRANSFER_ST2084
+TRANSFER_ARIB_B67
+
+
+
+
+

Color Primaries

+
PRIMARIES_BT709
+PRIMARIES_UNSPECIFIED
+PRIMARIES_BT470_M
+PRIMARIES_BT470_BG
+PRIMARIES_ST170_M
+PRIMARIES_ST240_M
+PRIMARIES_FILM
+PRIMARIES_BT2020
+PRIMARIES_ST428
+PRIMARIES_ST431_2
+PRIMARIES_ST432_1
+PRIMARIES_EBU3213_E
+
+
+
+
+
+

Audio

+
+

Channels

+
FRONT_LEFT
+FRONT_RIGHT
+FRONT_CENTER
+LOW_FREQUENCY
+BACK_LEFT
+BACK_RIGHT
+FRONT_LEFT_OF_CENTER
+FRONT_RIGHT_OF_CENTER
+BACK_CENTER
+SIDE_LEFT
+SIDE_RIGHT
+TOP_CENTER
+TOP_FRONT_LEFT
+TOP_FRONT_CENTER
+TOP_FRONT_RIGHT
+TOP_BACK_LEFT
+TOP_BACK_CENTER
+TOP_BACK_RIGHT
+STEREO_LEFT
+STEREO_RIGHT
+WIDE_LEFT
+WIDE_RIGHT
+SURROUND_DIRECT_LEFT
+SURROUND_DIRECT_RIGHT
+LOW_FREQUENCY2
+
+
+
+
+
+

Sample Type

+
INTEGER
+FLOAT
+
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Programs/doc/search.html b/Programs/doc/search.html new file mode 100644 index 0000000..eb0561f --- /dev/null +++ b/Programs/doc/search.html @@ -0,0 +1,130 @@ + + + + + + Search — VapourSynth R64 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2012-2023, Fredrik Mellbin.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/Programs/doc/searchindex.js b/Programs/doc/searchindex.js new file mode 100644 index 0000000..4f7c5ad --- /dev/null +++ b/Programs/doc/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["api/vapoursynth4.h", "api/vshelper4.h", "api/vsscript4.h", "apireference", "applications", "functions", "functions/audio/assumesamplerate", "functions/audio/audiogain", "functions/audio/audioloop", "functions/audio/audiomix", "functions/audio/audioreverse", "functions/audio/audiosplice", "functions/audio/audiotrim", "functions/audio/blankaudio", "functions/audio/setaudiocache", "functions/audio/shufflechannels", "functions/audio/splitchannels", "functions/general/loadallplugins", "functions/general/loadplugin", "functions/general/loadpluginavs", "functions/general/setmaxcpu", "functions/video/addborders", "functions/video/assumefps", "functions/video/averageframes", "functions/video/binarize_binarizemask", "functions/video/blankclip", "functions/video/boxblur", "functions/video/cliptoprop", "functions/video/convolution", "functions/video/copyframeprops", "functions/video/crop_cropabs", "functions/video/deflate_inflate", "functions/video/deleteframes", "functions/video/doubleweave", "functions/video/duplicateframes", "functions/video/expr", "functions/video/flipvertical_fliphorizontal", "functions/video/frameeval", "functions/video/freezeframes", "functions/video/interleave", "functions/video/invert_invertmask", "functions/video/levels", "functions/video/limiter", "functions/video/loop", "functions/video/lut", "functions/video/lut2", "functions/video/makediff", "functions/video/makefulldiff", "functions/video/maskedmerge", "functions/video/median", "functions/video/merge", "functions/video/mergediff", "functions/video/mergefulldiff", "functions/video/minimum_maximum", "functions/video/modifyframe", "functions/video/pemverifier", "functions/video/planestats", "functions/video/premultiply", "functions/video/prewitt_sobel", "functions/video/proptoclip", "functions/video/removeframeprops", "functions/video/resize", "functions/video/reverse", "functions/video/selectevery", "functions/video/separatefields", "functions/video/setfieldbased", "functions/video/setframeprop", "functions/video/setframeprops", "functions/video/setvideocache", "functions/video/shuffleplanes", "functions/video/splice", "functions/video/splitplanes", "functions/video/stackvertical_stackhorizontal", "functions/video/text/clipinfo", "functions/video/text/coreinfo", "functions/video/text/framenum", "functions/video/text/frameprops", "functions/video/text/text", "functions/video/transpose", "functions/video/trim", "functions/video/turn180", "gettingstarted", "index", "installation", "introduction", "output", "pythonreference"], "filenames": ["api\\vapoursynth4.h.rst", "api\\vshelper4.h.rst", "api\\vsscript4.h.rst", "apireference.rst", "applications.rst", "functions.rst", "functions\\audio\\assumesamplerate.rst", "functions\\audio\\audiogain.rst", "functions\\audio\\audioloop.rst", "functions\\audio\\audiomix.rst", "functions\\audio\\audioreverse.rst", "functions\\audio\\audiosplice.rst", "functions\\audio\\audiotrim.rst", "functions\\audio\\blankaudio.rst", "functions\\audio\\setaudiocache.rst", "functions\\audio\\shufflechannels.rst", "functions\\audio\\splitchannels.rst", "functions\\general\\loadallplugins.rst", "functions\\general\\loadplugin.rst", "functions\\general\\loadpluginavs.rst", "functions\\general\\setmaxcpu.rst", "functions\\video\\addborders.rst", "functions\\video\\assumefps.rst", "functions\\video\\averageframes.rst", "functions\\video\\binarize_binarizemask.rst", "functions\\video\\blankclip.rst", "functions\\video\\boxblur.rst", "functions\\video\\cliptoprop.rst", "functions\\video\\convolution.rst", "functions\\video\\copyframeprops.rst", "functions\\video\\crop_cropabs.rst", "functions\\video\\deflate_inflate.rst", "functions\\video\\deleteframes.rst", "functions\\video\\doubleweave.rst", "functions\\video\\duplicateframes.rst", "functions\\video\\expr.rst", "functions\\video\\flipvertical_fliphorizontal.rst", "functions\\video\\frameeval.rst", "functions\\video\\freezeframes.rst", "functions\\video\\interleave.rst", "functions\\video\\invert_invertmask.rst", "functions\\video\\levels.rst", "functions\\video\\limiter.rst", "functions\\video\\loop.rst", "functions\\video\\lut.rst", "functions\\video\\lut2.rst", "functions\\video\\makediff.rst", "functions\\video\\makefulldiff.rst", "functions\\video\\maskedmerge.rst", "functions\\video\\median.rst", "functions\\video\\merge.rst", "functions\\video\\mergediff.rst", "functions\\video\\mergefulldiff.rst", "functions\\video\\minimum_maximum.rst", "functions\\video\\modifyframe.rst", "functions\\video\\pemverifier.rst", "functions\\video\\planestats.rst", "functions\\video\\premultiply.rst", "functions\\video\\prewitt_sobel.rst", "functions\\video\\proptoclip.rst", "functions\\video\\removeframeprops.rst", "functions\\video\\resize.rst", "functions\\video\\reverse.rst", "functions\\video\\selectevery.rst", "functions\\video\\separatefields.rst", "functions\\video\\setfieldbased.rst", "functions\\video\\setframeprop.rst", "functions\\video\\setframeprops.rst", "functions\\video\\setvideocache.rst", "functions\\video\\shuffleplanes.rst", "functions\\video\\splice.rst", "functions\\video\\splitplanes.rst", "functions\\video\\stackvertical_stackhorizontal.rst", "functions\\video\\text\\clipinfo.rst", "functions\\video\\text\\coreinfo.rst", "functions\\video\\text\\framenum.rst", "functions\\video\\text\\frameprops.rst", "functions\\video\\text\\text.rst", "functions\\video\\transpose.rst", "functions\\video\\trim.rst", "functions\\video\\turn180.rst", "gettingstarted.rst", "index.rst", "installation.rst", "introduction.rst", "output.rst", "pythonreference.rst"], "titles": ["VapourSynth4.h", "VSHelper4.h", "VSScript4.h", "VapourSynth C API Reference", "Applications and Libraries", "Function Reference", "AssumeSampleRate", "AudioGain", "AudioLoop", "AudioMix", "AudioReverse", "AudioSplice", "AudioTrim", "BlankAudio", "SetAudioCache", "ShuffleChannels", "SplitChannels", "LoadAllPlugins", "LoadPlugin", "LoadPlugin (Avisynth Compatibility)", "SetMaxCPU", "AddBorders", "AssumeFPS", "AverageFrames", "Binarize/BinarizeMask", "BlankClip", "BoxBlur", "ClipToProp", "Convolution", "CopyFrameProps", "Crop/CropAbs", "Deflate/Inflate", "DeleteFrames", "DoubleWeave", "DuplicateFrames", "Expr", "FlipVertical/FlipHorizontal", "FrameEval", "FreezeFrames", "Interleave", "Invert/InvertMask", "Levels", "Limiter", "Loop", "Lut", "Lut2", "MakeDiff", "MakeFullDiff", "MaskedMerge", "Median", "Merge", "MergeDiff", "MergeFullDiff", "Minimum/Maximum", "ModifyFrame", "PEMVerifier", "PlaneStats", "PreMultiply", "Prewitt/Sobel", "PropToClip", "RemoveFrameProps", "Resize", "Reverse", "SelectEvery", "SeparateFields", "SetFieldBased", "SetFrameProp", "SetFrameProps", "SetVideoCache", "ShufflePlanes", "Splice", "SplitPlanes", "StackVertical/StackHorizontal", "ClipInfo", "CoreInfo", "FrameNum", "FrameProps", "Text", "Transpose", "Trim", "Turn180", "Getting Started", "Welcome to VapourSynth\u2019s documentation!", "Installation", "Introduction", "Output", "Python Reference"], "terms": {"deal": [0, 19, 86], "core": [0, 1, 2, 3, 33, 37, 38, 46, 47, 51, 52, 65, 74, 81, 82, 83, 84, 86], "createcor": 0, "freecor": 0, "setmaxcaches": 0, "setthreadcount": 0, "getcoreinfo": 0, "getapivers": 0, "log": [0, 2, 35, 61, 86], "addloghandl": 0, "removeloghandl": 0, "logmessag": 0, "frame": [0, 2, 4, 8, 10, 12, 13, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 48, 49, 50, 53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 72, 75, 76, 77, 78, 79, 80, 82, 84, 85], "newvideofram": 0, "newvideoframe2": 0, "newaudiofram": 0, "newaudioframe2": 0, "freefram": 0, "addframeref": 0, "copyfram": 0, "getframepropertiesro": 0, "getframepropertiesrw": 0, "getstrid": 0, "getreadptr": 0, "getwriteptr": 0, "getvideoframeformat": 0, "getaudioframeformat": 0, "getframetyp": 0, "getframewidth": 0, "getframeheight": 0, "getframelength": 0, "filter": [0, 3, 18, 19, 23, 27, 37, 47, 55, 61, 68, 77, 82, 84, 85], "node": [0, 2, 68, 85, 86], "createvideofilt": 0, "createvideofilter2": 0, "createaudiofilt": 0, "createaudiofilter2": 0, "setlinearfilt": 0, "setcachemod": 0, "setcacheopt": 0, "freenod": 0, "addnoderef": 0, "getnodetyp": 0, "getvideoinfo": 0, "getaudioinfo": 0, "format": [0, 1, 2, 3, 4, 7, 9, 11, 15, 19, 23, 24, 25, 28, 31, 35, 37, 39, 40, 41, 42, 44, 45, 48, 49, 50, 53, 54, 55, 56, 57, 58, 61, 69, 70, 72, 73, 84, 85], "getvideoformatnam": 0, "getaudioformatnam": 0, "queryvideoformat": 0, "queryaudioformat": 0, "queryvideoformatid": 0, "getvideoformatbyid": 0, "map": [0, 2, 3, 15, 86], "createmap": 0, "freemap": 0, "clearmap": 0, "mapgeterror": 0, "mapseterror": 0, "mapnumkei": 0, "mapgetkei": 0, "mapdeletekei": 0, "mapnumel": 0, "mapgettyp": 0, "mapsetempti": 0, "mapgetint": 0, "mapgetintsatur": 0, "mapgetintarrai": 0, "mapsetint": 0, "mapsetintarrai": 0, "mapgetfloat": 0, "mapgetfloatsatur": 0, "mapgetfloatarrai": 0, "mapsetfloat": 0, "mapsetfloatarrai": 0, "mapgetdata": 0, "mapgetdatas": 0, "mapgetdatatypehint": 0, "mapsetdata": 0, "mapgetnod": 0, "mapsetnod": 0, "mapconsumenod": 0, "mapgetfram": 0, "mapsetfram": 0, "mapconsumefram": 0, "mapgetfunct": 0, "mapsetfunct": 0, "mapconsumefunct": 0, "registerfunct": 0, "getpluginbyid": 0, "getpluginbynamespac": 0, "getnextplugin": 0, "getpluginnam": 0, "getpluginid": 0, "getpluginnamespac": 0, "getnextpluginfunct": 0, "getpluginfunctionbynam": 0, "getpluginfunctionnam": 0, "getpluginfunctionargu": 0, "getpluginfunctionreturntyp": 0, "getpluginpath": 0, "getpluginvers": 0, "invok": [0, 8, 10, 11, 12, 19, 43, 62, 63, 70, 79, 86], "wrap": [0, 19, 77, 86], "extern": [0, 77], "createfunct": 0, "freefunct": 0, "addfunctionref": 0, "callfunct": 0, "ar": [0, 1, 2, 3, 7, 9, 13, 15, 17, 18, 19, 20, 23, 24, 25, 28, 31, 32, 35, 37, 39, 40, 41, 42, 44, 45, 46, 48, 49, 50, 51, 53, 55, 58, 60, 61, 63, 65, 68, 69, 72, 77, 79, 81, 83, 84, 86], "us": [0, 1, 2, 3, 4, 8, 9, 11, 13, 15, 19, 20, 23, 24, 25, 26, 29, 30, 33, 35, 37, 39, 40, 43, 44, 45, 46, 47, 48, 50, 51, 52, 54, 55, 57, 58, 59, 61, 63, 66, 68, 69, 70, 74, 77, 81, 83, 85, 86], "fetch": 0, "insid": [0, 86], "getfram": [0, 3], "getframeasync": 0, "getframefilt": 0, "requestframefilt": 0, "releaseframeearli": 0, "cachefram": 0, "setfiltererror": 0, "getvapoursynthapi": [0, 86], "vsinitplugin": 0, "vsfiltergetfram": 0, "vsfilterfre": 0, "thi": [0, 1, 2, 3, 13, 17, 18, 19, 20, 22, 23, 25, 27, 28, 30, 35, 37, 38, 41, 46, 47, 51, 52, 53, 56, 57, 58, 59, 61, 65, 68, 69, 73, 74, 75, 76, 83, 85, 86], "i": [0, 1, 2, 3, 7, 8, 9, 11, 12, 13, 15, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 37, 39, 40, 41, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 63, 64, 65, 66, 69, 70, 72, 73, 74, 75, 76, 77, 78, 79, 81, 83, 84, 85, 86], "": [0, 1, 2, 3, 7, 9, 15, 17, 18, 19, 24, 28, 29, 33, 35, 39, 40, 41, 48, 54, 61, 63, 64, 65, 69, 81, 83, 84, 85, 86], "main": [0, 23, 37, 83, 84, 85, 86], "header": [0, 82, 85, 86], "file": [0, 2, 4, 81, 82, 83, 85], "applic": [0, 2, 61, 81, 82, 83, 84, 85, 86], "librari": [0, 2, 77, 82, 83, 84, 86], "must": [0, 1, 2, 15, 21, 24, 28, 31, 33, 35, 38, 40, 41, 42, 44, 48, 49, 50, 53, 54, 57, 58, 63, 86], "includ": [0, 18, 55, 83, 86], "public": [0, 2, 55, 82], "api": [0, 2, 4, 82, 86], "all": [0, 1, 2, 3, 7, 11, 17, 20, 23, 24, 29, 32, 34, 35, 37, 38, 39, 40, 41, 44, 45, 46, 48, 50, 51, 56, 58, 60, 61, 68, 70, 72, 76, 81, 83, 84, 85, 86], "c": [0, 1, 2, 4, 9, 17, 18, 19, 35, 61, 66, 67, 81, 82, 84, 85, 86], "vapoursynth4": [3, 82], "defin": [0, 1, 2, 3, 83, 86], "some": [0, 9, 15, 63, 69, 81, 83, 84, 86], "preprocessor": 0, "make": [0, 19, 30, 37, 45, 54, 57, 61, 83, 85, 86], "programm": 0, "life": 0, "easier": [0, 1], "The": [0, 1, 2, 3, 9, 13, 15, 19, 21, 22, 23, 24, 25, 28, 30, 31, 33, 35, 37, 38, 39, 40, 41, 44, 45, 48, 50, 53, 54, 55, 56, 57, 61, 63, 64, 65, 66, 68, 69, 72, 77, 83, 84, 85, 86], "relev": 0, "ones": [0, 2, 23, 29, 86], "describ": [0, 3, 83, 86], "below": [0, 3, 9, 15, 24, 63, 69, 85], "expand": [0, 1], "call": [0, 2, 19, 30, 38, 54, 78, 79, 81, 86], "convent": [0, 86], "meant": 0, "init": 0, "free": [0, 1, 2, 84, 86], "etc": [0, 2], "exampl": [0, 2, 3, 9, 10, 15, 19, 35, 39, 41, 54, 57, 61, 62, 63, 65, 66, 67, 69, 82, 83, 86], "static": [0, 1], "void": [0, 1, 2], "fooinit": 0, "platform": [0, 20], "specif": [0, 18, 40, 45, 61, 83, 86], "magic": 0, "requir": [0, 3, 37, 72], "export": [0, 4], "share": [0, 3, 83, 85], "It": [0, 1, 2, 3, 22, 24, 25, 27, 28, 31, 37, 40, 41, 42, 49, 53, 55, 58, 59, 61, 77, 81, 83, 84, 85, 86], "also": [0, 1, 3, 8, 10, 11, 12, 13, 15, 18, 23, 25, 35, 37, 43, 45, 48, 50, 53, 61, 62, 63, 64, 70, 72, 79, 81, 83, 85, 86], "take": [0, 2, 9, 13, 15, 25, 33, 35, 45, 69, 77, 84, 86], "care": 0, "ad": [0, 4, 21, 28, 64, 66, 83, 86], "when": [0, 1, 2, 13, 19, 25, 28, 35, 37, 47, 53, 57, 61, 64, 68, 69, 83, 84, 85, 86], "need": [0, 3, 23, 44, 45, 54, 61, 69, 72, 83, 84, 86], "entri": [0, 15, 45], "point": [0, 5, 24, 35, 41, 44, 45, 61, 86], "like": [0, 3, 19, 47, 48, 61, 83, 84, 85, 86], "so": [0, 2, 3, 19, 27, 37, 54, 55, 79, 81, 83, 84, 86], "vapoursynthplugininit2": 0, "major": [0, 84], "version": [0, 2, 18, 24, 40, 74, 77, 83, 85, 86], "minor": [0, 3], "bump": 0, "new": [0, 2, 3, 13, 22, 25, 84, 86], "behavior": [0, 1, 2, 18, 41, 68, 86], "notic": 0, "chang": [0, 2, 3, 7, 13, 22, 23, 25, 31, 53, 61, 83, 84, 86], "high": [0, 4], "16": [0, 2, 13, 24, 28, 31, 35, 40, 41, 42, 44, 49, 53, 57, 58, 61, 77], "bit": [0, 3, 13, 19, 24, 28, 31, 35, 40, 41, 42, 44, 45, 49, 53, 57, 58, 61, 83, 85, 86], "low": [0, 77], "number": [0, 1, 3, 15, 19, 21, 22, 23, 28, 32, 33, 34, 37, 38, 39, 53, 54, 61, 63, 69, 75, 77, 83, 84, 85, 86], "audio": [0, 1, 9, 12, 13, 15, 16, 81, 82], "sampl": [0, 3, 8, 10, 12, 24, 28, 31, 35, 40, 41, 42, 43, 49, 53, 58, 62, 81, 82], "an": [0, 1, 2, 4, 11, 13, 15, 18, 19, 22, 23, 24, 25, 28, 30, 31, 32, 35, 37, 39, 40, 41, 42, 44, 45, 48, 49, 50, 53, 54, 55, 57, 58, 61, 64, 69, 70, 77, 79, 81, 83, 84, 86], "possibl": [0, 9, 13, 15, 20, 28, 35, 48, 61, 65, 68, 69, 81, 86], "calcul": [0, 37, 46, 47, 51, 52, 56, 57, 68], "which": [0, 2, 3, 15, 24, 26, 28, 30, 31, 35, 37, 40, 41, 42, 45, 46, 47, 49, 51, 52, 53, 54, 58, 61, 66, 69, 77, 83, 86], "retriev": [0, 2, 86], "creat": [0, 2, 4, 58, 81, 83, 84, 85, 86], "first": [0, 2, 3, 9, 12, 15, 33, 35, 38, 39, 45, 48, 54, 55, 63, 64, 65, 66, 67, 69, 72, 79, 83, 85, 86], "argument": [0, 1, 3, 9, 13, 15, 19, 21, 25, 27, 30, 35, 37, 39, 44, 45, 61, 64, 68, 69, 79, 82, 83, 85], "second": [0, 3, 13, 25, 27, 35, 48, 50, 69, 83, 86], "cfundefin": 0, "cfgrai": 0, "cfrgb": 0, "cfyuv": 0, "stinteg": 0, "stfloat": 0, "preset": [0, 1], "suffix": [0, 61], "have": [0, 1, 2, 3, 9, 10, 13, 19, 24, 25, 28, 31, 33, 35, 37, 39, 40, 41, 42, 44, 48, 49, 50, 53, 54, 58, 61, 62, 65, 81, 83, 84, 86], "float": [0, 1, 3, 7, 9, 13, 21, 23, 24, 25, 28, 31, 35, 40, 41, 42, 44, 45, 48, 49, 50, 53, 55, 56, 58, 61, 66, 86], "type": [0, 3, 24, 28, 31, 40, 41, 42, 49, 53, 58, 61, 66, 82, 83, 85], "stand": 0, "half": 0, "precis": 0, "singl": [0, 3, 7, 15, 23, 35, 38, 50, 54, 69, 86], "respect": [0, 23, 28, 41, 69, 85], "planar": [0, 61, 86], "see": [0, 2, 3, 14, 61, 65, 83, 86], "current": [0, 3, 13, 23, 37, 54, 55, 75, 83, 86], "video": [0, 1, 2, 4, 25, 61, 81, 82, 84, 85], "pf": 0, "control": [0, 15, 39, 41, 68, 69, 86], "how": [0, 28, 30, 31, 35, 37, 44, 45, 48, 50, 53, 54, 68, 81, 86], "multithread": [0, 3, 84], "fmparallel": 0, "complet": [0, 2, 4, 19, 83, 86], "parallel": [0, 3], "execut": [0, 86], "multipl": [0, 2, 8, 18, 19, 23, 26, 28, 43, 86], "thread": [0, 3, 86], "sever": [0, 3, 34, 61, 83, 85, 86], "fmparallelrequest": 0, "For": [0, 2, 9, 10, 19, 35, 39, 41, 57, 61, 62, 65, 66, 67, 69, 72, 81, 83, 86], "serial": 0, "natur": [0, 84], "can": [0, 2, 3, 4, 7, 8, 9, 10, 11, 12, 13, 15, 19, 22, 23, 24, 25, 26, 30, 35, 37, 38, 42, 43, 44, 45, 46, 47, 54, 57, 58, 61, 62, 63, 65, 66, 69, 70, 79, 81, 83, 84, 85, 86], "request": [0, 2, 13, 25, 37, 68, 85], "advanc": [0, 4, 84], "one": [0, 1, 2, 3, 9, 15, 23, 35, 37, 47, 52, 54, 59, 69, 74, 79, 81, 83, 84, 86], "more": [0, 2, 3, 9, 15, 35, 37, 50, 54, 57, 61, 81, 83, 86], "thei": [0, 3, 9, 15, 19, 21, 23, 35, 39, 61, 83, 86], "A": [0, 1, 2, 3, 26, 34, 38, 39, 48, 50, 69, 83, 86], "from": [0, 1, 2, 3, 9, 13, 15, 22, 23, 25, 27, 29, 30, 33, 35, 37, 39, 40, 41, 45, 48, 49, 50, 53, 54, 59, 61, 68, 69, 72, 77, 79, 81, 83, 85, 86], "time": [0, 2, 3, 8, 13, 25, 34, 43, 68, 83, 84, 85, 86], "activ": [0, 86], "reason": [0, 2, 13, 25, 54, 86], "ariniti": [0, 3], "onli": [0, 2, 3, 7, 19, 20, 22, 23, 24, 31, 33, 35, 37, 54, 61, 63, 64, 66, 69, 76, 77, 79, 83, 86], "arallframesreadi": 0, "fmunord": [0, 3], "modifi": [0, 3, 18, 22, 37, 54, 77, 86], "examin": 0, "intern": [0, 1, 33, 86], "state": [0, 86], "determin": [0, 9, 15, 61, 69, 86], "while": [0, 41, 83, 86], "run": [0, 3, 83, 85, 86], "happen": [0, 2, 9, 23, 47, 86], "ani": [0, 2, 3, 22, 24, 28, 31, 35, 38, 40, 41, 42, 49, 53, 54, 58, 77, 83, 84, 85, 86], "order": [0, 9, 10, 11, 15, 18, 33, 35, 57, 61, 62, 64, 66, 67, 70, 83], "0": [0, 1, 2, 3, 8, 9, 10, 12, 13, 21, 24, 25, 26, 28, 30, 31, 33, 35, 37, 38, 39, 40, 41, 42, 43, 44, 46, 48, 49, 50, 51, 53, 54, 56, 58, 61, 62, 63, 65, 68, 69, 70, 78, 79, 81, 83, 86], "again": [0, 8, 43], "1": [0, 3, 8, 9, 10, 13, 15, 22, 24, 25, 26, 28, 31, 35, 37, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 56, 58, 61, 62, 63, 65, 68, 69, 73, 74, 75, 76, 77, 78, 81, 86], "fmframest": 0, "compat": [0, 5, 61, 82, 84, 85, 86], "other": [0, 2, 3, 9, 20, 24, 27, 28, 30, 31, 37, 40, 41, 42, 44, 45, 48, 49, 53, 58, 61, 65, 68, 82, 83], "architectur": 0, "do": [0, 3, 19, 54, 61, 78, 83, 84, 85, 86], "NOT": 0, "IN": 0, "ever": 0, "get": [0, 37, 61, 77, 82, 83, 85, 86], "unlik": [0, 27, 86], "process": [0, 2, 24, 26, 28, 31, 40, 41, 42, 44, 45, 46, 48, 49, 51, 53, 58, 84, 85, 86], "indic": [0, 2, 61], "object": [0, 2, 3, 81, 83, 86], "mtvideo": 0, "mtaudio": 0, "channel": [0, 3, 7, 9, 13, 15, 16, 27, 35, 57, 61, 69, 81], "posit": [0, 3, 77, 86], "mirror": [0, 1], "ffmpeg": [0, 81, 83], "constant": [0, 1, 3, 9, 13, 15, 61, 82], "older": [0, 86], "avail": [0, 2, 61, 83, 86], "valu": [0, 2, 3, 7, 13, 15, 20, 24, 26, 28, 35, 40, 41, 42, 44, 45, 49, 50, 53, 55, 56, 61, 65, 67, 68, 83, 85, 86], "ac": 0, "properti": [0, 1, 9, 13, 15, 22, 25, 27, 29, 33, 37, 48, 50, 54, 56, 59, 60, 61, 64, 65, 66, 67, 69, 72, 76, 82, 84, 86], "store": [0, 1, 27, 35, 56, 59, 86], "ptunset": 0, "ptint": 0, "ptfloat": 0, "ptdata": 0, "ptfunction": 0, "ptvideonod": 0, "ptaudionod": 0, "ptvideofram": 0, "ptaudiofram": 0, "mapget": 0, "fail": [0, 2, 17, 18, 19, 83, 86], "return": [0, 1, 2, 3, 8, 9, 10, 11, 13, 15, 16, 18, 22, 24, 25, 28, 29, 30, 31, 32, 35, 37, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 53, 54, 58, 60, 61, 62, 63, 64, 69, 70, 71, 79, 83, 86], "err": 0, "paramet": [0, 9, 15, 28, 45, 61, 66, 69, 77, 86], "error": [0, 2, 3, 11, 15, 18, 19, 22, 24, 25, 28, 30, 31, 32, 35, 39, 40, 41, 42, 48, 49, 50, 53, 54, 55, 58, 61, 64, 69, 70, 79, 82, 83, 86], "non": [0, 2, 15, 35, 41, 61, 83, 86], "zero": [0, 2, 9, 15, 35, 50, 69], "pesuccess": 0, "peunset": 0, "kei": [0, 2, 3, 67, 77, 85], "wa": [0, 2, 3, 38, 59, 77, 84, 86], "found": [0, 17, 83, 84], "petyp": 0, "wrong": 0, "e": [0, 1, 3, 35, 61, 85, 86], "g": [0, 61, 69, 85], "peindex": 0, "index": [0, 2, 4, 9, 15, 35, 61, 69, 81, 82, 85, 86], "out": [0, 3, 30, 41, 55, 61, 81, 83, 84, 85], "bound": [0, 24, 42, 55, 86], "peerror": 0, "ha": [0, 1, 2, 18, 23, 33, 35, 48, 52, 54, 64, 65, 68, 69, 83, 84, 85, 86], "set": [0, 2, 3, 13, 18, 20, 21, 23, 25, 27, 33, 35, 39, 44, 45, 48, 54, 55, 61, 63, 64, 65, 66, 67, 68, 77, 81, 83, 85, 86], "behaviour": 0, "friend": 0, "mareplac": 0, "exist": [0, 1, 2, 15, 29, 37, 67, 83, 84, 86], "associ": [0, 2, 68, 86], "replac": [0, 29, 31, 38, 49, 53, 67, 83, 86], "maappend": 0, "append": [0, 11, 19, 44, 45, 70, 86], "list": [0, 4, 13, 15, 37, 44, 45, 48, 54, 61, 83, 86], "arerror": 0, "mtdebug": 0, "mtinform": 0, "mtwarn": 0, "mtcritic": 0, "mtfatal": 0, "option": [0, 2, 45, 61, 68, 82, 83, 86], "ccfenablegraphinspect": 0, "graph": [0, 3, 37, 85, 86], "inspect": [0, 86], "increas": [0, 58], "memori": [0, 74, 83, 86], "usag": 0, "due": [0, 2, 35, 86], "extra": [0, 83], "inform": [0, 61, 73, 74, 83, 86], "ccfdisableautoload": 0, "don": [0, 81, 84, 85, 86], "t": [0, 1, 2, 3, 30, 35, 55, 61, 64, 77, 81, 83, 84, 85, 86], "autoload": [0, 82], "user": [0, 2, 45, 61, 83, 86], "alwai": [0, 2, 3, 28, 35, 44, 45, 56, 68, 83, 85, 86], "load": [0, 2, 17, 18, 19, 35, 81, 83, 86], "ccfdisablelibraryunload": 0, "unload": 0, "destroi": [0, 86], "small": [0, 3], "amount": 0, "leak": 0, "everi": [0, 13, 24, 25, 37, 54, 63, 66, 67, 68, 86], "window": [0, 1, 2, 77, 82, 85], "featur": [0, 4, 20, 84, 86], "my": 0, "fault": 0, "mai": [0, 3, 33, 34, 41, 54, 61, 68, 81, 83, 86], "help": [0, 1, 3, 84], "extrem": 0, "script": [0, 2, 4, 82, 84, 85, 86], "reload": 0, "pcmodifi": 0, "allow": [0, 2, 7, 13, 23, 24, 31, 35, 37, 40, 41, 42, 53, 55, 61, 68, 79, 84, 86], "after": [0, 2, 38, 83, 86], "phase": 0, "mostli": [0, 1, 2, 86], "avisynth": [0, 5, 28, 37, 82, 83, 84], "foreign": 0, "loader": [0, 19, 83], "sinc": [0, 2, 3, 23, 33, 35, 37, 41, 48, 84, 85], "data": [0, 3, 66, 82], "contain": [0, 2, 3, 35, 37, 45, 53, 83, 85, 86], "both": [0, 1, 13, 22, 25, 27, 28, 30, 69, 79, 83], "pure": 0, "binari": [0, 2, 66, 83], "printabl": 0, "string": [0, 2, 3, 17, 18, 19, 20, 27, 28, 35, 56, 59, 60, 61, 66, 76, 77, 81, 86], "hint": [0, 3, 37], "whether": [0, 2, 3, 23, 39, 86], "human": [0, 86], "readabl": [0, 86], "gener": [0, 9, 13, 15, 25, 37, 61, 68, 69, 82, 84, 86], "unknown": [0, 1, 2, 3, 61], "should": [0, 2, 3, 13, 25, 27, 37, 54, 68, 83, 86], "veri": [0, 3, 18, 19, 48, 81, 83], "rare": [0, 19, 86], "almost": [0, 69], "artifact": 0, "api3": 0, "dtunknown": 0, "dtbinari": 0, "dtutf8": 0, "upstream": 0, "pattern": [0, 63, 68, 86], "rpgener": 0, "anyth": 0, "goe": 0, "note": [0, 1, 3, 19, 23, 29, 33, 35, 37, 41, 52, 57, 61, 68, 83, 85, 86], "beyond": [0, 23, 30], "end": [0, 18, 19, 77, 79, 85, 86], "length": [0, 3, 8, 9, 12, 13, 15, 25, 27, 37, 39, 43, 79], "repeat": [0, 8, 43, 86], "last": [0, 3, 12, 15, 29, 38, 79, 83, 85, 86], "mode": [0, 1, 2, 3, 14, 23, 28, 48, 68, 86], "rpnoframereus": 0, "Will": [0, 2, 86], "input": [0, 9, 15, 16, 19, 23, 28, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41, 42, 45, 53, 54, 56, 57, 61, 64, 69, 71], "most": [0, 3, 9, 15, 19, 23, 27, 35, 48, 69, 81, 83, 84, 85, 86], "onc": [0, 18, 84, 86], "output": [0, 2, 9, 15, 23, 27, 28, 31, 33, 35, 37, 39, 41, 44, 45, 47, 48, 53, 58, 61, 64, 69, 82, 83], "exactli": [0, 12, 53, 69, 86], "trim": [0, 5, 82, 86], "revers": [0, 5, 10, 35, 82, 86], "selecteveri": [0, 5, 33, 82, 86], "rpstrictspati": 0, "n": [0, 35, 37, 54, 85, 86], "differ": [0, 9, 11, 15, 19, 23, 24, 35, 39, 46, 47, 51, 52, 56, 61, 69, 70, 83, 86], "fix": [0, 2, 30, 63, 86], "known": [0, 1, 53, 61, 83], "ahead": 0, "lut": [0, 5, 45, 82], "expr": [0, 5, 37, 82], "condition": 0, "similar": [0, 4, 86], "cach": [0, 37, 68, 86], "cmauto": 0, "enabl": [0, 35, 68, 86], "disabl": [0, 68], "base": [0, 3, 4, 35, 65, 68, 77, 84, 85], "report": [0, 3, 83, 86], "consum": 0, "cmforcedis": 0, "never": [0, 3, 25, 83, 86], "cmforceen": 0, "opaqu": [0, 86], "access": [0, 2, 37, 81, 82], "hold": [0, 86], "each": [0, 7, 9, 16, 19, 21, 23, 24, 27, 28, 30, 31, 35, 42, 49, 50, 53, 71, 85, 86], "row": [0, 78], "pixel": [0, 3, 21, 24, 28, 30, 31, 35, 40, 42, 45, 48, 49, 53, 55, 56, 58, 61], "guarante": [0, 2, 3, 35], "align": [0, 1, 61, 73, 74, 75, 76, 77], "least": 0, "32": [0, 19, 24, 28, 31, 35, 40, 41, 42, 49, 53, 58, 83, 85], "byte": [0, 1, 35, 77, 86], "two": [0, 1, 3, 23, 30, 35, 45, 48, 50, 56, 83, 86], "same": [0, 1, 2, 9, 12, 13, 15, 18, 24, 25, 28, 32, 33, 35, 37, 39, 40, 48, 50, 54, 61, 63, 67, 72, 78, 83, 86], "width": [0, 1, 25, 30, 61, 65, 72, 86], "per": [0, 3, 35, 37, 48, 61, 83, 84, 86], "stride": [0, 86], "attach": [0, 3, 27, 59, 76, 84, 86], "refer": [0, 2, 13, 25, 61, 69, 82, 83], "construct": 0, "Its": [0, 37, 86], "primari": [0, 3, 61], "repres": [0, 27, 61, 86], "instanc": [0, 3, 81, 86], "individu": [0, 7, 13, 24, 25, 35, 42], "keep": [0, 13, 25, 35], "track": [0, 81], "There": [0, 3, 13, 19, 25, 83, 86], "few": [0, 2, 35, 83, 86], "built": [0, 3, 4, 77, 83], "therefor": [0, 1, 28, 86], "basic": [0, 1, 81, 82, 86], "identifi": [0, 9, 18, 83, 86], "com": [0, 83, 84], "std": [0, 1, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 78, 79, 80, 81, 83, 86], "namespac": [0, 1, 18, 19, 83, 86], "resiz": [0, 1, 5, 37, 48, 57, 65, 82, 86], "modul": [0, 2, 19, 83, 84, 86], "av": [0, 19, 83, 85], "dylib": 0, "dll": [0, 18, 19, 37, 83, 85, 86], "pointer": [0, 1, 2, 86], "pass": [0, 2, 3, 19, 26, 35, 44, 45, 54, 81, 83, 85, 86], "attribut": [0, 61, 81, 86], "uniqu": [0, 86], "among": 0, "becaus": [0, 30, 35, 54, 84], "what": [0, 56, 78, 81], "sure": [0, 86], "up": [0, 2, 18, 19, 35, 44, 45, 77, 83, 86], "full": [0, 3, 41, 48, 61, 85, 86], "name": [0, 1, 2, 3, 18, 19, 23, 27, 44, 56, 60, 61, 66, 85, 86], "messag": [0, 2, 55, 85, 86], "thing": [0, 3, 19, 37, 69, 83, 86], "you": [0, 2, 3, 19, 27, 35, 37, 54, 61, 65, 81, 83, 84, 85, 86], "enumer": [0, 61], "its": [0, 1, 2, 9, 15, 31, 49, 53, 68, 83, 85, 86], "locat": [0, 2, 61, 83], "system": [0, 61, 83, 86], "freed": [0, 2, 86], "belong": [0, 86], "primarili": [0, 3, 27], "queri": 0, "editor": [0, 4, 81, 83, 85, 86], "One": [0, 33, 83], "peculiar": 0, "cannot": [0, 83, 86], "instead": [0, 12, 13, 23, 25, 28, 29, 35, 44, 45, 54, 61, 83, 86], "done": [0, 28, 35, 83, 86], "between": [0, 9, 24, 28, 31, 40, 41, 42, 46, 47, 49, 53, 56, 58, 61, 63, 69, 79, 84, 86], "layer": 0, "pair": [0, 3], "arrai": [0, 9, 28, 35, 44, 53, 76, 77, 86], "integ": [0, 1, 7, 13, 23, 24, 28, 31, 35, 40, 41, 42, 49, 53, 58, 61, 77, 86], "sort": [0, 49], "In": [0, 8, 10, 11, 12, 15, 19, 35, 43, 48, 49, 61, 62, 63, 69, 70, 79, 83], "alphanumer": 0, "charact": [0, 3, 17, 18, 19, 77, 86], "underscor": [0, 77, 86], "prefix": [0, 1, 83, 86], "eras": 0, "regist": [0, 85, 86], "logger": [0, 86], "clip": [0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 86], "fill": 0, "proper": [0, 3], "check": [0, 1, 55, 69, 81, 83, 86], "manual": [0, 3, 82, 85, 86], "discourag": 0, "illeg": [0, 35, 86], "combin": [0, 9, 15, 19, 33, 69, 78, 81], "caus": [0, 19, 48, 83], "undefin": [0, 35, 86], "int": [0, 1, 2, 3, 6, 8, 9, 12, 13, 14, 15, 21, 22, 23, 24, 25, 26, 28, 30, 31, 32, 34, 35, 38, 40, 41, 42, 43, 44, 45, 46, 48, 49, 51, 53, 56, 58, 61, 63, 65, 66, 68, 69, 73, 74, 75, 76, 77, 79], "colorfamili": [0, 69], "sampletyp": [0, 13], "bitspersampl": 0, "signific": 0, "bytespersampl": 0, "power": [0, 86], "2": [0, 3, 4, 10, 15, 19, 24, 28, 31, 33, 35, 37, 38, 40, 41, 42, 44, 45, 46, 47, 48, 49, 51, 52, 53, 58, 61, 62, 63, 65, 66, 67, 69, 78, 81, 85, 86], "smallest": [0, 53], "fit": [0, 77], "subsamplingw": 0, "subsamplingh": 0, "log2": 0, "subsampl": [0, 1, 21, 30, 35, 61, 69, 86], "factor": [0, 77], "appli": [0, 7, 9, 23, 27, 28, 32, 34, 35, 44, 45, 48], "third": [0, 48, 50, 69, 86], "plane": [0, 1, 23, 24, 26, 28, 31, 35, 37, 40, 41, 42, 44, 45, 46, 48, 49, 50, 51, 53, 56, 58, 69, 71, 86], "conveni": [0, 1, 2, 65, 73, 74, 75, 76, 77, 83], "uv_width": 0, "y_width": 0, "numplan": 0, "about": [0, 3, 73, 74, 81, 82, 86], "vari": [0, 61], "int64_t": [0, 1], "fpsnum": [0, 22, 25], "numer": [0, 9, 61, 86], "part": [0, 84, 86], "rate": [0, 22, 39, 63, 64, 86], "reduc": [0, 1], "fraction": [0, 3, 86], "fpsden": [0, 22, 25], "denomin": [0, 86], "height": [0, 1, 25, 30, 61, 65, 72, 86], "dimens": [0, 1, 11, 39, 48, 50, 61, 69, 70, 86], "numfram": 0, "numchannel": 0, "uint64_t": 0, "channellayout": 0, "bitmask": 0, "present": [0, 9, 33, 86], "left": [0, 3, 15, 21, 30, 35, 61, 78, 80], "shift": [0, 48, 61], "sampler": [0, 1, 6, 13], "numsampl": 0, "const": [0, 1, 2], "char": [0, 2], "versionstr": 0, "copyright": 0, "numthread": 0, "worker": 0, "maxframebuffers": 0, "framebuff": [0, 86], "grow": 0, "size": [0, 1, 25, 30, 61, 69, 84, 86], "befor": [0, 2, 23, 28, 58, 83, 86], "aggress": [0, 86], "reclaim": 0, "usedframebuffers": 0, "sourc": [0, 3, 15, 33, 37, 61, 65, 81, 83, 85], "requestpattern": 0, "initi": [0, 3, 83], "configplugin": 0, "pluginnamespac": 0, "pluginvers": 0, "apivers": 0, "flag": [0, 2, 86], "provid": [0, 1, 2, 19, 37, 61, 83, 86], "recommend": [0, 2, 3, 61], "If": [0, 1, 2, 3, 8, 9, 13, 15, 18, 19, 23, 24, 25, 27, 28, 31, 35, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 53, 54, 55, 56, 58, 60, 61, 63, 64, 66, 67, 74, 79, 81, 83, 85, 86], "know": [0, 61, 81, 86], "actual": [0, 86], "simpli": [0, 1, 2, 24, 28, 31, 40, 41, 42, 44, 49, 53, 54, 57, 58, 83, 85, 86], "match": [0, 3, 83], "re": [0, 83], "compil": [0, 35, 82], "against": 0, "consist": 0, "ORed": 0, "togeth": [0, 23, 28, 33, 46, 47, 51, 52, 72, 86], "typic": [0, 61], "success": [0, 2, 18, 19, 86], "arg": [0, 85], "returntyp": 0, "vspublicfunct": 0, "argsfunc": 0, "functiondata": 0, "giant": 0, "wai": [0, 2, 9, 15, 17, 18, 19, 22, 23, 37, 69, 77, 78, 79, 83, 85, 86], "case": [0, 2, 19, 37, 69, 86], "shouldn": 0, "desir": [0, 86], "sane": 0, "default": [0, 2, 13, 20, 24, 25, 28, 31, 35, 41, 42, 44, 45, 46, 48, 50, 51, 53, 55, 61, 68, 74, 83, 86], "suit": 0, "been": [0, 2, 18, 48, 65, 84, 86], "releas": [0, 83, 86], "maximum": [0, 1, 5, 8, 20, 24, 40, 41, 43, 82, 86], "automat": [0, 2, 37, 68, 81, 83, 86], "detect": [0, 83, 86], "info": [0, 85], "highest": [0, 9, 42, 49], "support": [0, 2, 4, 20, 35, 81, 82, 83, 84, 86], "msgtype": 0, "msg": 0, "send": [0, 84, 86], "through": [0, 2, 35, 44, 45, 54, 86], "framework": [0, 86], "abort": 0, "deliv": 0, "handler": [0, 86], "vsloghandlerfre": 0, "userdata": 0, "instal": [0, 4, 81, 82, 85, 86], "custom": [0, 2, 86], "variou": [0, 81, 86], "emit": [0, 86], "handl": [0, 2, 61, 84, 86], "hundr": 0, "soon": 0, "warn": [0, 1], "auto": [0, 37, 81], "won": [0, 2, 55, 83], "disappear": 0, "typedef": 0, "null": [0, 2, 66], "restor": [0, 86], "remov": [0, 54, 60, 63, 79, 86], "invalid": [0, 35, 86], "obtain": [0, 2, 85, 86], "propsrc": 0, "copi": [0, 1, 3, 9, 13, 24, 25, 28, 31, 35, 40, 41, 42, 48, 49, 50, 53, 54, 58, 72, 83, 86], "anoth": [0, 1, 3, 22, 27, 54, 59, 61, 86], "fatal": [0, 3, 19], "uninitialis": 0, "colorspac": [0, 4, 40, 48, 61, 84, 86], "greater": [0, 24, 31, 35, 41], "than": [0, 3, 8, 15, 24, 29, 31, 35, 37, 41, 43, 50, 52, 53, 54, 61, 86], "suitabl": [0, 57], "ownership": [0, 2], "transfer": [0, 3, 61, 86], "caller": [0, 1, 86], "planesrc": 0, "element": [0, 28, 53], "correspond": [0, 15, 28, 53, 61, 77, 86], "assum": [0, 15, 35, 41, 48, 81, 83], "framea": 0, "frameb": 0, "framec": 0, "3": [0, 2, 3, 10, 28, 35, 37, 53, 61, 62, 63, 68, 69, 78, 79, 83, 84, 86], "newfram": 0, "f": [0, 35, 37, 45, 54, 86], "w": [0, 35], "now": [0, 2, 81, 86], "apart": [0, 85, 86], "channelsrc": 0, "nth": [0, 15], "decrement": 0, "count": [0, 2, 86], "delet": [0, 32, 33, 64, 65], "reach": [0, 8, 43], "safe": [0, 2, 19, 86], "increment": [0, 2, 86], "duplic": [0, 34, 35, 63, 86], "just": [0, 48, 81, 83, 84], "As": 0, "buffer": [0, 2, 86], "fashion": 0, "realli": [0, 19, 86], "until": [0, 2, 8, 43], "oper": [0, 2, 3, 8, 9, 11, 12, 15, 27, 35, 43, 53, 57, 58, 63, 69, 70, 81, 83, 86], "occur": 0, "transpar": 0, "read": [0, 1, 2, 3, 19, 22, 54, 85, 86], "valid": [0, 1, 2, 28, 33, 86], "long": [0, 13, 25, 54, 77, 86], "live": [0, 86], "ptrdiff_t": 0, "distanc": 0, "consecut": 0, "line": [0, 77, 81, 83, 86], "doesn": [0, 2, 77], "isn": [0, 2, 35, 64], "uint8_t": 0, "three": [0, 19, 35, 69], "alloc": [0, 83], "contigu": [0, 86], "chunk": [0, 86], "distinguish": 0, "given": [0, 1, 7, 9, 11, 15, 22, 24, 25, 35, 44, 50, 63, 69, 70, 72, 76, 86], "depend": [0, 3, 18, 23, 66, 68, 83, 86], "chroma": [0, 1, 3, 50, 61], "vi": [0, 1], "filtermod": [0, 81], "numdep": 0, "instancedata": 0, "pleas": 0, "easi": [0, 23, 83], "identif": 0, "level": [0, 5, 82, 84, 86], "effici": [0, 86], "configur": [0, 83, 86], "privat": 0, "someth": [0, 3, 27, 84, 86], "went": 0, "ident": [0, 61, 86], "except": [0, 35, 61, 83, 85, 86], "ai": 0, "immedi": 0, "creation": [0, 2], "upper": [0, 24, 42, 55, 86], "mani": [0, 4, 23, 30, 68, 83, 86], "addit": [0, 3, 11, 15, 54, 61, 70, 84, 85, 86], "try": [0, 19, 48, 61, 84], "linear": [0, 41, 61], "strategi": 0, "debug": [0, 20, 83, 86], "work": [0, 2, 19, 23, 83, 84, 86], "well": [0, 19, 50, 56, 68, 84, 86], "silent": [0, 17, 77, 83], "ignor": [0, 19, 83, 86], "reset": [0, 68], "discard": 0, "fixeds": [0, 14, 68], "maxsiz": [0, 14, 68], "maxhistorys": 0, "detail": [0, 86], "adjust": [0, 41, 63, 68, 83], "algorithm": 0, "unless": [0, 11, 39, 61, 70, 86], "recent": [0, 83, 85], "evict": 0, "off": [0, 2], "shrink": 0, "benefici": 0, "effect": [0, 33, 41, 45, 64, 86], "decreas": [0, 58], "tri": [0, 19, 83, 86], "fairli": [0, 26, 68, 86], "destin": [0, 61], "At": [0, 2, 23, 86], "termin": [0, 66, 83], "written": [0, 2, 4, 35, 84], "meaning": [0, 19, 86], "compon": [0, 4, 86], "rang": [0, 3, 24, 28, 35, 38, 41, 42, 44, 45, 48, 50, 57, 61, 85], "8": [0, 24, 28, 31, 35, 38, 40, 41, 42, 49, 53, 57, 58, 61, 77, 78, 83], "horizont": [0, 28, 36, 81, 86], "4": [0, 3, 28, 45, 46, 47, 51, 52, 53, 61, 63, 83], "vertic": [0, 28, 36, 86], "rgb": [0, 19, 61, 69, 86], "contruct": [], "bitshift": 0, "stereo": [0, 9, 13, 15], "express": [0, 35], "acfrontleft": 0, "acfrontright": 0, "uint32_t": 0, "id": [0, 1, 37, 61, 86], "gotten": [0, 54, 86], "failur": [0, 2, 54], "dealloc": 0, "later": [0, 57, 83, 86], "leav": 0, "empti": [0, 2, 13, 25, 35, 83], "next": [0, 2, 3, 28], "errormessag": 0, "add": [0, 1, 2, 21, 28, 46, 47, 66, 67, 83, 85], "clear": [0, 2, 61, 86], "encount": [0, 55, 83, 86], "lost": 0, "otherwis": [0, 8, 13, 19, 24, 25, 39, 43, 47, 86], "alreadi": [0, 18, 66, 67, 83, 84, 85, 86], "specifi": [0, 2, 3, 13, 15, 17, 21, 22, 24, 25, 28, 30, 31, 32, 34, 35, 40, 41, 42, 44, 45, 48, 49, 50, 53, 54, 56, 58, 61, 64, 67, 69, 79, 84, 85, 86], "die": 0, "total": [0, 83], "here": [0, 2, 3, 28, 53, 78, 81, 86], "problem": [0, 3, 19], "convert": [0, 1, 35, 41, 61, 77, 86], "satur": [0, 1, 28], "lot": 0, "faster": 0, "loop": [0, 1, 5, 82, 86], "descript": [0, 86], "overwritten": [0, 66], "old": [0, 83], "neg": [0, 7, 15, 28, 35], "doubl": [0, 1, 64], "d": [0, 1, 35], "arbitrari": [0, 37, 66, 86], "consid": [0, 1, 11, 35, 39, 50, 53, 68, 70, 79], "alter": [0, 68], "longer": [0, 2, 29, 68], "everyth": [0, 35, 83, 85], "propgetfram": 0, "vsfunctionref": 0, "mapgetfunc": 0, "func": [0, 19, 37, 44, 45, 54, 82, 86], "url": 0, "better": [0, 57], "over": [0, 2, 8, 23, 33, 43, 68, 84, 86], "final": [0, 28, 68, 83, 86], "absolut": [0, 2, 3, 28, 35, 56], "path": [0, 2, 17, 18, 19, 37, 61, 82, 83], "real": [0, 85], "symbol": 0, "link": [0, 83], "delimit": 0, "forward": 0, "slash": 0, "retain": [0, 2], "declar": [0, 86], "smoothli": 0, "readi": 0, "where": [0, 2, 9, 24, 40, 48, 61, 68, 83, 86], "successfulli": [0, 86], "either": [0, 1, 7, 19, 22, 24, 44, 45, 61, 83, 86], "loadplugin": [0, 5, 17, 37, 82, 83], "obviou": 0, "vsfreefunctiondata": 0, "context": [0, 86], "callback": [0, 2, 86], "task": 0, "errormsg": 0, "bufsiz": 0, "synchron": [0, 3], "necessari": [0, 48, 83], "dure": [0, 55], "want": [0, 3, 65, 81, 83, 84, 86], "trail": [0, 86], "vsframedonecallback": 0, "client": [0, 2], "were": 0, "reorder": 0, "them": [0, 3, 19, 37, 54, 60, 61, 83, 85, 86], "previous": [0, 84, 86], "usual": [0, 3, 13, 25, 35, 46, 47, 51, 52, 61, 83, 85, 86], "framectx": 0, "arframereadi": 0, "best": 0, "ascend": 0, "By": [0, 20, 35, 44, 45, 46, 48, 51], "referenc": [0, 37], "20": 0, "batch": [0, 85], "letter": [0, 3], "word": [0, 49], "za": 0, "z": [0, 3, 35], "z0": 0, "9_": 0, "pascalcas": 0, "separ": [0, 7, 16, 64, 71, 86], "semicolon": 0, "made": [0, 84, 86], "field": [0, 3, 33, 61, 64, 65, 66, 67], "colon": 0, "insert": 0, "whitespac": 0, "lowercas": [0, 86], "anod": [0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], "vnode": [0, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80], "afram": 0, "vframe": 0, "opt": 0, "place": [0, 1, 2, 83, 86], "without": [0, 35, 37, 61], "remain": [0, 86], "follow": [0, 19, 61, 83], "blah": 0, "moo": 0, "asdf": [0, 83], "accept": [0, 3, 30, 61, 69, 86], "matter": [0, 56], "similarli": 0, "import": [0, 2, 35, 37, 81, 83], "often": [0, 61], "foocreat": 0, "initialis": 0, "perform": [0, 12, 26, 28, 37, 48, 61, 86], "usabl": [0, 2], "push": 0, "greatli": 0, "benefit": 0, "produc": [0, 3, 35, 54], "Such": [0, 35], "necessarili": 0, "global": [0, 19, 83, 85, 86], "doe": [0, 22, 27, 78, 86], "meet": 0, "minimum": [0, 1, 5, 41, 82], "simpl": [0, 3, 28, 37, 77, 85, 86], "five": 0, "foogetfram": 0, "foofre": 0, "These": [0, 19, 35, 83, 86], "sdk": [0, 3], "folder": [0, 83], "vspapi": 0, "purpos": [0, 20, 35, 85, 86], "subset": 0, "activationreason": 0, "framedata": 0, "local": [0, 82, 83, 86], "persist": 0, "could": [0, 2, 85], "concurr": [0, 85, 86], "freeli": 0, "splice": [0, 5, 11, 82, 86], "collect": 1, "vsh_": 1, "vsh": 1, "document": [1, 83], "plugin": [1, 2, 4, 17, 18, 19, 82, 84, 86], "attempt": [1, 83, 86], "portabl": [1, 82, 85], "definit": 1, "c99": 1, "restrict": [1, 21, 30, 35, 61], "keyword": [1, 82], "counterpart": 1, "pptr": 1, "_aligned_malloc": 1, "posix_memalign": 1, "elsewher": 1, "style": [1, 86], "ptr": 1, "_aligned_fre": 1, "b": [1, 35, 37, 39, 48, 50, 61, 65, 69, 81, 86], "size_t": 1, "templat": 1, "malloc": 1, "inlin": 1, "bool": 1, "vsvideoinfo": 1, "v1": [1, 24], "v2": [1, 85], "unsign": 1, "presetformat": 1, "vsvideoformat": 1, "v": [1, 9, 15, 25, 28, 35, 37, 61, 69, 83, 85, 86], "vscore": [1, 2, 86], "vsapi": [1, 2], "true": [1, 11, 19, 28, 33, 35, 39, 48, 63, 64, 70, 86], "framer": [1, 3, 22, 73, 86], "taken": [1, 3, 35], "consider": [1, 3, 35, 86], "compar": [1, 84], "vsaudioinfo": 1, "num": 1, "den": 1, "mul": 1, "div": 1, "multipli": [1, 23, 28, 39, 48, 57, 58, 63], "ration": [1, 3, 22], "result": [1, 28, 35, 46, 51, 57, 61, 83, 84, 86], "ensur": [1, 86], "addnum": 1, "addden": 1, "sign": 1, "silenc": 1, "vsmap": [1, 2], "avoid": [1, 23, 47, 83, 86], "unexpect": 1, "overflow": [1, 35], "dstp": 1, "dst_stride": 1, "srcp": 1, "src_stride": 1, "row_siz": 1, "memcpi": 1, "vsformat": 1, "fi": 1, "particular": 1, "regard": 1, "wrapper": [2, 4, 83, 86], "vapoursynth": [0, 2, 4, 17, 18, 33, 37, 61, 74, 79, 81, 83, 84, 85], "interfac": 2, "evalu": [2, 35, 37, 44, 85], "everywher": 2, "els": [2, 27, 37, 83, 85, 86], "python": [2, 4, 8, 10, 11, 12, 17, 18, 19, 43, 62, 63, 70, 79, 81, 82, 84], "vspipe": [2, 82, 83, 86], "vsvfw": [2, 85, 86], "program": [2, 4, 82, 85], "player": [2, 4], "mpv": [2, 4, 81], "libvapoursynth": [2, 83], "dlopen": 2, "rtld_global": 2, "abl": 2, "design": [2, 3, 84], "environ": [2, 82, 85, 86], "commun": [2, 83], "vsscript_api_vers": 2, "explicitli": 2, "pre": [2, 48, 57], "regardless": [2, 40, 48], "yet": [2, 19, 86], "scriptfilenam": 2, "entir": [2, 86], "displai": 2, "special": [2, 3, 30, 35, 83, 84, 86], "__file__": 2, "variabl": [2, 19, 25, 30, 69, 83, 86], "sy": [2, 86], "exit": [2, 85, 86], "code": [2, 3, 35, 55, 61, 83, 85, 86], "directori": [2, 83, 85], "mib": 2, "enough": 2, "everyon": 2, "behav": 2, "okai": 2, "dst": 2, "vsscript_setvari": 2, "var": 2, "vsnode": 2, "mark": [2, 61, 86], "alpha": [2, 3, 19, 27, 48, 57, 59, 86], "altern": [2, 15, 45, 84, 86], "mean": [2, 3, 19, 26, 33, 35, 48, 50, 56, 61, 64, 69, 86], "multip": [], "exact": [2, 83, 86], "disregard": 2, "alt": 2, "cancel": 2, "finish": [2, 86], "setcwd": 2, "temporarili": 2, "dir": [3, 83], "simplefilt": 3, "function": [3, 18, 19, 20, 30, 37, 44, 45, 46, 47, 51, 52, 54, 55, 56, 59, 61, 65, 68, 73, 74, 75, 76, 77, 82, 83, 85], "relat": [3, 83], "aren": [3, 30, 61], "checklist": 3, "watch": 3, "sometim": [3, 61, 86], "own": [3, 18, 83, 84, 86], "deep": 3, "appear": [3, 85], "vapoursynthplugininit": 3, "constructor": 3, "destructor": 3, "complic": 3, "howev": [3, 19, 61, 86], "even": [3, 26, 35, 41, 61, 63, 86], "fmserial": 3, "enter": [3, 83], "simultan": 3, "misconsept": 3, "rule": [3, 86], "And": 3, "those": [3, 76, 83, 86], "lock": 3, "9": [3, 28, 61, 77], "camelcas": [3, 86], "categori": [3, 86], "start": [3, 63, 79, 82, 83, 84, 85, 86], "_": [3, 61], "strictli": 3, "_chromaloc": 3, "yuv": [3, 35, 41, 44, 61, 69, 86], "center": [3, 23, 28, 31, 61], "topleft": 3, "top": [3, 21, 30, 33, 35, 61, 64, 65, 66, 67, 83], "bottomleft": 3, "5": [3, 9, 19, 28, 35, 50, 53, 61, 63, 78, 85, 86], "bottom": [3, 21, 30, 33, 61, 64, 65], "_colorrang": 3, "limit": [3, 5, 31, 41, 44, 48, 53, 57, 61, 82, 86], "pc": [3, 61], "tv": [3, 61], "_primari": [3, 86], "color": [3, 21, 25, 37, 48, 61, 69], "itu": [3, 61], "h": [3, 28, 61, 82, 86], "265": [3, 61], "tabl": [3, 44, 45, 61], "_matrix": [3, 86], "matrix": [3, 9, 28, 46, 47, 51, 52, 61, 78], "coeffici": [3, 9, 28, 61], "_transfer": [3, 86], "characterist": [3, 61], "_fieldbas": [3, 33, 61, 64, 65, 66, 67], "compos": 3, "independ": 3, "interlac": [3, 61, 65], "progress": [3, 61, 65, 85, 86], "_absolutetim": 3, "timestamp": 3, "durat": [3, 22, 39, 63, 64], "_durationnum": [3, 22], "_durationden": [3, 22], "normal": [3, 18, 35, 51, 52, 56, 86], "bint": [3, 13, 18, 23, 25, 28, 33, 39, 44, 45, 48, 53, 61, 63, 64, 70], "_comb": [3, 54], "postprocess": 3, "_field": [3, 33, 64, 65], "separatefield": [3, 5, 33, 82], "signal": 3, "_picttyp": 3, "ipb": 3, "_sarnum": 3, "_sarden": 3, "aspect": 3, "ratio": 3, "_scenechangenext": 3, "scene": [3, 23], "_scenechangeprev": 3, "_alpha": [3, 27, 59], "d2v": 4, "witch": 4, "open": [4, 81, 83, 85, 86], "d2vsourc": 4, "hybrid": 4, "doom9": 4, "encod": [4, 65, 81], "gui": 4, "net": 4, "media": 4, "smoothvideo": 4, "project": [4, 84], "realtim": 4, "interpol": 4, "staxrip": 4, "extend": [4, 9, 15, 30, 39], "syntax": 4, "fast": [4, 26, 35], "preview": [4, 82, 86], "spiritu": 4, "successor": 4, "virtualdub2": 4, "virtualdub": [4, 19, 81], "bitdepth": [4, 19, 28, 47, 52, 85], "vsmkv": 4, "fuse": 4, "virtual": [4, 85], "filesystem": [4, 85], "uncompress": [4, 85], "matroska": 4, "mkv": [4, 65, 81, 85], "vspreview": 4, "standalon": [4, 86], "too": [4, 7, 77, 86], "r": [4, 17, 18, 19, 61, 69, 83, 85, 86], "minim": 4, "wobbli": 4, "ivtc": 4, "assist": 4, "yatta": 4, "yuuno": 4, "incorpor": 4, "jupyt": 4, "nim": 4, "bind": [4, 86], "languag": [4, 83, 84], "rust": 4, "vsxx": 4, "github": [4, 83], "action": 4, "your": [4, 81, 83, 85, 86], "loadallplugin": [5, 82], "setmaxcpu": [5, 82], "addbord": [5, 82], "assumefp": [5, 82], "averagefram": [5, 82], "binar": [5, 82], "binarizemask": [5, 82], "blankclip": [5, 37, 74, 82, 86], "boxblur": [5, 82], "cliptoprop": [5, 59, 82], "convolut": [5, 23, 46, 47, 51, 52, 82], "copyframeprop": [5, 82], "crop": [5, 82], "cropab": [5, 82], "deflat": [5, 82], "inflat": [5, 82], "deletefram": [5, 82], "doubleweav": [5, 82], "duplicatefram": [5, 82], "flipvert": [5, 78, 82, 86], "fliphorizont": [5, 78, 81, 82], "frameev": [5, 54, 82], "freezefram": [5, 82], "interleav": [5, 33, 64, 82], "invert": [5, 82], "invertmask": [5, 82], "lut2": [5, 82], "makediff": [5, 47, 51, 82], "makefulldiff": [5, 52, 82], "maskedmerg": [5, 57, 82], "median": [5, 82], "merg": [5, 15, 48, 51, 52, 69, 82], "mergediff": [5, 46, 82], "mergefulldiff": [5, 47, 82], "modifyfram": [5, 37, 82], "pemverifi": [5, 82], "planestat": [5, 37, 82], "premultipli": [5, 48, 82], "prewitt": [5, 82], "sobel": [5, 82], "proptoclip": [5, 27, 82], "removeframeprop": [5, 82], "bilinear": [5, 37, 61, 65], "bicub": [5, 61, 86], "lanczo": [5, 61], "spline16": [5, 61], "spline36": [5, 61], "spline64": [5, 61], "bob": [5, 61], "setfieldbas": [5, 82], "setframeprop": [5, 65, 82], "setvideocach": [5, 14, 82], "shuffleplan": [5, 82], "splitplan": [5, 82], "stackvert": [5, 82], "stackhorizont": [5, 82], "transpos": [5, 82], "turn180": [5, 82], "clipinfo": [5, 77], "coreinfo": [5, 77], "framenum": [5, 77], "frameprop": [5, 77, 86], "assumesampler": [5, 82], "audiogain": [5, 81, 82], "audioloop": [5, 82, 86], "audiomix": [5, 82], "audiorevers": [5, 82, 86], "audiosplic": [5, 82, 86], "audiotrim": [5, 82, 86], "blankaudio": [5, 82], "setaudiocach": [5, 82], "shufflechannel": [5, 82], "splitchannel": [5, 82], "src": [6, 22], "gain": [7, 81], "volum": [7, 85], "suppli": [7, 23, 56, 74, 86], "larg": [7, 19, 26, 84], "lead": 7, "less": [8, 31, 41, 43, 53, 86], "channels_out": [9, 15], "mix": [9, 35], "implicitli": [9, 15, 69], "ll": [9, 15, 83], "longest": [9, 15, 39], "front_left": [9, 13, 15, 86], "front_right": [9, 13, 15, 86], "lowest": [9, 42, 49], "downmix": 9, "mono": [9, 15], "front_cent": [9, 86], "7071": 9, "low_frequ": [9, 86], "back_left": [9, 86], "back_right": [9, 86], "would": [10, 47, 57, 62, 78], "slice": [10, 12, 62, 63, 79, 82], "mismatch": [11, 39, 48, 70, 86], "unit": [12, 61, 86], "obvious": 12, "44100": 13, "10": [13, 25, 35, 45, 61, 86], "edit": [13, 25, 27, 84], "test": [13, 20, 25, 61, 83, 86], "44": 13, "1khz": 13, "preced": [13, 25, 33], "twice": [13, 15, 32, 78], "historys": [14, 68], "channels_in": 15, "extract": [15, 59, 69, 85], "reus": [15, 86], "swap": [15, 35, 69], "right": [15, 21, 23, 30, 78, 80], "clipa": [15, 35, 45, 46, 47, 48, 50, 51, 52, 56], "clipb": [15, 35, 45, 46, 47, 48, 50, 51, 52, 56], "nativ": [17, 18, 83], "skip": 17, "bewar": [17, 18, 19], "escap": [17, 18, 19, 86], "correct": [17, 18, 19, 83, 86], "altsearchpath": 18, "fals": [18, 28, 33, 35, 64, 86], "prevent": [18, 41, 68, 83, 86], "collis": [18, 19, 86], "being": [18, 23, 35, 86], "search": [18, 82, 83], "6": [19, 28, 35, 53, 61, 85], "64": [19, 35, 83, 85], "higher": [19, 45, 47, 52, 85], "pack": [19, 86], "coincident": 19, "expect": [19, 86], "yuy2": [19, 86], "rgb32": 19, "yuv422p8": [19, 86], "rgb24": [19, 25, 37, 61, 86], "compatpack": 19, "env": [19, 86], "trigger": 19, "distinct": 19, "func_2": 19, "func_3": 19, "overload": 19, "give": 19, "insan": 19, "common": [19, 82, 86], "cpu": [20, 35], "intend": [20, 24, 27, 40, 86], "instruct": [20, 35, 83], "optim": [20, 35, 61], "x86": 20, "avx2": 20, "sse2": 20, "none": [20, 37, 61, 86], "black": [21, 25, 37], "border": 21, "side": [21, 30, 83], "obei": 21, "newli": 21, "metadata": [22, 84, 86], "assign": 22, "overwrit": [22, 83], "comput": [22, 84], "weight": [23, 48, 50], "scale": [23, 45, 58, 61, 73, 74, 75, 76, 77, 84], "scenechang": 23, "averag": [23, 31, 35, 45, 50, 56], "seen": 23, "tempor": 23, "sum": [23, 28], "divid": [23, 28, 39, 63], "odd": [23, 28, 63, 86], "rest": 23, "31": 23, "threshold": [24, 31, 53], "v0": 24, "turn": [24, 61, 77, 80, 86], "imag": [24, 61, 84], "mask": [24, 27, 40, 46, 47, 48, 51, 52, 58, 59, 86], "depth": [24, 28, 31, 40, 41, 42, 45, 49, 53, 58], "middl": [24, 28, 49], "lower": [24, 42, 45, 55], "equal": 24, "unprocess": [24, 28, 31, 40, 41, 42, 48, 49, 53, 58], "640": [25, 61], "480": 25, "24": 25, "varsiz": 25, "varformat": 25, "640x480": 25, "24fp": 25, "themselv": 25, "still": [25, 30, 86], "hradiu": 26, "hpass": 26, "vradiu": 26, "vpass": 26, "box": [26, 83], "blur": [26, 28], "radiu": 26, "cheapli": 26, "approxim": [26, 35], "gaussian": 26, "mclip": 27, "prop": [27, 37, 54, 56, 59, 60, 66, 76, 86], "deriv": [27, 61, 83], "invers": [27, 59], "bia": 28, "divisor": 28, "spatial": 28, "3x3": [28, 31, 49, 53], "neighbourhood": [28, 31, 49, 53], "nine": [28, 49], "round": [28, 61, 84], "nearest": 28, "larger": [28, 35], "clamp": [28, 35, 41, 45, 46, 47, 51], "25": [28, 86], "5x5": 28, "1023": [28, 35], "inclus": [28, 38, 79, 86], "7": [28, 53, 61, 73, 74, 75, 76, 77, 83], "principl": 28, "becom": [28, 31, 53], "select": [28, 61, 63, 85, 86], "squar": 28, "hv": 28, "vh": 28, "equival": [28, 35, 48, 57, 61, 69, 86], "stronger": 28, "58": 28, "prop_src": [29, 37], "simplest": [30, 37], "croprel": 30, "alia": [30, 61], "hand": 30, "area": 30, "thu": 30, "whole": [30, 61, 86], "pictur": [30, 78, 86], "awai": 30, "met": 30, "eight": 31, "much": [31, 53, 57, 86], "65535": 31, "tff": [33, 61, 64], "weav": 33, "back": [33, 46, 47, 51, 52, 86], "weak": [33, 86], "notion": 33, "undo": 33, "sep": 33, "woven": 33, "accordingli": 33, "26": 35, "polish": 35, "notat": 35, "previou": [35, 68], "fewer": 35, "practic": [35, 86], "incompat": 35, "content": [35, 57, 78, 82, 86], "runtim": [35, 83, 84], "pitfal": [35, 82], "speed": 35, "255": [35, 37, 41, 57, 61], "difficult": 35, "u": [35, 61, 69], "co": 35, "cg": 35, "bits_per_sampl": [35, 44, 45, 86], "overrid": [35, 83], "f16c": 35, "logic": 35, "arithmet": 35, "comparison": 35, "stack": [35, 72], "manipul": [35, 84], "dup": 35, "former": 35, "topmost": 35, "latter": [35, 86], "swapn": 35, "dupn": 35, "form": [35, 47, 86], "step": [35, 83, 86], "dup0": 35, "swap1": 35, "machin": 35, "origin": [35, 38], "finit": 35, "neither": [35, 79], "nan": 35, "nor": [35, 79, 86], "inf": 35, "especi": 35, "transcendent": 35, "exp": 35, "x": [35, 37, 44, 45, 61, 69, 82], "88": 35, "3e": 35, "38": 35, "pow": 35, "1e": 35, "sqrt": [35, 37], "sin": 35, "ab": 35, "max": [35, 37, 42, 44, 55, 56], "min": [35, 42, 44, 55, 56], "xor": 35, "within": [35, 86], "2e": 35, "magnitud": 35, "1e5": 35, "accuraci": 35, "whose": [35, 83, 86], "2e5": 35, "y": [35, 45, 61], "uv": [35, 41, 61], "unchang": [35, 44, 45, 48, 50], "clipc": 35, "clipa16bit": 35, "clipb10bit": [35, 45], "clipa8bit": [35, 45], "256": 35, "junk": [35, 86], "direct": [35, 36, 81, 86], "clipa10bit": 35, "clipb16bit": 35, "yuv420p16": [35, 86], "flip": [36, 78, 81], "eval": 37, "clip_src": 37, "reliabl": 37, "deduc": 37, "mainli": [37, 59], "decis": 37, "improv": [37, 65, 84], "encourag": 37, "accomplish": 37, "anim": 37, "scriptclip": 37, "condit": [37, 54], "fade": 37, "white": [37, 61], "functool": 37, "base_clip": 37, "yuv420p8": [37, 61, 86], "1000": 37, "128": [37, 57, 61], "def": [37, 44, 45, 54], "animated_clip": 37, "partial": 37, "set_output": [37, 81, 85, 86], "balanc": 37, "show": [37, 85], "math": 37, "grayworld1adjust": 37, "small_numb": 37, "000000001": 37, "red": [37, 61], "planestatsaverag": 37, "green": [37, 61], "blue": [37, 61], "max_rgb": 37, "red_corr": 37, "green_corr": 37, "blue_corr": 37, "norm": 37, "r_gain": 37, "g_gain": 37, "b_gain": 37, "repr": 37, "grayworld1": 37, "matrix_": [37, 61], "rgb_clip": 37, "r_avg": 37, "g_avg": 37, "b_avg": 37, "adjusted_clip": 37, "bestsourc": [37, 81], "videosourc": [37, 65, 81], "freez": 38, "100": [38, 61, 85, 86], "231": 38, "15": [38, 61], "112": 38, "300": [38, 61], "50": [38, 86], "overlap": 38, "modify_dur": [39, 63, 64], "treat": [39, 65], "subtract": 40, "min_in": 41, "max_in": 41, "gamma": 41, "min_out": 41, "max_out": 41, "bright": [41, 61], "contrast": [41, 61], "remap": 41, "unintuit": 41, "235": [41, 44, 61], "240": [41, 44, 65], "undesir": 41, "degre": [41, 80], "convers": [41, 45, 61], "brighten": 41, "darken": 41, "lutf": [44, 45], "floatout": [44, 45], "look": [44, 45, 83], "luti": 44, "lutuv": 44, "ret": 44, "limited_clip": 44, "limiti": 44, "limituv": 44, "account": 45, "clip1": [45, 54, 86], "clip2": [45, 54, 86], "respons": [45, 86], "understand": 45, "clipi": 45, "clipx": 45, "unsharp": [46, 47, 51, 52], "luma": [46, 50, 51, 57, 69], "blur_clip": [46, 47, 51, 52], "diff_clip": [46, 47, 51, 52], "sharpened_clip": [46, 47, 51, 52], "wraparound": 47, "issu": 47, "first_plan": 48, "interv": 48, "grayscal": [48, 57, 69], "bilinearli": 48, "blend": 48, "horribl": 48, "unintend": 48, "bad": [48, 55, 69], "idea": 48, "pick": 49, "outsid": 50, "coordin": [53, 55], "eros": 53, "find": 53, "largest": 53, "dilat": 53, "selector": 54, "probabl": [54, 83], "framenumb": 54, "set_frame_numb": 54, "fout": 54, "remove_properti": 54, "del": 54, "certain": [54, 61, 83, 86], "transfer_properti": 54, "develop": [55, 84], "badli": 55, "go": 55, "unnot": 55, "diff": 56, "yield": [57, 86], "exclud": 57, "offset": [57, 63, 86], "60": [57, 86], "edg": 58, "intens": 58, "unset": 60, "enum": 61, "chromaloc": 61, "matrix_in": 61, "transfer_in": 61, "primaries_in": 61, "range_in": 61, "chromaloc_in": 61, "filter_param_a": 61, "filter_param_b": 61, "resample_filter_uv": 61, "filter_param_a_uv": 61, "filter_param_b_uv": 61, "dither_typ": 61, "cpu_typ": 61, "src_left": 61, "src_top": 61, "src_width": 61, "src_height": 61, "nominal_lumin": 61, "choos": [61, 86], "good": [61, 69, 86], "neutral": 61, "rudimentari": 61, "deinterlac": [61, 85], "denot": 61, "annex": 61, "bt": 61, "709": 61, "3074": 61, "yourself": [61, 86], "unspecifi": 61, "accord": 61, "sub": [61, 86], "resampl": 61, "qualiti": [61, 65], "kind": [61, 84], "method": [61, 86], "ycocg": [61, 86], "famili": [61, 69], "legal": 61, "btb": 61, "wtw": 61, "studio": [61, 83], "mpeg": 61, "figur": 61, "top_left": 61, "bottom_left": 61, "scaler": 61, "tap": 61, "dither": 61, "random": [61, 83], "error_diffus": 61, "region": 61, "physic": 61, "cd": 61, "m": [61, 83], "To": [61, 83, 85, 86], "yv12": 61, "1920": 61, "1080": 61, "matrix_in_": 61, "abbrevi": 61, "parenthes": 61, "gbr": 61, "yzx": 61, "xyz": 61, "kr": 61, "2126": 61, "kb": 61, "0722": 61, "rec": 61, "unspec": 61, "fcc": 61, "470bg": 61, "299": 61, "114": 61, "470": 61, "histor": 61, "170m": 61, "smpte": 61, "2004": 61, "240m": 61, "ycgco": 61, "2020ncl": 61, "2627": 61, "0593": 61, "2020": 61, "lumin": 61, "2020cl": 61, "chromancl": 61, "12": 61, "chromat": 61, "chromacl": 61, "13": [61, 78], "ictcp": 61, "14": 61, "lc0": 61, "45": 61, "lc": 61, "500": 61, "601": 61, "2020_10": 61, "2020_12": 61, "470m": 61, "525": 61, "625": 61, "log100": 61, "log316": 61, "316": 61, "xvycc": 61, "11": [61, 83, 86], "iec": 61, "61966": 61, "srgb": 61, "st2084": 61, "st": 61, "2084": 61, "b67": 61, "18": 61, "arib": 61, "600": 61, "150": 61, "060": 61, "330": 61, "d65": 61, "3127": 61, "3290": 61, "310": 61, "595": 61, "155": 61, "070": 61, "630": 61, "340": 61, "1999": 61, "film": 61, "170": 61, "797": 61, "131": 61, "046": 61, "708": 61, "292": 61, "st428": 61, "commonli": 61, "st431": 61, "dci": 61, "p3": 61, "tradit": 61, "st432": 61, "jedec": 61, "p22": 61, "22": 61, "standard": [61, 83, 85, 86], "FOR": 61, "toler": 61, "monitor": 61, "3213": 61, "eq": 61, "clip1i": 61, "bitdepthi": 61, "219": 61, "cb": [61, 86], "clip1c": 61, "bitdepthc": 61, "224": 61, "pb": 61, "cr": 61, "pr": 61, "dynam": [61, 83], "cycl": [63, 86], "decim": 63, "fourth": 63, "manner": 63, "halv": 64, "materi": 65, "rule6": [65, 86], "320": 65, "intval": 66, "floatval": 66, "overridden": [68, 86], "self": 68, "explanatori": 68, "histori": 68, "touch": 68, "grai": [69, 86], "rel": [69, 83], "likewis": [69, 79], "yclip": 69, "uclip": 69, "vclip": 69, "cast": 69, "yuvclip": 69, "text": [73, 74, 75, 76, 82], "print": [73, 74, 75, 76, 77, 81, 83, 85, 86], "blank": 74, "draw": 77, "bitmap": 77, "font": 77, "bold": 77, "terminu": 77, "pcf": 77, "cover": 77, "1252": 77, "superset": 77, "iso": 77, "8859": 77, "aka": 77, "latin1": 77, "unprint": 77, "dumb": 77, "drop": 77, "numpad": 77, "synthes": 78, "rotat": 78, "noth": [78, 86], "slower": 78, "illustr": 78, "55": 78, "89": 78, "21": 78, "34": 78, "144": 78, "233": 78, "377": 78, "180": 80, "manag": [81, 83, 86], "tutori": 81, "plai": 81, "around": [81, 83], "interpret": 81, "vpy": [81, 85], "inspir": [81, 84], "filenam": 81, "audiosourc": 81, "2x": 81, "rememb": [81, 86], "quit": [81, 86], "nice": 81, "represent": 81, "directli": [81, 83, 86], "pipe": [81, 85, 86], "x264": [81, 85], "flac": 81, "command": [81, 83], "y4m": [81, 85, 86], "demux": [81, 85], "264": 81, "wav": [81, 85], "o": [81, 82, 85, 86], "introduct": 82, "author": 82, "linux": 82, "vsrepo": 82, "structur": 82, "grammar": 82, "syntact": 82, "sugar": 82, "raw": [82, 85], "class": [82, 85], "get_output": [82, 86], "clear_output": [82, 86], "construct_signatur": [82, 86], "register_on_destroi": [82, 86], "unregister_on_destroi": [82, 86], "videonod": [82, 86], "videooutputtupl": [82, 86], "videofram": [82, 86], "videoformat": [82, 86], "audionod": [82, 86], "audiofram": [82, 86], "get_current_environ": [82, 86], "environmentpolici": [82, 86], "environmentpolicyapi": [82, 86], "register_polici": [82, 86], "_try_enable_introspect": [82, 86], "has_polici": [82, 86], "environmentdata": [82, 86], "synopsi": 82, "avf": [82, 83, 86], "vfw": [82, 86], "tool": [82, 86], "reserv": 82, "page": 82, "press": 83, "along": 83, "instanti": [83, 86], "fact": 83, "download": 83, "visual": 83, "2019": 83, "mention": 83, "begin": 83, "bug": 83, "pyd": 83, "ly": 83, "decompress": 83, "embedd": 83, "archiv": [83, 85], "bat": 83, "xcode": 83, "appstor": 83, "homebrew": 83, "wait": [83, 84], "brew": 83, "OF": 83, "date": 83, "deb": 83, "multimedia": 83, "repositori": 83, "guid": 83, "offici": 83, "websit": 83, "epel": 83, "enterpris": 83, "unoffici": 83, "portag": 83, "tree": 83, "ebuild": 83, "nixpkg": 83, "via": 83, "python3packag": 83, "unstabl": [83, 86], "Be": [83, 86], "awar": [83, 86], "broken": 83, "maco": 83, "backport": 83, "stabl": [83, 86], "branch": 83, "newest": [83, 86], "32bit": 83, "64bit": 83, "msvc": 83, "innosetup": 83, "zip": 83, "compress": 83, "clone": 83, "git": 83, "http": 83, "zimg": 83, "sekrit": 83, "twc": 83, "recurs": 83, "submodul": 83, "avisynthplu": 83, "libp2p": 83, "solut": 83, "py": 83, "pip": 83, "txt": [83, 85], "cython_build": 83, "docs_build": 83, "abov": 83, "7z": 83, "ex": [83, 85], "plan": 84, "ok": [], "grab": 83, "pfm": 83, "192": 83, "win": 83, "make_port": 83, "make_instal": 83, "properli": 83, "across": 83, "boundari": 83, "trolololol": 83, "autoconf": 83, "automak": 83, "libtool": 83, "pkg": 83, "config": 83, "gcc": 83, "newer": 83, "clang": 83, "cython": 83, "28": 83, "sphinx": 83, "python3": 83, "libass": 83, "imagemagick": 83, "pip3": 83, "ve": 83, "updat": [83, 86], "upgrad": 83, "haven": 83, "Or": [83, 84], "pull": 83, "autogen": 83, "sh": 83, "usr": 83, "pop": 83, "No": [83, 86], "lib": 83, "ld_library_path": 83, "site": 83, "pythonpath": 83, "makefil": 83, "doc": 83, "html": 83, "cp": 83, "vsdb": 83, "On": [83, 85], "visit": 83, "put": 83, "think": [83, 84], "mechan": 83, "save": 83, "blow": 83, "your_python_vers": 83, "_pth": 83, "might": [83, 86], "crash": 83, "cough": 83, "wxgtk": 83, "decid": 83, "accid": 83, "appdata": 83, "plugins32": 83, "plugins64": 83, "modern": 83, "roam": 83, "shortcut": 83, "menu": 83, "futur": [83, 86], "vapoursynth32": 83, "coreplugin": 83, "vapoursynth64": 83, "xdg_config_hom": 83, "conf": 83, "home": 83, "vapoursynth_conf_path": 83, "userplugindir": 83, "systemplugindir": 83, "libdir": 83, "plugindir": 83, "hard": 84, "tell": [84, 86], "came": 84, "month": 84, "period": 84, "softwar": [84, 85, 86], "heavili": 84, "aim": 84, "21st": 84, "centuri": 84, "rewrit": 84, "advantag": 84, "late": 84, "90": 84, "implement": [84, 86], "learn": 84, "stick": 84, "fredrik": 84, "mellbin": 84, "electr": 84, "engin": 84, "focu": 84, "analysi": 84, "medic": 84, "he": 84, "digit": 84, "electron": 84, "hi": 84, "spare": 84, "dai": 84, "himself": 84, "job": 84, "repli": 84, "choic": 84, "him": 84, "interest": 84, "feel": 84, "contact": 84, "me": 84, "thingi": 84, "gmail": 84, "port": 84, "sponsor": 84, "outfil": 85, "hyphen": 85, "write": [85, 86], "dot": [85, 86], "anywher": 85, "str": 85, "dict": [85, 86], "outputindex": 85, "w64": 85, "timecod": 85, "p": 85, "stderr": 85, "record": 85, "spent": 85, "stdout": [85, 86], "ye": 85, "fluffi": 85, "kitten": 85, "packag": [85, 86], "easili": 85, "avi": 85, "bridg": 85, "gap": 85, "plain": 85, "core32": 85, "core64": 85, "alt_output": [85, 86], "profession": [85, 86], "easiest": 85, "thechaoscod": 85, "registri": 85, "00": 85, "hkey_local_machin": 85, "clsid": 85, "58f74ca0": 85, "bd0e": 85, "4664": 85, "a49b": 85, "8d10e6f0c131": 85, "inprocserver32": 85, "threadingmodel": 85, "avifil": 85, "extens": 85, "section": 86, "explain": 86, "expos": 86, "vsscript": 86, "__name__": 86, "__vapoursynth__": 86, "__main__": 86, "singleton": 86, "sai": 86, "conflict": 86, "short": 86, "chain": 86, "2000": 86, "quival": 86, "strip": 86, "lambda_": 86, "dictionari": 86, "kwarg": 86, "lambda": 86, "pep8": 86, "backslash": 86, "normcas": 86, "incorrect": 86, "yuv422p10": 86, "adob": 86, "product": 86, "i420": 86, "iyuv": 86, "uyvi": 86, "v210": 86, "some_clip": 86, "get_read_ptr": 86, "get_write_ptr": 86, "get_strid": 86, "ctype": 86, "friendli": 86, "get_fram": 86, "stuff": 86, "prefer": 86, "throw": 86, "hasn": 86, "signatur": 86, "inject": 86, "registr": 86, "resourc": 86, "unregist": 86, "num_thread": 86, "hardwar": 86, "max_cache_s": 86, "megabyt": 86, "get_video_format": 86, "query_video_format": 86, "color_famili": 86, "sample_typ": 86, "subsampling_w": 86, "subsampling_h": 86, "create_video_fram": 86, "uniniti": 86, "add_log_handl": 86, "handler_func": 86, "loghandl": 86, "messagetyp": 86, "remove_log_handl": 86, "log_messag": 86, "message_typ": 86, "version_numb": 86, "__version__": 86, "__api_version__": 86, "l": 86, "itself": 86, "num_fram": 86, "fp": 86, "fps_num": 86, "deprec": 86, "fps_den": 86, "get_frame_async": 86, "thrown": 86, "render": 86, "callabl": 86, "r58": 86, "vsf": 86, "fourcc": 86, "fileobj": 86, "prefetch": 86, "progress_upd": 86, "backlog": 86, "yuv4mpeg2": 86, "current_fram": 86, "total_fram": 86, "close": 86, "iter": 86, "unconsum": 86, "did": 86, "stop": 86, "backward": 86, "is_inspect": 86, "truthi": 86, "underli": 86, "maintain": 86, "introspect": 86, "omit": 86, "readonli": 86, "writabl": 86, "forcefulli": 86, "forget": 86, "thin": 86, "readchunk": 86, "dump": 86, "disk": 86, "wb": 86, "held": 86, "n_plane": 86, "grant": 86, "assur": 86, "plane_idx": 86, "memoryview": 86, "consult": 86, "group": 86, "bytes_per_sampl": 86, "storag": 86, "pad": 86, "num_plan": 86, "modif": 86, "channel_layout": 86, "num_channel": 86, "sample_r": 86, "playback": 86, "sensic": 86, "concept": 86, "lump": 86, "return_signatur": 86, "come": 86, "switch": 86, "is_singl": 86, "_not_": 86, "env_id": 86, "aliv": 86, "r51": 86, "block": 86, "enclos": 86, "statement": 86, "rais": 86, "we": 86, "subclass": 86, "runner": 86, "concret": 86, "polici": 86, "referenci": 86, "on_policy_regist": 86, "abus": 86, "runtimeerror": 86, "special_api": 86, "proivd": 86, "hidden": 86, "useless": 86, "harm": 86, "on_policy_clear": 86, "unregister_polici": 86, "set_environ": 86, "dead": 86, "act": 86, "is_al": 86, "destroy_environ": 86, "wrap_environ": 86, "create_environ": 86, "sensit": 86, "set_logg": 86, "r52": 86, "get_vapoursynth_api": 86, "c_void_p": 86, "provision": 86, "r62": 86, "get_core_ptr": 86, "r50": 86, "exhaust": 86, "vsscript_init": 86, "succe": 86, "vsfunc": 86, "familiar": 86, "mayb": 86, "uncommon": 86, "handi": 86, "predefin": 86, "gray8": 86, "gray9": 86, "gray10": 86, "gray12": 86, "gray14": 86, "gray16": 86, "gray32": 86, "grayh": 86, "yuv444p8": 86, "yuv410p8": 86, "yuv411p8": 86, "yuv440p8": 86, "yuv420p9": 86, "yuv422p9": 86, "yuv444p9": 86, "yuv420p10": 86, "yuv444p10": 86, "yuv420p12": 86, "yuv422p12": 86, "yuv444p12": 86, "yuv420p14": 86, "yuv422p14": 86, "yuv444p14": 86, "yuv422p16": 86, "yuv444p16": 86, "yuv444ph": 86, "yuv444p": 86, "rgb27": 86, "rgb30": 86, "rgb36": 86, "rgb42": 86, "rgb48": 86, "rgbh": 86, "chroma_left": 86, "chroma_cent": 86, "chroma_top_left": 86, "chroma_top": 86, "chroma_bottom_left": 86, "chroma_bottom": 86, "field_progress": 86, "field_top": 86, "field_bottom": 86, "range_ful": 86, "range_limit": 86, "matrix_rgb": 86, "matrix_bt709": 86, "matrix_unspecifi": 86, "matrix_fcc": 86, "matrix_bt470_bg": 86, "matrix_st170_m": 86, "matrix_st240_m": 86, "matrix_ycgco": 86, "matrix_bt2020_ncl": 86, "matrix_bt2020_cl": 86, "matrix_chromaticity_derived_ncl": 86, "matrix_chromaticity_derived_cl": 86, "matrix_ictcp": 86, "transfer_bt709": 86, "transfer_unspecifi": 86, "transfer_bt470_m": 86, "transfer_bt470_bg": 86, "transfer_bt601": 86, "transfer_st240_m": 86, "transfer_linear": 86, "transfer_log_100": 86, "transfer_log_316": 86, "transfer_iec_61966_2_4": 86, "transfer_iec_61966_2_1": 86, "transfer_bt2020_10": 86, "transfer_bt2020_12": 86, "transfer_st2084": 86, "transfer_arib_b67": 86, "primaries_bt709": 86, "primaries_unspecifi": 86, "primaries_bt470_m": 86, "primaries_bt470_bg": 86, "primaries_st170_m": 86, "primaries_st240_m": 86, "primaries_film": 86, "primaries_bt2020": 86, "primaries_st428": 86, "primaries_st431_2": 86, "primaries_st432_1": 86, "primaries_ebu3213_": 86, "front_left_of_cent": 86, "front_right_of_cent": 86, "back_cent": 86, "side_left": 86, "side_right": 86, "top_cent": 86, "top_front_left": 86, "top_front_cent": 86, "top_front_right": 86, "top_back_left": 86, "top_back_cent": 86, "top_back_right": 86, "stereo_left": 86, "stereo_right": 86, "wide_left": 86, "wide_right": 86, "surround_direct_left": 86, "surround_direct_right": 86, "low_frequency2": 86, "vshelper4": [3, 82], "vsscript4": [3, 82]}, "objects": {"": [[0, 0, 1, "c.api", "api"], [0, 0, 1, "c.bitsPerSample", "bitsPerSample"], [0, 0, 1, "c.bitsPerSample", "bitsPerSample"], [0, 0, 1, "c.bytesPerSample", "bytesPerSample"], [0, 0, 1, "c.bytesPerSample", "bytesPerSample"], [0, 0, 1, "c.channelLayout", "channelLayout"], [0, 0, 1, "c.colorFamily", "colorFamily"], [0, 0, 1, "c.core", "core"], [2, 1, 1, "c.createScript", "createScript"], [2, 1, 1, "c.evalSetWorkingDir", "evalSetWorkingDir"], [2, 1, 1, "c.evaluateBuffer", "evaluateBuffer"], [2, 1, 1, "c.evaluateFile", "evaluateFile"], [0, 0, 1, "c.format", "format"], [0, 0, 1, "c.format", "format"], [0, 0, 1, "c.fpsDen", "fpsDen"], [0, 0, 1, "c.fpsNum", "fpsNum"], [2, 1, 1, "c.freeScript", "freeScript"], [2, 1, 1, "c.getAltOutputMode", "getAltOutputMode"], [2, 1, 1, "c.getApiVersion", "getApiVersion"], [2, 1, 1, "c.getCore", "getCore"], [2, 1, 1, "c.getError", "getError"], [2, 1, 1, "c.getExitCode", "getExitCode"], [2, 1, 1, "c.getOutputAlphaNode", "getOutputAlphaNode"], [2, 1, 1, "c.getOutputNode", "getOutputNode"], [2, 1, 1, "c.getVSAPI", "getVSAPI"], [2, 1, 1, "c.getVSScriptAPI", "getVSScriptAPI"], [2, 1, 1, "c.getVariable", "getVariable"], [0, 0, 1, "c.height", "height"], [0, 0, 1, "c.maxFramebufferSize", "maxFramebufferSize"], [0, 0, 1, "c.numChannels", "numChannels"], [0, 0, 1, "c.numFrames", "numFrames"], [0, 0, 1, "c.numFrames", "numFrames"], [0, 0, 1, "c.numPlanes", "numPlanes"], [0, 0, 1, "c.numSamples", "numSamples"], [0, 0, 1, "c.numThreads", "numThreads"], [0, 0, 1, "c.requestPattern", "requestPattern"], [0, 0, 1, "c.sampleRate", "sampleRate"], [0, 0, 1, "c.sampleType", "sampleType"], [0, 0, 1, "c.sampleType", "sampleType"], [0, 0, 1, "c.source", "source"], [0, 0, 1, "c.subSamplingH", "subSamplingH"], [0, 0, 1, "c.subSamplingW", "subSamplingW"], [0, 0, 1, "c.usedFramebufferSize", "usedFramebufferSize"], [0, 0, 1, "c.versionString", "versionString"], [2, 1, 1, "c.vsscript_setVariable", "vsscript_setVariable"], [0, 0, 1, "c.width", "width"], [1, 3, 1, "_CPPv4N3vsh11addRationalEP7int64_tP7int64_t7int64_t7int64_t", "vsh::addRational"], [1, 4, 1, "_CPPv4N3vsh11addRationalEP7int64_tP7int64_t7int64_t7int64_t", "vsh::addRational::addden"], [1, 4, 1, "_CPPv4N3vsh11addRationalEP7int64_tP7int64_t7int64_t7int64_t", "vsh::addRational::addnum"], [1, 4, 1, "_CPPv4N3vsh11addRationalEP7int64_tP7int64_t7int64_t7int64_t", "vsh::addRational::den"], [1, 4, 1, "_CPPv4N3vsh11addRationalEP7int64_tP7int64_t7int64_t7int64_t", "vsh::addRational::num"], [1, 3, 1, "_CPPv4N3vsh18areValidDimensionsEPK8VSFormatii", "vsh::areValidDimensions"], [1, 4, 1, "_CPPv4N3vsh18areValidDimensionsEPK8VSFormatii", "vsh::areValidDimensions::fi"], [1, 4, 1, "_CPPv4N3vsh18areValidDimensionsEPK8VSFormatii", "vsh::areValidDimensions::height"], [1, 4, 1, "_CPPv4N3vsh18areValidDimensionsEPK8VSFormatii", "vsh::areValidDimensions::width"], [1, 3, 1, "_CPPv4N3vsh6bitbltEPviPKvi6size_t6size_t", "vsh::bitblt"], [1, 4, 1, "_CPPv4N3vsh6bitbltEPviPKvi6size_t6size_t", "vsh::bitblt::dst_stride"], [1, 4, 1, "_CPPv4N3vsh6bitbltEPviPKvi6size_t6size_t", "vsh::bitblt::dstp"], [1, 4, 1, "_CPPv4N3vsh6bitbltEPviPKvi6size_t6size_t", "vsh::bitblt::height"], [1, 4, 1, "_CPPv4N3vsh6bitbltEPviPKvi6size_t6size_t", "vsh::bitblt::row_size"], [1, 4, 1, "_CPPv4N3vsh6bitbltEPviPKvi6size_t6size_t", "vsh::bitblt::src_stride"], [1, 4, 1, "_CPPv4N3vsh6bitbltEPviPKvi6size_t6size_t", "vsh::bitblt::srcp"], [1, 3, 1, "_CPPv4N3vsh14doubleToFloatSEd", "vsh::doubleToFloatS"], [1, 4, 1, "_CPPv4N3vsh14doubleToFloatSEd", "vsh::doubleToFloatS::d"], [1, 3, 1, "_CPPv4N3vsh11int64ToIntSE7int64_t", "vsh::int64ToIntS"], [1, 4, 1, "_CPPv4N3vsh11int64ToIntSE7int64_t", "vsh::int64ToIntS::i"], [1, 3, 1, "_CPPv4N3vsh16isConstantFormatEPK11VSVideoInfo", "vsh::isConstantFormat"], [1, 4, 1, "_CPPv4N3vsh16isConstantFormatEPK11VSVideoInfo", "vsh::isConstantFormat::vi"], [1, 3, 1, "_CPPv4N3vsh17isSameAudioFormatEPK11VSAudioInfoPK11VSAudioInfo", "vsh::isSameAudioFormat"], [1, 4, 1, "_CPPv4N3vsh17isSameAudioFormatEPK11VSAudioInfoPK11VSAudioInfo", "vsh::isSameAudioFormat::v1"], [1, 4, 1, "_CPPv4N3vsh17isSameAudioFormatEPK11VSAudioInfoPK11VSAudioInfo", "vsh::isSameAudioFormat::v2"], [1, 3, 1, "_CPPv4N3vsh15isSameAudioInfoEPK11VSAudioInfoPK11VSAudioInfo", "vsh::isSameAudioInfo"], [1, 4, 1, "_CPPv4N3vsh15isSameAudioInfoEPK11VSAudioInfoPK11VSAudioInfo", "vsh::isSameAudioInfo::v1"], [1, 4, 1, "_CPPv4N3vsh15isSameAudioInfoEPK11VSAudioInfoPK11VSAudioInfo", "vsh::isSameAudioInfo::v2"], [1, 3, 1, "_CPPv4N3vsh17isSameVideoFormatEPK11VSVideoInfoPK11VSVideoInfo", "vsh::isSameVideoFormat"], [1, 4, 1, "_CPPv4N3vsh17isSameVideoFormatEPK11VSVideoInfoPK11VSVideoInfo", "vsh::isSameVideoFormat::v1"], [1, 4, 1, "_CPPv4N3vsh17isSameVideoFormatEPK11VSVideoInfoPK11VSVideoInfo", "vsh::isSameVideoFormat::v2"], [1, 3, 1, "_CPPv4N3vsh15isSameVideoInfoEPK11VSVideoInfoPK11VSVideoInfo", "vsh::isSameVideoInfo"], [1, 4, 1, "_CPPv4N3vsh15isSameVideoInfoEPK11VSVideoInfoPK11VSVideoInfo", "vsh::isSameVideoInfo::v1"], [1, 4, 1, "_CPPv4N3vsh15isSameVideoInfoEPK11VSVideoInfoPK11VSVideoInfo", "vsh::isSameVideoInfo::v2"], [1, 3, 1, "_CPPv4N3vsh23isSameVideoPresetFormatEjPK13VSVideoFormatP6VSCorePK5VSAPI", "vsh::isSameVideoPresetFormat"], [1, 4, 1, "_CPPv4N3vsh23isSameVideoPresetFormatEjPK13VSVideoFormatP6VSCorePK5VSAPI", "vsh::isSameVideoPresetFormat::core"], [1, 4, 1, "_CPPv4N3vsh23isSameVideoPresetFormatEjPK13VSVideoFormatP6VSCorePK5VSAPI", "vsh::isSameVideoPresetFormat::presetFormat"], [1, 4, 1, "_CPPv4N3vsh23isSameVideoPresetFormatEjPK13VSVideoFormatP6VSCorePK5VSAPI", "vsh::isSameVideoPresetFormat::v"], [1, 4, 1, "_CPPv4N3vsh23isSameVideoPresetFormatEjPK13VSVideoFormatP6VSCorePK5VSAPI", "vsh::isSameVideoPresetFormat::vsapi"], [1, 3, 1, "_CPPv4N3vsh14muldivRationalEP7int64_tP7int64_t7int64_t7int64_t", "vsh::muldivRational"], [1, 4, 1, "_CPPv4N3vsh14muldivRationalEP7int64_tP7int64_t7int64_t7int64_t", "vsh::muldivRational::den"], [1, 4, 1, "_CPPv4N3vsh14muldivRationalEP7int64_tP7int64_t7int64_t7int64_t", "vsh::muldivRational::div"], [1, 4, 1, "_CPPv4N3vsh14muldivRationalEP7int64_tP7int64_t7int64_t7int64_t", "vsh::muldivRational::mul"], [1, 4, 1, "_CPPv4N3vsh14muldivRationalEP7int64_tP7int64_t7int64_t7int64_t", "vsh::muldivRational::num"], [1, 3, 1, "_CPPv4N3vsh14reduceRationalEP7int64_tP7int64_t", "vsh::reduceRational"], [1, 4, 1, "_CPPv4N3vsh14reduceRationalEP7int64_tP7int64_t", "vsh::reduceRational::den"], [1, 4, 1, "_CPPv4N3vsh14reduceRationalEP7int64_tP7int64_t", "vsh::reduceRational::num"], [1, 3, 1, "_CPPv4N3vsh16vsh_aligned_freeEPv", "vsh::vsh_aligned_free"], [1, 4, 1, "_CPPv4N3vsh16vsh_aligned_freeEPv", "vsh::vsh_aligned_free::ptr"], [1, 3, 1, "_CPPv4N3vsh18vsh_aligned_mallocE6size_t6size_t", "vsh::vsh_aligned_malloc"], [1, 4, 1, "_CPPv4N3vsh18vsh_aligned_mallocE6size_t6size_t", "vsh::vsh_aligned_malloc::alignment"], [1, 4, 1, "_CPPv4N3vsh18vsh_aligned_mallocE6size_t6size_t", "vsh::vsh_aligned_malloc::size"], [86, 5, 1, "", "AudioFrame"], [86, 5, 1, "", "AudioNode"], [86, 5, 1, "", "Core"], [86, 5, 1, "", "Environment"], [86, 5, 1, "", "EnvironmentData"], [86, 5, 1, "", "EnvironmentPolicy"], [86, 5, 1, "", "EnvironmentPolicyAPI"], [86, 9, 1, "", "Error"], [86, 5, 1, "", "Func"], [86, 5, 1, "", "Function"], [86, 5, 1, "", "Local"], [86, 5, 1, "", "Plugin"], [86, 5, 1, "", "VideoFormat"], [86, 5, 1, "", "VideoFrame"], [86, 5, 1, "", "VideoNode"], [86, 5, 1, "", "VideoOutputTuple"], [86, 8, 1, "try_enable_introspection", "_try_enable_introspection"], [86, 8, 1, "", "clear_output"], [86, 8, 1, "", "clear_outputs"], [86, 8, 1, "", "construct_signature"], [86, 6, 1, "", "core"], [86, 8, 1, "", "get_current_environment"], [86, 8, 1, "", "get_output"], [86, 8, 1, "", "get_outputs"], [86, 8, 1, "", "has_policy"], [86, 8, 1, "", "register_on_destroy"], [86, 8, 1, "", "register_policy"], [86, 8, 1, "", "unregister_on_destroy"]], "createScript": [[2, 2, 1, "c.createScript", "core"]], "evalSetWorkingDir": [[2, 2, 1, "c.evalSetWorkingDir", "handle"], [2, 2, 1, "c.evalSetWorkingDir", "setCWD"]], "evaluateBuffer": [[2, 2, 1, "c.evaluateBuffer", "buffer"], [2, 2, 1, "c.evaluateBuffer", "handle"], [2, 2, 1, "c.evaluateBuffer", "scriptFilename"]], "evaluateFile": [[2, 2, 1, "c.evaluateFile", "handle"], [2, 2, 1, "c.evaluateFile", "scriptFilename"]], "freeScript": [[2, 2, 1, "c.freeScript", "handle"]], "getAltOutputMode": [[2, 2, 1, "c.getAltOutputMode", "handle"], [2, 2, 1, "c.getAltOutputMode", "index"]], "getCore": [[2, 2, 1, "c.getCore", "handle"]], "getError": [[2, 2, 1, "c.getError", "handle"]], "getExitCode": [[2, 2, 1, "c.getExitCode", "handle"]], "getOutputAlphaNode": [[2, 2, 1, "c.getOutputAlphaNode", "handle"], [2, 2, 1, "c.getOutputAlphaNode", "index"]], "getOutputNode": [[2, 2, 1, "c.getOutputNode", "handle"], [2, 2, 1, "c.getOutputNode", "index"]], "getVSAPI": [[2, 2, 1, "c.getVSAPI", "version"]], "getVSScriptAPI": [[2, 2, 1, "c.getVSScriptAPI", "version"]], "getVariable": [[2, 2, 1, "c.getVariable", "dst"], [2, 2, 1, "c.getVariable", "handle"], [2, 2, 1, "c.getVariable", "name"]], "vsscript_setVariable": [[2, 2, 1, "c.vsscript_setVariable", "handle"], [2, 2, 1, "c.vsscript_setVariable", "vars"]], "AudioFrame": [[86, 6, 1, "", "bits_per_sample"], [86, 6, 1, "", "bytes_per_sample"], [86, 6, 1, "", "channel_layout"], [86, 7, 1, "", "copy"], [86, 7, 1, "", "get_read_ptr"], [86, 7, 1, "", "get_stride"], [86, 7, 1, "", "get_write_ptr"], [86, 6, 1, "", "num_channels"], [86, 6, 1, "", "props"], [86, 6, 1, "", "readonly"], [86, 6, 1, "", "sample_type"]], "AudioNode": [[86, 6, 1, "", "bits_per_sample"], [86, 6, 1, "", "bytes_per_sample"], [86, 6, 1, "", "channel_layout"], [86, 7, 1, "", "frames"], [86, 7, 1, "", "get_frame"], [86, 7, 1, "", "get_frame_async"], [86, 7, 1, "", "is_inspectable"], [86, 6, 1, "", "num_channels"], [86, 6, 1, "", "sample_rate"], [86, 6, 1, "", "sample_type"], [86, 7, 1, "", "set_output"]], "Core": [[86, 7, 1, "", "add_log_handler"], [86, 7, 1, "", "create_video_frame"], [86, 7, 1, "", "get_video_format"], [86, 7, 1, "", "log_message"], [86, 6, 1, "", "max_cache_size"], [86, 6, 1, "", "num_threads"], [86, 7, 1, "", "plugins"], [86, 7, 1, "", "query_video_format"], [86, 7, 1, "", "remove_log_handler"], [86, 7, 1, "", "rule6"], [86, 7, 1, "", "version"], [86, 7, 1, "", "version_number"]], "Environment": [[86, 6, 1, "", "alive"], [86, 7, 1, "", "copy"], [86, 6, 1, "", "env_id"], [86, 8, 1, "", "is_single"], [86, 6, 1, "", "single"], [86, 7, 1, "", "use"]], "EnvironmentPolicy": [[86, 7, 1, "", "get_current_environment"], [86, 7, 1, "", "is_alive"], [86, 7, 1, "", "on_policy_cleared"], [86, 7, 1, "", "on_policy_registered"], [86, 7, 1, "", "set_environment"]], "EnvironmentPolicyAPI": [[86, 7, 1, "", "create_environment"], [86, 7, 1, "", "destroy_environment"], [86, 7, 1, "", "get_core_ptr"], [86, 7, 1, "", "get_vapoursynth_api"], [86, 7, 1, "", "set_logger"], [86, 7, 1, "", "unregister_policy"], [86, 7, 1, "", "wrap_environment"]], "Function": [[86, 6, 1, "", "name"], [86, 6, 1, "", "plugin"], [86, 6, 1, "", "return_signature"], [86, 6, 1, "", "signature"]], "Plugin": [[86, 7, 1, "", "functions"], [86, 6, 1, "", "identifier"], [86, 6, 1, "", "name"], [86, 6, 1, "", "namespace"]], "VideoFormat": [[86, 6, 1, "", "bits_per_sample"], [86, 6, 1, "", "bytes_per_sample"], [86, 6, 1, "", "color_family"], [86, 6, 1, "", "id"], [86, 6, 1, "", "name"], [86, 6, 1, "", "num_planes"], [86, 7, 1, "", "replace"], [86, 6, 1, "", "sample_type"], [86, 6, 1, "", "subsampling_h"], [86, 6, 1, "", "subsampling_w"]], "VideoFrame": [[86, 7, 1, "", "close"], [86, 6, 1, "", "closed"], [86, 7, 1, "", "copy"], [86, 6, 1, "", "format"], [86, 7, 1, "", "get_read_ptr"], [86, 7, 1, "", "get_stride"], [86, 7, 1, "", "get_write_ptr"], [86, 6, 1, "", "height"], [86, 6, 1, "", "props"], [86, 7, 1, "", "readchunks"], [86, 6, 1, "", "readonly"], [86, 6, 1, "", "width"]], "VideoNode": [[86, 6, 1, "", "denominator"], [86, 6, 1, "", "flags"], [86, 6, 1, "", "format"], [86, 6, 1, "", "fps"], [86, 6, 1, "", "fps_den"], [86, 6, 1, "", "fps_num"], [86, 7, 1, "", "frames"], [86, 7, 1, "", "get_frame"], [86, 7, 1, "", "get_frame_async"], [86, 6, 1, "", "height"], [86, 7, 1, "", "is_inspectable"], [86, 6, 1, "", "num_frames"], [86, 6, 1, "", "numerator"], [86, 7, 1, "", "output"], [86, 7, 1, "", "set_output"], [86, 6, 1, "", "width"]], "VideoOutputTuple": [[86, 6, 1, "", "alpha"], [86, 6, 1, "", "alt_output"], [86, 6, 1, "", "clip"]], "avs": [[19, 8, 1, "", "LoadPlugin"]], "resize": [[61, 8, 1, "", "Bicubic"], [61, 8, 1, "", "Bilinear"], [61, 8, 1, "", "Bob"], [61, 8, 1, "", "Lanczos"], [61, 8, 1, "", "Point"], [61, 8, 1, "", "Spline16"], [61, 8, 1, "", "Spline36"], [61, 8, 1, "", "Spline64"]], "std": [[21, 8, 1, "", "AddBorders"], [22, 8, 1, "", "AssumeFPS"], [6, 8, 1, "", "AssumeSampleRate"], [7, 8, 1, "", "AudioGain"], [8, 8, 1, "", "AudioLoop"], [9, 8, 1, "", "AudioMix"], [10, 8, 1, "", "AudioReverse"], [11, 8, 1, "", "AudioSplice"], [12, 8, 1, "", "AudioTrim"], [23, 8, 1, "", "AverageFrames"], [24, 8, 1, "", "Binarize"], [24, 8, 1, "", "BinarizeMask"], [13, 8, 1, "", "BlankAudio"], [25, 8, 1, "", "BlankClip"], [26, 8, 1, "", "BoxBlur"], [27, 8, 1, "", "ClipToProp"], [28, 8, 1, "", "Convolution"], [29, 8, 1, "", "CopyFrameProps"], [30, 8, 1, "", "Crop"], [30, 8, 1, "", "CropAbs"], [31, 8, 1, "", "Deflate"], [32, 8, 1, "", "DeleteFrames"], [33, 8, 1, "", "DoubleWeave"], [34, 8, 1, "", "DuplicateFrames"], [35, 8, 1, "", "Expr"], [36, 8, 1, "", "FlipHorizontal"], [36, 8, 1, "", "FlipVertical"], [37, 8, 1, "", "FrameEval"], [38, 8, 1, "", "FreezeFrames"], [31, 8, 1, "", "Inflate"], [39, 8, 1, "", "Interleave"], [40, 8, 1, "", "Invert"], [40, 8, 1, "", "InvertMask"], [41, 8, 1, "", "Levels"], [42, 8, 1, "", "Limiter"], [17, 8, 1, "", "LoadAllPlugins"], [18, 8, 1, "", "LoadPlugin"], [43, 8, 1, "", "Loop"], [44, 8, 1, "", "Lut"], [45, 8, 1, "", "Lut2"], [46, 8, 1, "", "MakeDiff"], [47, 8, 1, "", "MakeFullDiff"], [48, 8, 1, "", "MaskedMerge"], [53, 8, 1, "", "Maximum"], [49, 8, 1, "", "Median"], [50, 8, 1, "", "Merge"], [51, 8, 1, "", "MergeDiff"], [52, 8, 1, "", "MergeFullDiff"], [53, 8, 1, "", "Minimum"], [54, 8, 1, "", "ModifyFrame"], [55, 8, 1, "", "PEMVerifier"], [56, 8, 1, "", "PlaneStats"], [57, 8, 1, "", "PreMultiply"], [58, 8, 1, "", "Prewitt"], [59, 8, 1, "", "PropToClip"], [60, 8, 1, "", "RemoveFrameProps"], [62, 8, 1, "", "Reverse"], [63, 8, 1, "", "SelectEvery"], [64, 8, 1, "", "SeparateFields"], [14, 8, 1, "", "SetAudioCache"], [65, 8, 1, "", "SetFieldBased"], [66, 8, 1, "", "SetFrameProp"], [67, 8, 1, "", "SetFrameProps"], [20, 8, 1, "", "SetMaxCPU"], [68, 8, 1, "", "SetVideoCache"], [15, 8, 1, "", "ShuffleChannels"], [69, 8, 1, "", "ShufflePlanes"], [58, 8, 1, "", "Sobel"], [70, 8, 1, "", "Splice"], [16, 8, 1, "", "SplitChannels"], [71, 8, 1, "", "SplitPlanes"], [72, 8, 1, "", "StackHorizontal"], [72, 8, 1, "", "StackVertical"], [78, 8, 1, "", "Transpose"], [79, 8, 1, "", "Trim"], [80, 8, 1, "", "Turn180"]], "text": [[73, 8, 1, "", "ClipInfo"], [74, 8, 1, "", "CoreInfo"], [75, 8, 1, "", "FrameNum"], [76, 8, 1, "", "FrameProps"], [77, 8, 1, "", "Text"]]}, "objtypes": {"0": "c:member", "1": "c:function", "2": "c:functionParam", "3": "cpp:function", "4": "cpp:functionParam", "5": "py:class", "6": "py:attribute", "7": "py:method", "8": "py:function", "9": "py:exception"}, "objnames": {"0": ["c", "member", "C member"], "1": ["c", "function", "C function"], "2": ["c", "functionParam", "C function parameter"], "3": ["cpp", "function", "C++ function"], "4": ["cpp", "functionParam", "C++ function parameter"], "5": ["py", "class", "Python class"], "6": ["py", "attribute", "Python attribute"], "7": ["py", "method", "Python method"], "8": ["py", "function", "Python function"], "9": ["py", "exception", "Python exception"]}, "titleterms": {"vapoursynth": [3, 82, 86], "h": [0, 1, 2], "tabl": [0, 1, 2, 82], "content": [0, 1, 2], "introduct": [0, 1, 2, 84], "macro": [0, 1], "vs_cc": 0, "vs_external_api": 0, "vapoursynth_api_major": 0, "vapoursynth_api_minor": 0, "vapoursynth_api_vers": 0, "vs_audio_frame_sampl": 0, "vs_make_vers": 0, "enum": 0, "vscolorfamili": 0, "vssampletyp": 0, "vspresetvideoformat": 0, "vsfiltermod": 0, "vsmediatyp": 0, "vsaudiochannel": 0, "vspropertytyp": 0, "vsmappropertyerror": 0, "vsmapappendmod": 0, "vsactivationreason": 0, "vsmessagetyp": 0, "vscorecreationflag": 0, "vspluginconfigflag": 0, "vsdatatypehint": 0, "vsrequestpattern": 0, "vscachemod": 0, "struct": [0, 2], "vsframe": 0, "vsnode": 0, "vscore": 0, "vsplugin": 0, "vspluginfunct": 0, "vsfunction": 0, "vsmap": 0, "vsloghandl": 0, "vsframecontext": 0, "vsvideoformat": 0, "vsvideoinfo": 0, "vsaudioformat": 0, "vsaudioinfo": 0, "vscoreinfo": 0, "vsfilterdepend": 0, "vspluginapi": 0, "vsapi": 0, "function": [0, 1, 2, 5, 86], "write": 0, "plugin": [0, 3, 83], "vshelper4": 1, "vsh_std_plugin_id": 1, "vsh_resize_plugin_id": 1, "vsh_text_plugin_id": 1, "vs_restrict": 1, "vsh_aligned_malloc": 1, "vsh_aligned_fre": 1, "vsmin": 1, "vsmax": 1, "isconstantformat": 1, "issamevideoformat": 1, "issamevideopresetformat": 1, "issamevideoinfo": 1, "issameaudioformat": 1, "issameaudioinfo": 1, "muldivr": 1, "reducer": 1, "addrat": 1, "int64toint": 1, "doubletofloat": 1, "bitblt": 1, "arevaliddimens": 1, "vsscript4": 2, "vsscript": 2, "vsscriptapi": 2, "getvsscriptapi": 2, "getapivers": 2, "getvsapi": 2, "createscript": 2, "getcor": 2, "evaluatebuff": 2, "evaluatefil": 2, "geterror": 2, "getexitcod": 2, "getvari": 2, "setvari": 2, "getoutputnod": 2, "getoutputalphanod": 2, "getaltoutputmod": 2, "freescript": 2, "evalsetworkingdir": 2, "c": [3, 83], "api": 3, "refer": [3, 5, 86], "public": 3, "header": 3, "common": 3, "pitfal": 3, "gener": [3, 5], "reserv": 3, "frame": [3, 86], "properti": 3, "applic": 4, "librari": 4, "tool": 4, "video": [5, 86], "text": [5, 77], "audio": [5, 86], "assumesampler": 6, "audiogain": 7, "audioloop": 8, "audiomix": 9, "audiorevers": 10, "audiosplic": 11, "audiotrim": 12, "blankaudio": 13, "setaudiocach": 14, "shufflechannel": 15, "splitchannel": 16, "loadallplugin": 17, "loadplugin": [18, 19], "avisynth": [19, 85], "compat": 19, "setmaxcpu": 20, "addbord": 21, "assumefp": 22, "averagefram": 23, "binar": 24, "binarizemask": 24, "blankclip": 25, "boxblur": 26, "cliptoprop": 27, "convolut": 28, "copyframeprop": 29, "crop": 30, "cropab": 30, "deflat": 31, "inflat": 31, "deletefram": 32, "doubleweav": 33, "duplicatefram": 34, "expr": 35, "flipvert": 36, "fliphorizont": 36, "frameev": 37, "freezefram": 38, "interleav": 39, "invert": 40, "invertmask": 40, "level": 41, "limit": 42, "loop": 43, "lut": 44, "lut2": 45, "makediff": 46, "makefulldiff": 47, "maskedmerg": 48, "median": 49, "merg": 50, "mergediff": 51, "mergefulldiff": 52, "minimum": 53, "maximum": 53, "modifyfram": 54, "pemverifi": 55, "planestat": 56, "premultipli": 57, "prewitt": 58, "sobel": 58, "proptoclip": 59, "removeframeprop": 60, "resiz": 61, "revers": 62, "selecteveri": 63, "separatefield": 64, "setfieldbas": 65, "setframeprop": [66, 67], "setvideocach": 68, "shuffleplan": 69, "splice": 70, "splitplan": 71, "stackvert": 72, "stackhorizont": 72, "clipinfo": 73, "coreinfo": 74, "framenum": 75, "frameprop": 76, "transpos": 78, "trim": 79, "turn180": 80, "get": 81, "start": 81, "exampl": [81, 85], "script": [81, 83], "preview": 81, "output": [81, 85, 86], "vspipe": [81, 85], "welcom": 82, "": 82, "document": 82, "indic": 82, "instal": 83, "basic": 83, "program": 83, "window": [83, 86], "prerequisit": 83, "portabl": 83, "o": 83, "x": 83, "linux": 83, "debian": 83, "fedora": 83, "cento": 83, "rhel": 83, "gentoo": 83, "arch": 83, "nix": 83, "nixo": 83, "compil": 83, "prepar": 83, "build": 83, "environ": 83, "project": 83, "python": [83, 86], "distribut": 83, "requir": 83, "packag": 83, "vsrepo": 83, "manual": 83, "autoload": 83, "about": 84, "author": 84, "synopsi": 85, "option": 85, "avf": 85, "support": 85, "vfw": 85, "structur": 86, "grammar": 86, "slice": 86, "other": 86, "syntact": 86, "sugar": 86, "keyword": 86, "filter": 86, "argument": 86, "file": 86, "path": 86, "raw": 86, "access": 86, "data": 86, "class": 86, "constant": 86, "color": 86, "famili": 86, "format": 86, "chroma": 86, "locat": 86, "field": 86, "base": 86, "rang": 86, "matrix": 86, "coeffici": 86, "transfercharacterist": 86, "primari": 86, "channel": 86, "sampl": 86, "type": 86, "vapoursynth4": 0}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"VapourSynth4.h": [[0, "vapoursynth4-h"]], "Table of contents": [[0, "table-of-contents"], [1, "table-of-contents"], [2, "table-of-contents"]], "Introduction": [[0, "introduction"], [1, "introduction"], [2, "introduction"], [84, "introduction"]], "Macros": [[0, "macros"], [1, "macros"]], "VS_CC": [[0, "vs-cc"]], "VS_EXTERNAL_API": [[0, "vs-external-api"]], "VAPOURSYNTH_API_MAJOR": [[0, "vapoursynth-api-major"]], "VAPOURSYNTH_API_MINOR": [[0, "vapoursynth-api-minor"]], "VAPOURSYNTH_API_VERSION": [[0, "vapoursynth-api-version"]], "VS_AUDIO_FRAME_SAMPLES": [[0, "vs-audio-frame-samples"]], "VS_MAKE_VERSION": [[0, "vs-make-version"]], "Enums": [[0, "enums"]], "enum VSColorFamily": [[0, "enum-vscolorfamily"]], "enum VSSampleType": [[0, "enum-vssampletype"]], "enum VSPresetVideoFormat": [[0, "enum-vspresetvideoformat"]], "enum VSFilterMode": [[0, "enum-vsfiltermode"]], "enum VSMediaType": [[0, "enum-vsmediatype"]], "enum VSAudioChannels": [[0, "enum-vsaudiochannels"]], "enum VSPropertyType": [[0, "enum-vspropertytype"]], "enum VSMapPropertyError": [[0, "enum-vsmappropertyerror"]], "enum VSMapAppendMode": [[0, "enum-vsmapappendmode"]], "enum VSActivationReason": [[0, "enum-vsactivationreason"]], "enum VSMessageType": [[0, "enum-vsmessagetype"]], "enum VSCoreCreationFlags": [[0, "enum-vscorecreationflags"]], "enum VSPluginConfigFlags": [[0, "enum-vspluginconfigflags"]], "enum VSDataTypeHint": [[0, "enum-vsdatatypehint"]], "enum VSRequestPattern": [[0, "enum-vsrequestpattern"]], "enum VSCacheMode": [[0, "enum-vscachemode"]], "Structs": [[0, "structs"], [2, "structs"]], "struct VSFrame": [[0, "struct-vsframe"]], "struct VSNode": [[0, "struct-vsnode"]], "struct VSCore": [[0, "struct-vscore"]], "struct VSPlugin": [[0, "struct-vsplugin"]], "struct VSPluginFunction": [[0, "struct-vspluginfunction"]], "struct VSFunction": [[0, "struct-vsfunction"]], "struct VSMap": [[0, "struct-vsmap"]], "struct VSLogHandle": [[0, "struct-vsloghandle"]], "struct VSFrameContext": [[0, "struct-vsframecontext"]], "struct VSVideoFormat": [[0, "struct-vsvideoformat"]], "struct VSVideoInfo": [[0, "struct-vsvideoinfo"]], "struct VSAudioFormat": [[0, "struct-vsaudioformat"]], "struct VSAudioInfo": [[0, "struct-vsaudioinfo"]], "struct VSCoreInfo": [[0, "struct-vscoreinfo"]], "struct VSFilterDependency": [[0, "struct-vsfilterdependency"]], "struct VSPLUGINAPI": [[0, "struct-vspluginapi"]], "struct VSAPI": [[0, "struct-vsapi"]], "Functions": [[0, "functions"], [1, "functions"], [2, "functions"]], "Writing plugins": [[0, "writing-plugins"]], "VSHelper4.h": [[1, "vshelper4-h"]], "VSH_STD_PLUGIN_ID": [[1, "vsh-std-plugin-id"]], "VSH_RESIZE_PLUGIN_ID": [[1, "vsh-resize-plugin-id"]], "VSH_TEXT_PLUGIN_ID": [[1, "vsh-text-plugin-id"]], "VS_RESTRICT": [[1, "vs-restrict"]], "VSH_ALIGNED_MALLOC": [[1, "vsh-aligned-malloc"]], "VSH_ALIGNED_FREE": [[1, "vsh-aligned-free"]], "VSMIN": [[1, "vsmin"]], "VSMAX": [[1, "vsmax"]], "vsh_aligned_malloc": [[1, "vsh-aligned-malloc-cpp"]], "vsh_aligned_free": [[1, "vsh-aligned-free-cpp"]], "isConstantFormat": [[1, "isconstantformat"]], "isSameVideoFormat": [[1, "issamevideoformat"]], "isSameVideoPresetFormat": [[1, "issamevideopresetformat"]], "isSameVideoInfo": [[1, "issamevideoinfo"]], "isSameAudioFormat": [[1, "issameaudioformat"]], "isSameAudioInfo": [[1, "issameaudioinfo"]], "muldivRational": [[1, "muldivrational"]], "reduceRational": [[1, "reducerational"]], "addRational": [[1, "addrational"]], "int64ToIntS": [[1, "int64toints"]], "doubleToFloatS": [[1, "doubletofloats"]], "bitblt": [[1, "bitblt"]], "areValidDimensions": [[1, "arevaliddimensions"]], "VSScript4.h": [[2, "vsscript4-h"]], "VSScript": [[2, "vsscript"]], "VSScriptAPI": [[2, "vsscriptapi"]], "getVSScriptAPI": [[2, "getvsscriptapi"]], "getApiVersion": [[2, "getapiversion"]], "getVSAPI": [[2, "getvsapi"]], "createScript": [[2, "createscript"]], "getCore": [[2, "getcore"]], "evaluateBuffer": [[2, "evaluatebuffer"]], "evaluateFile": [[2, "evaluatefile"]], "getError": [[2, "geterror"]], "getExitCode": [[2, "getexitcode"]], "getVariable": [[2, "getvariable"]], "setVariables": [[2, "setvariables"]], "getOutputNode": [[2, "getoutputnode"]], "getOutputAlphaNode": [[2, "getoutputalphanode"]], "getAltOutputMode": [[2, "getaltoutputmode"]], "freeScript": [[2, "freescript"]], "evalSetWorkingDir": [[2, "evalsetworkingdir"]], "VapourSynth C API Reference": [[3, "vapoursynth-c-api-reference"]], "Public Headers": [[3, "public-headers"]], "Common Pitfalls": [[3, "common-pitfalls"]], "General API": [[3, "general-api"]], "Plugins": [[3, "plugins"]], "Reserved Frame Properties": [[3, "reserved-frame-properties"]], "Applications and Libraries": [[4, "applications-and-libraries"]], "Applications": [[4, "applications"]], "Libraries": [[4, "libraries"]], "Tools": [[4, "tools"]], "Function Reference": [[5, "function-reference"]], "General Functions": [[5, "general-functions"]], "Video Functions": [[5, "video-functions"]], "Text": [[5, "text"], [77, "text"]], "Audio Functions": [[5, "audio-functions"]], "AssumeSampleRate": [[6, "assumesamplerate"]], "AudioGain": [[7, "audiogain"]], "AudioLoop": [[8, "audioloop"]], "AudioMix": [[9, "audiomix"]], "AudioReverse": [[10, "audioreverse"]], "AudioSplice": [[11, "audiosplice"]], "AudioTrim": [[12, "audiotrim"]], "BlankAudio": [[13, "blankaudio"]], "SetAudioCache": [[14, "setaudiocache"]], "ShuffleChannels": [[15, "shufflechannels"]], "SplitChannels": [[16, "splitchannels"]], "LoadAllPlugins": [[17, "loadallplugins"]], "LoadPlugin": [[18, "loadplugin"]], "LoadPlugin (Avisynth Compatibility)": [[19, "loadplugin-avisynth-compatibility"]], "SetMaxCPU": [[20, "setmaxcpu"]], "AddBorders": [[21, "addborders"]], "AssumeFPS": [[22, "assumefps"]], "AverageFrames": [[23, "averageframes"]], "Binarize/BinarizeMask": [[24, "binarize-binarizemask"]], "BlankClip": [[25, "blankclip"]], "BoxBlur": [[26, "boxblur"]], "ClipToProp": [[27, "cliptoprop"]], "Convolution": [[28, "convolution"]], "CopyFrameProps": [[29, "copyframeprops"]], "Crop/CropAbs": [[30, "crop-cropabs"]], "Deflate/Inflate": [[31, "deflate-inflate"]], "DeleteFrames": [[32, "deleteframes"]], "DoubleWeave": [[33, "doubleweave"]], "DuplicateFrames": [[34, "duplicateframes"]], "Expr": [[35, "expr"]], "FlipVertical/FlipHorizontal": [[36, "flipvertical-fliphorizontal"]], "FrameEval": [[37, "frameeval"]], "FreezeFrames": [[38, "freezeframes"]], "Interleave": [[39, "interleave"]], "Invert/InvertMask": [[40, "invert-invertmask"]], "Levels": [[41, "levels"]], "Limiter": [[42, "limiter"]], "Loop": [[43, "loop"]], "Lut": [[44, "lut"]], "Lut2": [[45, "lut2"]], "MakeDiff": [[46, "makediff"]], "MakeFullDiff": [[47, "makefulldiff"]], "MaskedMerge": [[48, "maskedmerge"]], "Median": [[49, "median"]], "Merge": [[50, "merge"]], "MergeDiff": [[51, "mergediff"]], "MergeFullDiff": [[52, "mergefulldiff"]], "Minimum/Maximum": [[53, "minimum-maximum"]], "ModifyFrame": [[54, "modifyframe"]], "PEMVerifier": [[55, "pemverifier"]], "PlaneStats": [[56, "planestats"]], "PreMultiply": [[57, "premultiply"]], "Prewitt/Sobel": [[58, "prewitt-sobel"]], "PropToClip": [[59, "proptoclip"]], "RemoveFrameProps": [[60, "removeframeprops"]], "Resize": [[61, "resize"]], "Reverse": [[62, "reverse"]], "SelectEvery": [[63, "selectevery"]], "SeparateFields": [[64, "separatefields"]], "SetFieldBased": [[65, "setfieldbased"]], "SetFrameProp": [[66, "setframeprop"]], "SetFrameProps": [[67, "setframeprops"]], "SetVideoCache": [[68, "setvideocache"]], "ShufflePlanes": [[69, "shuffleplanes"]], "Splice": [[70, "splice"]], "SplitPlanes": [[71, "splitplanes"]], "StackVertical/StackHorizontal": [[72, "stackvertical-stackhorizontal"]], "ClipInfo": [[73, "clipinfo"]], "CoreInfo": [[74, "coreinfo"]], "FrameNum": [[75, "framenum"]], "FrameProps": [[76, "frameprops"]], "Transpose": [[78, "transpose"]], "Trim": [[79, "trim"]], "Turn180": [[80, "turn180"]], "Getting Started": [[81, "getting-started"]], "Example Script": [[81, "example-script"]], "Preview": [[81, "preview"]], "Output with VSPipe": [[81, "output-with-vspipe"]], "Welcome to VapourSynth\u2019s documentation!": [[82, "welcome-to-vapoursynths-documentation"]], "Indices and tables": [[82, "indices-and-tables"]], "Installation": [[83, "installation"], [83, "id1"]], "Basic Program": [[83, "basic-program"]], "Windows Installation": [[83, "windows-installation"]], "Prerequisites": [[83, "prerequisites"]], "Windows Installation (Portable)": [[83, "windows-installation-portable"]], "OS X Installation": [[83, "os-x-installation"]], "Linux installation": [[83, "linux-installation"]], "Debian": [[83, "debian"]], "Fedora, CentOS and RHEL": [[83, "fedora-centos-and-rhel"]], "Gentoo": [[83, "gentoo"]], "Arch Linux": [[83, "arch-linux"]], "Nix and NixOS": [[83, "nix-and-nixos"]], "Windows Compilation": [[83, "windows-compilation"]], "Preparing the Build Environment on Windows": [[83, "preparing-the-build-environment-on-windows"]], "Preparing the C++ Project": [[83, "preparing-the-c-project"]], "Preparing the Python Project": [[83, "preparing-the-python-project"]], "Distribution": [[83, "distribution"]], "Linux and OS X Compilation": [[83, "linux-and-os-x-compilation"]], "Required packages (OS X)": [[83, "required-packages-os-x"]], "Compilation": [[83, "compilation"]], "Plugins and Scripts": [[83, "plugins-and-scripts"]], "Installing with VSRepo": [[83, "installing-with-vsrepo"]], "Installing Manually": [[83, "installing-manually"]], "Plugin Autoloading": [[83, "plugin-autoloading"]], "Windows": [[83, "windows"]], "Windows Portable": [[83, "windows-portable"]], "Linux": [[83, "linux"]], "OS X": [[83, "os-x"]], "About the author": [[84, "about-the-author"]], "Output": [[85, "output"], [86, "output"]], "VSPipe": [[85, "vspipe"]], "Synopsis": [[85, "synopsis"]], "Options": [[85, "options"]], "Examples": [[85, "examples"]], "AVFS": [[85, "avfs"]], "Avisynth Support": [[85, "avisynth-support"]], "VFW": [[85, "vfw"]], "Python Reference": [[86, "python-reference"]], "VapourSynth Structure": [[86, "vapoursynth-structure"]], "Grammar": [[86, "grammar"]], "Slicing and Other Syntactic Sugar": [[86, "slicing-and-other-syntactic-sugar"]], "Python Keywords as Filter Arguments": [[86, "python-keywords-as-filter-arguments"]], "Windows File Paths": [[86, "windows-file-paths"]], "Raw Access to Frame Data": [[86, "raw-access-to-frame-data"]], "Classes and Functions": [[86, "classes-and-functions"]], "Constants": [[86, "constants"]], "Video": [[86, "video"]], "Color Family": [[86, "color-family"]], "Format": [[86, "format"]], "Chroma Location": [[86, "chroma-location"]], "Field Based": [[86, "field-based"]], "Color Range": [[86, "color-range"]], "Matrix Coefficients": [[86, "matrix-coefficients"]], "TransferCharacteristics": [[86, "transfercharacteristics"]], "Color Primaries": [[86, "color-primaries"]], "Audio": [[86, "audio"]], "Channels": [[86, "channels"]], "Sample Type": [[86, "sample-type"]]}, "indexentries": {"api (c member)": [[0, "c.api"]], "bitspersample (c member)": [[0, "c.bitsPerSample"]], "bytespersample (c member)": [[0, "c.bytesPerSample"]], "channellayout (c member)": [[0, "c.channelLayout"]], "colorfamily (c member)": [[0, "c.colorFamily"]], "core (c member)": [[0, "c.core"]], "format (c member)": [[0, "c.format"]], "fpsden (c member)": [[0, "c.fpsDen"]], "fpsnum (c member)": [[0, "c.fpsNum"]], "height (c member)": [[0, "c.height"]], "maxframebuffersize (c member)": [[0, "c.maxFramebufferSize"]], "numchannels (c member)": [[0, "c.numChannels"]], "numframes (c member)": [[0, "c.numFrames"]], "numplanes (c member)": [[0, "c.numPlanes"]], "numsamples (c member)": [[0, "c.numSamples"]], "numthreads (c member)": [[0, "c.numThreads"]], "requestpattern (c member)": [[0, "c.requestPattern"]], "samplerate (c member)": [[0, "c.sampleRate"]], "sampletype (c member)": [[0, "c.sampleType"]], "source (c member)": [[0, "c.source"]], "subsamplingh (c member)": [[0, "c.subSamplingH"]], "subsamplingw (c member)": [[0, "c.subSamplingW"]], "usedframebuffersize (c member)": [[0, "c.usedFramebufferSize"]], "versionstring (c member)": [[0, "c.versionString"]], "width (c member)": [[0, "c.width"]], "vsh::addrational (c++ function)": [[1, "_CPPv4N3vsh11addRationalEP7int64_tP7int64_t7int64_t7int64_t"]], "vsh::arevaliddimensions (c++ function)": [[1, "_CPPv4N3vsh18areValidDimensionsEPK8VSFormatii"]], "vsh::bitblt (c++ function)": [[1, "_CPPv4N3vsh6bitbltEPviPKvi6size_t6size_t"]], "vsh::doubletofloats (c++ function)": [[1, "_CPPv4N3vsh14doubleToFloatSEd"]], "vsh::int64toints (c++ function)": [[1, "_CPPv4N3vsh11int64ToIntSE7int64_t"]], "vsh::isconstantformat (c++ function)": [[1, "_CPPv4N3vsh16isConstantFormatEPK11VSVideoInfo"]], "vsh::issameaudioformat (c++ function)": [[1, "_CPPv4N3vsh17isSameAudioFormatEPK11VSAudioInfoPK11VSAudioInfo"]], "vsh::issameaudioinfo (c++ function)": [[1, "_CPPv4N3vsh15isSameAudioInfoEPK11VSAudioInfoPK11VSAudioInfo"]], "vsh::issamevideoformat (c++ function)": [[1, "_CPPv4N3vsh17isSameVideoFormatEPK11VSVideoInfoPK11VSVideoInfo"]], "vsh::issamevideoinfo (c++ function)": [[1, "_CPPv4N3vsh15isSameVideoInfoEPK11VSVideoInfoPK11VSVideoInfo"]], "vsh::issamevideopresetformat (c++ function)": [[1, "_CPPv4N3vsh23isSameVideoPresetFormatEjPK13VSVideoFormatP6VSCorePK5VSAPI"]], "vsh::muldivrational (c++ function)": [[1, "_CPPv4N3vsh14muldivRationalEP7int64_tP7int64_t7int64_t7int64_t"]], "vsh::reducerational (c++ function)": [[1, "_CPPv4N3vsh14reduceRationalEP7int64_tP7int64_t"]], "vsh::vsh_aligned_free (c++ function)": [[1, "_CPPv4N3vsh16vsh_aligned_freeEPv"]], "vsh::vsh_aligned_malloc (c++ function)": [[1, "_CPPv4N3vsh18vsh_aligned_mallocE6size_t6size_t"]], "createscript (c function)": [[2, "c.createScript"]], "evalsetworkingdir (c function)": [[2, "c.evalSetWorkingDir"]], "evaluatebuffer (c function)": [[2, "c.evaluateBuffer"]], "evaluatefile (c function)": [[2, "c.evaluateFile"]], "freescript (c function)": [[2, "c.freeScript"]], "getaltoutputmode (c function)": [[2, "c.getAltOutputMode"]], "getapiversion (c function)": [[2, "c.getApiVersion"]], "getcore (c function)": [[2, "c.getCore"]], "geterror (c function)": [[2, "c.getError"]], "getexitcode (c function)": [[2, "c.getExitCode"]], "getoutputalphanode (c function)": [[2, "c.getOutputAlphaNode"]], "getoutputnode (c function)": [[2, "c.getOutputNode"]], "getvsapi (c function)": [[2, "c.getVSAPI"]], "getvsscriptapi (c function)": [[2, "c.getVSScriptAPI"]], "getvariable (c function)": [[2, "c.getVariable"]], "vsscript_setvariable (c function)": [[2, "c.vsscript_setVariable"]], "assumesamplerate() (in module std)": [[6, "std.AssumeSampleRate"]], "audiogain() (in module std)": [[7, "std.AudioGain"]], "audioloop() (in module std)": [[8, "std.AudioLoop"]], "audiomix() (in module std)": [[9, "std.AudioMix"]], "audioreverse() (in module std)": [[10, "std.AudioReverse"]], "audiosplice() (in module std)": [[11, "std.AudioSplice"]], "audiotrim() (in module std)": [[12, "std.AudioTrim"]], "blankaudio() (in module std)": [[13, "std.BlankAudio"]], "setaudiocache() (in module std)": [[14, "std.SetAudioCache"]], "shufflechannels() (in module std)": [[15, "std.ShuffleChannels"]], "splitchannels() (in module std)": [[16, "std.SplitChannels"]], "loadallplugins() (in module std)": [[17, "std.LoadAllPlugins"]], "loadplugin() (in module std)": [[18, "std.LoadPlugin"]], "loadplugin() (in module avs)": [[19, "avs.LoadPlugin"]], "setmaxcpu() (in module std)": [[20, "std.SetMaxCPU"]], "addborders() (in module std)": [[21, "std.AddBorders"]], "assumefps() (in module std)": [[22, "std.AssumeFPS"]], "averageframes() (in module std)": [[23, "std.AverageFrames"]], "binarize() (in module std)": [[24, "std.Binarize"]], "binarizemask() (in module std)": [[24, "std.BinarizeMask"]], "blankclip() (in module std)": [[25, "std.BlankClip"]], "boxblur() (in module std)": [[26, "std.BoxBlur"]], "cliptoprop() (in module std)": [[27, "std.ClipToProp"]], "convolution() (in module std)": [[28, "std.Convolution"]], "copyframeprops() (in module std)": [[29, "std.CopyFrameProps"]], "crop() (in module std)": [[30, "std.Crop"]], "cropabs() (in module std)": [[30, "std.CropAbs"]], "deflate() (in module std)": [[31, "std.Deflate"]], "inflate() (in module std)": [[31, "std.Inflate"]], "deleteframes() (in module std)": [[32, "std.DeleteFrames"]], "doubleweave() (in module std)": [[33, "std.DoubleWeave"]], "duplicateframes() (in module std)": [[34, "std.DuplicateFrames"]], "expr() (in module std)": [[35, "std.Expr"]], "fliphorizontal() (in module std)": [[36, "std.FlipHorizontal"]], "flipvertical() (in module std)": [[36, "std.FlipVertical"]], "frameeval() (in module std)": [[37, "std.FrameEval"]], "freezeframes() (in module std)": [[38, "std.FreezeFrames"]], "interleave() (in module std)": [[39, "std.Interleave"]], "invert() (in module std)": [[40, "std.Invert"]], "invertmask() (in module std)": [[40, "std.InvertMask"]], "levels() (in module std)": [[41, "std.Levels"]], "limiter() (in module std)": [[42, "std.Limiter"]], "loop() (in module std)": [[43, "std.Loop"]], "lut() (in module std)": [[44, "std.Lut"]], "lut2() (in module std)": [[45, "std.Lut2"]], "makediff() (in module std)": [[46, "std.MakeDiff"]], "makefulldiff() (in module std)": [[47, "std.MakeFullDiff"]], "maskedmerge() (in module std)": [[48, "std.MaskedMerge"]], "median() (in module std)": [[49, "std.Median"]], "merge() (in module std)": [[50, "std.Merge"]], "mergediff() (in module std)": [[51, "std.MergeDiff"]], "mergefulldiff() (in module std)": [[52, "std.MergeFullDiff"]], "maximum() (in module std)": [[53, "std.Maximum"]], "minimum() (in module std)": [[53, "std.Minimum"]], "modifyframe() (in module std)": [[54, "std.ModifyFrame"]], "pemverifier() (in module std)": [[55, "std.PEMVerifier"]], "planestats() (in module std)": [[56, "std.PlaneStats"]], "premultiply() (in module std)": [[57, "std.PreMultiply"]], "prewitt() (in module std)": [[58, "std.Prewitt"]], "sobel() (in module std)": [[58, "std.Sobel"]], "proptoclip() (in module std)": [[59, "std.PropToClip"]], "removeframeprops() (in module std)": [[60, "std.RemoveFrameProps"]], "bicubic() (in module resize)": [[61, "resize.Bicubic"]], "bilinear() (in module resize)": [[61, "resize.Bilinear"]], "bob() (in module resize)": [[61, "resize.Bob"]], "lanczos() (in module resize)": [[61, "resize.Lanczos"]], "point() (in module resize)": [[61, "resize.Point"]], "spline16() (in module resize)": [[61, "resize.Spline16"]], "spline36() (in module resize)": [[61, "resize.Spline36"]], "spline64() (in module resize)": [[61, "resize.Spline64"]], "reverse() (in module std)": [[62, "std.Reverse"]], "selectevery() (in module std)": [[63, "std.SelectEvery"]], "separatefields() (in module std)": [[64, "std.SeparateFields"]], "setfieldbased() (in module std)": [[65, "std.SetFieldBased"]], "setframeprop() (in module std)": [[66, "std.SetFrameProp"]], "setframeprops() (in module std)": [[67, "std.SetFrameProps"]], "setvideocache() (in module std)": [[68, "std.SetVideoCache"]], "shuffleplanes() (in module std)": [[69, "std.ShufflePlanes"]], "splice() (in module std)": [[70, "std.Splice"]], "splitplanes() (in module std)": [[71, "std.SplitPlanes"]], "stackhorizontal() (in module std)": [[72, "std.StackHorizontal"]], "stackvertical() (in module std)": [[72, "std.StackVertical"]], "clipinfo() (in module text)": [[73, "text.ClipInfo"]], "coreinfo() (in module text)": [[74, "text.CoreInfo"]], "framenum() (in module text)": [[75, "text.FrameNum"]], "frameprops() (in module text)": [[76, "text.FrameProps"]], "text() (in module text)": [[77, "text.Text"]], "transpose() (in module std)": [[78, "std.Transpose"]], "trim() (in module std)": [[79, "std.Trim"]], "turn180() (in module std)": [[80, "std.Turn180"]], "audioframe (built-in class)": [[86, "AudioFrame"]], "audionode (built-in class)": [[86, "AudioNode"]], "core (built-in class)": [[86, "Core"]], "environment (built-in class)": [[86, "Environment"]], "environment.is_single()": [[86, "Environment.is_single"]], "environmentdata (built-in class)": [[86, "EnvironmentData"]], "environmentpolicy (built-in class)": [[86, "EnvironmentPolicy"]], "environmentpolicyapi (built-in class)": [[86, "EnvironmentPolicyAPI"]], "error": [[86, "Error"]], "func (built-in class)": [[86, "Func"]], "function (built-in class)": [[86, "Function"]], "local (built-in class)": [[86, "Local"]], "plugin (built-in class)": [[86, "Plugin"]], "videoformat (built-in class)": [[86, "VideoFormat"]], "videoframe (built-in class)": [[86, "VideoFrame"]], "videonode (built-in class)": [[86, "VideoNode"]], "videooutputtuple (built-in class)": [[86, "VideoOutputTuple"]], "_try_enable_introspection()": [[86, "try_enable_introspection"]], "add_log_handler() (core method)": [[86, "Core.add_log_handler"]], "alive (environment attribute)": [[86, "Environment.alive"]], "alpha (videooutputtuple attribute)": [[86, "VideoOutputTuple.alpha"]], "alt_output (videooutputtuple attribute)": [[86, "VideoOutputTuple.alt_output"]], "bits_per_sample (audioframe attribute)": [[86, "AudioFrame.bits_per_sample"]], "bits_per_sample (audionode attribute)": [[86, "AudioNode.bits_per_sample"]], "bits_per_sample (videoformat attribute)": [[86, "VideoFormat.bits_per_sample"]], "built-in function": [[86, "Environment.is_single"], [86, "clear_output"], [86, "clear_outputs"], [86, "construct_signature"], [86, "get_current_environment"], [86, "get_output"], [86, "get_outputs"], [86, "has_policy"], [86, "register_on_destroy"], [86, "register_policy"], [86, "try_enable_introspection"], [86, "unregister_on_destroy"]], "bytes_per_sample (audioframe attribute)": [[86, "AudioFrame.bytes_per_sample"]], "bytes_per_sample (audionode attribute)": [[86, "AudioNode.bytes_per_sample"]], "bytes_per_sample (videoformat attribute)": [[86, "VideoFormat.bytes_per_sample"]], "channel_layout (audioframe attribute)": [[86, "AudioFrame.channel_layout"]], "channel_layout (audionode attribute)": [[86, "AudioNode.channel_layout"]], "clear_output()": [[86, "clear_output"]], "clear_outputs()": [[86, "clear_outputs"]], "clip (videooutputtuple attribute)": [[86, "VideoOutputTuple.clip"]], "close() (videoframe method)": [[86, "VideoFrame.close"]], "closed (videoframe attribute)": [[86, "VideoFrame.closed"]], "color_family (videoformat attribute)": [[86, "VideoFormat.color_family"]], "construct_signature()": [[86, "construct_signature"]], "copy() (audioframe method)": [[86, "AudioFrame.copy"]], "copy() (environment method)": [[86, "Environment.copy"]], "copy() (videoframe method)": [[86, "VideoFrame.copy"]], "core": [[86, "core"]], "create_environment() (environmentpolicyapi method)": [[86, "EnvironmentPolicyAPI.create_environment"]], "create_video_frame() (core method)": [[86, "Core.create_video_frame"]], "denominator (videonode attribute)": [[86, "VideoNode.denominator"]], "destroy_environment() (environmentpolicyapi method)": [[86, "EnvironmentPolicyAPI.destroy_environment"]], "env_id (environment attribute)": [[86, "Environment.env_id"]], "flags (videonode attribute)": [[86, "VideoNode.flags"]], "format (videoframe attribute)": [[86, "VideoFrame.format"]], "format (videonode attribute)": [[86, "VideoNode.format"]], "fps (videonode attribute)": [[86, "VideoNode.fps"]], "fps_den (videonode attribute)": [[86, "VideoNode.fps_den"]], "fps_num (videonode attribute)": [[86, "VideoNode.fps_num"]], "frames() (audionode method)": [[86, "AudioNode.frames"]], "frames() (videonode method)": [[86, "VideoNode.frames"]], "functions() (plugin method)": [[86, "Plugin.functions"]], "get_core_ptr() (environmentpolicyapi method)": [[86, "EnvironmentPolicyAPI.get_core_ptr"]], "get_current_environment()": [[86, "get_current_environment"]], "get_current_environment() (environmentpolicy method)": [[86, "EnvironmentPolicy.get_current_environment"]], "get_frame() (audionode method)": [[86, "AudioNode.get_frame"]], "get_frame() (videonode method)": [[86, "VideoNode.get_frame"]], "get_frame_async() (audionode method)": [[86, "AudioNode.get_frame_async"]], "get_frame_async() (videonode method)": [[86, "VideoNode.get_frame_async"]], "get_output()": [[86, "get_output"]], "get_outputs()": [[86, "get_outputs"]], "get_read_ptr() (audioframe method)": [[86, "AudioFrame.get_read_ptr"]], "get_read_ptr() (videoframe method)": [[86, "VideoFrame.get_read_ptr"]], "get_stride() (audioframe method)": [[86, "AudioFrame.get_stride"]], "get_stride() (videoframe method)": [[86, "VideoFrame.get_stride"]], "get_vapoursynth_api() (environmentpolicyapi method)": [[86, "EnvironmentPolicyAPI.get_vapoursynth_api"]], "get_video_format() (core method)": [[86, "Core.get_video_format"]], "get_write_ptr() (audioframe method)": [[86, "AudioFrame.get_write_ptr"]], "get_write_ptr() (videoframe method)": [[86, "VideoFrame.get_write_ptr"]], "has_policy()": [[86, "has_policy"]], "height (videoframe attribute)": [[86, "VideoFrame.height"]], "height (videonode attribute)": [[86, "VideoNode.height"]], "id (videoformat attribute)": [[86, "VideoFormat.id"]], "identifier (plugin attribute)": [[86, "Plugin.identifier"]], "is_alive() (environmentpolicy method)": [[86, "EnvironmentPolicy.is_alive"]], "is_inspectable() (audionode method)": [[86, "AudioNode.is_inspectable"]], "is_inspectable() (videonode method)": [[86, "VideoNode.is_inspectable"]], "log_message() (core method)": [[86, "Core.log_message"]], "max_cache_size (core attribute)": [[86, "Core.max_cache_size"]], "name (function attribute)": [[86, "Function.name"]], "name (plugin attribute)": [[86, "Plugin.name"]], "name (videoformat attribute)": [[86, "VideoFormat.name"]], "namespace (plugin attribute)": [[86, "Plugin.namespace"]], "num_channels (audioframe attribute)": [[86, "AudioFrame.num_channels"]], "num_channels (audionode attribute)": [[86, "AudioNode.num_channels"]], "num_frames (videonode attribute)": [[86, "VideoNode.num_frames"]], "num_planes (videoformat attribute)": [[86, "VideoFormat.num_planes"]], "num_threads (core attribute)": [[86, "Core.num_threads"]], "numerator (videonode attribute)": [[86, "VideoNode.numerator"]], "on_policy_cleared() (environmentpolicy method)": [[86, "EnvironmentPolicy.on_policy_cleared"]], "on_policy_registered() (environmentpolicy method)": [[86, "EnvironmentPolicy.on_policy_registered"]], "output() (videonode method)": [[86, "VideoNode.output"]], "plugin (function attribute)": [[86, "Function.plugin"]], "plugins() (core method)": [[86, "Core.plugins"]], "props (audioframe attribute)": [[86, "AudioFrame.props"]], "props (videoframe attribute)": [[86, "VideoFrame.props"]], "query_video_format() (core method)": [[86, "Core.query_video_format"]], "readchunks() (videoframe method)": [[86, "VideoFrame.readchunks"]], "readonly (audioframe attribute)": [[86, "AudioFrame.readonly"]], "readonly (videoframe attribute)": [[86, "VideoFrame.readonly"]], "register_on_destroy()": [[86, "register_on_destroy"]], "register_policy()": [[86, "register_policy"]], "remove_log_handler() (core method)": [[86, "Core.remove_log_handler"]], "replace() (videoformat method)": [[86, "VideoFormat.replace"]], "return_signature (function attribute)": [[86, "Function.return_signature"]], "rule6() (core method)": [[86, "Core.rule6"]], "sample_rate (audionode attribute)": [[86, "AudioNode.sample_rate"]], "sample_type (audioframe attribute)": [[86, "AudioFrame.sample_type"]], "sample_type (audionode attribute)": [[86, "AudioNode.sample_type"]], "sample_type (videoformat attribute)": [[86, "VideoFormat.sample_type"]], "set_environment() (environmentpolicy method)": [[86, "EnvironmentPolicy.set_environment"]], "set_logger() (environmentpolicyapi method)": [[86, "EnvironmentPolicyAPI.set_logger"]], "set_output() (audionode method)": [[86, "AudioNode.set_output"]], "set_output() (videonode method)": [[86, "VideoNode.set_output"]], "signature (function attribute)": [[86, "Function.signature"]], "single (environment attribute)": [[86, "Environment.single"]], "subsampling_h (videoformat attribute)": [[86, "VideoFormat.subsampling_h"]], "subsampling_w (videoformat attribute)": [[86, "VideoFormat.subsampling_w"]], "unregister_on_destroy()": [[86, "unregister_on_destroy"]], "unregister_policy() (environmentpolicyapi method)": [[86, "EnvironmentPolicyAPI.unregister_policy"]], "use() (environment method)": [[86, "Environment.use"]], "version() (core method)": [[86, "Core.version"]], "version_number() (core method)": [[86, "Core.version_number"]], "width (videoframe attribute)": [[86, "VideoFrame.width"]], "width (videonode attribute)": [[86, "VideoNode.width"]], "wrap_environment() (environmentpolicyapi method)": [[86, "EnvironmentPolicyAPI.wrap_environment"]]}}) \ No newline at end of file diff --git a/Programs/ffmpeg.exe b/Programs/ffmpeg.exe new file mode 100644 index 0000000..7006ace Binary files /dev/null and b/Programs/ffmpeg.exe differ diff --git a/Programs/havsfunc.py b/Programs/havsfunc.py new file mode 100644 index 0000000..b3e1cfa --- /dev/null +++ b/Programs/havsfunc.py @@ -0,0 +1,6465 @@ +""" +Holy's ported AviSynth functions for VapourSynth. + +Main functions: + daa + daa3mod + mcdaa3 + santiag + FixChromaBleedingMod + Deblock_QED + DeHalo_alpha + EdgeCleaner + FineDehalo, FineDehalo2 + YAHR + HQDeringmod + QTGMC + smartfademod + srestore + dec_txt60mc + ivtc_txt30mc + ivtc_txt60mc + logoNR + Vinverse + Vinverse2 + LUTDeCrawl + LUTDeRainbow + Stab + GrainStabilizeMC + MCTemporalDenoise + SMDegrain + STPresso + bbmod + GrainFactory3 + InterFrame + FixColumnBrightness, FixRowBrightness + FixColumnBrightnessProtect, FixRowBrightnessProtect + FixColumnBrightnessProtect2, FixRowBrightnessProtect2 + SmoothLevels + FastLineDarkenMOD + Toon + LSFmod + +Utility functions: + AverageFrames + AvsPrewitt + ChangeFPS + Gauss + mt_clamp + KNLMeansCL + Overlay + Padding + SCDetect + Weave + ContraSharpening + MinBlur + sbr, sbrV + DitherLumaRebuild + mt_expand_multi, mt_inpand_multi + mt_inflate_multi, mt_deflate_multi +""" + +from __future__ import annotations +import importlib + +import math +from functools import partial +from typing import Any, Mapping, Optional, Sequence, Union + +import mvsfunc as mvf +import vapoursynth as vs +from vsutil import Dither, depth, fallback, get_depth, get_y, join, plane, scale_value + +core = vs.core + + +def daa( + c: vs.VideoNode, + nsize: Optional[int] = None, + nns: Optional[int] = None, + qual: Optional[int] = None, + pscrn: Optional[int] = None, + int16_prescreener: Optional[bool] = None, + int16_predictor: Optional[bool] = None, + exp: Optional[int] = None, + opencl: bool = False, + device: Optional[int] = None, +) -> vs.VideoNode: + ''' + Anti-aliasing with contra-sharpening by Didée. + + It averages two independent interpolations, where each interpolation set works between odd-distanced pixels. + This on its own provides sufficient amount of blurring. Enough blurring that the script uses a contra-sharpening step to counteract the blurring. + ''' + if not isinstance(c, vs.VideoNode): + raise vs.Error('daa: this is not a clip') + + if opencl: + nnedi3 = partial(core.nnedi3cl.NNEDI3CL, nsize=nsize, nns=nns, qual=qual, pscrn=pscrn, device=device) + else: + nnedi3 = partial( + core.znedi3.nnedi3, nsize=nsize, nns=nns, qual=qual, pscrn=pscrn, int16_prescreener=int16_prescreener, int16_predictor=int16_predictor, exp=exp + ) + + nn = nnedi3(c, field=3) + dbl = core.std.Merge(nn[::2], nn[1::2]) + dblD = core.std.MakeDiff(c, dbl) + shrpD = core.std.MakeDiff(dbl, dbl.std.Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1] if c.width > 1100 else [1, 2, 1, 2, 4, 2, 1, 2, 1])) + DD = core.rgvs.Repair(shrpD, dblD, mode=13) + return core.std.MergeDiff(dbl, DD) + + +def daa3mod( + c1: vs.VideoNode, + nsize: Optional[int] = None, + nns: Optional[int] = None, + qual: Optional[int] = None, + pscrn: Optional[int] = None, + int16_prescreener: Optional[bool] = None, + int16_predictor: Optional[bool] = None, + exp: Optional[int] = None, + opencl: bool = False, + device: Optional[int] = None, +) -> vs.VideoNode: + if not isinstance(c1, vs.VideoNode): + raise vs.Error('daa3mod: this is not a clip') + + c = c1.resize.Spline36(c1.width, c1.height * 3 // 2) + return daa(c, nsize, nns, qual, pscrn, int16_prescreener, int16_predictor, exp, opencl, device).resize.Spline36(c1.width, c1.height) + + +def mcdaa3( + input: vs.VideoNode, + nsize: Optional[int] = None, + nns: Optional[int] = None, + qual: Optional[int] = None, + pscrn: Optional[int] = None, + int16_prescreener: Optional[bool] = None, + int16_predictor: Optional[bool] = None, + exp: Optional[int] = None, + opencl: bool = False, + device: Optional[int] = None, +) -> vs.VideoNode: + if not isinstance(input, vs.VideoNode): + raise vs.Error('mcdaa3: this is not a clip') + + sup = input.hqdn3d.Hqdn3d().fft3dfilter.FFT3DFilter().mv.Super(sharp=1) + fv1 = sup.mv.Analyse(isb=False, delta=1, truemotion=False, dct=2) + fv2 = sup.mv.Analyse(isb=True, delta=1, truemotion=True, dct=2) + csaa = daa3mod(input, nsize, nns, qual, pscrn, int16_prescreener, int16_predictor, exp, opencl, device) + momask1 = input.mv.Mask(fv1, ml=2, kind=1) + momask2 = input.mv.Mask(fv2, ml=3, kind=1) + momask = core.std.Merge(momask1, momask2) + return core.std.MaskedMerge(input, csaa, momask) + + +def santiag( + c: vs.VideoNode, + strh: int = 1, + strv: int = 1, + type: str = 'nnedi3', + nsize: Optional[int] = None, + nns: Optional[int] = None, + qual: Optional[int] = None, + pscrn: Optional[int] = None, + int16_prescreener: Optional[bool] = None, + int16_predictor: Optional[bool] = None, + exp: Optional[int] = None, + aa: Optional[int] = None, + alpha: Optional[float] = None, + beta: Optional[float] = None, + gamma: Optional[float] = None, + nrad: Optional[int] = None, + mdis: Optional[int] = None, + vcheck: Optional[int] = None, + fw: Optional[int] = None, + fh: Optional[int] = None, + halfres: bool = False, + typeh: Optional[str] = None, + typev: Optional[str] = None, + opencl: bool = False, + device: Optional[int] = None, +) -> vs.VideoNode: + ''' + santiag v1.6 + Simple antialiasing + + type = "nnedi3", "eedi2", "eedi3" or "sangnom" + ''' + + def santiag_dir(c: vs.VideoNode, strength: int, type: str, fw: Optional[int] = None, fh: Optional[int] = None) -> vs.VideoNode: + fw = fallback(fw, c.width) + fh = fallback(fh, c.height) + + c = santiag_stronger(c, strength, type) + + return c.resize.Spline36(fw, fh, src_top=0 if halfres else 0.5) + + def santiag_stronger(c: vs.VideoNode, strength: int, type: str) -> vs.VideoNode: + if opencl: + nnedi3 = partial(core.nnedi3cl.NNEDI3CL, nsize=nsize, nns=nns, qual=qual, pscrn=pscrn, device=device) + eedi3 = partial(core.eedi3m.EEDI3CL, alpha=alpha, beta=beta, gamma=gamma, nrad=nrad, mdis=mdis, vcheck=vcheck, device=device) + else: + nnedi3 = partial( + core.znedi3.nnedi3, nsize=nsize, nns=nns, qual=qual, pscrn=pscrn, int16_prescreener=int16_prescreener, int16_predictor=int16_predictor, exp=exp + ) + eedi3 = partial(core.eedi3m.EEDI3, alpha=alpha, beta=beta, gamma=gamma, nrad=nrad, mdis=mdis, vcheck=vcheck) + + strength = max(strength, 0) + field = strength % 2 + dh = strength <= 0 and not halfres + + if strength > 0: + c = santiag_stronger(c, strength - 1, type) + + w = c.width + h = c.height + + if type == 'nnedi3': + return nnedi3(c, field=field, dh=dh) + elif type == 'eedi2': + if not dh: + c = c.resize.Point(w, h // 2, src_top=1 - field) + return c.eedi2.EEDI2(field=field) + elif type == 'eedi3': + sclip = nnedi3(c, field=field, dh=dh) + return eedi3(c, field=field, dh=dh, sclip=sclip) + elif type == 'sangnom': + if dh: + c = c.resize.Spline36(w, h * 2, src_top=-0.25) + return c.sangnom.SangNom(order=field + 1, aa=aa) + else: + raise vs.Error('santiag: unexpected value for type') + + if not isinstance(c, vs.VideoNode): + raise vs.Error('santiag: this is not a clip') + + type = type.lower() + typeh = type if typeh is None else typeh.lower() + typev = type if typev is None else typev.lower() + + w = c.width + h = c.height + fwh = fw if strv < 0 else w + fhh = fh if strv < 0 else h + + if strh >= 0: + c = santiag_dir(c, strh, typeh, fwh, fhh) + if strv >= 0: + c = santiag_dir(c.std.Transpose(), strv, typev, fh, fw).std.Transpose() + + fw = fallback(fw, w) + fh = fallback(fh, h) + if strh < 0 and strv < 0: + c = c.resize.Spline36(fw, fh) + return c + + +def FixChromaBleedingMod(input: vs.VideoNode, cx: int = 4, cy: int = 4, thr: float = 4.0, strength: float = 0.8, blur: bool = False) -> vs.VideoNode: + ''' + FixChromaBleedingMod v1.36 + A script to reduce color bleeding, over-saturation, and color shifting mainly in red and blue areas. + + Parameters: + input: Clip to process. + + cx: Horizontal chroma shift. Positive value shifts chroma to the left, negative value shifts chroma to the right. + + cy: Vertical chroma shift. Positive value shifts chroma upwards, negative value shifts chroma downwards. + + thr: Masking threshold, higher values treat more areas as color bleed. + + strength: Saturation strength in clip to be merged with the original chroma. + Values below 1.0 reduce the saturation, a value of 1.0 leaves the saturation intact. + + blur: Set to true to blur the mask clip. + ''' + from adjust import Tweak + + if not isinstance(input, vs.VideoNode): + raise vs.Error('FixChromaBleedingMod: this is not a clip') + + if input.format.color_family != vs.YUV or input.format.sample_type != vs.INTEGER: + raise vs.Error('FixChromaBleedingMod: only YUV format with integer sample type is supported') + + # prepare to work on the V channel and filter noise + vch = plane(Tweak(input, sat=thr), 2) + if blur: + area = vch.std.Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]) + else: + area = vch + + bits = get_depth(input) + i16 = scale_value(16, 8, bits) + i25 = scale_value(25, 8, bits) + i231 = scale_value(231, 8, bits) + i235 = scale_value(235, 8, bits) + i240 = scale_value(240, 8, bits) + + # select and normalize both extremes of the scale + red = area.std.Levels(min_in=i235, max_in=i235, min_out=i235, max_out=i16) + blue = area.std.Levels(min_in=i16, max_in=i16, min_out=i16, max_out=i235) + + # merge both masks + mask = core.std.Merge(red, blue) + if not blur: + mask = mask.std.Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]) + mask = mask.std.Levels(min_in=i231, max_in=i231, min_out=i235, max_out=i16) + + # expand to cover beyond the bleeding areas and shift to compensate the resizing + mask = mask.std.Convolution(matrix=[0, 0, 0, 1, 0, 0, 0, 0, 0], divisor=1, saturate=False).std.Convolution( + matrix=[1, 1, 1, 1, 1, 1, 0, 0, 0], divisor=8, saturate=False + ) + + # binarize (also a trick to expand) + mask = mask.std.Levels(min_in=i25, max_in=i25, min_out=i16, max_out=i240).std.Inflate() + + # prepare a version of the image that has its chroma shifted and less saturated + input_c = Tweak(input.resize.Spline16(src_left=cx, src_top=cy), sat=strength) + + # combine both images using the mask + fu = core.std.MaskedMerge(plane(input, 1), plane(input_c, 1), mask) + fv = core.std.MaskedMerge(plane(input, 2), plane(input_c, 2), mask) + return join([input, fu, fv]) + + +def Deblock_QED( + clp: vs.VideoNode, quant1: int = 24, quant2: int = 26, aOff1: int = 1, bOff1: int = 2, aOff2: int = 1, bOff2: int = 2, uv: int = 3 +) -> vs.VideoNode: + ''' + A postprocessed Deblock: Uses full frequencies of Deblock's changes on block borders, but DCT-lowpassed changes on block interiours. + + Parameters: + clp: Clip to process. + + quant1: Strength of block edge deblocking. + + quant2: Strength of block internal deblocking. + + aOff1: Halfway "sensitivity" and halfway a strength modifier for borders. + + bOff1: "Sensitivity to detect blocking" for borders. + + aOff2: Halfway "sensitivity" and halfway a strength modifier for block interiors. + + bOff2: "Sensitivity to detect blocking" for block interiors. + + uv: + 3 = use proposed method for chroma deblocking + 2 = no chroma deblocking at all (fastest method) + 1 = directly use chroma debl. from the normal Deblock() + -1 = directly use chroma debl. from the strong Deblock() + ''' + if not isinstance(clp, vs.VideoNode): + raise vs.Error('Deblock_QED: this is not a clip') + + is_gray = clp.format.color_family == vs.GRAY + planes = [0, 1, 2] if uv > 2 and not is_gray else 0 + + if clp.format.sample_type == vs.INTEGER: + bits = get_depth(clp) + neutral = 1 << (bits - 1) + peak = (1 << bits) - 1 + else: + neutral = 0.0 + peak = 1.0 + + # add borders if clp is not mod 8 + w = clp.width + h = clp.height + padX = 8 - w % 8 if w & 7 else 0 + padY = 8 - h % 8 if h & 7 else 0 + if padX or padY: + clp = clp.resize.Point(w + padX, h + padY, src_width=w + padX, src_height=h + padY) + + # block + block = clp.std.BlankClip(width=6, height=6, format=clp.format.replace(color_family=vs.GRAY, subsampling_w=0, subsampling_h=0), length=1, color=0) + block = block.std.AddBorders(1, 1, 1, 1, color=peak) + block = core.std.StackHorizontal([block for _ in range(clp.width // 8)]) + block = core.std.StackVertical([block for _ in range(clp.height // 8)]) + if not is_gray: + blockc = block.std.CropAbs(width=clp.width >> clp.format.subsampling_w, height=clp.height >> clp.format.subsampling_h) + block = core.std.ShufflePlanes([block, blockc], planes=[0, 0, 0], colorfamily=clp.format.color_family) + block = block.std.Loop(times=clp.num_frames) + + # create normal deblocking (for block borders) and strong deblocking (for block interiour) + normal = clp.deblock.Deblock(quant=quant1, aoffset=aOff1, boffset=bOff1, planes=[0, 1, 2] if uv != 2 and not is_gray else 0) + strong = clp.deblock.Deblock(quant=quant2, aoffset=aOff2, boffset=bOff2, planes=[0, 1, 2] if uv != 2 and not is_gray else 0) + + # build difference maps of both + normalD = core.std.MakeDiff(clp, normal, planes=planes) + strongD = core.std.MakeDiff(clp, strong, planes=planes) + + # separate border values of the difference maps, and set the interiours to '128' + expr = f'y {peak} = x {neutral} ?' + normalD2 = core.std.Expr([normalD, block], expr=expr if uv > 2 or is_gray else [expr, '']) + strongD2 = core.std.Expr([strongD, block], expr=expr if uv > 2 or is_gray else [expr, '']) + + # interpolate the border values over the whole block: DCTFilter can do it. (Kiss to Tom Barry!) + # (Note: this is not fully accurate, but a reasonable approximation.) + # add borders if clp is not mod 16 + sw = strongD2.width + sh = strongD2.height + remX = 16 - sw % 16 if sw & 15 else 0 + remY = 16 - sh % 16 if sh & 15 else 0 + if remX or remY: + strongD2 = strongD2.resize.Point(sw + remX, sh + remY, src_width=sw + remX, src_height=sh + remY) + expr = f'x {neutral} - 1.01 * {neutral} +' + strongD3 = ( + strongD2.std.Expr(expr=expr if uv > 2 or is_gray else [expr, '']) + .dctf.DCTFilter(factors=[1, 1, 0, 0, 0, 0, 0, 0], planes=planes) + .std.Crop(right=remX, bottom=remY) + ) + + # apply compensation from "normal" deblocking to the borders of the full-block-compensations calculated from "strong" deblocking ... + expr = f'y {neutral} = x y ?' + strongD4 = core.std.Expr([strongD3, normalD2], expr=expr if uv > 2 or is_gray else [expr, '']) + + # ... and apply it. + deblocked = core.std.MakeDiff(clp, strongD4, planes=planes) + + # simple decisions how to treat chroma + if not is_gray: + if uv < 0: + deblocked = core.std.ShufflePlanes([deblocked, strong], planes=[0, 1, 2], colorfamily=clp.format.color_family) + elif uv < 2: + deblocked = core.std.ShufflePlanes([deblocked, normal], planes=[0, 1, 2], colorfamily=clp.format.color_family) + + # remove mod 8 borders + return deblocked.std.Crop(right=padX, bottom=padY) + + +def DeHalo_alpha( + clp: vs.VideoNode, + rx: float = 2.0, + ry: float = 2.0, + darkstr: float = 1.0, + brightstr: float = 1.0, + lowsens: float = 50.0, + highsens: float = 50.0, + ss: float = 1.5, +) -> vs.VideoNode: + ''' + Reduce halo artifacts that can occur when sharpening. + + Parameters: + clp: Clip to process. + + rx, ry: As usual, the radii for halo removal. This function is rather sensitive to the radius settings. + Set it as low as possible! If radius is set too high, it will start missing small spots. + + darkstr, brightstr: The strength factors for processing dark and bright halos. Default 1.0 both for symmetrical processing. + On Comic/Anime, darkstr=0.4~0.8 sometimes might be better ... sometimes. In General, the function seems to preserve dark lines rather good. + + lowsens, highsens: Sensitivity settings, not that easy to describe them exactly ... + In a sense, they define a window between how weak an achieved effect has to be to get fully accepted, + and how strong an achieved effect has to be to get fully discarded. + + ss: Supersampling factor, to avoid creation of aliasing. + ''' + if not isinstance(clp, vs.VideoNode): + raise vs.Error('DeHalo_alpha: this is not a clip') + + if clp.format.color_family == vs.RGB: + raise vs.Error('DeHalo_alpha: RGB format is not supported') + + bits = get_depth(clp) + + if clp.format.color_family != vs.GRAY: + clp_orig = clp + clp = get_y(clp) + else: + clp_orig = None + + ox = clp.width + oy = clp.height + + halos = clp.resize.Bicubic(m4(ox / rx), m4(oy / ry), filter_param_a=1 / 3, filter_param_b=1 / 3).resize.Bicubic(ox, oy, filter_param_a=1, filter_param_b=0) + are = core.std.Expr([clp.std.Maximum(), clp.std.Minimum()], expr='x y -') + ugly = core.std.Expr([halos.std.Maximum(), halos.std.Minimum()], expr='x y -') + so = core.std.Expr( + [ugly, are], + expr=f'y x - y 0.000001 + / {scale_value(255, 8, bits)} * {scale_value(lowsens, 8, bits)} - y {scale_value(256, 8, bits)} + {scale_value(512, 8, bits)} / {highsens / 100} + *', + ) + if clp.format.sample_type == vs.FLOAT: + so = so.std.Limiter() + lets = core.std.MaskedMerge(halos, clp, so) + if ss <= 1: + remove = core.rgvs.Repair(clp, lets, mode=1) + else: + remove = core.std.Expr( + [ + core.std.Expr( + [ + clp.resize.Lanczos(m4(ox * ss), m4(oy * ss)), + lets.std.Maximum().resize.Bicubic(m4(ox * ss), m4(oy * ss), filter_param_a=1 / 3, filter_param_b=1 / 3), + ], + expr='x y min', + ), + lets.std.Minimum().resize.Bicubic(m4(ox * ss), m4(oy * ss), filter_param_a=1 / 3, filter_param_b=1 / 3), + ], + expr='x y max', + ).resize.Lanczos(ox, oy) + them = core.std.Expr([clp, remove], expr=f'x y < x x y - {darkstr} * - x x y - {brightstr} * - ?') + + if clp_orig is not None: + them = core.std.ShufflePlanes([them, clp_orig], planes=[0, 1, 2], colorfamily=clp_orig.format.color_family) + return them + + +def EdgeCleaner(c: vs.VideoNode, strength: int = 10, rep: bool = True, rmode: int = 17, smode: int = 0, hot: bool = False) -> vs.VideoNode: + ''' + EdgeCleaner v1.04 + A simple edge cleaning and weak dehaloing function. + + Parameters: + c: Clip to process. + + strength: Specifies edge denoising strength. + + rep: Activates Repair for the aWarpSharped clip. + + rmode: Specifies the Repair mode. + 1 is very mild and good for halos, + 16 and 18 are good for edge structure preserval on strong settings but keep more halos and edge noise, + 17 is similar to 16 but keeps much less haloing, other modes are not recommended. + + smode: Specifies what method will be used for finding small particles, ie stars. 0 is disabled, 1 uses RemoveGrain. + + hot: Specifies whether removal of hot pixels should take place. + ''' + if not isinstance(c, vs.VideoNode): + raise vs.Error('EdgeCleaner: this is not a clip') + + if c.format.color_family == vs.RGB: + raise vs.Error('EdgeCleaner: RGB format is not supported') + + bits = get_depth(c) + peak = (1 << bits) - 1 + + if c.format.color_family != vs.GRAY: + c_orig = c + c = get_y(c) + else: + c_orig = None + + if smode > 0: + strength += 4 + + main = Padding(c, 6, 6, 6, 6).warp.AWarpSharp2(blur=1, depth=cround(strength / 2)).std.Crop(6, 6, 6, 6) + if rep: + main = core.rgvs.Repair(main, c, mode=rmode) + + mask = ( + AvsPrewitt(c) + .std.Expr(expr=f'x {scale_value(4, 8, bits)} < 0 x {scale_value(32, 8, bits)} > {peak} x ? ?') + .std.InvertMask() + .std.Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1]) + ) + + final = core.std.MaskedMerge(c, main, mask) + if hot: + final = core.rgvs.Repair(final, c, mode=2) + if smode > 0: + clean = c.rgvs.RemoveGrain(mode=17) + diff = core.std.MakeDiff(c, clean) + mask = AvsPrewitt(diff.std.Levels(min_in=scale_value(40, 8, bits), max_in=scale_value(168, 8, bits), gamma=0.35).rgvs.RemoveGrain(mode=7)).std.Expr( + expr=f'x {scale_value(4, 8, bits)} < 0 x {scale_value(16, 8, bits)} > {peak} x ? ?' + ) + final = core.std.MaskedMerge(final, c, mask) + + if c_orig is not None: + final = core.std.ShufflePlanes([final, c_orig], planes=[0, 1, 2], colorfamily=c_orig.format.color_family) + return final + + +def FineDehalo( + src: vs.VideoNode, + rx: float = 2.0, + ry: Optional[float] = None, + thmi: int = 80, + thma: int = 128, + thlimi: int = 50, + thlima: int = 100, + darkstr: float = 1.0, + brightstr: float = 1.0, + showmask: int = 0, + contra: float = 0.0, + excl: bool = True, + edgeproc: float = 0.0, + mask: Optional[vs.VideoNode] = None, +) -> vs.VideoNode: + ''' + Halo removal script that uses DeHalo_alpha with a few masks and optional contra-sharpening to try remove halos without removing important details. + + Parameters: + src: Clip to process. + + rx, ry: The radii for halo removal in DeHalo_alpha. + + thmi, thma: Minimum and maximum threshold for sharp edges; keep only the sharpest edges (line edges). + To see the effects of these settings take a look at the strong mask (showmask=4). + + thlimi, thlima: Minimum and maximum limiting threshold; includes more edges than previously, but ignores simple details. + + darkstr, brightstr: The strength factors for processing dark and bright halos in DeHalo_alpha. + + showmask: Shows mask; useful for adjusting settings. + 0 = none + 1 = outside mask + 2 = shrink mask + 3 = edge mask + 4 = strong mask + + contra: Contra-sharpening. + + excl: Activates an additional step (exclusion zones) to make sure that the main edges are really excluded. + + mask: Basic edge mask to apply the threshold instead of applying to the mask created by AvsPrewitt. + ''' + if not isinstance(src, vs.VideoNode): + raise vs.Error('FineDehalo: this is not a clip') + + if src.format.color_family == vs.RGB: + raise vs.Error('FineDehalo: RGB format is not supported') + + if mask is not None: + if not isinstance(mask, vs.VideoNode): + raise vs.Error('FineDehalo: mask is not a clip') + + if mask.format.color_family != vs.GRAY: + raise vs.Error('FineDehalo: mask must be Gray format') + + is_float = src.format.sample_type == vs.FLOAT + + bits = get_depth(src) + + if src.format.color_family != vs.GRAY: + src_orig = src + src = get_y(src) + else: + src_orig = None + + ry = fallback(ry, rx) + + rx_i = cround(rx) + ry_i = cround(ry) + + # Dehaloing # + + dehaloed = DeHalo_alpha(src, rx=rx, ry=ry, darkstr=darkstr, brightstr=brightstr) + + # Contrasharpening + if contra > 0: + dehaloed = FineDehalo_contrasharp(dehaloed, src, contra) + + # Main edges # + + # Basic edge detection, thresholding will be applied later + edges = fallback(mask, AvsPrewitt(src)) + + # Keeps only the sharpest edges (line edges) + strong = edges.std.Expr(expr=f'x {scale_value(thmi, 8, bits)} - {thma - thmi} / 255 *') + if is_float: + strong = strong.std.Limiter() + + # Extends them to include the potential halos + large = mt_expand_multi(strong, sw=rx_i, sh=ry_i) + + # Exclusion zones # + + # When two edges are close from each other (both edges of a single line or multiple parallel color bands), + # the halo removal oversmoothes them or makes seriously bleed the bands, producing annoying artifacts. + # Therefore we have to produce a mask to exclude these zones from the halo removal. + + # Includes more edges than previously, but ignores simple details + light = edges.std.Expr(expr=f'x {scale_value(thlimi, 8, bits)} - {thlima - thlimi} / 255 *') + if is_float: + light = light.std.Limiter() + + # To build the exclusion zone, we make grow the edge mask, then shrink it to its original shape. + # During the growing stage, close adjacent edge masks will join and merge, forming a solid area, which will remain solid even after the shrinking stage. + + # Mask growing + shrink = mt_expand_multi(light, mode='ellipse', sw=rx_i, sh=ry_i) + + # At this point, because the mask was made of a shades of grey, we may end up with large areas of dark grey after shrinking. + # To avoid this, we amplify and saturate the mask here (actually we could even binarize it). + shrink = shrink.std.Expr(expr='x 4 *') + if is_float: + shrink = shrink.std.Limiter() + + # Mask shrinking + shrink = mt_inpand_multi(shrink, mode='ellipse', sw=rx_i, sh=ry_i) + + # This mask is almost binary, which will produce distinct discontinuities once applied. Then we have to smooth it. + shrink = shrink.std.Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1]).std.Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1]) + + # Final mask building # + + # Previous mask may be a bit weak on the pure edge side, so we ensure that the main edges are really excluded. + # We do not want them to be smoothed by the halo removal. + if excl: + shr_med = core.std.Expr([strong, shrink], expr='x y max') + else: + shr_med = strong + + # Subtracts masks and amplifies the difference to be sure we get 255 on the areas to be processed + outside = core.std.Expr([large, shr_med], expr='x y - 2 *') + if is_float: + outside = outside.std.Limiter() + + # If edge processing is required, adds the edgemask + if edgeproc > 0: + outside = core.std.Expr([outside, strong], expr=f'x y {edgeproc * 0.66} * +') + if is_float: + outside = outside.std.Limiter() + + # Smooth again and amplify to grow the mask a bit, otherwise the halo parts sticking to the edges could be missed + outside = outside.std.Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1]).std.Expr(expr='x 2 *') + if is_float: + outside = outside.std.Limiter() + + # Masking # + + if showmask <= 0: + last = core.std.MaskedMerge(src, dehaloed, outside) + + if src_orig is not None: + if showmask <= 0: + return core.std.ShufflePlanes([last, src_orig], planes=[0, 1, 2], colorfamily=src_orig.format.color_family) + elif showmask == 1: + return outside.resize.Bicubic(format=src_orig.format) + elif showmask == 2: + return shrink.resize.Bicubic(format=src_orig.format) + elif showmask == 3: + return edges.resize.Bicubic(format=src_orig.format) + else: + return strong.resize.Bicubic(format=src_orig.format) + else: + if showmask <= 0: + return last + elif showmask == 1: + return outside + elif showmask == 2: + return shrink + elif showmask == 3: + return edges + else: + return strong + + +def FineDehalo_contrasharp(dehaloed: vs.VideoNode, src: vs.VideoNode, level: float) -> vs.VideoNode: + '''level == 1.0 : normal contrasharp''' + if not (isinstance(dehaloed, vs.VideoNode) and isinstance(src, vs.VideoNode)): + raise vs.Error('FineDehalo_contrasharp: this is not a clip') + + if dehaloed.format.color_family == vs.RGB: + raise vs.Error('FineDehalo_contrasharp: RGB format is not supported') + + if dehaloed.format.id != src.format.id: + raise vs.Error('FineDehalo_contrasharp: clips must have the same format') + + neutral = 1 << (get_depth(dehaloed) - 1) if dehaloed.format.sample_type == vs.INTEGER else 0.0 + + if dehaloed.format.color_family != vs.GRAY: + dehaloed_orig = dehaloed + dehaloed = get_y(dehaloed) + src = get_y(src) + else: + dehaloed_orig = None + + bb = dehaloed.std.Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]) + bb2 = core.rgvs.Repair(bb, core.rgvs.Repair(bb, bb.ctmf.CTMF(radius=2), mode=1), mode=1) + xd = core.std.MakeDiff(bb, bb2) + xd = xd.std.Expr(expr=f'x {neutral} - 2.49 * {level} * {neutral} +') + xdd = core.std.Expr( + [xd, core.std.MakeDiff(src, dehaloed)], expr=f'x {neutral} - y {neutral} - * 0 < {neutral} x {neutral} - abs y {neutral} - abs < x y ? ?' + ) + last = core.std.MergeDiff(dehaloed, xdd) + + if dehaloed_orig is not None: + last = core.std.ShufflePlanes([last, dehaloed_orig], planes=[0, 1, 2], colorfamily=dehaloed_orig.format.color_family) + return last + + +def FineDehalo2( + src: vs.VideoNode, hconv: Sequence[int] = [-1, -2, 0, 0, 40, 0, 0, -2, -1], vconv: Sequence[int] = [-2, -1, 0, 0, 40, 0, 0, -1, -2], showmask: bool = False +) -> vs.VideoNode: + ''' + Try to remove 2nd order halos. + + Parameters: + src: Clip to process. + + hconv, vconv: Horizontal and vertical convolutions. + + showmask: Shows mask. + ''' + + def grow_mask(mask: vs.VideoNode, coordinates: Sequence[int]) -> vs.VideoNode: + mask = mask.std.Maximum(coordinates=coordinates).std.Minimum(coordinates=coordinates) + mask_1 = mask.std.Maximum(coordinates=coordinates) + mask_2 = mask_1.std.Maximum(coordinates=coordinates).std.Maximum(coordinates=coordinates) + mask = core.std.Expr([mask_2, mask_1], expr='x y -') + return mask.std.Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]).std.Expr(expr='x 1.8 *') + + if not isinstance(src, vs.VideoNode): + raise vs.Error('FineDehalo2: this is not a clip') + + if src.format.color_family == vs.RGB: + raise vs.Error('FineDehalo2: RGB format is not supported') + + is_float = src.format.sample_type == vs.FLOAT + + if src.format.color_family != vs.GRAY: + src_orig = src + src = get_y(src) + else: + src_orig = None + + fix_h = src.std.Convolution(matrix=vconv, mode='v') + fix_v = src.std.Convolution(matrix=hconv, mode='h') + mask_h = src.std.Convolution(matrix=[1, 2, 1, 0, 0, 0, -1, -2, -1], divisor=4, saturate=False) + mask_v = src.std.Convolution(matrix=[1, 0, -1, 2, 0, -2, 1, 0, -1], divisor=4, saturate=False) + temp_h = core.std.Expr([mask_h, mask_v], expr='x 3 * y -') + temp_v = core.std.Expr([mask_v, mask_h], expr='x 3 * y -') + if is_float: + temp_h = temp_h.std.Limiter() + temp_v = temp_v.std.Limiter() + mask_h = grow_mask(temp_h, [0, 1, 0, 0, 0, 0, 1, 0]) + mask_v = grow_mask(temp_v, [0, 0, 0, 1, 1, 0, 0, 0]) + if is_float: + mask_h = mask_h.std.Limiter() + mask_v = mask_v.std.Limiter() + + if not showmask: + last = core.std.MaskedMerge(src, fix_h, mask_h) + last = core.std.MaskedMerge(last, fix_v, mask_v) + else: + last = core.std.Expr([mask_h, mask_v], expr='x y max') + + if src_orig is not None: + if not showmask: + last = core.std.ShufflePlanes([last, src_orig], planes=[0, 1, 2], colorfamily=src_orig.format.color_family) + else: + last = last.resize.Bicubic(format=src_orig.format) + return last + + +def YAHR(clp: vs.VideoNode, blur: int = 2, depth: int = 32) -> vs.VideoNode: + ''' + Y'et A'nother H'alo R'educing script + + Parameters: + clp: Clip to process. + + blur: "blur" parameter of AWarpSharp2. + + depth: "depth" parameter of AWarpSharp2. + ''' + if not isinstance(clp, vs.VideoNode): + raise vs.Error('YAHR: this is not a clip') + + if clp.format.color_family == vs.RGB: + raise vs.Error('YAHR: RGB format is not supported') + + if clp.format.color_family != vs.GRAY: + clp_orig = clp + clp = get_y(clp) + else: + clp_orig = None + + b1 = MinBlur(clp, 2).std.Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]) + b1D = core.std.MakeDiff(clp, b1) + w1 = Padding(clp, 6, 6, 6, 6).warp.AWarpSharp2(blur=blur, depth=depth).std.Crop(6, 6, 6, 6) + w1b1 = MinBlur(w1, 2).std.Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]) + w1b1D = core.std.MakeDiff(w1, w1b1) + DD = core.rgvs.Repair(b1D, w1b1D, mode=13) + DD2 = core.std.MakeDiff(b1D, DD) + last = core.std.MakeDiff(clp, DD2) + + if clp_orig is not None: + last = core.std.ShufflePlanes([last, clp_orig], planes=[0, 1, 2], colorfamily=clp_orig.format.color_family) + return last + + +def HQDeringmod( + input: vs.VideoNode, + smoothed: Optional[vs.VideoNode] = None, + ringmask: Optional[vs.VideoNode] = None, + mrad: int = 1, + msmooth: int = 1, + incedge: bool = False, + mthr: int = 60, + minp: int = 1, + nrmode: Optional[int] = None, + sigma: float = 128.0, + sigma2: Optional[float] = None, + sbsize: Optional[int] = None, + sosize: Optional[int] = None, + sharp: int = 1, + drrep: Optional[int] = None, + thr: float = 12.0, + elast: float = 2.0, + darkthr: Optional[float] = None, + planes: Union[int, Sequence[int]] = 0, + show: bool = False, + cuda: bool = False, +) -> vs.VideoNode: + ''' + HQDering mod v1.8 + Applies deringing by using a smart smoother near edges (where ringing occurs) only. + + Parameters: + input: Clip to process. + + mrad: Expanding of edge mask, higher value means more aggressive processing. + + msmooth: Inflate of edge mask, smooth boundaries of mask. + + incedge: Whether to include edge in ring mask, by default ring mask only include area near edges. + + mthr: Threshold of prewitt edge mask, lower value means more aggressive processing. + But for strong ringing, lower value will treat some ringing as edge, which protects this ringing from being processed. + + minp: Inpanding of prewitt edge mask, higher value means more aggressive processing. + + nrmode: Kernel of deringing. + 0 = DFTTest + 1 = MinBlur(r=1) + 2 = MinBlur(r=2) + 3 = MinBlur(r=3) + + sigma: Sigma for medium frequecies in DFTTest. + + sigma2: Sigma for low & high frequecies in DFTTest. + + sbsize: Length of the sides of the spatial window in DFTTest. + + sosize: Spatial overlap amount in DFTTest. + + sharp: Whether to use contra-sharpening to resharp deringed clip, 1-3 represents radius, 0 means no sharpening. + + drrep: Use repair for details retention, recommended values are 24/23/13/12/1. + + thr: The same meaning with "thr" in LimitFilter. + + elast: The same meaning with "elast" in LimitFilter. + + darkthr: Threshold for darker area near edges, by default equals to thr/4. Set it lower if you think de-ringing destroys too much lines, etc. + When "darkthr" is not equal to "thr", "thr" limits darkening while "darkthr" limits brightening. + + planes: Specifies which planes will be processed. Any unprocessed planes will be simply copied. + + show: Whether to output mask clip instead of filtered clip. + + cuda: Whether to enable CUDA functionality (for dfttest2). + ''' + from mvsfunc import LimitFilter + + if not isinstance(input, vs.VideoNode): + raise vs.Error('HQDeringmod: this is not a clip') + + if input.format.color_family == vs.RGB: + raise vs.Error('HQDeringmod: RGB format is not supported') + + if smoothed is not None: + if not isinstance(smoothed, vs.VideoNode): + raise vs.Error('HQDeringmod: smoothed is not a clip') + + if smoothed.format.id != input.format.id: + raise vs.Error("HQDeringmod: smoothed must have the same format as input") + + if ringmask is not None and not isinstance(ringmask, vs.VideoNode): + raise vs.Error("HQDeringmod: ringmask is not a clip") + + is_gray = input.format.color_family == vs.GRAY + + bits = get_depth(input) + neutral = 1 << (bits - 1) + peak = (1 << bits) - 1 + + plane_range = range(input.format.num_planes) + + if isinstance(planes, int): + planes = [planes] + + HD = input.width > 1024 or input.height > 576 + + nrmode = fallback(nrmode, 2 if HD else 1) + sigma2 = fallback(sigma2, sigma / 16) + sbsize = fallback(sbsize, 8 if HD else 6) + sosize = fallback(sosize, 6 if HD else 4) + drrep = fallback(drrep, 24 if nrmode > 0 else 0) + darkthr = fallback(darkthr, thr / 4) + + # Kernel: Smoothing + if smoothed is None: + if nrmode <= 0: + try: + dfttest2 = importlib.import_module('dfttest2') + except ModuleNotFoundError: + dfttest2 = None + # Currently the CPU backend only supports `sbsize == 16` + use_dfttest2 = dfttest2 and (cuda or sbsize == 16) + if use_dfttest2: + if sbsize == 16: + # NVRTC is faster than cuFFT but only supports `sbsize == 16` + backend = dfttest2.Backend.NVRTC if cuda else dfttest2.Backend.CPU + else: + backend = dfttest2.Backend.cuFFT + smoothed = dfttest2.DFTTest( + input, sbsize=sbsize, sosize=sosize, tbsize=1, slocation=[0.0, sigma2, 0.05, sigma, 0.5, sigma, 0.75, sigma2, 1.0, 0.0], planes=planes, backend=backend + ) + else: + smoothed = input.dfttest.DFTTest( + sbsize=sbsize, sosize=sosize, tbsize=1, slocation=[0.0, sigma2, 0.05, sigma, 0.5, sigma, 0.75, sigma2, 1.0, 0.0], planes=planes + ) + else: + smoothed = MinBlur(input, nrmode, planes) + + # Post-Process: Contra-Sharpening + matrix1 = [1, 2, 1, 2, 4, 2, 1, 2, 1] + matrix2 = [1, 1, 1, 1, 1, 1, 1, 1, 1] + + if sharp <= 0: + sclp = smoothed + else: + pre = smoothed.std.Median(planes=planes) + if sharp == 1: + method = pre.std.Convolution(matrix=matrix1, planes=planes) + elif sharp == 2: + method = pre.std.Convolution(matrix=matrix1, planes=planes).std.Convolution(matrix=matrix2, planes=planes) + else: + method = ( + pre.std.Convolution(matrix=matrix1, planes=planes).std.Convolution(matrix=matrix2, planes=planes).std.Convolution(matrix=matrix2, planes=planes) + ) + sharpdiff = core.std.MakeDiff(pre, method, planes=planes) + allD = core.std.MakeDiff(input, smoothed, planes=planes) + ssDD = core.rgvs.Repair(sharpdiff, allD, mode=[1 if i in planes else 0 for i in plane_range]) + ssDD = core.std.Expr( + [ssDD, sharpdiff], expr=[f'x {neutral} - abs y {neutral} - abs <= x y ?' if i in planes else '' for i in plane_range] + ) + sclp = core.std.MergeDiff(smoothed, ssDD, planes=planes) + + # Post-Process: Repairing + if drrep <= 0: + repclp = sclp + else: + repclp = core.rgvs.Repair(input, sclp, mode=[drrep if i in planes else 0 for i in plane_range]) + + # Post-Process: Limiting + if (thr <= 0 and darkthr <= 0) or (thr >= 255 and darkthr >= 255): + limitclp = repclp + else: + limitclp = LimitFilter(repclp, input, thr=thr, elast=elast, brighten_thr=darkthr, planes=planes) + + # Post-Process: Ringing Mask Generating + if ringmask is None: + expr = f'x {scale_value(mthr, 8, bits)} < 0 x ?' + prewittm = AvsPrewitt(input, planes=0).std.Expr(expr=expr if is_gray else [expr, '']) + fmask = core.misc.Hysteresis(prewittm.std.Median(planes=0), prewittm, planes=0) + if mrad > 0: + omask = mt_expand_multi(fmask, planes=0, sw=mrad, sh=mrad) + else: + omask = fmask + if msmooth > 0: + omask = mt_inflate_multi(omask, planes=0, radius=msmooth) + if incedge: + ringmask = omask + else: + if minp > 3: + imask = fmask.std.Minimum(planes=0).std.Minimum(planes=0) + elif minp > 2: + imask = fmask.std.Inflate(planes=0).std.Minimum(planes=0).std.Minimum(planes=0) + elif minp > 1: + imask = fmask.std.Minimum(planes=0) + elif minp > 0: + imask = fmask.std.Inflate(planes=0).std.Minimum(planes=0) + else: + imask = fmask + expr = f'x {peak} y - * {peak} /' + ringmask = core.std.Expr([omask, imask], expr=expr if is_gray else [expr, '']) + + # Mask Merging & Output + if show: + if is_gray: + return ringmask + else: + return ringmask.std.Expr(expr=['', repr(neutral)]) + else: + return core.std.MaskedMerge(input, limitclp, ringmask, planes=planes, first_plane=True) + + +QTGMC_globals = {} + + +def QTGMC( + Input: vs.VideoNode, + Preset: str = 'Slower', + TR0: Optional[int] = None, + TR1: Optional[int] = None, + TR2: Optional[int] = None, + Rep0: Optional[int] = None, + Rep1: int = 0, + Rep2: Optional[int] = None, + EdiMode: Optional[str] = None, + RepChroma: bool = True, + NNSize: Optional[int] = None, + NNeurons: Optional[int] = None, + EdiQual: int = 1, + EdiMaxD: Optional[int] = None, + ChromaEdi: str = '', + EdiExt: Optional[vs.VideoNode] = None, + Sharpness: Optional[float] = None, + SMode: Optional[int] = None, + SLMode: Optional[int] = None, + SLRad: Optional[int] = None, + SOvs: int = 0, + SVThin: float = 0.0, + Sbb: Optional[int] = None, + SrchClipPP: Optional[int] = None, + SubPel: Optional[int] = None, + SubPelInterp: int = 2, + BlockSize: Optional[int] = None, + Overlap: Optional[int] = None, + Search: Optional[int] = None, + SearchParam: Optional[int] = None, + PelSearch: Optional[int] = None, + ChromaMotion: Optional[bool] = None, + TrueMotion: bool = False, + Lambda: Optional[int] = None, + LSAD: Optional[int] = None, + PNew: Optional[int] = None, + PLevel: Optional[int] = None, + GlobalMotion: bool = True, + DCT: int = 0, + ThSAD1: int = 640, + ThSAD2: int = 256, + ThSCD1: int = 180, + ThSCD2: int = 98, + SourceMatch: int = 0, + MatchPreset: Optional[str] = None, + MatchEdi: Optional[str] = None, + MatchPreset2: Optional[str] = None, + MatchEdi2: Optional[str] = None, + MatchTR2: int = 1, + MatchEnhance: float = 0.5, + Lossless: int = 0, + NoiseProcess: Optional[int] = None, + EZDenoise: Optional[float] = None, + EZKeepGrain: Optional[float] = None, + NoisePreset: str = 'Fast', + Denoiser: Optional[str] = None, + FftThreads: int = 1, + DenoiseMC: Optional[bool] = None, + NoiseTR: Optional[int] = None, + Sigma: Optional[float] = None, + ChromaNoise: bool = False, + ShowNoise: Union[bool, float] = 0.0, + GrainRestore: Optional[float] = None, + NoiseRestore: Optional[float] = None, + NoiseDeint: Optional[str] = None, + StabilizeNoise: Optional[bool] = None, + InputType: int = 0, + ProgSADMask: Optional[float] = None, + FPSDivisor: int = 1, + ShutterBlur: int = 0, + ShutterAngleSrc: float = 180.0, + ShutterAngleOut: float = 180.0, + SBlurLimit: int = 4, + Border: bool = False, + Precise: Optional[bool] = None, + Tuning: str = 'None', + ShowSettings: bool = False, + GlobalNames: str = 'QTGMC', + PrevGlobals: str = 'Replace', + ForceTR: int = 0, + Str: float = 2.0, + Amp: float = 0.0625, + FastMA: bool = False, + ESearchP: bool = False, + RefineMotion: bool = False, + TFF: Optional[bool] = None, + nnedi3_args: Mapping[str, Any] = {}, + eedi3_args: Mapping[str, Any] = {}, + opencl: bool = False, + device: Optional[int] = None, +) -> vs.VideoNode: + ''' + QTGMC 3.33 + + A very high quality deinterlacer with a range of features for both quality and convenience. These include a simple presets system, extensive noise + processing capabilities, support for repair of progressive material, precision source matching, shutter speed simulation, etc. Originally based on + TempGaussMC_beta2 by Didée. + + Parameters: + Input: Clip to process. + + Preset: Sets a range of defaults for different encoding speeds. + Select from "Placebo", "Very Slow", "Slower", "Slow", "Medium", "Fast", "Faster", "Very Fast", "Super Fast", "Ultra Fast" & "Draft". + + TR0: Temporal binomial smoothing radius used to create motion search clip. In general 2=quality, 1=speed, 0=don't use. + + TR1: Temporal binomial smoothing radius used on interpolated clip for initial output. In general 2=quality, 1=speed, 0=don't use. + + TR2: Temporal linear smoothing radius used for final stablization / denoising. Increase for smoother output. + + Rep0: Repair motion search clip (0=off): repair unwanted blur after temporal smooth TR0 (see QTGMC_KeepOnlyBobShimmerFixes function for details). + + Rep1: Repair initial output clip (0=off): repair unwanted blur after temporal smooth TR1. + + Rep2: Repair final output clip (0=off): unwanted blur after temporal smooth TR2 (will also repair TR1 blur if Rep1 not used). + + EdiMode: Interpolation method, from "NNEDI3", "EEDI3+NNEDI3" (EEDI3 with sclip from NNEDI3), "EEDI3" or "Bwdif", anything else uses "Bob". + + RepChroma: Whether the repair modes affect chroma. + + NNSize: Area around each pixel used as predictor for NNEDI3. A larger area is slower with better quality, read the NNEDI3 docs to see the area choices. + Note: area sizes are not in increasing order (i.e. increased value doesn't always mean increased quality). + + NNeurons: Controls number of neurons in NNEDI3, larger = slower and better quality but improvements are small. + + EdiQual: Quality setting for NNEDI3. Higher values for better quality - but improvements are marginal. + + EdiMaxD: Spatial search distance for finding connecting edges in EEDI3. + + ChromaEdi: Interpolation method used for chroma. Set to "" to use EdiMode above (default). Otherwise choose from "NNEDI3", "Bwdif" or "Bob" - all high + speed variants. This can give a minor speed-up if using a very slow EdiMode (i.e. one of the EEDIx modes). + + EdiExt: Provide externally created interpolated clip rather than use one of the above modes. + + Sharpness: How much to resharpen the temporally blurred clip (default is always 1.0 unlike original TGMC). + + SMode: Resharpening mode. + 0 = none + 1 = difference from 3x3 blur kernel + 2 = vertical max/min average + 3x3 kernel + + SLMode: Sharpness limiting. + 0 = off + [1 = spatial, 2 = temporal]: before final temporal smooth + [3 = spatial, 4 = temporal]: after final temporal smooth + + SLRad: Temporal or spatial radius used with sharpness limiting (depends on SLMode). Temporal radius can only be 0, 1 or 3. + + SOvs: Amount of overshoot allowed with temporal sharpness limiting (SLMode=2,4), i.e. allow some oversharpening. + + SVThin: How much to thin down 1-pixel wide lines that have been widened due to interpolation into neighboring field lines. + + Sbb: Back blend (blurred) difference between pre & post sharpened clip (minor fidelity improvement). + 0 = off + 1 = before (1st) sharpness limiting + 2 = after (1st) sharpness limiting + 3 = both + + SrchClipPP: Pre-filtering for motion search clip. + 0 = none + 1 = simple blur + 2 = Gauss blur + 3 = Gauss blur + edge soften + + SubPel: Sub-pixel accuracy for motion analysis. + 1 = 1 pixel + 2 = 1/2 pixel + 4 = 1/4 pixel + + SubPelInterp: Interpolation used for sub-pixel motion analysis. + 0 = bilinear (soft) + 1 = bicubic (sharper) + 2 = Weiner (sharpest) + + BlockSize: Size of blocks that are matched during motion analysis. + + Overlap: How much to overlap motion analysis blocks (requires more blocks, but essential to smooth block edges in motion compenstion). + + Search: Search method used for matching motion blocks - see MVTools2 documentation for available algorithms. + + SearchParam: Parameter for search method chosen. For default search method (hexagon search) it is the search range. + + PelSearch: Search parameter (as above) for the finest sub-pixel level (see SubPel). + + ChromaMotion: Whether to consider chroma when analyzing motion. Setting to false gives good speed-up, + but may very occasionally make incorrect motion decision. + + TrueMotion: Whether to use the 'truemotion' defaults from MAnalyse (see MVTools2 documentation). + + Lambda: Motion vector field coherence - how much the motion analysis favors similar motion vectors for neighboring blocks. + Should be scaled by BlockSize*BlockSize/64. + + LSAD: How much to reduce need for vector coherence (i.e. Lambda above) if prediction of motion vector from neighbors is poor, + typically in areas of complex motion. This value is scaled in MVTools (unlike Lambda). + + PNew: Penalty for choosing a new motion vector for a block over an existing one - avoids choosing new vectors for minor gain. + + PLevel: Mode for scaling lambda across different sub-pixel levels - see MVTools2 documentation for choices. + + GlobalMotion: Whether to estimate camera motion to assist in selecting block motion vectors. + + DCT: Modes to use DCT (frequency analysis) or SATD as part of the block matching process - see MVTools2 documentation for choices. + + ThSAD1: SAD threshold for block match on shimmer-removing temporal smooth (TR1). Increase to reduce bob-shimmer more (may smear/blur). + + ThSAD2: SAD threshold for block match on final denoising temporal smooth (TR2). Increase to strengthen final smooth (may smear/blur). + + ThSCD1: Scene change detection parameter 1 - see MVTools documentation. + + ThSCD2: Scene change detection parameter 2 - see MVTools documentation. + + SourceMatch: + 0 = source-matching off (standard algorithm) + 1 = basic source-match + 2 = refined match + 3 = twice refined match + + MatchPreset: Speed/quality for basic source-match processing, select from "Placebo", "Very Slow", "Slower", "Slow", "Medium", "Fast", "Faster", + "Very Fast", "Super Fast", "Ultra Fast" ("Draft" is not supported). Ideal choice is the same as main preset, + but can choose a faster setting (but not a slower setting). Default is 3 steps faster than main Preset. + + MatchEdi: Override default interpolation method for basic source-match. Default method is same as main EdiMode setting (usually NNEDI3). + Only need to override if using slow method for main interpolation (e.g. EEDI3) and want a faster method for source-match. + + MatchPreset2: Speed/quality for refined source-match processing, select from "Placebo", "Very Slow", "Slower", "Slow", "Medium", "Fast", "Faster", + "Very Fast", "Super Fast", "Ultra Fast" ("Draft" is not supported). Default is 2 steps faster than MatchPreset. + Faster settings are usually sufficient but can use slower settings if you get extra aliasing in this mode. + + MatchEdi2: Override interpolation method for refined source-match. Can be a good idea to pick MatchEdi2="Bob" for speed. + + MatchTR2: Temporal radius for refined source-matching. 2=smoothness, 1=speed/sharper, 0=not recommended. Differences are very marginal. + Basic source-match doesn't need this setting as its temporal radius must match TR1 core setting (i.e. there is no MatchTR1). + + MatchEnhance: Enhance the detail found by source-match modes 2 & 3. A slight cheat - will enhance noise if set too strong. Best set < 1.0. + + Lossless: Puts exact source fields into result & cleans any artefacts. 0=off, 1=after final temporal smooth, 2=before resharpening. + Adds some extra detail but: mode 1 gets shimmer / minor combing, mode 2 is more stable/tweakable but not exactly lossless. + + NoiseProcess: Bypass mode. + 0 = disable + 1 = denoise source & optionally restore some noise back at end of script [use for stronger denoising] + 2 = identify noise only & optionally restore some after QTGMC smoothing [for grain retention / light denoising] + + EZDenoise: Automatic setting to denoise source. Set > 0.0 to enable. Higher values denoise more. Can use ShowNoise to help choose value. + + EZKeepGrain: Automatic setting to retain source grain/detail. Set > 0.0 to enable. Higher values retain more grain. A good starting point = 1.0. + + NoisePreset: Automatic setting for quality of noise processing. Choices: "Slower", "Slow", "Medium", "Fast", and "Faster". + + Denoiser: Select denoiser to use for noise bypass / denoising. Select from "bm3d", "dfttest", "fft3dfilter" or "knlmeanscl". + Unknown value selects "fft3dfilter". + + FftThreads: Number of threads to use if using "fft3dfilter" for Denoiser. + + DenoiseMC: Whether to provide a motion-compensated clip to the denoiser for better noise vs detail detection (will be a little slower). + + NoiseTR: Temporal radius used when analyzing clip for noise extraction. Higher values better identify noise vs detail but are slower. + + Sigma: Amount of noise known to be in the source, sensible values vary by source and denoiser, so experiment. Use ShowNoise to help. + + ChromaNoise: When processing noise (NoiseProcess > 0), whether to process chroma noise or not (luma noise is always processed). + + ShowNoise: Display extracted and "deinterlaced" noise rather than normal output. Set to true or false, or set a value (around 4 to 16) to specify + contrast for displayed noise. Visualising noise helps to determine suitable value for Sigma or EZDenoise - want to see noise and noisy detail, + but not too much clean structure or edges - fairly subjective. + + GrainRestore: How much removed noise/grain to restore before final temporal smooth. Retain "stable" grain and some detail (effect depends on TR2). + + NoiseRestore: How much removed noise/grain to restore after final temporal smooth. Retains any kind of noise. + + NoiseDeint: When noise is taken from interlaced source, how to 'deinterlace' it before restoring. + "Bob" & "DoubleWeave" are fast but with minor issues: "Bob" is coarse and "Doubleweave" lags by one frame. + "Generate" is a high quality mode that generates fresh noise lines, but it is slower. Unknown value selects "DoubleWeave". + + StabilizeNoise: Use motion compensation to limit shimmering and strengthen detail within the restored noise. Recommended for "Generate" mode. + + InputType: Default = 0 for interlaced input. Settings 1, 2 & 3 accept progressive input for deshimmer or repair. Frame rate of progressive source is not + doubled. Mode 1 is for general progressive material. Modes 2 & 3 are designed for badly deinterlaced material. + + ProgSADMask: Only applies to InputType=2,3. If ProgSADMask > 0.0 then blend InputType modes 1 and 2/3 based on block motion SAD. + Higher values help recover more detail, but repair less artefacts. Reasonable range about 2.0 to 20.0, or 0.0 for no blending. + + FPSDivisor: 1=Double-rate output, 2=Single-rate output. Higher values can be used too (e.g. 60fps & FPSDivisor=3 gives 20fps output). + + ShutterBlur: 0=Off, 1=Enable, 2,3=Higher precisions (slower). Higher precisions reduce blur "bleeding" into static areas a little. + + ShutterAngleSrc: Shutter angle used in source. If necessary, estimate from motion blur seen in a single frame. + 0=pin-sharp, 360=fully blurred from frame to frame. + + ShutterAngleOut: Shutter angle to simulate in output. Extreme values may be rejected (depends on other settings). + Cannot reduce motion blur already in the source. + + SBlurLimit: Limit motion blur where motion lower than given value. Increase to reduce blur "bleeding". 0=Off. Sensible range around 2-12. + + Border: Pad a little vertically while processing (doesn't affect output size) - set true you see flickering on the very top or bottom line of the + output. If you have wider edge effects than that, you should crop afterwards instead. + + Precise: Set to false to use faster algorithms with *very* slight imprecision in places. + + Tuning: Tweaks the defaults for different source types. Choose from "None", "DV-SD", "DV-HD". + + ShowSettings: Display all the current parameter values - useful to find preset defaults. + + GlobalNames: The name used to expose intermediate clips to calling script. QTGMC now exposes its motion vectors and other intermediate clips to the + calling script through global variables. These globals are uniquely named. By default they begin with the prefix "QTGMC_". The available clips are: + Backward motion vectors bVec1, bVec2, bVec3 (temporal radius 1 to 3) + Forward motion vectors fVec1, fVec2, fVec3 + Filtered clip used for motion analysis srchClip + MVTools "super" clip for filtered clip srchSuper + Not all these clips are necessarily created - it depends on your QTGMC settings. To ensure motion vector creation to radius X, set ForceTR=X + Clips can be accessed from other scripts with havsfunc.QTGMC_globals['Prefix_Name'] + + PrevGlobals: What to do with global variables from earlier QTGMC call that match above name. Either "Replace", or "Reuse" (for a speed-up). + Set PrevGlobals="Reuse" to reuse existing similar named globals for this run & not recalculate motion vectors etc. This will improve performance. + Set PrevGlobals="Replace" to overwrite similar named globals from a previous run. This is the default and easiest option for most use cases. + + ForceTR: Ensure globally exposed motion vectors are calculated to this radius even if not needed by QTGMC. + + Str: With this parameter you control the strength of the brightening of the prefilter clip for motion analysis. + This is good when problems with dark areas arise. + + Amp: Use this together with Str (active when Str is different from 1.0). This defines the amplitude of the brightening in the luma range, + for example by using 1.0 all the luma range will be used and the brightening will find its peak at luma value 128 in the original. + + FastMA: Use 8-bit for faster motion analysis when using high bit depth input. + + ESearchP: Use wider search range for hex and umh search method. + + RefineMotion: Refines and recalculates motion data of previously estimated motion vectors with new parameters set (e.g. lesser block size). + The two-stage method may be also useful for more stable (robust) motion estimation. + + TFF: Since VapourSynth only has a weak notion of field order internally, TFF may have to be set. Setting TFF to true means top field first and false + means bottom field first. Note that the _FieldBased frame property, if present, takes precedence over TFF. + + nnedi3_args: Additional arguments to pass to NNEDI3. + + eedi3_args: Additional arguments to pass to EEDI3. + + opencl: Whether to use the OpenCL version of NNEDI3 and EEDI3. + + device: Sets target OpenCL device. + ''' + if not isinstance(Input, vs.VideoNode): + raise vs.Error('QTGMC: this is not a clip') + + if EdiExt is not None: + if not isinstance(EdiExt, vs.VideoNode): + raise vs.Error('QTGMC: EdiExt is not a clip') + + if EdiExt.format.id != Input.format.id: + raise vs.Error('QTGMC: EdiExt must have the same format as input') + + if InputType != 1 and TFF is None: + with Input.get_frame(0) as f: + if (field_based := f.props.get('_FieldBased')) not in [1, 2]: + raise vs.Error('QTGMC: TFF was not specified and field order could not be determined from frame properties') + + TFF = field_based == 2 + + is_gray = Input.format.color_family == vs.GRAY + + bits = get_depth(Input) + neutral = 1 << (bits - 1) + + SOvs = scale_value(SOvs, 8, bits) + + # --------------------------------------- + # Presets + + # Select presets / tuning + Preset = Preset.lower() + presets = ['placebo', 'very slow', 'slower', 'slow', 'medium', 'fast', 'faster', 'very fast', 'super fast', 'ultra fast', 'draft'] + try: + pNum = presets.index(Preset) + except ValueError: + raise vs.Error("QTGMC: 'Preset' choice is invalid") + + if MatchPreset is None: + mpNum1 = min(pNum + 3, 9) + MatchPreset = presets[mpNum1] + else: + try: + mpNum1 = presets[:10].index(MatchPreset.lower()) + except ValueError: + raise vs.Error("QTGMC: 'MatchPreset' choice is invalid/unsupported") + + if MatchPreset2 is None: + mpNum2 = min(mpNum1 + 2, 9) + MatchPreset2 = presets[mpNum2] + else: + try: + mpNum2 = presets[:10].index(MatchPreset2.lower()) + except ValueError: + raise vs.Error("QTGMC: 'MatchPreset2' choice is invalid/unsupported") + + try: + npNum = presets[2:7].index(NoisePreset.lower()) + except ValueError: + raise vs.Error("QTGMC: 'NoisePreset' choice is invalid") + + try: + tNum = ['none', 'dv-sd', 'dv-hd'].index(Tuning.lower()) + except ValueError: + raise vs.Error("QTGMC: 'Tuning' choice is invalid") + + # Tunings only affect blocksize in this version + bs = [16, 16, 32][tNum] + bs2 = 32 + + # fmt: off + # Very Very Super Ultra + # Preset groups: Placebo Slow Slower Slow Medium Fast Faster Fast Fast Fast Draft + TR0 = fallback(TR0, [ 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 0 ][pNum]) + TR1 = fallback(TR1, [ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 ][pNum]) + TR2X = fallback(TR2, [ 3, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0 ][pNum]) + Rep0 = fallback(Rep0, [ 4, 4, 4, 4, 3, 3, 0, 0, 0, 0, 0 ][pNum]) + Rep2 = fallback(Rep2, [ 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 0 ][pNum]) + EdiMode = fallback(EdiMode, ['NNEDI3', 'NNEDI3', 'NNEDI3', 'NNEDI3', 'NNEDI3', 'NNEDI3', 'NNEDI3', 'NNEDI3', 'NNEDI3', 'Bwdif', 'Bob' ][pNum]).lower() + NNSize = fallback(NNSize, [ 1, 1, 1, 1, 5, 5, 4, 4, 4, 4, 4 ][pNum]) + NNeurons = fallback(NNeurons, [ 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0 ][pNum]) + EdiMaxD = fallback(EdiMaxD, [ 12, 10, 8, 7, 7, 6, 6, 5, 4, 4, 4 ][pNum]) + SMode = fallback(SMode, [ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0 ][pNum]) + SLModeX = fallback(SLMode, [ 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0 ][pNum]) + SLRad = fallback(SLRad, [ 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ][pNum]) + Sbb = fallback(Sbb, [ 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 ][pNum]) + SrchClipPP = fallback(SrchClipPP, [ 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 0 ][pNum]) + SubPel = fallback(SubPel, [ 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1 ][pNum]) + BlockSize = fallback(BlockSize, [ bs, bs, bs, bs, bs, bs, bs2, bs2, bs2, bs2, bs2 ][pNum]) + bs = BlockSize + Overlap = fallback(Overlap, [ bs // 2, bs // 2, bs // 2, bs // 2, bs // 2, bs // 2, bs // 2, bs // 4, bs // 4, bs // 4, bs // 4][pNum]) + Search = fallback(Search, [ 5, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0 ][pNum]) + SearchParam = fallback(SearchParam, [ 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1 ][pNum]) + PelSearch = fallback(PelSearch, [ 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1 ][pNum]) + ChromaMotion = fallback(ChromaMotion, [ True, True, True, False, False, False, False, False, False, False, False ][pNum]) + Precise = fallback(Precise, [ True, True, False, False, False, False, False, False, False, False, False ][pNum]) + ProgSADMask = fallback(ProgSADMask, [ 10.0, 10.0, 10.0, 10.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ][pNum]) + + if ESearchP and Search in [4, 5]: + if pNum < 4: + SearchParam = 24 + elif pNum < 8: + SearchParam = 16 + + # Noise presets Slower Slow Medium Fast Faster + Denoiser = fallback(Denoiser, ['dfttest', 'dfttest', 'dfttest', 'fft3df', 'fft3df'][npNum]).lower() + DenoiseMC = fallback(DenoiseMC, [ True, True, False, False, False ][npNum]) + NoiseTR = fallback(NoiseTR, [ 2, 1, 1, 1, 0 ][npNum]) + NoiseDeint = fallback(NoiseDeint, ['Generate', 'Bob', '', '', '' ][npNum]).lower() + StabilizeNoise = fallback(StabilizeNoise, [ True, True, True, False, False ][npNum]) + # fmt: on + + # The basic source-match step corrects and re-runs the interpolation of the input clip. So it initially uses same interpolation settings as the main preset + MatchNNSize = NNSize + MatchNNeurons = NNeurons + MatchEdiMaxD = EdiMaxD + MatchEdiQual = EdiQual + + # However, can use a faster initial interpolation when using source-match allowing the basic source-match step to "correct" it with higher quality settings + if SourceMatch > 0 and mpNum1 < pNum: + raise vs.Error("QTGMC: 'MatchPreset' cannot use a slower setting than 'Preset'") + # Basic source-match presets + if SourceMatch > 0: + # fmt: off + # Very Very Super Ultra + # Placebo Slow Slower Slow Medium Fast Faster Fast Fast Fast + NNSize = [1, 1, 1, 1, 5, 5, 4, 4, 4, 4 ][mpNum1] + NNeurons = [2, 2, 1, 1, 1, 0, 0, 0, 0, 0 ][mpNum1] + EdiMaxD = [12, 10, 8, 7, 7, 6, 6, 5, 4, 4 ][mpNum1] + EdiQual = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ][mpNum1] + # fmt: on + TempEdi = EdiMode # Main interpolation is actually done by basic-source match step when enabled, so a little swap and wriggle is needed + if SourceMatch > 0: + EdiMode = fallback(MatchEdi, EdiMode if mpNum1 < 9 else 'Bwdif').lower() # Force Bwdif for "Ultra Fast" basic source match + MatchEdi = TempEdi + + # fmt: off + # Very Very Super Ultra + # Refined source-match presets Placebo Slow Slower Slow Medium Fast Faster Fast Fast Fast + MatchEdi2 = fallback(MatchEdi2, ['NNEDI3', 'NNEDI3', 'NNEDI3', 'NNEDI3', 'NNEDI3', 'NNEDI3', 'NNEDI3', 'NNEDI3', 'NNEDI3', '' ][mpNum2]).lower() + MatchNNSize2 = [ 1, 1, 1, 1, 5, 5, 4, 4, 4, 4 ][mpNum2] + MatchNNeurons2 = [ 2, 2, 1, 1, 1, 0, 0, 0, 0, 0 ][mpNum2] + MatchEdiMaxD2 = [ 12, 10, 8, 7, 7, 6, 6, 5, 4, 4 ][mpNum2] + MatchEdiQual2 = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ][mpNum2] + # fmt: on + + # --------------------------------------- + # Settings + + # Core defaults + TR2 = fallback(TR2, max(TR2X, 1)) if SourceMatch > 0 else TR2X # ***TR2 defaults always at least 1 when using source-match*** + + # Source-match defaults + MatchTR1 = TR1 + + # Sharpness defaults. Sharpness default is always 1.0 (0.2 with source-match), but adjusted to give roughly same sharpness for all settings + if Sharpness is not None and Sharpness <= 0: + SMode = 0 + SLMode = fallback(SLMode, 0) if SourceMatch > 0 else SLModeX # ***Sharpness limiting disabled by default for source-match*** + if SLRad <= 0: + SLMode = 0 + spatialSL = SLMode in [1, 3] + temporalSL = SLMode in [2, 4] + Sharpness = fallback(Sharpness, 0.0 if SMode <= 0 else 0.2 if SourceMatch > 0 else 1.0) # Default sharpness is 1.0, or 0.2 if using source-match + sharpMul = 2 if temporalSL else 1.5 if spatialSL else 1 # Adjust sharpness based on other settings + sharpAdj = Sharpness * (sharpMul * (0.2 + TR1 * 0.15 + TR2 * 0.25) + (0.1 if SMode == 1 else 0)) # [This needs a bit more refinement] + if SMode <= 0: + Sbb = 0 + + # Noise processing settings + if EZDenoise is not None and EZDenoise > 0 and EZKeepGrain is not None and EZKeepGrain > 0: + raise vs.Error("QTGMC: EZDenoise and EZKeepGrain cannot be used together") + if NoiseProcess is None: + if EZDenoise is not None and EZDenoise > 0: + NoiseProcess = 1 + elif (EZKeepGrain is not None and EZKeepGrain > 0) or Preset in ['placebo', 'very slow']: + NoiseProcess = 2 + else: + NoiseProcess = 0 + if GrainRestore is None: + if EZDenoise is not None and EZDenoise > 0: + GrainRestore = 0.0 + elif EZKeepGrain is not None and EZKeepGrain > 0: + GrainRestore = 0.3 * math.sqrt(EZKeepGrain) + else: + GrainRestore = [0.0, 0.7, 0.3][NoiseProcess] + if NoiseRestore is None: + if EZDenoise is not None and EZDenoise > 0: + NoiseRestore = 0.0 + elif EZKeepGrain is not None and EZKeepGrain > 0: + NoiseRestore = 0.1 * math.sqrt(EZKeepGrain) + else: + NoiseRestore = [0.0, 0.3, 0.1][NoiseProcess] + if Sigma is None: + if EZDenoise is not None and EZDenoise > 0: + Sigma = EZDenoise + elif EZKeepGrain is not None and EZKeepGrain > 0: + Sigma = 4.0 * EZKeepGrain + else: + Sigma = 2.0 + if isinstance(ShowNoise, bool): + ShowNoise = 10.0 if ShowNoise else 0.0 + if ShowNoise > 0: + NoiseProcess = 2 + NoiseRestore = 1.0 + if NoiseProcess <= 0: + NoiseTR = 0 + GrainRestore = 0.0 + NoiseRestore = 0.0 + totalRestore = GrainRestore + NoiseRestore + if totalRestore <= 0: + StabilizeNoise = False + noiseTD = [1, 3, 5][NoiseTR] + noiseCentre = scale_value(128.5, 8, bits) if Denoiser in ['fft3df', 'fft3dfilter'] else neutral + + # MVTools settings + Lambda = fallback(Lambda, (1000 if TrueMotion else 100) * BlockSize * BlockSize // 64) + LSAD = fallback(LSAD, 1200 if TrueMotion else 400) + PNew = fallback(PNew, 50 if TrueMotion else 25) + PLevel = fallback(PLevel, 1 if TrueMotion else 0) + + # Motion blur settings + if ShutterAngleOut * FPSDivisor == ShutterAngleSrc: # If motion blur output is same as input + ShutterBlur = 0 + + # Miscellaneous + PrevGlobals = PrevGlobals.lower() + ReplaceGlobals = PrevGlobals in ['replace', 'reuse'] # If reusing existing globals put them back afterwards - simplifies logic later + ReuseGlobals = PrevGlobals == 'reuse' + if InputType < 2: + ProgSADMask = 0.0 + + # Get maximum temporal radius needed + maxTR = max(SLRad if temporalSL else 0, MatchTR2, TR1, TR2, NoiseTR) + if (ProgSADMask > 0 or StabilizeNoise or ShutterBlur > 0) and maxTR < 1: + maxTR = 1 + maxTR = max(ForceTR, maxTR) + + # --------------------------------------- + # Pre-Processing + + w = Input.width + h = Input.height + + # Reverse "field" dominance for progressive repair mode 3 (only difference from mode 2) + if InputType >= 3: + TFF = not TFF + + # Pad vertically during processing (to prevent artefacts at top & bottom edges) + if Border: + h += 8 + clip = Input.resize.Point(w, h, src_top=-4, src_height=h) + else: + clip = Input + + hpad = vpad = BlockSize + + # --------------------------------------- + # Motion Analysis + + # Bob the input as a starting point for motion search clip + if InputType <= 0: + bobbed = clip.resize.Bob(tff=TFF, filter_param_a=0, filter_param_b=0.5) + elif InputType == 1: + bobbed = clip + else: + bobbed = clip.std.Convolution(matrix=[1, 2, 1], mode='v') + + # If required, get any existing global clips with a matching "GlobalNames" setting. Unmatched values get None + if ReuseGlobals: + srchClip = QTGMC_GetUserGlobal(GlobalNames, 'srchClip') + srchSuper = QTGMC_GetUserGlobal(GlobalNames, 'srchSuper') + bVec1 = QTGMC_GetUserGlobal(GlobalNames, 'bVec1') + fVec1 = QTGMC_GetUserGlobal(GlobalNames, 'fVec1') + bVec2 = QTGMC_GetUserGlobal(GlobalNames, 'bVec2') + fVec2 = QTGMC_GetUserGlobal(GlobalNames, 'fVec2') + bVec3 = QTGMC_GetUserGlobal(GlobalNames, 'bVec3') + fVec3 = QTGMC_GetUserGlobal(GlobalNames, 'fVec3') + else: + srchClip = srchSuper = bVec1 = fVec1 = bVec2 = fVec2 = bVec3 = fVec3 = None + + CMplanes = [0, 1, 2] if ChromaMotion and not is_gray else [0] + + # The bobbed clip will shimmer due to being derived from alternating fields. Temporally smooth over the neighboring frames using a binomial kernel. Binomial + # kernels give equal weight to even and odd frames and hence average away the shimmer. The two kernels used are [1 2 1] and [1 4 6 4 1] for radius 1 and 2. + # These kernels are approximately Gaussian kernels, which work well as a prefilter before motion analysis (hence the original name for this script) + # Create linear weightings of neighbors first -2 -1 0 1 2 + if not isinstance(srchClip, vs.VideoNode): + if TR0 > 0: + ts1 = AverageFrames(bobbed, weights=[1] * 3, scenechange=28 / 255, planes=CMplanes) # 0.00 0.33 0.33 0.33 0.00 + if TR0 > 1: + ts2 = AverageFrames(bobbed, weights=[1] * 5, scenechange=28 / 255, planes=CMplanes) # 0.20 0.20 0.20 0.20 0.20 + + # Combine linear weightings to give binomial weightings - TR0=0: (1), TR0=1: (1:2:1), TR0=2: (1:4:6:4:1) + if isinstance(srchClip, vs.VideoNode): + binomial0 = None + elif TR0 <= 0: + binomial0 = bobbed + elif TR0 == 1: + binomial0 = core.std.Merge(ts1, bobbed, weight=0.25 if ChromaMotion or is_gray else [0.25, 0]) + else: + binomial0 = core.std.Merge( + core.std.Merge(ts1, ts2, weight=0.357 if ChromaMotion or is_gray else [0.357, 0]), bobbed, weight=0.125 if ChromaMotion or is_gray else [0.125, 0] + ) + + # Remove areas of difference between temporal blurred motion search clip and bob that are not due to bob-shimmer - removes general motion blur + if isinstance(srchClip, vs.VideoNode) or Rep0 <= 0: + repair0 = binomial0 + else: + repair0 = QTGMC_KeepOnlyBobShimmerFixes(binomial0, bobbed, Rep0, RepChroma and ChromaMotion) + + matrix = [1, 2, 1, 2, 4, 2, 1, 2, 1] + + # Blur image and soften edges to assist in motion matching of edge blocks. Blocks are matched by SAD (sum of absolute differences between blocks), but even + # a slight change in an edge from frame to frame will give a high SAD due to the higher contrast of edges + if not isinstance(srchClip, vs.VideoNode): + if SrchClipPP == 1: + spatialBlur = repair0.resize.Bilinear(w // 2, h // 2).std.Convolution(matrix=matrix, planes=CMplanes).resize.Bilinear(w, h) + elif SrchClipPP >= 2: + spatialBlur = Gauss(repair0.std.Convolution(matrix=matrix, planes=CMplanes), p=2.35) + spatialBlur = core.std.Merge(spatialBlur, repair0, weight=0.1 if ChromaMotion or is_gray else [0.1, 0]) + if SrchClipPP <= 0: + srchClip = repair0 + elif SrchClipPP < 3: + srchClip = spatialBlur + else: + expr = 'x {i3} + y < x {i3} + x {i3} - y > x {i3} - y ? ?'.format(i3=scale_value(3, 8, bits)) + tweaked = core.std.Expr([repair0, bobbed], expr=expr if ChromaMotion or is_gray else [expr, '']) + expr = 'x {i7} + y < x {i2} + x {i7} - y > x {i2} - x 51 * y 49 * + 100 / ? ?'.format(i7=scale_value(7, 8, bits), i2=scale_value(2, 8, bits)) + srchClip = core.std.Expr([spatialBlur, tweaked], expr=expr if ChromaMotion or is_gray else [expr, '']) + srchClip = DitherLumaRebuild(srchClip, s0=Str, c=Amp, chroma=ChromaMotion) + if bits > 8 and FastMA: + srchClip = depth(srchClip, 8, dither_type=Dither.NONE) + + super_args = dict(pel=SubPel, hpad=hpad, vpad=vpad) + analyse_args = dict( + blksize=BlockSize, + overlap=Overlap, + search=Search, + searchparam=SearchParam, + pelsearch=PelSearch, + truemotion=TrueMotion, + lambda_=Lambda, + lsad=LSAD, + pnew=PNew, + plevel=PLevel, + global_=GlobalMotion, + dct=DCT, + chroma=ChromaMotion, + ) + recalculate_args = dict( + thsad=ThSAD1 // 2, + blksize=max(BlockSize // 2, 4), + search=Search, + searchparam=SearchParam, + chroma=ChromaMotion, + truemotion=TrueMotion, + pnew=PNew, + overlap=max(Overlap // 2, 2), + dct=DCT, + ) + + # Calculate forward and backward motion vectors from motion search clip + if maxTR > 0: + if not isinstance(srchSuper, vs.VideoNode): + srchSuper = srchClip.mv.Super(sharp=SubPelInterp, chroma=ChromaMotion, **super_args) + if not isinstance(bVec1, vs.VideoNode): + bVec1 = srchSuper.mv.Analyse(isb=True, delta=1, **analyse_args) + if RefineMotion: + bVec1 = core.mv.Recalculate(srchSuper, bVec1, **recalculate_args) + if not isinstance(fVec1, vs.VideoNode): + fVec1 = srchSuper.mv.Analyse(isb=False, delta=1, **analyse_args) + if RefineMotion: + fVec1 = core.mv.Recalculate(srchSuper, fVec1, **recalculate_args) + if maxTR > 1: + if not isinstance(bVec2, vs.VideoNode): + bVec2 = srchSuper.mv.Analyse(isb=True, delta=2, **analyse_args) + if RefineMotion: + bVec2 = core.mv.Recalculate(srchSuper, bVec2, **recalculate_args) + if not isinstance(fVec2, vs.VideoNode): + fVec2 = srchSuper.mv.Analyse(isb=False, delta=2, **analyse_args) + if RefineMotion: + fVec2 = core.mv.Recalculate(srchSuper, fVec2, **recalculate_args) + if maxTR > 2: + if not isinstance(bVec3, vs.VideoNode): + bVec3 = srchSuper.mv.Analyse(isb=True, delta=3, **analyse_args) + if RefineMotion: + bVec3 = core.mv.Recalculate(srchSuper, bVec3, **recalculate_args) + if not isinstance(fVec3, vs.VideoNode): + fVec3 = srchSuper.mv.Analyse(isb=False, delta=3, **analyse_args) + if RefineMotion: + fVec3 = core.mv.Recalculate(srchSuper, fVec3, **recalculate_args) + + # Expose search clip, motion search super clip and motion vectors to calling script through globals + if ReplaceGlobals: + QTGMC_SetUserGlobal(GlobalNames, 'srchClip', srchClip) + QTGMC_SetUserGlobal(GlobalNames, 'srchSuper', srchSuper) + QTGMC_SetUserGlobal(GlobalNames, 'bVec1', bVec1) + QTGMC_SetUserGlobal(GlobalNames, 'fVec1', fVec1) + QTGMC_SetUserGlobal(GlobalNames, 'bVec2', bVec2) + QTGMC_SetUserGlobal(GlobalNames, 'fVec2', fVec2) + QTGMC_SetUserGlobal(GlobalNames, 'bVec3', bVec3) + QTGMC_SetUserGlobal(GlobalNames, 'fVec3', fVec3) + + # --------------------------------------- + # Noise Processing + + # Expand fields to full frame size before extracting noise (allows use of motion vectors which are frame-sized) + if NoiseProcess > 0: + if InputType > 0: + fullClip = clip + else: + fullClip = clip.resize.Bob(tff=TFF, filter_param_a=0, filter_param_b=1) + if NoiseTR > 0: + fullSuper = fullClip.mv.Super(levels=1, chroma=ChromaNoise, **super_args) # TEST chroma OK? + + CNplanes = [0, 1, 2] if ChromaNoise and not is_gray else [0] + + if NoiseProcess > 0: + # Create a motion compensated temporal window around current frame and use to guide denoisers + if not DenoiseMC or NoiseTR <= 0: + noiseWindow = fullClip + elif NoiseTR == 1: + noiseWindow = core.std.Interleave( + [ + core.mv.Compensate(fullClip, fullSuper, fVec1, thscd1=ThSCD1, thscd2=ThSCD2), + fullClip, + core.mv.Compensate(fullClip, fullSuper, bVec1, thscd1=ThSCD1, thscd2=ThSCD2), + ] + ) + else: + noiseWindow = core.std.Interleave( + [ + core.mv.Compensate(fullClip, fullSuper, fVec2, thscd1=ThSCD1, thscd2=ThSCD2), + core.mv.Compensate(fullClip, fullSuper, fVec1, thscd1=ThSCD1, thscd2=ThSCD2), + fullClip, + core.mv.Compensate(fullClip, fullSuper, bVec1, thscd1=ThSCD1, thscd2=ThSCD2), + core.mv.Compensate(fullClip, fullSuper, bVec2, thscd1=ThSCD1, thscd2=ThSCD2), + ] + ) + if Denoiser == 'bm3d': + dnWindow = mvf.BM3D(noiseWindow, radius1=NoiseTR, sigma=[Sigma if plane in CNplanes else 0 for plane in range(3)]) + elif Denoiser == 'dfttest': + dnWindow = noiseWindow.dfttest.DFTTest(sigma=Sigma * 4, tbsize=noiseTD, planes=CNplanes) + elif Denoiser in ['knlm', 'knlmeanscl']: + if ChromaNoise and not is_gray: + dnWindow = KNLMeansCL(noiseWindow, d=NoiseTR, h=Sigma) + else: + dnWindow = noiseWindow.knlm.KNLMeansCL(d=NoiseTR, h=Sigma) + else: + dnWindow = noiseWindow.fft3dfilter.FFT3DFilter(sigma=Sigma, planes=CNplanes, bt=noiseTD, ncpu=FftThreads) + + # Rework denoised clip to match source format - various code paths here: discard the motion compensation window, discard doubled lines (from point resize) + # Also reweave to get interlaced noise if source was interlaced (could keep the full frame of noise, but it will be poor quality from the point resize) + if not DenoiseMC: + if InputType > 0: + denoised = dnWindow + else: + denoised = Weave(dnWindow.std.SeparateFields(tff=TFF).std.SelectEvery(cycle=4, offsets=[0, 3]), tff=TFF) + elif InputType > 0: + if NoiseTR <= 0: + denoised = dnWindow + else: + denoised = dnWindow.std.SelectEvery(cycle=noiseTD, offsets=NoiseTR) + else: + denoised = Weave(dnWindow.std.SeparateFields(tff=TFF).std.SelectEvery(cycle=noiseTD * 4, offsets=[NoiseTR * 2, NoiseTR * 6 + 3]), tff=TFF) + + if totalRestore > 0: + # Get actual noise from difference. Then 'deinterlace' where we have weaved noise - create the missing lines of noise in various ways + noise = core.std.MakeDiff(clip, denoised, planes=CNplanes) + if InputType > 0: + deintNoise = noise + elif NoiseDeint == 'bob': + deintNoise = noise.resize.Bob(tff=TFF, filter_param_a=0, filter_param_b=0.5) + elif NoiseDeint == 'generate': + deintNoise = QTGMC_Generate2ndFieldNoise(noise, denoised, ChromaNoise, TFF) + else: + deintNoise = noise.std.SeparateFields(tff=TFF).std.DoubleWeave(tff=TFF) + + # Motion-compensated stabilization of generated noise + if StabilizeNoise: + noiseSuper = deintNoise.mv.Super(sharp=SubPelInterp, levels=1, chroma=ChromaNoise, **super_args) + mcNoise = core.mv.Compensate(deintNoise, noiseSuper, bVec1, thscd1=ThSCD1, thscd2=ThSCD2) + expr = f'x {neutral} - abs y {neutral} - abs > x y ? 0.6 * x y + 0.2 * +' + finalNoise = core.std.Expr([deintNoise, mcNoise], expr=expr if ChromaNoise or is_gray else [expr, '']) + else: + finalNoise = deintNoise + + # If NoiseProcess=1 denoise input clip. If NoiseProcess=2 leave noise in the clip and let the temporal blurs "denoise" it for a stronger effect + innerClip = denoised if NoiseProcess == 1 else clip + + # --------------------------------------- + # Interpolation + + # Support badly deinterlaced progressive content - drop half the fields and reweave to get 1/2fps interlaced stream appropriate for QTGMC processing + if InputType > 1: + ediInput = Weave(innerClip.std.SeparateFields(tff=TFF).std.SelectEvery(cycle=4, offsets=[0, 3]), tff=TFF) + else: + ediInput = innerClip + + # Create interpolated image as starting point for output + if EdiExt is not None: + edi1 = EdiExt.resize.Point(w, h, src_top=(EdiExt.height - h) // 2, src_height=h) + else: + edi1 = QTGMC_Interpolate( + ediInput, InputType, EdiMode, NNSize, NNeurons, EdiQual, EdiMaxD, bobbed, ChromaEdi.lower(), TFF, nnedi3_args, eedi3_args, opencl, device + ) + + # InputType=2,3: use motion mask to blend luma between original clip & reweaved clip based on ProgSADMask setting. Use chroma from original clip in any case + if InputType < 2: + edi = edi1 + elif ProgSADMask <= 0: + if not is_gray: + edi = core.std.ShufflePlanes([edi1, innerClip], planes=[0, 1, 2], colorfamily=Input.format.color_family) + else: + edi = edi1 + else: + inputTypeBlend = core.mv.Mask(srchClip, bVec1, kind=1, ml=ProgSADMask) + edi = core.std.MaskedMerge(innerClip, edi1, inputTypeBlend, planes=0) + + # Get the max/min value for each pixel over neighboring motion-compensated frames - used for temporal sharpness limiting + if TR1 > 0 or temporalSL: + ediSuper = edi.mv.Super(sharp=SubPelInterp, levels=1, **super_args) + if temporalSL: + bComp1 = core.mv.Compensate(edi, ediSuper, bVec1, thscd1=ThSCD1, thscd2=ThSCD2) + fComp1 = core.mv.Compensate(edi, ediSuper, fVec1, thscd1=ThSCD1, thscd2=ThSCD2) + tMax = core.std.Expr([core.std.Expr([edi, fComp1], expr='x y max'), bComp1], expr='x y max') + tMin = core.std.Expr([core.std.Expr([edi, fComp1], expr='x y min'), bComp1], expr='x y min') + if SLRad > 1: + bComp3 = core.mv.Compensate(edi, ediSuper, bVec3, thscd1=ThSCD1, thscd2=ThSCD2) + fComp3 = core.mv.Compensate(edi, ediSuper, fVec3, thscd1=ThSCD1, thscd2=ThSCD2) + tMax = core.std.Expr([core.std.Expr([tMax, fComp3], expr='x y max'), bComp3], expr='x y max') + tMin = core.std.Expr([core.std.Expr([tMin, fComp3], expr='x y min'), bComp3], expr='x y min') + + # --------------------------------------- + # Create basic output + + # Use motion vectors to blur interpolated image (edi) with motion-compensated previous and next frames. As above, this is done to remove shimmer from + # alternate frames so the same binomial kernels are used. However, by using motion-compensated smoothing this time we avoid motion blur. The use of + # MDegrain1 (motion compensated) rather than TemporalSmooth makes the weightings *look* different, but they evaluate to the same values + # Create linear weightings of neighbors first -2 -1 0 1 2 + if TR1 > 0: + degrain1 = core.mv.Degrain1(edi, ediSuper, bVec1, fVec1, thsad=ThSAD1, thscd1=ThSCD1, thscd2=ThSCD2) # 0.00 0.33 0.33 0.33 0.00 + if TR1 > 1: + degrain2 = core.mv.Degrain1(edi, ediSuper, bVec2, fVec2, thsad=ThSAD1, thscd1=ThSCD1, thscd2=ThSCD2) # 0.33 0.00 0.33 0.00 0.33 + + # Combine linear weightings to give binomial weightings - TR1=0: (1), TR1=1: (1:2:1), TR1=2: (1:4:6:4:1) + if TR1 <= 0: + binomial1 = edi + elif TR1 == 1: + binomial1 = core.std.Merge(degrain1, edi, weight=0.25) + else: + binomial1 = core.std.Merge(core.std.Merge(degrain1, degrain2, weight=0.2), edi, weight=0.0625) + + # Remove areas of difference between smoothed image and interpolated image that are not bob-shimmer fixes: repairs residual motion blur from temporal smooth + if Rep1 <= 0: + repair1 = binomial1 + else: + repair1 = QTGMC_KeepOnlyBobShimmerFixes(binomial1, edi, Rep1, RepChroma) + + # Apply source match - use difference between output and source to succesively refine output [extracted to function to clarify main code path] + if SourceMatch <= 0: + match = repair1 + else: + match = QTGMC_ApplySourceMatch( + repair1, + InputType, + ediInput, + bVec1 if maxTR > 0 else None, + fVec1 if maxTR > 0 else None, + bVec2 if maxTR > 1 else None, + fVec2 if maxTR > 1 else None, + SubPel, + SubPelInterp, + hpad, + vpad, + ThSAD1, + ThSCD1, + ThSCD2, + SourceMatch, + MatchTR1, + MatchEdi, + MatchNNSize, + MatchNNeurons, + MatchEdiQual, + MatchEdiMaxD, + MatchTR2, + MatchEdi2, + MatchNNSize2, + MatchNNeurons2, + MatchEdiQual2, + MatchEdiMaxD2, + MatchEnhance, + TFF, + nnedi3_args, + eedi3_args, + opencl, + device, + ) + + # Lossless=2 - after preparing an interpolated, de-shimmered clip, restore the original source fields into it and clean up any artefacts + # This mode will not give a true lossless result because the resharpening and final temporal smooth are still to come, but it will add further detail + # However, it can introduce minor combing. This setting is best used together with source-match (it's effectively the final source-match stage) + if Lossless >= 2: + lossed1 = QTGMC_MakeLossless(match, innerClip, InputType, TFF) + else: + lossed1 = match + + # --------------------------------------- + # Resharpen / retouch output + + # Resharpen to counteract temporal blurs. Little sharpening needed for source-match mode since it has already recovered sharpness from source + if SMode <= 0: + resharp = lossed1 + elif SMode == 1: + resharp = core.std.Expr([lossed1, lossed1.std.Convolution(matrix=matrix)], expr=f'x x y - {sharpAdj} * +') + else: + vresharp1 = core.std.Merge(lossed1.std.Maximum(coordinates=[0, 1, 0, 0, 0, 0, 1, 0]), lossed1.std.Minimum(coordinates=[0, 1, 0, 0, 0, 0, 1, 0])) + if Precise: # Precise mode: reduce tiny overshoot + vresharp = core.std.Expr([vresharp1, lossed1], expr='x y < x {i1} + x y > x {i1} - x ? ?'.format(i1=scale_value(1, 8, bits))) + else: + vresharp = vresharp1 + resharp = core.std.Expr([lossed1, vresharp.std.Convolution(matrix=matrix)], expr=f'x x y - {sharpAdj} * +') + + # Slightly thin down 1-pixel high horizontal edges that have been widened into neighboring field lines by the interpolator + SVThinSc = SVThin * 6.0 + if SVThin > 0: + expr = f'y x - {SVThinSc} * {neutral} +' + vertMedD = core.std.Expr([lossed1, lossed1.rgvs.VerticalCleaner(mode=1 if is_gray else [1, 0])], expr=expr if is_gray else [expr, '']) + vertMedD = vertMedD.std.Convolution(matrix=[1, 2, 1], planes=0, mode='h') + expr = f'y {neutral} - abs x {neutral} - abs > y {neutral} ?' + neighborD = core.std.Expr([vertMedD, vertMedD.std.Convolution(matrix=matrix, planes=0)], expr=expr if is_gray else [expr, '']) + thin = core.std.MergeDiff(resharp, neighborD, planes=0) + else: + thin = resharp + + # Back blend the blurred difference between sharpened & unsharpened clip, before (1st) sharpness limiting (Sbb == 1,3). A small fidelity improvement + if Sbb not in [1, 3]: + backBlend1 = thin + else: + backBlend1 = core.std.MakeDiff(thin, Gauss(core.std.MakeDiff(thin, lossed1, planes=0).std.Convolution(matrix=matrix, planes=0), p=5), planes=0) + + # Limit over-sharpening by clamping to neighboring (spatial or temporal) min/max values in original + # Occurs here (before final temporal smooth) if SLMode == 1,2. This location will restrict sharpness more, but any artefacts introduced will be smoothed + if SLMode == 1: + if SLRad <= 1: + sharpLimit1 = core.rgvs.Repair(backBlend1, edi, mode=1) + else: + sharpLimit1 = core.rgvs.Repair(backBlend1, core.rgvs.Repair(backBlend1, edi, mode=12), mode=1) + elif SLMode == 2: + sharpLimit1 = mt_clamp(backBlend1, tMax, tMin, SOvs, SOvs) + else: + sharpLimit1 = backBlend1 + + # Back blend the blurred difference between sharpened & unsharpened clip, after (1st) sharpness limiting (Sbb == 2,3). A small fidelity improvement + if Sbb < 2: + backBlend2 = sharpLimit1 + else: + backBlend2 = core.std.MakeDiff( + sharpLimit1, Gauss(core.std.MakeDiff(sharpLimit1, lossed1, planes=0).std.Convolution(matrix=matrix, planes=0), p=5), planes=0 + ) + + # Add back any extracted noise, prior to final temporal smooth - this will restore detail that was removed as "noise" without restoring the noise itself + # Average luma of FFT3DFilter extracted noise is 128.5, so deal with that too + if GrainRestore <= 0: + addNoise1 = backBlend2 + else: + expr = f'x {noiseCentre} - {GrainRestore} * {neutral} +' + addNoise1 = core.std.MergeDiff(backBlend2, finalNoise.std.Expr(expr=expr if ChromaNoise or is_gray else [expr, '']), planes=CNplanes) + + # Final light linear temporal smooth for denoising + if TR2 > 0: + stableSuper = addNoise1.mv.Super(sharp=SubPelInterp, levels=1, **super_args) + if TR2 <= 0: + stable = addNoise1 + elif TR2 == 1: + stable = core.mv.Degrain1(addNoise1, stableSuper, bVec1, fVec1, thsad=ThSAD2, thscd1=ThSCD1, thscd2=ThSCD2) + elif TR2 == 2: + stable = core.mv.Degrain2(addNoise1, stableSuper, bVec1, fVec1, bVec2, fVec2, thsad=ThSAD2, thscd1=ThSCD1, thscd2=ThSCD2) + else: + stable = core.mv.Degrain3(addNoise1, stableSuper, bVec1, fVec1, bVec2, fVec2, bVec3, fVec3, thsad=ThSAD2, thscd1=ThSCD1, thscd2=ThSCD2) + + # Remove areas of difference between final output & basic interpolated image that are not bob-shimmer fixes: repairs motion blur caused by temporal smooth + if Rep2 <= 0: + repair2 = stable + else: + repair2 = QTGMC_KeepOnlyBobShimmerFixes(stable, edi, Rep2, RepChroma) + + # Limit over-sharpening by clamping to neighboring (spatial or temporal) min/max values in original + # Occurs here (after final temporal smooth) if SLMode == 3,4. Allows more sharpening here, but more prone to introducing minor artefacts + if SLMode == 3: + if SLRad <= 1: + sharpLimit2 = core.rgvs.Repair(repair2, edi, mode=1) + else: + sharpLimit2 = core.rgvs.Repair(repair2, core.rgvs.Repair(repair2, edi, mode=12), mode=1) + elif SLMode >= 4: + sharpLimit2 = mt_clamp(repair2, tMax, tMin, SOvs, SOvs) + else: + sharpLimit2 = repair2 + + # Lossless=1 - inject source fields into result and clean up inevitable artefacts. Provided NoiseRestore=0.0 or 1.0, this mode will make the script result + # properly lossless, but this will retain source artefacts and cause some combing (where the smoothed deinterlace doesn't quite match the source) + if Lossless == 1: + lossed2 = QTGMC_MakeLossless(sharpLimit2, innerClip, InputType, TFF) + else: + lossed2 = sharpLimit2 + + # Add back any extracted noise, after final temporal smooth. This will appear as noise/grain in the output + # Average luma of FFT3DFilter extracted noise is 128.5, so deal with that too + if NoiseRestore <= 0: + addNoise2 = lossed2 + else: + expr = f'x {noiseCentre} - {NoiseRestore} * {neutral} +' + addNoise2 = core.std.MergeDiff(lossed2, finalNoise.std.Expr(expr=expr if ChromaNoise or is_gray else [expr, '']), planes=CNplanes) + + # --------------------------------------- + # Post-Processing + + # Shutter motion blur - get level of blur depending on output framerate and blur already in source + blurLevel = (ShutterAngleOut * FPSDivisor - ShutterAngleSrc) * 100 / 360 + if blurLevel < 0: + raise vs.Error('QTGMC: cannot reduce motion blur already in source: increase ShutterAngleOut or FPSDivisor') + if blurLevel > 200: + raise vs.Error('QTGMC: exceeded maximum motion blur level: decrease ShutterAngleOut or FPSDivisor') + + # ShutterBlur mode 2,3 - get finer resolution motion vectors to reduce blur "bleeding" into static areas + rBlockDivide = [1, 1, 2, 4][ShutterBlur] + rBlockSize = max(BlockSize // rBlockDivide, 4) + rOverlap = max(Overlap // rBlockDivide, 2) + rBlockDivide = BlockSize // rBlockSize + rLambda = Lambda // (rBlockDivide * rBlockDivide) + if ShutterBlur > 1: + recalculate_args = dict( + thsad=ThSAD1, + blksize=rBlockSize, + overlap=rOverlap, + search=Search, + searchparam=SearchParam, + truemotion=TrueMotion, + lambda_=rLambda, + pnew=PNew, + dct=DCT, + chroma=ChromaMotion, + ) + sbBVec1 = core.mv.Recalculate(srchSuper, bVec1, **recalculate_args) + sbFVec1 = core.mv.Recalculate(srchSuper, fVec1, **recalculate_args) + elif ShutterBlur > 0: + sbBVec1 = bVec1 + sbFVec1 = fVec1 + + # Shutter motion blur - use MFlowBlur to blur along motion vectors + if ShutterBlur > 0: + sblurSuper = addNoise2.mv.Super(sharp=SubPelInterp, levels=1, **super_args) + sblur = core.mv.FlowBlur(addNoise2, sblurSuper, sbBVec1, sbFVec1, blur=blurLevel, thscd1=ThSCD1, thscd2=ThSCD2) + + # Shutter motion blur - use motion mask to reduce blurring in areas of low motion - also helps reduce blur "bleeding" into static areas, then select blur type + if ShutterBlur <= 0: + sblurred = addNoise2 + elif SBlurLimit <= 0: + sblurred = sblur + else: + sbMotionMask = core.mv.Mask(srchClip, bVec1, kind=0, ml=SBlurLimit) + sblurred = core.std.MaskedMerge(addNoise2, sblur, sbMotionMask) + + # Reduce frame rate + if FPSDivisor > 1: + decimated = sblurred.std.SelectEvery(cycle=FPSDivisor, offsets=0) + else: + decimated = sblurred + + # Crop off temporary vertical padding + if Border: + cropped = decimated.std.Crop(top=4, bottom=4) + else: + cropped = decimated + + # Show output of choice + settings + if ShowNoise <= 0: + output = cropped + else: + expr = f'x {neutral} - {ShowNoise} * {neutral} +' + output = finalNoise.std.Expr(expr=expr if ChromaNoise or is_gray else [expr, repr(neutral)]) + output = output.std.SetFieldBased(value=0) + if not ShowSettings: + return output + else: + text = ( + f'{TR0=} | {TR1=} | {TR2=} | {Rep0=} | {Rep1=} | {Rep2=} | {RepChroma=} | {EdiMode=} | {NNSize=} | {NNeurons=} | {EdiQual=} | {EdiMaxD=} | ' + + f'{ChromaEdi=} | {Sharpness=} | {SMode=} | {SLMode=} | {SLRad=} | {SOvs=} | {SVThin=} | {Sbb=} | {SrchClipPP=} | {SubPel=} | {SubPelInterp=} | ' + + f'{BlockSize=} | {Overlap=} | {Search=} | {SearchParam=} | {PelSearch=} | {ChromaMotion=} | {TrueMotion=} | {Lambda=} | {LSAD=} | {PNew=} | ' + + f'{PLevel=} | {GlobalMotion=} | {DCT=} | {ThSAD1=} | {ThSAD2=} | {ThSCD1=} | {ThSCD2=} | {SourceMatch=} | {MatchPreset=} | {MatchEdi=} | ' + + f'{MatchPreset2=} | {MatchEdi2=} | {MatchTR2=} | {MatchEnhance=} | {Lossless=} | {NoiseProcess=} | {Denoiser=} | {FftThreads=} | {DenoiseMC=} | ' + + f'{NoiseTR=} | {Sigma=} | {ChromaNoise=} | {ShowNoise=} | {GrainRestore=} | {NoiseRestore=} | {NoiseDeint=} | {StabilizeNoise=} | {InputType=} | ' + + f'{ProgSADMask=} | {FPSDivisor=} | {ShutterBlur=} | {ShutterAngleSrc=} | {ShutterAngleOut=} | {SBlurLimit=} | {Border=} | {Precise=} | ' + + f'{Preset=} | {Tuning=} | {GlobalNames=} | {PrevGlobals=} | {ForceTR=} | {Str=} | {Amp=} | {FastMA=} | {ESearchP=} | {RefineMotion=}' + ) + return output.text.Text(text=text) + + +def QTGMC_Interpolate( + Input: vs.VideoNode, + InputType: int, + EdiMode: str, + NNSize: int, + NNeurons: int, + EdiQual: int, + EdiMaxD: int, + Fallback: Optional[vs.VideoNode] = None, + ChromaEdi: str = '', + TFF: Optional[bool] = None, + nnedi3_args: Mapping[str, Any] = {}, + eedi3_args: Mapping[str, Any] = {}, + opencl: bool = False, + device: Optional[int] = None, +) -> vs.VideoNode: + ''' + Interpolate input clip using method given in EdiMode. Use Fallback or Bob as result if mode not in list. If ChromaEdi string if set then interpolate chroma + separately with that method (only really useful for EEDIx). The function is used as main algorithm starting point and for first two source-match stages + ''' + is_gray = Input.format.color_family == vs.GRAY + if is_gray: + ChromaEdi = '' + planes = [0, 1, 2] if ChromaEdi == '' and not is_gray else [0] + + field = 3 if TFF else 2 + + if opencl: + nnedi3 = partial(core.nnedi3cl.NNEDI3CL, field=field, device=device, **nnedi3_args) + eedi3 = partial(core.eedi3m.EEDI3CL, field=field, planes=planes, mdis=EdiMaxD, device=device, **eedi3_args) + else: + nnedi3 = partial(core.znedi3.nnedi3, field=field, **nnedi3_args) + eedi3 = partial(core.eedi3m.EEDI3, field=field, planes=planes, mdis=EdiMaxD, **eedi3_args) + + if InputType == 1: + return Input + elif EdiMode == 'nnedi3': + interp = nnedi3(Input, planes=planes, nsize=NNSize, nns=NNeurons, qual=EdiQual) + elif EdiMode == 'eedi3+nnedi3': + interp = eedi3(Input, sclip=nnedi3(Input, planes=planes, nsize=NNSize, nns=NNeurons, qual=EdiQual)) + elif EdiMode == 'eedi3': + interp = eedi3(Input) + elif EdiMode == 'bwdif': + interp = Input.bwdif.Bwdif(field=field) + else: + interp = fallback(Fallback, Input.resize.Bob(tff=TFF, filter_param_a=0, filter_param_b=0.5)) + + if ChromaEdi == 'nnedi3': + interpuv = nnedi3(Input, planes=[1, 2], nsize=4, nns=0, qual=1) + elif ChromaEdi == 'bwdif': + interpuv = Input.bwdif.Bwdif(field=field) + elif ChromaEdi == 'bob': + interpuv = Input.resize.Bob(tff=TFF, filter_param_a=0, filter_param_b=0.5) + else: + return interp + + return core.std.ShufflePlanes([interp, interpuv], planes=[0, 1, 2], colorfamily=Input.format.color_family) + + +def QTGMC_KeepOnlyBobShimmerFixes(Input: vs.VideoNode, Ref: vs.VideoNode, Rep: int = 1, Chroma: bool = True) -> vs.VideoNode: + ''' + Helper function: Compare processed clip with reference clip: only allow thin, horizontal areas of difference, i.e. bob shimmer fixes + Rough algorithm: Get difference, deflate vertically by a couple of pixels or so, then inflate again. Thin regions will be removed + by this process. Restore remaining areas of difference back to as they were in reference clip + ''' + is_gray = Input.format.color_family == vs.GRAY + planes = [0, 1, 2] if Chroma and not is_gray else [0] + + bits = get_depth(Input) + neutral = 1 << (bits - 1) + + # ed is the erosion distance - how much to deflate then reflate to remove thin areas of interest: 0 = minimum to 6 = maximum + # od is over-dilation level - extra inflation to ensure areas to restore back are fully caught: 0 = none to 3 = one full pixel + # If Rep < 10, then ed = Rep and od = 0, otherwise ed = 10s digit and od = 1s digit (nasty method, but kept for compatibility with original TGMC) + ed = Rep if Rep < 10 else Rep // 10 + od = 0 if Rep < 10 else Rep % 10 + + diff = core.std.MakeDiff(Ref, Input) + + coordinates = [0, 1, 0, 0, 0, 0, 1, 0] + + # Areas of positive difference + choke1 = diff.std.Minimum(planes=planes, coordinates=coordinates) + if ed > 2: + choke1 = choke1.std.Minimum(planes=planes, coordinates=coordinates) + if ed > 5: + choke1 = choke1.std.Minimum(planes=planes, coordinates=coordinates) + if ed % 3 != 0: + choke1 = choke1.std.Deflate(planes=planes) + if ed in [2, 5]: + choke1 = choke1.std.Median(planes=planes) + choke1 = choke1.std.Maximum(planes=planes, coordinates=coordinates) + if ed > 1: + choke1 = choke1.std.Maximum(planes=planes, coordinates=coordinates) + if ed > 4: + choke1 = choke1.std.Maximum(planes=planes, coordinates=coordinates) + + # Over-dilation - extra reflation up to about 1 pixel + if od == 1: + choke1 = choke1.std.Inflate(planes=planes) + elif od == 2: + choke1 = choke1.std.Inflate(planes=planes).std.Inflate(planes=planes) + elif od >= 3: + choke1 = choke1.std.Maximum(planes=planes) + + # Areas of negative difference (similar to above) + choke2 = diff.std.Maximum(planes=planes, coordinates=coordinates) + if ed > 2: + choke2 = choke2.std.Maximum(planes=planes, coordinates=coordinates) + if ed > 5: + choke2 = choke2.std.Maximum(planes=planes, coordinates=coordinates) + if ed % 3 != 0: + choke2 = choke2.std.Inflate(planes=planes) + if ed in [2, 5]: + choke2 = choke2.std.Median(planes=planes) + choke2 = choke2.std.Minimum(planes=planes, coordinates=coordinates) + if ed > 1: + choke2 = choke2.std.Minimum(planes=planes, coordinates=coordinates) + if ed > 4: + choke2 = choke2.std.Minimum(planes=planes, coordinates=coordinates) + + if od == 1: + choke2 = choke2.std.Deflate(planes=planes) + elif od == 2: + choke2 = choke2.std.Deflate(planes=planes).std.Deflate(planes=planes) + elif od >= 3: + choke2 = choke2.std.Minimum(planes=planes) + + # Combine above areas to find those areas of difference to restore + expr1 = f'x {scale_value(129, 8, bits)} < x y {neutral} < {neutral} y ? ?' + expr2 = f'x {scale_value(127, 8, bits)} > x y {neutral} > {neutral} y ? ?' + restore = core.std.Expr( + [core.std.Expr([diff, choke1], expr=expr1 if Chroma or is_gray else [expr1, '']), choke2], expr=expr2 if Chroma or is_gray else [expr2, ''] + ) + return core.std.MergeDiff(Input, restore, planes=planes) + + +def QTGMC_Generate2ndFieldNoise(Input: vs.VideoNode, InterleavedClip: vs.VideoNode, ChromaNoise: bool = False, TFF: Optional[bool] = None) -> vs.VideoNode: + ''' + Given noise extracted from an interlaced source (i.e. the noise is interlaced), generate "progressive" noise with a new "field" of noise injected. The new + noise is centered on a weighted local average and uses the difference between local min & max as an estimate of local variance + ''' + is_gray = Input.format.color_family == vs.GRAY + planes = [0, 1, 2] if ChromaNoise and not is_gray else [0] + + bits = get_depth(Input) + neutral = 1 << (bits - 1) + + origNoise = Input.std.SeparateFields(tff=TFF) + noiseMax = origNoise.std.Maximum(planes=planes).std.Maximum(planes=planes, coordinates=[0, 0, 0, 1, 1, 0, 0, 0]) + noiseMin = origNoise.std.Minimum(planes=planes).std.Minimum(planes=planes, coordinates=[0, 0, 0, 1, 1, 0, 0, 0]) + random = ( + InterleavedClip.std.SeparateFields(tff=TFF) + .std.BlankClip(color=[neutral] * Input.format.num_planes) + .grain.Add(var=1800, uvar=1800 if ChromaNoise else 0) + ) + expr = f'x {neutral} - y * {scale_value(256, 8, bits)} / {neutral} +' + varRandom = core.std.Expr([core.std.MakeDiff(noiseMax, noiseMin, planes=planes), random], expr=expr if ChromaNoise or is_gray else [expr, '']) + newNoise = core.std.MergeDiff(noiseMin, varRandom, planes=planes) + return Weave(core.std.Interleave([origNoise, newNoise]), tff=TFF) + + +def QTGMC_MakeLossless(Input: vs.VideoNode, Source: vs.VideoNode, InputType: int, TFF: Optional[bool] = None) -> vs.VideoNode: + ''' + Insert the source lines into the result to create a true lossless output. However, the other lines in the result have had considerable processing and won't + exactly match source lines. There will be some slight residual combing. Use vertical medians to clean a little of this away + ''' + if InputType == 1: + raise vs.Error('QTGMC: lossless modes are incompatible with InputType=1') + + neutral = 1 << (get_depth(Input) - 1) + + # Weave the source fields and the "new" fields that have generated in the input + if InputType <= 0: + srcFields = Source.std.SeparateFields(tff=TFF) + else: + srcFields = Source.std.SeparateFields(tff=TFF).std.SelectEvery(cycle=4, offsets=[0, 3]) + newFields = Input.std.SeparateFields(tff=TFF).std.SelectEvery(cycle=4, offsets=[1, 2]) + processed = Weave(core.std.Interleave([srcFields, newFields]).std.SelectEvery(cycle=4, offsets=[0, 1, 3, 2]), tff=TFF) + + # Clean some of the artefacts caused by the above - creating a second version of the "new" fields + vertMedian = processed.rgvs.VerticalCleaner(mode=1) + vertMedDiff = core.std.MakeDiff(processed, vertMedian) + vmNewDiff1 = vertMedDiff.std.SeparateFields(tff=TFF).std.SelectEvery(cycle=4, offsets=[1, 2]) + vmNewDiff2 = core.std.Expr( + [vmNewDiff1.rgvs.VerticalCleaner(mode=1), vmNewDiff1], expr=f'x {neutral} - y {neutral} - * 0 < {neutral} x {neutral} - abs y {neutral} - abs < x y ? ?' + ) + vmNewDiff3 = core.rgvs.Repair(vmNewDiff2, vmNewDiff2.rgvs.RemoveGrain(mode=2), mode=1) + + # Reweave final result + return Weave(core.std.Interleave([srcFields, core.std.MakeDiff(newFields, vmNewDiff3)]).std.SelectEvery(cycle=4, offsets=[0, 1, 3, 2]), tff=TFF) + + +def QTGMC_ApplySourceMatch( + Deinterlace: vs.VideoNode, + InputType: int, + Source: vs.VideoNode, + bVec1: Union[vs.VideoNode, None], + fVec1: Union[vs.VideoNode, None], + bVec2: Union[vs.VideoNode, None], + fVec2: Union[vs.VideoNode, None], + SubPel: int, + SubPelInterp: int, + hpad: int, + vpad: int, + ThSAD1: int, + ThSCD1: int, + ThSCD2: int, + SourceMatch: int, + MatchTR1: int, + MatchEdi: str, + MatchNNSize: int, + MatchNNeurons: int, + MatchEdiQual: int, + MatchEdiMaxD: int, + MatchTR2: int, + MatchEdi2: str, + MatchNNSize2: int, + MatchNNeurons2: int, + MatchEdiQual2: int, + MatchEdiMaxD2: int, + MatchEnhance: float, + TFF: Optional[bool] = None, + nnedi3_args: Mapping[str, Any] = {}, + eedi3_args: Mapping[str, Any] = {}, + opencl: bool = False, + device: Optional[int] = None, +) -> vs.VideoNode: + ''' + Source-match, a three stage process that takes the difference between deinterlaced input and the original interlaced source, to shift the input more towards + the source without introducing shimmer. All other arguments defined in main script + ''' + + # Basic source-match. Find difference between source clip & equivalent fields in interpolated/smoothed clip (called the "error" in formula below). Ideally + # there should be no difference, we want the fields in the output to be as close as possible to the source whilst remaining shimmer-free. So adjust the + # *source* in such a way that smoothing it will give a result closer to the unadjusted source. Then rerun the interpolation (edi) and binomial smooth with + # this new source. Result will still be shimmer-free and closer to the original source. + # Formula used for correction is P0' = P0 + (P0-P1)/(k+S(1-k)), where P0 is original image, P1 is the 1st attempt at interpolation/smoothing , P0' is the + # revised image to use as new source for interpolation/smoothing, k is the weighting given to the current frame in the smooth, and S is a factor indicating + # "temporal similarity" of the error from frame to frame, i.e. S = average over all pixels of [neighbor frame error / current frame error] . Decreasing + # S will make the result sharper, sensible range is about -0.25 to 1.0. Empirically, S=0.5 is effective [will do deeper analysis later] + errorTemporalSimilarity = 0.5 # S in formula described above + errorAdjust1 = [1.0, 2.0 / (1.0 + errorTemporalSimilarity), 8.0 / (3.0 + 5.0 * errorTemporalSimilarity)][MatchTR1] + if SourceMatch < 1 or InputType == 1: + match1Clip = Deinterlace + else: + match1Clip = Weave(Deinterlace.std.SeparateFields(tff=TFF).std.SelectEvery(cycle=4, offsets=[0, 3]), tff=TFF) + if SourceMatch < 1 or MatchTR1 <= 0: + match1Update = Source + else: + match1Update = core.std.Expr([Source, match1Clip], expr=f'x {errorAdjust1 + 1} * y {errorAdjust1} * -') + if SourceMatch > 0: + match1Edi = QTGMC_Interpolate( + match1Update, + InputType, + MatchEdi, + MatchNNSize, + MatchNNeurons, + MatchEdiQual, + MatchEdiMaxD, + TFF=TFF, + nnedi3_args=nnedi3_args, + eedi3_args=eedi3_args, + opencl=opencl, + device=device, + ) + if MatchTR1 > 0: + match1Super = match1Edi.mv.Super(pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad) + match1Degrain1 = core.mv.Degrain1(match1Edi, match1Super, bVec1, fVec1, thsad=ThSAD1, thscd1=ThSCD1, thscd2=ThSCD2) + if MatchTR1 > 1: + match1Degrain2 = core.mv.Degrain1(match1Edi, match1Super, bVec2, fVec2, thsad=ThSAD1, thscd1=ThSCD1, thscd2=ThSCD2) + if SourceMatch < 1: + match1 = Deinterlace + elif MatchTR1 <= 0: + match1 = match1Edi + elif MatchTR1 == 1: + match1 = core.std.Merge(match1Degrain1, match1Edi, weight=0.25) + else: + match1 = core.std.Merge(core.std.Merge(match1Degrain1, match1Degrain2, weight=0.2), match1Edi, weight=0.0625) + + if SourceMatch < 2: + return match1 + + # Enhance effect of source-match stages 2 & 3 by sharpening clip prior to refinement (source-match tends to underestimate so this will leave result sharper) + if SourceMatch > 1 and MatchEnhance > 0: + match1Shp = core.std.Expr([match1, match1.std.Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1])], expr=f'x x y - {MatchEnhance} * +') + else: + match1Shp = match1 + + # Source-match refinement. Find difference between source clip & equivalent fields in (updated) interpolated/smoothed clip. Interpolate & binomially smooth + # this difference then add it back to output. Helps restore differences that the basic match missed. However, as this pass works on a difference rather than + # the source image it can be prone to occasional artefacts (difference images are not ideal for interpolation). In fact a lower quality interpolation such + # as a simple bob often performs nearly as well as advanced, slower methods (e.g. NNEDI3) + if SourceMatch < 2 or InputType == 1: + match2Clip = match1Shp + else: + match2Clip = Weave(match1Shp.std.SeparateFields(tff=TFF).std.SelectEvery(cycle=4, offsets=[0, 3]), tff=TFF) + if SourceMatch > 1: + match2Diff = core.std.MakeDiff(Source, match2Clip) + match2Edi = QTGMC_Interpolate( + match2Diff, + InputType, + MatchEdi2, + MatchNNSize2, + MatchNNeurons2, + MatchEdiQual2, + MatchEdiMaxD2, + TFF=TFF, + nnedi3_args=nnedi3_args, + eedi3_args=eedi3_args, + opencl=opencl, + device=device, + ) + if MatchTR2 > 0: + match2Super = match2Edi.mv.Super(pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad) + match2Degrain1 = core.mv.Degrain1(match2Edi, match2Super, bVec1, fVec1, thsad=ThSAD1, thscd1=ThSCD1, thscd2=ThSCD2) + if MatchTR2 > 1: + match2Degrain2 = core.mv.Degrain1(match2Edi, match2Super, bVec2, fVec2, thsad=ThSAD1, thscd1=ThSCD1, thscd2=ThSCD2) + if SourceMatch < 2: + match2 = match1 + elif MatchTR2 <= 0: + match2 = match2Edi + elif MatchTR2 == 1: + match2 = core.std.Merge(match2Degrain1, match2Edi, weight=0.25) + else: + match2 = core.std.Merge(core.std.Merge(match2Degrain1, match2Degrain2, weight=0.2), match2Edi, weight=0.0625) + + # Source-match second refinement - correct error introduced in the refined difference by temporal smoothing. Similar to error correction from basic step + errorAdjust2 = [1.0, 2.0 / (1.0 + errorTemporalSimilarity), 8.0 / (3.0 + 5.0 * errorTemporalSimilarity)][MatchTR2] + if SourceMatch < 3 or MatchTR2 <= 0: + match3Update = match2Edi + else: + match3Update = core.std.Expr([match2Edi, match2], expr=f'x {errorAdjust2 + 1} * y {errorAdjust2} * -') + if SourceMatch > 2: + if MatchTR2 > 0: + match3Super = match3Update.mv.Super(pel=SubPel, sharp=SubPelInterp, levels=1, hpad=hpad, vpad=vpad) + match3Degrain1 = core.mv.Degrain1(match3Update, match3Super, bVec1, fVec1, thsad=ThSAD1, thscd1=ThSCD1, thscd2=ThSCD2) + if MatchTR2 > 1: + match3Degrain2 = core.mv.Degrain1(match3Update, match3Super, bVec2, fVec2, thsad=ThSAD1, thscd1=ThSCD1, thscd2=ThSCD2) + if SourceMatch < 3: + match3 = match2 + elif MatchTR2 <= 0: + match3 = match3Update + elif MatchTR2 == 1: + match3 = core.std.Merge(match3Degrain1, match3Update, weight=0.25) + else: + match3 = core.std.Merge(core.std.Merge(match3Degrain1, match3Degrain2, weight=0.2), match3Update, weight=0.0625) + + # Apply difference calculated in source-match refinement + return core.std.MergeDiff(match1Shp, match3) + + +def QTGMC_SetUserGlobal(Prefix: str, Name: str, Value: Union[vs.VideoNode, None]) -> None: + '''Set global variable called "Prefix_Name" to "Value".''' + global QTGMC_globals + QTGMC_globals[f'{Prefix}_{Name}'] = Value + + +def QTGMC_GetUserGlobal(Prefix: str, Name: str) -> Union[vs.VideoNode, None]: + '''Return value of global variable called "Prefix_Name". Returns None if it doesn't exist''' + global QTGMC_globals + return QTGMC_globals.get(f'{Prefix}_{Name}') + + +def smartfademod(clip: vs.VideoNode, threshold: float = 0.4, show: bool = False, tff: Optional[bool] = None) -> vs.VideoNode: + ''' + Aimed at removing interlaced fades in anime. Uses luma difference between two fields as activation threshold. + + Parameters: + clip: Clip to process. + + threshold: Threshold for fade detection. + + show: Displays luma difference between fields without processing anything. + + tff: Since VapourSynth only has a weak notion of field order internally, tff may have to be set. Setting tff to true means top field first and false + means bottom field first. Note that the _FieldBased frame property, if present, takes precedence over tff. + ''' + + def frame_eval(n: int, f: Sequence[vs.VideoFrame], orig: vs.VideoNode, defade: vs.VideoNode) -> vs.VideoNode: + diff = abs(f[0].props['PlaneStatsAverage'] - f[1].props['PlaneStatsAverage']) * 255 + if show: + return orig.text.Text(text=diff) + return defade if diff > threshold else orig + + if not isinstance(clip, vs.VideoNode): + raise vs.Error('smartfademod: this is not a clip') + + if tff is None: + with clip.get_frame(0) as f: + if f.props.get('_FieldBased') not in [1, 2]: + raise vs.Error('smartfademod: tff was not specified and field order could not be determined from frame properties') + + sep = clip.std.SeparateFields(tff=tff) + even = sep[::2].std.PlaneStats() + odd = sep[1::2].std.PlaneStats() + defade = daa(clip) + return clip.std.FrameEval(eval=partial(frame_eval, orig=clip, defade=defade), prop_src=[even, odd], clip_src=[clip, defade]) + + +###### srestore v2.7e ###### +def srestore(source, frate=None, omode=6, speed=None, mode=2, thresh=16, dclip=None): + if not isinstance(source, vs.VideoNode): + raise vs.Error('srestore: this is not a clip') + + if source.format.color_family != vs.YUV: + raise vs.Error('srestore: only YUV format is supported') + + if dclip is None: + dclip = source + elif not isinstance(dclip, vs.VideoNode): + raise vs.Error("srestore: 'dclip' is not a clip") + elif dclip.format.color_family != vs.YUV: + raise vs.Error('srestore: only YUV format is supported') + + neutral = 1 << (source.format.bits_per_sample - 1) + peak = (1 << source.format.bits_per_sample) - 1 + + ###### parameters & other necessary vars ###### + srad = math.sqrt(abs(speed)) * 4 if speed is not None and abs(speed) >= 1 else 12 + irate = source.fps_num / source.fps_den + bsize = 16 if speed is not None and speed > 0 else 32 + bom = isinstance(omode, str) + thr = abs(thresh) + 0.01 + + if bom or abs(omode - 3) < 2.5: + frfac = 1 + elif frate is not None: + if frate * 5 < irate or frate > irate: + frfac = 1 + else: + frfac = abs(frate) / irate + elif cround(irate * 10010) % 30000 == 0: + frfac = 1001 / 2400 + else: + frfac = 480 / 1001 + + if abs(frfac * 1001 - cround(frfac * 1001)) < 0.01: + numr = cround(frfac * 1001) + elif abs(1001 / frfac - cround(1001 / frfac)) < 0.01: + numr = 1001 + else: + numr = cround(frfac * 9000) + if frate is not None and abs(irate * numr / cround(numr / frfac) - frate) > abs(irate * cround(frate * 100) / cround(irate * 100) - frate): + numr = cround(frate * 100) + denm = cround(numr / frfac) + + ###### source preparation & lut ###### + if abs(mode) >= 2 and not bom: + mec = core.std.Merge(core.std.Merge(source, source.std.Trim(first=1), weight=[0, 0.5]), source.std.Trim(first=1), weight=[0.5, 0]) + + if dclip.format.id != vs.YUV420P8: + dclip = dclip.resize.Bicubic(format=vs.YUV420P8) + dclip = dclip.resize.Point(dclip.width if srad == 4 else int(dclip.width / 2 / srad + 4) * 4, dclip.height if srad == 4 else int(dclip.height / 2 / srad + 4) * 4).std.Trim(first=2) + if mode < 0: + dclip = core.std.StackVertical([core.std.StackHorizontal([mvf.GetPlane(dclip, 1), mvf.GetPlane(dclip, 2)]), mvf.GetPlane(dclip, 0)]) + else: + dclip = mvf.GetPlane(dclip, 0) + if bom: + dclip = dclip.std.Expr(expr=['x 0.5 * 64 +']) + + expr1 = 'x 128 - y 128 - * 0 > x 128 - abs y 128 - abs < x 128 - 128 x - * y 128 - 128 y - * ? x y + 256 - dup * ? 0.25 * 128 +' + expr2 = 'x y - dup * 3 * x y + 256 - dup * - 128 +' + diff = core.std.MakeDiff(dclip, dclip.std.Trim(first=1)) + if not bom: + bclp = core.std.Expr([diff, diff.std.Trim(first=1)], expr=[expr1]).resize.Bilinear(bsize, bsize) + else: + bclp = core.std.Expr([diff.std.Trim(first=1), core.std.MergeDiff(diff, diff.std.Trim(first=2))], expr=[expr2]).resize.Bilinear(bsize, bsize) + dclp = diff.std.Trim(first=1).std.Lut(function=lambda x: max(cround(abs(x - 128) ** 1.1 - 1), 0)).resize.Bilinear(bsize, bsize) + + ###### postprocessing ###### + if bom: + sourceDuplicate = source.std.DuplicateFrames(frames=[0]) + sourceTrim1 = source.std.Trim(first=1) + sourceTrim2 = source.std.Trim(first=2) + + unblend1 = core.std.Expr([sourceDuplicate, source], expr=['y 2 * x -']) + unblend2 = core.std.Expr([sourceTrim1, sourceTrim2], expr=['x 2 * y -']) + + qmask1 = core.std.MakeDiff(unblend1.std.Convolution(matrix=[1, 1, 1, 1, 0, 1, 1, 1, 1], planes=[0]), unblend1, planes=[0]) + qmask2 = core.std.MakeDiff(unblend2.std.Convolution(matrix=[1, 1, 1, 1, 0, 1, 1, 1, 1], planes=[0]), unblend2, planes=[0]) + diffm = core.std.MakeDiff(sourceDuplicate, source, planes=[0]).std.Maximum(planes=[0]) + bmask = core.std.Expr([qmask1, qmask2], expr=[f'x {neutral} - dup * dup y {neutral} - dup * + / {peak} *', '']) + expr = 'x 2 * y < x {i} < and 0 y 2 * x < y {i} < and {peak} x x y + / {j} * {k} + ? ?'.format(i=scale(4, peak), peak=peak, j=scale(200, peak), k=scale(28, peak)) + dmask = core.std.Expr([diffm, diffm.std.Trim(first=2)], expr=[expr, '']) + pmask = core.std.Expr([dmask, bmask], expr=[f'y 0 > y {peak} < and x 0 = x {peak} = or and x y ?', '']) + + matrix = [1, 2, 1, 2, 4, 2, 1, 2, 1] + + omode = omode.lower() + if omode == 'pp0': + fin = core.std.Expr([sourceDuplicate, source, sourceTrim1, sourceTrim2], expr=['y x 2 / - z a 2 / - +']) + elif omode == 'pp1': + fin = core.std.MaskedMerge(unblend1, unblend2, dmask.std.Convolution(matrix=matrix, planes=[0]).std.Expr(expr=['', repr(neutral)])) + elif omode == 'pp2': + fin = core.std.MaskedMerge(unblend1, unblend2, bmask.std.Convolution(matrix=matrix, planes=[0]), first_plane=True) + elif omode == 'pp3': + fin = core.std.MaskedMerge(unblend1, unblend2, pmask.std.Convolution(matrix=matrix, planes=[0]), first_plane=True).std.Convolution(matrix=matrix, planes=[1, 2]) + else: + raise vs.Error('srestore: unexpected value for omode') + + ###### initialise variables ###### + lfr = -100 + offs = 0 + ldet = -100 + lpos = 0 + d32 = d21 = d10 = d01 = d12 = d23 = d34 = None + m42 = m31 = m20 = m11 = m02 = m13 = m24 = None + bp2 = bp1 = bn0 = bn1 = bn2 = bn3 = None + cp2 = cp1 = cn0 = cn1 = cn2 = cn3 = None + + def srestore_inside(n, f): + nonlocal lfr, offs, ldet, lpos, d32, d21, d10, d01, d12, d23, d34, m42, m31, m20, m11, m02, m13, m24, bp2, bp1, bn0, bn1, bn2, bn3, cp2, cp1, cn0, cn1, cn2, cn3 + + ### preparation ### + jmp = lfr + 1 == n + cfo = ((n % denm) * numr * 2 + denm + numr) % (2 * denm) - denm + bfo = cfo > -numr and cfo <= numr + lfr = n + offs = offs + 2 * denm if bfo and offs <= -4 * numr else offs - 2 * denm if bfo and offs >= 4 * numr else offs + pos = 0 if frfac == 1 else -cround((cfo + offs) / (2 * numr)) if bfo else lpos + cof = cfo + offs + 2 * numr * pos + ldet = -1 if n + pos == ldet else n + pos + + ### diff value shifting ### + d_v = f[1].props['PlaneStatsMax'] + 0.015625 + if jmp: + d43 = d32 + d32 = d21 + d21 = d10 + d10 = d01 + d01 = d12 + d12 = d23 + d23 = d34 + else: + d43 = d32 = d21 = d10 = d01 = d12 = d23 = d_v + d34 = d_v + + m_v = f[2].props['PlaneStatsDiff'] * 255 + 0.015625 if not bom and abs(omode) > 5 else 1 + if jmp: + m53 = m42 + m42 = m31 + m31 = m20 + m20 = m11 + m11 = m02 + m02 = m13 + m13 = m24 + else: + m53 = m42 = m31 = m20 = m11 = m02 = m13 = m_v + m24 = m_v + + ### get blend and clear values ### + b_v = 128 - f[0].props['PlaneStatsMin'] + if b_v < 1: + b_v = 0.125 + c_v = f[0].props['PlaneStatsMax'] - 128 + if c_v < 1: + c_v = 0.125 + + ### blend value shifting ### + if jmp: + bp3 = bp2 + bp2 = bp1 + bp1 = bn0 + bn0 = bn1 + bn1 = bn2 + bn2 = bn3 + else: + bp3 = b_v - c_v if bom else b_v + bp2 = bp1 = bn0 = bn1 = bn2 = bp3 + bn3 = b_v - c_v if bom else b_v + + ### clear value shifting ### + if jmp: + cp3 = cp2 + cp2 = cp1 + cp1 = cn0 + cn0 = cn1 + cn1 = cn2 + cn2 = cn3 + else: + cp3 = cp2 = cp1 = cn0 = cn1 = cn2 = c_v + cn3 = c_v + + ### used detection values ### + bb = [bp3, bp2, bp1, bn0, bn1][pos + 2] + bc = [bp2, bp1, bn0, bn1, bn2][pos + 2] + bn = [bp1, bn0, bn1, bn2, bn3][pos + 2] + + cb = [cp3, cp2, cp1, cn0, cn1][pos + 2] + cc = [cp2, cp1, cn0, cn1, cn2][pos + 2] + cn = [cp1, cn0, cn1, cn2, cn3][pos + 2] + + dbb = [d43, d32, d21, d10, d01][pos + 2] + dbc = [d32, d21, d10, d01, d12][pos + 2] + dcn = [d21, d10, d01, d12, d23][pos + 2] + dnn = [d10, d01, d12, d23, d34][pos + 2] + dn2 = [d01, d12, d23, d34, d34][pos + 2] + + mb1 = [m53, m42, m31, m20, m11][pos + 2] + mb = [m42, m31, m20, m11, m02][pos + 2] + mc = [m31, m20, m11, m02, m13][pos + 2] + mn = [m20, m11, m02, m13, m24][pos + 2] + mn1 = [m11, m02, m13, m24, 0.01][pos + 2] + + ### basic calculation ### + bbool = 0.8 * bc * cb > bb * cc and 0.8 * bc * cn > bn * cc and bc * bc > cc + blend = bbool and bc * 5 > cc and dbc + dcn > 1.5 * thr and (dbb < 7 * dbc or dbb < 8 * dcn) and (dnn < 8 * dcn or dnn < 7 * dbc) and (mb < mb1 and mb < mc or mn < mn1 and mn < mc or (dbb + dnn) * 4 < dbc + dcn or (bb * cc * 5 < bc * cb or mb > thr) and (bn * cc * 5 < bc * cn or mn > thr) and bc > thr) + clear = dbb + dbc > thr and dcn + dnn > thr and (bc < 2 * bb or bc < 2 * bn) and (dbb + dnn) * 2 > dbc + dcn and (mc < 0.96 * mb and mc < 0.96 * mn and (bb * 2 > cb or bn * 2 > cn) and cc > cb and cc > cn or frfac > 0.45 and frfac < 0.55 and 0.8 * mc > mb1 and 0.8 * mc > mn1 and mb > 0.8 * mn and mn > 0.8 * mb) + highd = dcn > 5 * dbc and dcn > 5 * dnn and dcn > thr and dbc < thr and dnn < thr + lowd = dcn * 5 < dbc and dcn * 5 < dnn and dbc > thr and dnn > thr and dcn < thr and frfac > 0.35 and (frfac < 0.51 or dcn * 5 < dbb) + res = d43 < thr and d32 < thr and d21 < thr and d10 < thr and d01 < thr and d12 < thr and d23 < thr and d34 < thr or dbc * 4 < dbb and dcn * 4 < dbb and dnn * 4 < dbb and dn2 * 4 < dbb or dcn * 4 < dbc and dnn * 4 < dbc and dn2 * 4 < dbc + + ### offset calculation ### + if blend: + odm = denm + elif clear: + odm = 0 + elif highd: + odm = denm - numr + elif lowd: + odm = 2 * denm - numr + else: + odm = cof + odm += cround((cof - odm) / (2 * denm)) * 2 * denm + + if blend: + odr = denm - numr + elif clear or highd: + odr = numr + elif frfac < 0.5: + odr = 2 * numr + else: + odr = 2 * (denm - numr) + odr *= 0.9 + + if ldet >= 0: + if cof > odm + odr: + if cof - offs - odm - odr > denm and res: + cof = odm + 2 * denm - odr + else: + cof = odm + odr + elif cof < odm - odr: + if offs > denm and res: + cof = odm - 2 * denm + odr + else: + cof = odm - odr + elif offs < -1.15 * denm and res: + cof += 2 * denm + elif offs > 1.25 * denm and res: + cof -= 2 * denm + + offs = 0 if frfac == 1 else cof - cfo - 2 * numr * pos + lpos = pos + opos = 0 if frfac == 1 else -cround((cfo + offs + (denm if bfo and offs <= -4 * numr else 0)) / (2 * numr)) + pos = min(max(opos, -2), 2) + + ### frame output calculation - resync - dup ### + dbb = [d43, d32, d21, d10, d01][pos + 2] + dbc = [d32, d21, d10, d01, d12][pos + 2] + dcn = [d21, d10, d01, d12, d23][pos + 2] + dnn = [d10, d01, d12, d23, d34][pos + 2] + + ### dup_hq - merge ### + if opos != pos or abs(mode) < 2 or abs(mode) == 3: + dup = 0 + elif dcn * 5 < dbc and dnn * 5 < dbc and (dcn < 1.25 * thr or bn < bc and pos == lpos) or (dcn * dcn < dbc or dcn * 5 < dbc) and bn < bc and pos == lpos and dnn < 0.9 * dbc or dnn * 9 < dbc and dcn * 3 < dbc: + dup = 1 + elif (dbc * dbc < dcn or dbc * 5 < dcn) and bb < bc and pos == lpos and dbb < 0.9 * dcn or dbb * 9 < dcn and dbc * 3 < dcn or dbb * 5 < dcn and dbc * 5 < dcn and (dbc < 1.25 * thr or bb < bc and pos == lpos): + dup = -1 + else: + dup = 0 + mer = not bom and opos == pos and dup == 0 and abs(mode) > 2 and (dbc * 8 < dcn or dbc * 8 < dbb or dcn * 8 < dbc or dcn * 8 < dnn or dbc * 2 < thr or dcn * 2 < thr or dnn * 9 < dbc and dcn * 3 < dbc or dbb * 9 < dcn and dbc * 3 < dcn) + + ### deblend - doubleblend removal - postprocessing ### + add = bp1 * cn2 > bn2 * cp1 * (1 + thr * 0.01) and bn0 * cn2 > bn2 * cn0 * (1 + thr * 0.01) and cn2 * bn1 > cn1 * bn2 * (1 + thr * 0.01) + if bom: + if bn0 > bp2 and bn0 >= bp1 and bn0 > bn1 and bn0 > bn2 and cn0 < 125: + if d12 * d12 < d10 or d12 * 9 < d10: + dup = 1 + elif d10 * d10 < d12 or d10 * 9 < d12: + dup = 0 + else: + dup = 4 + elif bp1 > bp3 and bp1 >= bp2 and bp1 > bn0 and bp1 > bn1: + dup = 1 + else: + dup = 0 + elif dup == 0: + if omode > 0 and omode < 5: + if not bbool: + dup = 0 + elif omode == 4 and bp1 * cn1 < bn1 * cp1 or omode == 3 and d10 < d01 or omode == 1: + dup = -1 + else: + dup = 1 + elif omode == 5: + if bp1 * cp2 > bp2 * cp1 * (1 + thr * 0.01) and bn0 * cp2 > bp2 * cn0 * (1 + thr * 0.01) and cp2 * bn1 > cn1 * bp2 * (1 + thr * 0.01) and (not add or cp2 * bn2 > cn2 * bp2): + dup = -2 + elif add: + dup = 2 + elif bn0 * cp1 > bp1 * cn0 and (bn0 * cn1 < bn1 * cn0 or cp1 * bn1 > cn1 * bp1): + dup = -1 + elif bn0 * cn1 > bn1 * cn0: + dup = 1 + else: + dup = 0 + else: + dup = 0 + + ### output clip ### + if dup == 4: + return fin + else: + oclp = mec if mer and dup == 0 else source + opos += dup - (1 if dup == 0 and mer and dbc < dcn else 0) + if opos < 0: + return oclp.std.DuplicateFrames(frames=[0] * -opos) + else: + return oclp.std.Trim(first=opos) + + ###### evaluation call & output calculation ###### + bclpYStats = bclp.std.PlaneStats() + dclpYStats = dclp.std.PlaneStats() + dclipYStats = core.std.PlaneStats(dclip, dclip.std.Trim(first=2)) + last = source.std.FrameEval(eval=srestore_inside, prop_src=[bclpYStats, dclpYStats, dclipYStats]) + + ###### final decimation ###### + return ChangeFPS(last.std.Cache(make_linear=True), source.fps_num * numr, source.fps_den * denm) + + +# frame_ref = start of AABCD pattern +def dec_txt60mc(src, frame_ref, srcbob=False, draft=False, tff=None, opencl=False, device=None): + if not isinstance(src, vs.VideoNode): + raise vs.Error('dec_txt60mc: this is not a clip') + + if not (srcbob or isinstance(tff, bool)): + raise vs.Error("dec_txt60mc: 'tff' must be set when srcbob=False. Setting tff to true means top field first and false means bottom field first") + + field_ref = frame_ref if srcbob else frame_ref * 2 + field_ref %= 5 + invpos = (5 - field_ref) % 5 + pel = 1 if draft else 2 + blksize = 16 if src.width > 1024 or src.height > 576 else 8 + overlap = blksize // 2 + + if srcbob: + last = src + elif draft: + last = src.resize.Bob(tff=tff, filter_param_a=1 / 3, filter_param_b=1 / 3) + else: + last = QTGMC(src, TR0=1, TR1=1, TR2=1, SourceMatch=3, Lossless=2, TFF=tff, opencl=opencl, device=device) + + clean = last.std.SelectEvery(cycle=5, offsets=[4 - invpos]) + if invpos > 2: + jitter = core.std.AssumeFPS(last.std.Trim(length=1) * 2 + last.std.SelectEvery(cycle=5, offsets=[6 - invpos, 7 - invpos]), fpsnum=24000, fpsden=1001) + elif invpos > 1: + jitter = core.std.AssumeFPS(last.std.Trim(length=1) + last.std.SelectEvery(cycle=5, offsets=[2 - invpos, 6 - invpos]), fpsnum=24000, fpsden=1001) + else: + jitter = last.std.SelectEvery(cycle=5, offsets=[1 - invpos, 2 - invpos]) + jsup_pre = DitherLumaRebuild(jitter, s0=1).mv.Super(pel=pel) + jsup = jitter.mv.Super(pel=pel, levels=1) + vect_f = jsup_pre.mv.Analyse(blksize=blksize, isb=False, delta=1, overlap=overlap) + vect_b = jsup_pre.mv.Analyse(blksize=blksize, isb=True, delta=1, overlap=overlap) + comp = core.mv.FlowInter(jitter, jsup, vect_b, vect_f) + fixed = comp[::2] + last = core.std.Interleave([fixed, clean]) + return last.std.Trim(first=invpos // 3) + + +# 30pテロ部を24pに変換して返す +def ivtc_txt30mc(src, frame_ref, draft=False, tff=None, opencl=False, device=None): + if not isinstance(src, vs.VideoNode): + raise vs.Error('ivtc_txt30mc: this is not a clip') + + if not isinstance(tff, bool): + raise vs.Error("ivtc_txt30mc: 'tff' must be set. Setting tff to true means top field first and false means bottom field first") + + frame_ref %= 5 + offset = [0, 0, -1, 1, 1][frame_ref] + pattern = [0, 1, 0, 0, 1][frame_ref] + direction = [-1, -1, 1, 1, 1][frame_ref] + pel = 1 if draft else 2 + blksize = 16 if src.width > 1024 or src.height > 576 else 8 + overlap = blksize // 2 + + if draft: + last = src.resize.Bob(tff=tff, filter_param_a=1 / 3, filter_param_b=1 / 3) + else: + last = QTGMC(src, TR0=1, TR1=1, TR2=1, SourceMatch=3, Lossless=2, TFF=tff, opencl=opencl, device=device) + + if pattern == 0: + if offset == -1: + c1 = core.std.AssumeFPS(last.std.Trim(length=1) + last.std.SelectEvery(cycle=10, offsets=[2 + offset, 7 + offset, 5 + offset, 10 + offset]), fpsnum=24000, fpsden=1001) + else: + c1 = last.std.SelectEvery(cycle=10, offsets=[offset, 2 + offset, 7 + offset, 5 + offset]) + if offset == 1: + part1 = last.std.SelectEvery(cycle=10, offsets=[4]) + part2 = last.std.SelectEvery(cycle=10, offsets=[5]) + part3 = last.std.Trim(first=10).std.SelectEvery(cycle=10, offsets=[0]) + part4 = last.std.SelectEvery(cycle=10, offsets=[9]) + c2 = core.std.Interleave([part1, part2, part3, part4]) + else: + c2 = last.std.SelectEvery(cycle=10, offsets=[3 + offset, 4 + offset, 9 + offset, 8 + offset]) + else: + if offset == 1: + part1 = last.std.SelectEvery(cycle=10, offsets=[3]) + part2 = last.std.SelectEvery(cycle=10, offsets=[5]) + part3 = last.std.Trim(first=10).std.SelectEvery(cycle=10, offsets=[0]) + part4 = last.std.SelectEvery(cycle=10, offsets=[8]) + c1 = core.std.Interleave([part1, part2, part3, part4]) + else: + c1 = last.std.SelectEvery(cycle=10, offsets=[2 + offset, 4 + offset, 9 + offset, 7 + offset]) + if offset == -1: + c2 = core.std.AssumeFPS(last.std.Trim(length=1) + last.std.SelectEvery(cycle=10, offsets=[1 + offset, 6 + offset, 5 + offset, 10 + offset]), fpsnum=24000, fpsden=1001) + else: + c2 = last.std.SelectEvery(cycle=10, offsets=[offset, 1 + offset, 6 + offset, 5 + offset]) + + super1_pre = DitherLumaRebuild(c1, s0=1).mv.Super(pel=pel) + super1 = c1.mv.Super(pel=pel, levels=1) + vect_f1 = super1_pre.mv.Analyse(blksize=blksize, isb=False, delta=1, overlap=overlap) + vect_b1 = super1_pre.mv.Analyse(blksize=blksize, isb=True, delta=1, overlap=overlap) + fix1 = core.mv.FlowInter(c1, super1, vect_b1, vect_f1, time=50 + direction * 25).std.SelectEvery(cycle=4, offsets=[0, 2]) + + super2_pre = DitherLumaRebuild(c2, s0=1).mv.Super(pel=pel) + super2 = c2.mv.Super(pel=pel, levels=1) + vect_f2 = super2_pre.mv.Analyse(blksize=blksize, isb=False, delta=1, overlap=overlap) + vect_b2 = super2_pre.mv.Analyse(blksize=blksize, isb=True, delta=1, overlap=overlap) + fix2 = core.mv.FlowInter(c2, super2, vect_b2, vect_f2).std.SelectEvery(cycle=4, offsets=[0, 2]) + + if pattern == 0: + return core.std.Interleave([fix1, fix2]) + else: + return core.std.Interleave([fix2, fix1]) + + +# Version 1.1 +# frame_ref = start of clean-combed-combed-clean-clean pattern +def ivtc_txt60mc(src, frame_ref, srcbob=False, draft=False, tff=None, opencl=False, device=None): + if not isinstance(src, vs.VideoNode): + raise vs.Error('ivtc_txt60mc: this is not a clip') + + if not (srcbob or isinstance(tff, bool)): + raise vs.Error("ivtc_txt60mc: 'tff' must be set when srcbob=False. Setting tff to true means top field first and false means bottom field first") + + field_ref = frame_ref if srcbob else frame_ref * 2 + field_ref %= 5 + invpos = (5 - field_ref) % 5 + pel = 1 if draft else 2 + blksize = 16 if src.width > 1024 or src.height > 576 else 8 + overlap = blksize // 2 + + if srcbob: + last = src + elif draft: + last = src.resize.Bob(tff=tff, filter_param_a=1 / 3, filter_param_b=1 / 3) + else: + last = QTGMC(src, TR0=1, TR1=1, TR2=1, SourceMatch=3, Lossless=2, TFF=tff, opencl=opencl, device=device) + + if invpos > 1: + clean = core.std.AssumeFPS(last.std.Trim(length=1) + last.std.SelectEvery(cycle=5, offsets=[6 - invpos]), fpsnum=12000, fpsden=1001) + else: + clean = last.std.SelectEvery(cycle=5, offsets=[1 - invpos]) + if invpos > 3: + jitter = core.std.AssumeFPS(last.std.Trim(length=1) + last.std.SelectEvery(cycle=5, offsets=[4 - invpos, 8 - invpos]), fpsnum=24000, fpsden=1001) + else: + jitter = last.std.SelectEvery(cycle=5, offsets=[3 - invpos, 4 - invpos]) + jsup_pre = DitherLumaRebuild(jitter, s0=1).mv.Super(pel=pel) + jsup = jitter.mv.Super(pel=pel, levels=1) + vect_f = jsup_pre.mv.Analyse(blksize=blksize, isb=False, delta=1, overlap=overlap) + vect_b = jsup_pre.mv.Analyse(blksize=blksize, isb=True, delta=1, overlap=overlap) + comp = core.mv.FlowInter(jitter, jsup, vect_b, vect_f) + fixed = comp[::2] + last = core.std.Interleave([clean, fixed]) + return last.std.Trim(first=invpos // 2) + + +################################################# +### ### +### logoNR ### +### ### +### by 06_taro - astrataro@gmail.com ### +### ### +### v0.1 - 22 March 2012 ### +### ### +################################################# +### +### Post-denoise filter of EraseLogo. +### Only process logo areas in logo frames, even if l/t/r/b are not set. Non-logo areas are left untouched. +### +### +### +---------+ +### | USAGE | +### +---------+ +### +### dlg [clip] +### ------------------ +### Clip after delogo. +### +### src [clip] +### ------------------ +### Clip before delogo. +### +### chroma [bool, default: True] +### ------------------ +### Process chroma plane or not. +### +### l/t/r/b [int, default: 0] +### ------------------ +### left/top/right/bottom pixels to be cropped for logo area. +### Have the same restriction as Crop, e.g., no odd value for YV12. +### logoNR only filters the logo areas in logo frames, no matter l/t/r/b are set or not. +### So if you have other heavy filters running in a pipeline and don't care much about the speed of logoNR, +### it is safe to left these values unset. +### Setting these values only makes logoNR run faster, with rarely noticeable difference in result, +### unless you set wrong values and the logo is not covered in your cropped target area. +### +### d/a/s/h [int, default: 1/2/2/3] +### ------------------ +### The same parameters of KNLMeansCL. +### +### +----------------+ +### | REQUIREMENTS | +### +----------------+ +### +### -> KNLMeansCL +### -> RGVS +def logoNR(dlg, src, chroma=True, l=0, t=0, r=0, b=0, d=1, a=2, s=2, h=3): + if not (isinstance(dlg, vs.VideoNode) and isinstance(src, vs.VideoNode)): + raise vs.Error('logoNR: this is not a clip') + + if dlg.format.id != src.format.id: + raise vs.Error('logoNR: clips must have the same format') + + if dlg.format.color_family == vs.GRAY: + chroma = False + + if not chroma and dlg.format.color_family != vs.GRAY: + dlg_orig = dlg + dlg = mvf.GetPlane(dlg, 0) + src = mvf.GetPlane(src, 0) + else: + dlg_orig = None + + b_crop = (l != 0) or (t != 0) or (r != 0) or (b != 0) + if b_crop: + src = src.std.Crop(left=l, right=r, top=t, bottom=b) + last = dlg.std.Crop(left=l, right=r, top=t, bottom=b) + else: + last = dlg + + if chroma: + clp_nr = KNLMeansCL(last, d=d, a=a, s=s, h=h) + else: + clp_nr = last.knlm.KNLMeansCL(d=d, a=a, s=s, h=h) + logoM = mt_expand_multi(core.std.Expr([last, src], expr=['x y - abs 16 *']), mode='losange', sw=3, sh=3).std.Convolution(matrix=[1, 1, 1, 1, 0, 1, 1, 1, 1]).std.Deflate() + clp_nr = core.std.MaskedMerge(last, clp_nr, logoM) + if b_crop: + clp_nr = Overlay(dlg, clp_nr, x=l, y=t) + + if dlg_orig is not None: + clp_nr = core.std.ShufflePlanes([clp_nr, dlg_orig], planes=[0, 1, 2], colorfamily=dlg_orig.format.color_family) + return clp_nr + + +# Vinverse: a small, but effective function against (residual) combing, by Didée +# sstr: strength of contra sharpening +# amnt: change no pixel by more than this (default=255: unrestricted) +# chroma: chroma mode, True=process chroma, False=pass chroma through +# scl: scale factor for vshrpD*vblurD < 0 +def Vinverse(clp, sstr=2.7, amnt=255, chroma=True, scl=0.25): + if not isinstance(clp, vs.VideoNode): + raise vs.Error('Vinverse: this is not a clip') + + if clp.format.sample_type == vs.INTEGER: + neutral = 1 << (clp.format.bits_per_sample - 1) + peak = (1 << clp.format.bits_per_sample) - 1 + else: + neutral = 0.0 + peak = 1.0 + + if not chroma and clp.format.color_family != vs.GRAY: + clp_orig = clp + clp = mvf.GetPlane(clp, 0) + else: + clp_orig = None + + vblur = clp.std.Convolution(matrix=[50, 99, 50], mode='v') + vblurD = core.std.MakeDiff(clp, vblur) + vshrp = core.std.Expr([vblur, vblur.std.Convolution(matrix=[1, 4, 6, 4, 1], mode='v')], expr=[f'x x y - {sstr} * +']) + vshrpD = core.std.MakeDiff(vshrp, vblur) + expr = f'x {neutral} - y {neutral} - * 0 < x {neutral} - abs y {neutral} - abs < x y ? {neutral} - {scl} * {neutral} + x {neutral} - abs y {neutral} - abs < x y ? ?' + vlimD = core.std.Expr([vshrpD, vblurD], expr=[expr]) + last = core.std.MergeDiff(vblur, vlimD) + if amnt <= 0: + return clp + elif amnt < 255: + last = core.std.Expr([clp, last], expr=['x {AMN} + y < x {AMN} + x {AMN} - y > x {AMN} - y ? ?'.format(AMN=scale(amnt, peak))]) + + if clp_orig is not None: + last = core.std.ShufflePlanes([last, clp_orig], planes=[0, 1, 2], colorfamily=clp_orig.format.color_family) + return last + + +def Vinverse2(clp, sstr=2.7, amnt=255, chroma=True, scl=0.25): + if not isinstance(clp, vs.VideoNode): + raise vs.Error('Vinverse2: this is not a clip') + + if clp.format.sample_type == vs.INTEGER: + neutral = 1 << (clp.format.bits_per_sample - 1) + peak = (1 << clp.format.bits_per_sample) - 1 + else: + neutral = 0.0 + peak = 1.0 + + if not chroma and clp.format.color_family != vs.GRAY: + clp_orig = clp + clp = mvf.GetPlane(clp, 0) + else: + clp_orig = None + + vblur = sbrV(clp) + vblurD = core.std.MakeDiff(clp, vblur) + vshrp = core.std.Expr([vblur, vblur.std.Convolution(matrix=[1, 2, 1], mode='v')], expr=[f'x x y - {sstr} * +']) + vshrpD = core.std.MakeDiff(vshrp, vblur) + expr = f'x {neutral} - y {neutral} - * 0 < x {neutral} - abs y {neutral} - abs < x y ? {neutral} - {scl} * {neutral} + x {neutral} - abs y {neutral} - abs < x y ? ?' + vlimD = core.std.Expr([vshrpD, vblurD], expr=[expr]) + last = core.std.MergeDiff(vblur, vlimD) + if amnt <= 0: + return clp + elif amnt < 255: + last = core.std.Expr([clp, last], expr=['x {AMN} + y < x {AMN} + x {AMN} - y > x {AMN} - y ? ?'.format(AMN=scale(amnt, peak))]) + + if clp_orig is not None: + last = core.std.ShufflePlanes([last, clp_orig], planes=[0, 1, 2], colorfamily=clp_orig.format.color_family) + return last + + +######################################################## +# # +# LUTDeCrawl, a dot crawl removal script by Scintilla # +# Created 10/3/08 # +# Last updated 10/3/08 # +# # +######################################################## +# +# Requires YUV input, frame-based only. +# Is of average speed (faster than VagueDenoiser, slower than HQDN3D). +# Suggestions for improvement welcome: scintilla@aquilinestudios.org +# +# Arguments: +# +# ythresh (int, default=10) - This determines how close the luma values of the +# pixel in the previous and next frames have to be for the pixel to +# be hit. Higher values (within reason) should catch more dot crawl, +# but may introduce unwanted artifacts. Probably shouldn't be set +# above 20 or so. +# +# cthresh (int, default=10) - This determines how close the chroma values of the +# pixel in the previous and next frames have to be for the pixel to +# be hit. Just as with ythresh. +# +# maxdiff (int, default=50) - This is the maximum difference allowed between the +# luma values of the pixel in the CURRENT frame and in each of its +# neighbour frames (so, the upper limit to what fluctuations are +# considered dot crawl). Lower values will reduce artifacts but may +# cause the filter to miss some dot crawl. Obviously, this should +# never be lower than ythresh. Meaningless if usemaxdiff = false. +# +# scnchg (int, default=25) - Scene change detection threshold. Any frame with +# total luma difference between it and the previous/next frame greater +# than this value will not be processed. +# +# usemaxdiff (bool, default=True) - Whether or not to reject luma fluctuations +# higher than maxdiff. Setting this to false is not recommended, as +# it may introduce artifacts; but on the other hand, it produces a +# 30% speed boost. Test on your particular source. +# +# mask (bool, default=False) - When set true, the function will return the mask +# instead of the image. Use to find the best values of cthresh, +# ythresh, and maxdiff. +# (The scene change threshold, scnchg, is not reflected in the mask.) +# +################### +def LUTDeCrawl(input, ythresh=10, cthresh=10, maxdiff=50, scnchg=25, usemaxdiff=True, mask=False): + def YDifferenceFromPrevious(n, f, clips): + if f.props['_SceneChangePrev']: + return clips[0] + else: + return clips[1] + + def YDifferenceToNext(n, f, clips): + if f.props['_SceneChangeNext']: + return clips[0] + else: + return clips[1] + + if not isinstance(input, vs.VideoNode) or input.format.color_family != vs.YUV or input.format.bits_per_sample > 10: + raise vs.Error('LUTDeCrawl: This is not an 8-10 bit YUV clip') + + shift = input.format.bits_per_sample - 8 + peak = (1 << input.format.bits_per_sample) - 1 + + ythresh = scale(ythresh, peak) + cthresh = scale(cthresh, peak) + maxdiff = scale(maxdiff, peak) + + input_minus = input.std.DuplicateFrames(frames=[0]) + input_plus = input.std.Trim(first=1) + input.std.Trim(first=input.num_frames - 1) + + input_y = mvf.GetPlane(input, 0) + input_minus_y = mvf.GetPlane(input_minus, 0) + input_minus_u = mvf.GetPlane(input_minus, 1) + input_minus_v = mvf.GetPlane(input_minus, 2) + input_plus_y = mvf.GetPlane(input_plus, 0) + input_plus_u = mvf.GetPlane(input_plus, 1) + input_plus_v = mvf.GetPlane(input_plus, 2) + + average_y = core.std.Expr([input_minus_y, input_plus_y], expr=[f'x y - abs {ythresh} < x y + 2 / 0 ?']) + average_u = core.std.Expr([input_minus_u, input_plus_u], expr=[f'x y - abs {cthresh} < {peak} 0 ?']) + average_v = core.std.Expr([input_minus_v, input_plus_v], expr=[f'x y - abs {cthresh} < {peak} 0 ?']) + + ymask = average_y.std.Binarize(threshold=1 << shift) + if usemaxdiff: + diffplus_y = core.std.Expr([input_plus_y, input_y], expr=[f'x y - abs {maxdiff} < {peak} 0 ?']) + diffminus_y = core.std.Expr([input_minus_y, input_y], expr=[f'x y - abs {maxdiff} < {peak} 0 ?']) + diffs_y = core.std.Lut2(diffplus_y, diffminus_y, function=lambda x, y: x & y) + ymask = core.std.Lut2(ymask, diffs_y, function=lambda x, y: x & y) + cmask = core.std.Lut2(average_u.std.Binarize(threshold=129 << shift), average_v.std.Binarize(threshold=129 << shift), function=lambda x, y: x & y) + cmask = cmask.resize.Point(input.width, input.height) + + themask = core.std.Lut2(ymask, cmask, function=lambda x, y: x & y) + + fixed_y = core.std.Merge(average_y, input_y) + + output = core.std.ShufflePlanes([core.std.MaskedMerge(input_y, fixed_y, themask), input], planes=[0, 1, 2], colorfamily=input.format.color_family) + + input = SCDetect(input, threshold=scnchg / 255) + output = output.std.FrameEval(eval=partial(YDifferenceFromPrevious, clips=[input, output]), prop_src=input) + output = output.std.FrameEval(eval=partial(YDifferenceToNext, clips=[input, output]), prop_src=input) + + if mask: + return themask + else: + return output + + +##################################################### +# # +# LUTDeRainbow, a derainbowing script by Scintilla # +# Last updated 2022-10-08 # +# # +##################################################### +# +# Requires YUV input, frame-based only. +# Is of reasonable speed (faster than aWarpSharp, slower than DeGrainMedian). +# Suggestions for improvement welcome: scintilla@aquilinestudios.org +# +# Arguments: +# +# cthresh (int, default=10) - This determines how close the chroma values of the +# pixel in the previous and next frames have to be for the pixel to +# be hit. Higher values (within reason) should catch more rainbows, +# but may introduce unwanted artifacts. Probably shouldn't be set +# above 20 or so. +# +# ythresh (int, default=10) - If the y parameter is set true, then this +# determines how close the luma values of the pixel in the previous +# and next frames have to be for the pixel to be hit. Just as with +# cthresh. +# +# y (bool, default=True) - Determines whether luma difference will be considered +# in determining which pixels to hit and which to leave alone. +# +# linkUV (bool, default=True) - Determines whether both chroma channels are +# considered in determining which pixels in each channel to hit. +# When set true, only pixels that meet the thresholds for both U and +# V will be hit; when set false, the U and V channels are masked +# separately (so a pixel could have its U hit but not its V, or vice +# versa). +# +# mask (bool, default=False) - When set true, the function will return the mask +# (for combined U/V) instead of the image. Formerly used to find the +# best values of cthresh and ythresh. If linkUV=false, then this +# mask won't actually be used anyway (because each chroma channel +# will have its own mask). +# +################### +def LUTDeRainbow(input, cthresh=10, ythresh=10, y=True, linkUV=True, mask=False): + if not isinstance(input, vs.VideoNode) or input.format.color_family != vs.YUV or input.format.bits_per_sample > 16: + raise vs.Error('LUTDeRainbow: This is not an 8-16 bit YUV clip') + + # Since LUT2 can't handle clips with more than 10 bits, we default to using + # Expr and MaskedMerge to handle the same logic for higher bit depths. + useExpr = input.format.bits_per_sample > 10 + + shift = input.format.bits_per_sample - 8 + peak = (1 << input.format.bits_per_sample) - 1 + + cthresh = scale(cthresh, peak) + ythresh = scale(ythresh, peak) + + input_minus = input.std.DuplicateFrames(frames=[0]) + input_plus = input.std.Trim(first=1) + input.std.Trim(first=input.num_frames - 1) + + input_u = mvf.GetPlane(input, 1) + input_v = mvf.GetPlane(input, 2) + input_minus_y = mvf.GetPlane(input_minus, 0) + input_minus_u = mvf.GetPlane(input_minus, 1) + input_minus_v = mvf.GetPlane(input_minus, 2) + input_plus_y = mvf.GetPlane(input_plus, 0) + input_plus_u = mvf.GetPlane(input_plus, 1) + input_plus_v = mvf.GetPlane(input_plus, 2) + + average_y = core.std.Expr([input_minus_y, input_plus_y], expr=[f'x y - abs {ythresh} < {peak} 0 ?']).resize.Bilinear(input_u.width, input_u.height) + average_u = core.std.Expr([input_minus_u, input_plus_u], expr=[f'x y - abs {cthresh} < x y + 2 / 0 ?']) + average_v = core.std.Expr([input_minus_v, input_plus_v], expr=[f'x y - abs {cthresh} < x y + 2 / 0 ?']) + + umask = average_u.std.Binarize(threshold=21 << shift) + vmask = average_v.std.Binarize(threshold=21 << shift) + + if useExpr: + themask = core.std.Expr([umask, vmask], expr=[f'x y + {peak + 1} < 0 {peak} ?']) + if y: + umask = core.std.MaskedMerge(core.std.BlankClip(average_y), average_y, umask) + vmask = core.std.MaskedMerge(core.std.BlankClip(average_y), average_y, vmask) + themask = core.std.MaskedMerge(core.std.BlankClip(average_y), average_y, themask) + else: + themask = core.std.Lut2(umask, vmask, function=lambda x, y: x & y) + if y: + umask = core.std.Lut2(umask, average_y, function=lambda x, y: x & y) + vmask = core.std.Lut2(vmask, average_y, function=lambda x, y: x & y) + themask = core.std.Lut2(themask, average_y, function=lambda x, y: x & y) + + fixed_u = core.std.Merge(average_u, input_u) + fixed_v = core.std.Merge(average_v, input_v) + + output_u = core.std.MaskedMerge(input_u, fixed_u, themask if linkUV else umask) + output_v = core.std.MaskedMerge(input_v, fixed_v, themask if linkUV else vmask) + + output = core.std.ShufflePlanes([input, output_u, output_v], planes=[0, 0, 0], colorfamily=input.format.color_family) + + if mask: + return themask.resize.Point(input.width, input.height) + else: + return output + + +############################################################################## +# Original script by g-force converted into a stand alone script by McCauley # +# latest version from December 10, 2008 # +############################################################################## +def Stab(clp, dxmax=4, dymax=4, mirror=0): + if not isinstance(clp, vs.VideoNode): + raise vs.Error('Stab: this is not a clip') + + temp = AverageFrames(clp, weights=[1] * 15, scenechange=25 / 255) + inter = core.std.Interleave([core.rgvs.Repair(temp, AverageFrames(clp, weights=[1] * 3, scenechange=25 / 255), mode=[1]), clp]) + mdata = inter.mv.DepanEstimate(trust=0, dxmax=dxmax, dymax=dymax) + last = inter.mv.DepanCompensate(data=mdata, offset=-1, mirror=mirror) + return last[::2] + + +###### +### +### GrainStabilizeMC v1.0 by mawen1250 2014.03.22 +### +### Requirements: MVTools, RGVS +### +### Temporal-only on-top grain stabilizer +### Only stabilize the difference ( on-top grain ) between source clip and spatial-degrained clip +### +### Parameters: +### nrmode (int) - Mode to get grain/noise from input clip. 0: 3x3 Average Blur, 1: 3x3 SBR, 2: 5x5 SBR, 3: 7x7 SBR. Or define your own denoised clip "p". Default is 2 for HD / 1 for SD +### radius (int) - Temporal radius of MDegrain for grain stabilize (1-3). Default is 1 +### adapt (int) - Threshold for luma-adaptative mask. -1: off, 0: source, 255: invert. Or define your own luma mask clip "Lmask". Default is -1 +### rep (int) - Mode of repair to avoid artifacts, set 0 to turn off this operation. Default is 13 +### planes (int[]) - Whether to process the corresponding plane. The other planes will be passed through unchanged. +### +###### +def GSMC(input, p=None, Lmask=None, nrmode=None, radius=1, adapt=-1, rep=13, planes=None, thSAD=300, thSADC=None, thSCD1=300, thSCD2=100, limit=None, limitc=None): + if not isinstance(input, vs.VideoNode): + raise vs.Error('GSMC: this is not a clip') + + if p is not None and (not isinstance(p, vs.VideoNode) or p.format.id != input.format.id): + raise vs.Error("GSMC: 'p' must be the same format as input") + + if Lmask is not None and not isinstance(Lmask, vs.VideoNode): + raise vs.Error("GSMC: 'Lmask' is not a clip") + + neutral = 1 << (input.format.bits_per_sample - 1) + peak = (1 << input.format.bits_per_sample) - 1 + + if planes is None: + planes = list(range(input.format.num_planes)) + elif isinstance(planes, int): + planes = [planes] + + HD = input.width > 1024 or input.height > 576 + + if nrmode is None: + nrmode = 2 if HD else 1 + if thSADC is None: + thSADC = thSAD // 2 + if limit is not None: + limit = scale(limit, peak) + if limitc is not None: + limitc = scale(limitc, peak) + + Y = 0 in planes + U = 1 in planes + V = 2 in planes + + chromamv = U or V + blksize = 32 if HD else 16 + overlap = blksize // 4 + if not Y: + if not U: + plane = 2 + elif not V: + plane = 1 + else: + plane = 3 + elif not (U or V): + plane = 0 + else: + plane = 4 + + # Kernel: Spatial Noise Dumping + if p is not None: + pre_nr = p + elif nrmode <= 0: + pre_nr = input.std.Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1], planes=planes) + else: + pre_nr = sbr(input, r=nrmode, planes=planes) + dif_nr = core.std.MakeDiff(input, pre_nr, planes=planes) + + # Kernel: MC Grain Stabilize + psuper = DitherLumaRebuild(pre_nr, s0=1, chroma=chromamv).mv.Super(pel=1, chroma=chromamv) + difsuper = dif_nr.mv.Super(pel=1, levels=1, chroma=chromamv) + + analyse_args = dict(blksize=blksize, chroma=chromamv, truemotion=False, global_=True, overlap=overlap) + fv1 = psuper.mv.Analyse(isb=False, delta=1, **analyse_args) + bv1 = psuper.mv.Analyse(isb=True, delta=1, **analyse_args) + if radius >= 2: + fv2 = psuper.mv.Analyse(isb=False, delta=2, **analyse_args) + bv2 = psuper.mv.Analyse(isb=True, delta=2, **analyse_args) + if radius >= 3: + fv3 = psuper.mv.Analyse(isb=False, delta=3, **analyse_args) + bv3 = psuper.mv.Analyse(isb=True, delta=3, **analyse_args) + + degrain_args = dict(thsad=thSAD, thsadc=thSADC, plane=plane, limit=limit, limitc=limitc, thscd1=thSCD1, thscd2=thSCD2) + if radius <= 1: + dif_sb = core.mv.Degrain1(dif_nr, difsuper, bv1, fv1, **degrain_args) + elif radius == 2: + dif_sb = core.mv.Degrain2(dif_nr, difsuper, bv1, fv1, bv2, fv2, **degrain_args) + else: + dif_sb = core.mv.Degrain3(dif_nr, difsuper, bv1, fv1, bv2, fv2, bv3, fv3, **degrain_args) + + # Post-Process: Luma-Adaptive Mask Merging & Repairing + stable = core.std.MergeDiff(pre_nr, dif_sb, planes=planes) + if rep > 0: + stable = core.rgvs.Repair(stable, input, mode=[rep if i in planes else 0 for i in range(input.format.num_planes)]) + + if Lmask is not None: + return core.std.MaskedMerge(input, stable, Lmask, planes=planes) + elif adapt <= -1: + return stable + else: + input_y = mvf.GetPlane(input, 0) + if adapt == 0: + Lmask = input_y.std.Convolution(matrix=[1, 1, 1, 1, 0, 1, 1, 1, 1]) + elif adapt >= 255: + Lmask = input_y.std.Invert().std.Convolution(matrix=[1, 1, 1, 1, 0, 1, 1, 1, 1]) + else: + expr = 'x {adapt} - abs {peak} * {adapt} {neutral} - abs {neutral} + /'.format(adapt=scale(adapt, peak), peak=peak, neutral=neutral) + Lmask = input_y.std.Expr(expr=[expr]).std.Convolution(matrix=[1, 1, 1, 1, 0, 1, 1, 1, 1]) + return core.std.MaskedMerge(input, stable, Lmask, planes=planes) + + +#################################################################################################################################### +### ### +### Motion-Compensated Temporal Denoise: MCTemporalDenoise() ### +### ### +### v1.4.20 by "LaTo INV." ### +### ### +### 2 July 2010 ### +### ### +#################################################################################################################################### +### +### +### +### /!\ Needed filters: MVTools, DFTTest, FFT3DFilter, TTempSmooth, RGVS, Deblock, DCTFilter +### ------------------- +### +### +### +### USAGE: MCTemporalDenoise(i, radius, pfMode, sigma, twopass, useTTmpSm, limit, limit2, post, chroma, refine, +### deblock, useQED, quant1, quant2, +### edgeclean, ECrad, ECthr, +### stabilize, maxr, TTstr, +### bwbh, owoh, blksize, overlap, +### bt, ncpu, +### thSAD, thSADC, thSAD2, thSADC2, thSCD1, thSCD2, +### truemotion, MVglobal, pel, pelsearch, search, searchparam, MVsharp, DCT, +### p, settings) +### +### +### +### PARAMETERS: +### ----------- +### +### +---------+ +### | DENOISE | +### +---------+--------------------------------------------------------------------------------------+ +### | radius : Temporal radius [1...6] | +### | pfMode : Pre-filter mode [-1=off,0=FFT3DFilter,1=MinBlur(1),2=MinBlur(2),3=DFTTest] | +### | sigma : FFT3D sigma for the pre-filtering clip (if pfMode=0) | +### | twopass : Do the denoising job in 2 stages (stronger but very slow) | +### | useTTmpSm : Use MDegrain (faster) or MCompensate+TTempSmooth (stronger) | +### | limit : Limit the effect of the first denoising [-1=auto,0=off,1...255] | +### | limit2 : Limit the effect of the second denoising (if twopass=true) [-1=auto,0=off,1...255] | +### | post : Sigma value for post-denoising with FFT3D [0=off,...] | +### | chroma : Process or not the chroma plane | +### | refine : Refine and recalculate motion data of previously estimated motion vectors | +### +------------------------------------------------------------------------------------------------+ +### +### +### +---------+ +### | DEBLOCK | +### +---------+-----------------------------------------------------------------------------------+ +### | deblock : Enable deblocking before the denoising | +### | useQED : If true, use Deblock_QED, else use Deblock (faster & stronger) | +### | quant1 : Deblock_QED "quant1" parameter (Deblock "quant" parameter is "(quant1+quant2)/2") | +### | quant2 : Deblock_QED "quant2" parameter (Deblock "quant" parameter is "(quant1+quant2)/2") | +### +---------------------------------------------------------------------------------------------+ +### +### +### +------------------------------+ +### | EDGECLEAN: DERING, DEHALO... | +### +------------------------------+-----------------------------------------------------------------------------------------------------+ +### | edgeclean : Enable safe edgeclean process after the denoising (only on edges which are in non-detailed areas, so less detail loss) | +### | ECrad : Radius for mask (the higher, the greater distance from the edge is filtered) | +### | ECthr : Threshold for mask (the higher, the less "small edges" are process) [0...255] | +### +------------------------------------------------------------------------------------------------------------------------------------+ +### +### +### +-----------+ +### | STABILIZE | +### +-----------+------------------------------------------------------------------------------------------------+ +### | stabilize : Enable TTempSmooth post processing to stabilize flat areas (background will be less "nervous") | +### | maxr : Temporal radius (the higher, the more stable image) | +### | TTstr : Strength (see TTempSmooth docs) | +### +------------------------------------------------------------------------------------------------------------+ +### +### +### +---------------------+ +### | BLOCKSIZE / OVERLAP | +### +---------------------+----------------+ +### | bwbh : FFT3D blocksize | +### | owoh : FFT3D overlap | +### | - for speed: bwbh/4 | +### | - for quality: bwbh/2 | +### | blksize : MVTools blocksize | +### | overlap : MVTools overlap | +### | - for speed: blksize/4 | +### | - for quality: blksize/2 | +### +--------------------------------------+ +### +### +### +-------+ +### | FFT3D | +### +-------+--------------------------+ +### | bt : FFT3D block temporal size | +### | ncpu : FFT3DFilter ncpu | +### +----------------------------------+ +### +### +### +---------+ +### | MVTOOLS | +### +---------+------------------------------------------------------+ +### | thSAD : MVTools thSAD for the first pass | +### | thSADC : MVTools thSADC for the first pass | +### | thSAD2 : MVTools thSAD for the second pass (if twopass=true) | +### | thSADC2 : MVTools thSADC for the second pass (if twopass=true) | +### | thSCD1 : MVTools thSCD1 | +### | thSCD2 : MVTools thSCD2 | +### +-----------------------------------+----------------------------+ +### | truemotion : MVTools truemotion | +### | MVglobal : MVTools global | +### | pel : MVTools pel | +### | pelsearch : MVTools pelsearch | +### | search : MVTools search | +### | searchparam : MVTools searchparam | +### | MVsharp : MVTools sharp | +### | DCT : MVTools DCT | +### +-----------------------------------+ +### +### +### +--------+ +### | GLOBAL | +### +--------+-----------------------------------------------------+ +### | p : Set an external prefilter clip | +### | settings : Global MCTemporalDenoise settings [default="low"] | +### | - "very low" | +### | - "low" | +### | - "medium" | +### | - "high" | +### | - "very high" | +### +--------------------------------------------------------------+ +### +### +### +### DEFAULTS: +### --------- +### +### +-------------+----------------------+----------------------+----------------------+----------------------+----------------------+ +### | SETTINGS | VERY LOW | LOW | MEDIUM | HIGH | VERY HIGH | +### |-------------+----------------------+----------------------+----------------------+----------------------+----------------------| +### | radius | 1 | 2 | 3 | 2 | 3 | +### | pfMode | 3 | 3 | 3 | 3 | 3 | +### | sigma | 2 | 4 | 8 | 12 | 16 | +### | twopass | false | false | false | true | true | +### | useTTmpSm | false | false | false | false | false | +### | limit | -1 | -1 | -1 | -1 | 0 | +### | limit2 | -1 | -1 | -1 | 0 | 0 | +### | post | 0 | 0 | 0 | 0 | 0 | +### | chroma | false | false | true | true | true | +### |-------------+----------------------+----------------------+----------------------+----------------------+----------------------| +### | deblock | false | false | false | false | false | +### | useQED | true | true | true | false | false | +### | quant1 | 10 | 20 | 30 | 30 | 40 | +### | quant2 | 20 | 40 | 60 | 60 | 80 | +### |-------------+----------------------+----------------------+----------------------+----------------------+----------------------| +### | edgeclean | false | false | false | false | false | +### | ECrad | 1 | 2 | 3 | 4 | 5 | +### | ECthr | 64 | 32 | 32 | 16 | 16 | +### |-------------+----------------------+----------------------+----------------------+----------------------+----------------------| +### | stabilize | false | false | false | true | true | +### | maxr | 1 | 1 | 2 | 2 | 2 | +### | TTstr | 1 | 1 | 1 | 2 | 2 | +### |-------------+----------------------+----------------------+----------------------+----------------------+----------------------| +### | bwbh | HD?16:8 | HD?16:8 | HD?16:8 | HD?16:8 | HD?16:8 | +### | owoh | HD? 8:4 | HD? 8:4 | HD? 8:4 | HD? 8:4 | HD? 8:4 | +### | blksize | HD?16:8 | HD?16:8 | HD?16:8 | HD?16:8 | HD?16:8 | +### | overlap | HD? 8:4 | HD? 8:4 | HD? 8:4 | HD? 8:4 | HD? 8:4 | +### |-------------+----------------------+----------------------+----------------------+----------------------+----------------------| +### | bt | 1 | 3 | 3 | 3 | 4 | +### | ncpu | 1 | 1 | 1 | 1 | 1 | +### |-------------+----------------------+----------------------+----------------------+----------------------+----------------------| +### | thSAD | 200 | 300 | 400 | 500 | 600 | +### | thSADC | thSAD/2 | thSAD/2 | thSAD/2 | thSAD/2 | thSAD/2 | +### | thSAD2 | 200 | 300 | 400 | 500 | 600 | +### | thSADC2 | thSAD2/2 | thSAD2/2 | thSAD2/2 | thSAD2/2 | thSAD2/2 | +### | thSCD1 | 200 | 300 | 400 | 500 | 600 | +### | thSCD2 | 90 | 100 | 100 | 130 | 130 | +### |-------------+----------------------+----------------------+----------------------+----------------------+----------------------| +### | truemotion | false | false | false | false | false | +### | MVglobal | true | true | true | true | true | +### | pel | 1 | 2 | 2 | 2 | 2 | +### | pelsearch | 1 | 2 | 2 | 2 | 2 | +### | search | 4 | 4 | 4 | 4 | 4 | +### | searchparam | 2 | 2 | 2 | 2 | 2 | +### | MVsharp | 2 | 2 | 2 | 1 | 0 | +### | DCT | 0 | 0 | 0 | 0 | 0 | +### +-------------+----------------------+----------------------+----------------------+----------------------+----------------------+ +### +#################################################################################################################################### +def MCTemporalDenoise(i, radius=None, pfMode=3, sigma=None, twopass=None, useTTmpSm=False, limit=None, limit2=None, post=0, chroma=None, refine=False, deblock=False, useQED=None, quant1=None, + quant2=None, edgeclean=False, ECrad=None, ECthr=None, stabilize=None, maxr=None, TTstr=None, bwbh=None, owoh=None, blksize=None, overlap=None, bt=None, ncpu=1, thSAD=None, + thSADC=None, thSAD2=None, thSADC2=None, thSCD1=None, thSCD2=None, truemotion=False, MVglobal=True, pel=None, pelsearch=None, search=4, searchparam=2, MVsharp=None, DCT=0, p=None, + settings='low'): + if not isinstance(i, vs.VideoNode): + raise vs.Error('MCTemporalDenoise: this is not a clip') + + if p is not None and (not isinstance(p, vs.VideoNode) or p.format.id != i.format.id): + raise vs.Error("MCTemporalDenoise: 'p' must be the same format as input") + + isGray = (i.format.color_family == vs.GRAY) + + neutral = 1 << (i.format.bits_per_sample - 1) + peak = (1 << i.format.bits_per_sample) - 1 + + ### DEFAULTS + try: + settings_num = ['very low', 'low', 'medium', 'high', 'very high'].index(settings.lower()) + except: + raise vs.Error('MCTemporalDenoise: these settings do not exist') + + HD = i.width > 1024 or i.height > 576 + + if radius is None: + radius = [1, 2, 3, 2, 3][settings_num] + if sigma is None: + sigma = [2, 4, 8, 12, 16][settings_num] + if twopass is None: + twopass = [False, False, False, True, True][settings_num] + if limit is None: + limit = [-1, -1, -1, -1, 0][settings_num] + if limit2 is None: + limit2 = [-1, -1, -1, 0, 0][settings_num] + if chroma is None: + chroma = [False, False, True, True, True][settings_num] + if useQED is None: + useQED = [True, True, True, False, False][settings_num] + if quant1 is None: + quant1 = [10, 20, 30, 30, 40][settings_num] + if quant2 is None: + quant2 = [20, 40, 60, 60, 80][settings_num] + if ECrad is None: + ECrad = [1, 2, 3, 4, 5][settings_num] + if ECthr is None: + ECthr = [64, 32, 32, 16, 16][settings_num] + if stabilize is None: + stabilize = [False, False, False, True, True][settings_num] + if maxr is None: + maxr = [1, 1, 2, 2, 2][settings_num] + if TTstr is None: + TTstr = [1, 1, 1, 2, 2][settings_num] + if bwbh is None: + bwbh = 16 if HD else 8 + if owoh is None: + owoh = 8 if HD else 4 + if blksize is None: + blksize = 16 if HD else 8 + if overlap is None: + overlap = 8 if HD else 4 + if bt is None: + bt = [1, 3, 3, 3, 4][settings_num] + if thSAD is None: + thSAD = [200, 300, 400, 500, 600][settings_num] + if thSADC is None: + thSADC = thSAD // 2 + if thSAD2 is None: + thSAD2 = [200, 300, 400, 500, 600][settings_num] + if thSADC2 is None: + thSADC2 = thSAD2 // 2 + if thSCD1 is None: + thSCD1 = [200, 300, 400, 500, 600][settings_num] + if thSCD2 is None: + thSCD2 = [90, 100, 100, 130, 130][settings_num] + if pel is None: + pel = [1, 2, 2, 2, 2][settings_num] + if pelsearch is None: + pelsearch = [1, 2, 2, 2, 2][settings_num] + if MVsharp is None: + MVsharp = [2, 2, 2, 1, 0][settings_num] + + sigma *= peak / 255 + limit = scale(limit, peak) + limit2 = scale(limit2, peak) + post *= peak / 255 + ECthr = scale(ECthr, peak) + planes = [0, 1, 2] if chroma and not isGray else [0] + + ### INPUT + mod = bwbh if bwbh >= blksize else blksize + xi = i.width + xf = math.ceil(xi / mod) * mod - xi + mod + xn = int(xi + xf) + yi = i.height + yf = math.ceil(yi / mod) * mod - yi + mod + yn = int(yi + yf) + + pointresize_args = dict(width=xn, height=yn, src_left=-xf / 2, src_top=-yf / 2, src_width=xn, src_height=yn) + i = i.resize.Point(**pointresize_args) + + ### PREFILTERING + fft3d_args = dict(planes=planes, bw=bwbh, bh=bwbh, bt=bt, ow=owoh, oh=owoh, ncpu=ncpu) + if p is not None: + p = p.resize.Point(**pointresize_args) + elif pfMode <= -1: + p = i + elif pfMode == 0: + p = i.fft3dfilter.FFT3DFilter(sigma=sigma * 0.8, sigma2=sigma * 0.6, sigma3=sigma * 0.4, sigma4=sigma * 0.2, **fft3d_args) + elif pfMode >= 3: + p = i.dfttest.DFTTest(tbsize=1, slocation=[0.0,4.0, 0.2,9.0, 1.0,15.0], planes=planes) + else: + p = MinBlur(i, r=pfMode, planes=planes) + + pD = core.std.MakeDiff(i, p, planes=planes) + p = DitherLumaRebuild(p, s0=1, chroma=chroma) + + ### DEBLOCKING + crop_args = dict(left=xf // 2, right=xf // 2, top=yf // 2, bottom=yf // 2) + if not deblock: + d = i + elif useQED: + d = Deblock_QED(i.std.Crop(**crop_args), quant1=quant1, quant2=quant2, uv=3 if chroma else 2).resize.Point(**pointresize_args) + else: + d = i.std.Crop(**crop_args).deblock.Deblock(quant=(quant1 + quant2) // 2, planes=planes).resize.Point(**pointresize_args) + + ### PREPARING + super_args = dict(hpad=0, vpad=0, pel=pel, chroma=chroma, sharp=MVsharp) + pMVS = p.mv.Super(rfilter=4 if refine else 2, **super_args) + if refine: + rMVS = p.mv.Super(levels=1, **super_args) + + analyse_args = dict(blksize=blksize, search=search, searchparam=searchparam, pelsearch=pelsearch, chroma=chroma, truemotion=truemotion, global_=MVglobal, overlap=overlap, dct=DCT) + recalculate_args = dict(thsad=thSAD // 2, blksize=max(blksize // 2, 4), search=search, chroma=chroma, truemotion=truemotion, overlap=max(overlap // 2, 2), dct=DCT) + f1v = pMVS.mv.Analyse(isb=False, delta=1, **analyse_args) + b1v = pMVS.mv.Analyse(isb=True, delta=1, **analyse_args) + if refine: + f1v = core.mv.Recalculate(rMVS, f1v, **recalculate_args) + b1v = core.mv.Recalculate(rMVS, b1v, **recalculate_args) + if radius > 1: + f2v = pMVS.mv.Analyse(isb=False, delta=2, **analyse_args) + b2v = pMVS.mv.Analyse(isb=True, delta=2, **analyse_args) + if refine: + f2v = core.mv.Recalculate(rMVS, f2v, **recalculate_args) + b2v = core.mv.Recalculate(rMVS, b2v, **recalculate_args) + if radius > 2: + f3v = pMVS.mv.Analyse(isb=False, delta=3, **analyse_args) + b3v = pMVS.mv.Analyse(isb=True, delta=3, **analyse_args) + if refine: + f3v = core.mv.Recalculate(rMVS, f3v, **recalculate_args) + b3v = core.mv.Recalculate(rMVS, b3v, **recalculate_args) + if radius > 3: + f4v = pMVS.mv.Analyse(isb=False, delta=4, **analyse_args) + b4v = pMVS.mv.Analyse(isb=True, delta=4, **analyse_args) + if refine: + f4v = core.mv.Recalculate(rMVS, f4v, **recalculate_args) + b4v = core.mv.Recalculate(rMVS, b4v, **recalculate_args) + if radius > 4: + f5v = pMVS.mv.Analyse(isb=False, delta=5, **analyse_args) + b5v = pMVS.mv.Analyse(isb=True, delta=5, **analyse_args) + if refine: + f5v = core.mv.Recalculate(rMVS, f5v, **recalculate_args) + b5v = core.mv.Recalculate(rMVS, b5v, **recalculate_args) + if radius > 5: + f6v = pMVS.mv.Analyse(isb=False, delta=6, **analyse_args) + b6v = pMVS.mv.Analyse(isb=True, delta=6, **analyse_args) + if refine: + f6v = core.mv.Recalculate(rMVS, f6v, **recalculate_args) + b6v = core.mv.Recalculate(rMVS, b6v, **recalculate_args) + + # if useTTmpSm or stabilize: + # mask_args = dict(ml=thSAD, gamma=0.999, kind=1, ysc=255) + # SAD_f1m = core.mv.Mask(d, f1v, **mask_args) + # SAD_b1m = core.mv.Mask(d, b1v, **mask_args) + + def MCTD_MVD(i, iMVS, thSAD, thSADC): + degrain_args = dict(thsad=thSAD, thsadc=thSADC, plane=4 if chroma else 0, thscd1=thSCD1, thscd2=thSCD2) + if radius <= 1: + sm = core.mv.Degrain1(i, iMVS, b1v, f1v, **degrain_args) + elif radius == 2: + sm = core.mv.Degrain2(i, iMVS, b1v, f1v, b2v, f2v, **degrain_args) + elif radius == 3: + sm = core.mv.Degrain3(i, iMVS, b1v, f1v, b2v, f2v, b3v, f3v, **degrain_args) + elif radius == 4: + mv12 = core.mv.Degrain2(i, iMVS, b1v, f1v, b2v, f2v, **degrain_args) + mv34 = core.mv.Degrain2(i, iMVS, b3v, f3v, b4v, f4v, **degrain_args) + sm = core.std.Merge(mv12, mv34, weight=[0.4444]) + elif radius == 5: + mv123 = core.mv.Degrain3(i, iMVS, b1v, f1v, b2v, f2v, b3v, f3v, **degrain_args) + mv45 = core.mv.Degrain2(i, iMVS, b4v, f4v, b5v, f5v, **degrain_args) + sm = core.std.Merge(mv123, mv45, weight=[0.4545]) + else: + mv123 = core.mv.Degrain3(i, iMVS, b1v, f1v, b2v, f2v, b3v, f3v, **degrain_args) + mv456 = core.mv.Degrain3(i, iMVS, b4v, f4v, b5v, f5v, b6v, f6v, **degrain_args) + sm = core.std.Merge(mv123, mv456, weight=[0.4615]) + + return sm + + def MCTD_TTSM(i, iMVS, thSAD): + compensate_args = dict(thsad=thSAD, thscd1=thSCD1, thscd2=thSCD2) + f1c = core.mv.Compensate(i, iMVS, f1v, **compensate_args) + b1c = core.mv.Compensate(i, iMVS, b1v, **compensate_args) + if radius > 1: + f2c = core.mv.Compensate(i, iMVS, f2v, **compensate_args) + b2c = core.mv.Compensate(i, iMVS, b2v, **compensate_args) + # SAD_f2m = core.mv.Mask(i, f2v, **mask_args) + # SAD_b2m = core.mv.Mask(i, b2v, **mask_args) + if radius > 2: + f3c = core.mv.Compensate(i, iMVS, f3v, **compensate_args) + b3c = core.mv.Compensate(i, iMVS, b3v, **compensate_args) + # SAD_f3m = core.mv.Mask(i, f3v, **mask_args) + # SAD_b3m = core.mv.Mask(i, b3v, **mask_args) + if radius > 3: + f4c = core.mv.Compensate(i, iMVS, f4v, **compensate_args) + b4c = core.mv.Compensate(i, iMVS, b4v, **compensate_args) + # SAD_f4m = core.mv.Mask(i, f4v, **mask_args) + # SAD_b4m = core.mv.Mask(i, b4v, **mask_args) + if radius > 4: + f5c = core.mv.Compensate(i, iMVS, f5v, **compensate_args) + b5c = core.mv.Compensate(i, iMVS, b5v, **compensate_args) + # SAD_f5m = core.mv.Mask(i, f5v, **mask_args) + # SAD_b5m = core.mv.Mask(i, b5v, **mask_args) + if radius > 5: + f6c = core.mv.Compensate(i, iMVS, f6v, **compensate_args) + b6c = core.mv.Compensate(i, iMVS, b6v, **compensate_args) + # SAD_f6m = core.mv.Mask(i, f6v, **mask_args) + # SAD_b6m = core.mv.Mask(i, b6v, **mask_args) + + # b = i.std.BlankClip(color=[0] if isGray else [0, neutral, neutral]) + if radius <= 1: + c = core.std.Interleave([f1c, i, b1c]) + # SAD_m = core.std.Interleave([SAD_f1m, b, SAD_b1m]) + elif radius == 2: + c = core.std.Interleave([f2c, f1c, i, b1c, b2c]) + # SAD_m = core.std.Interleave([SAD_f2m, SAD_f1m, b, SAD_b1m, SAD_b2m]) + elif radius == 3: + c = core.std.Interleave([f3c, f2c, f1c, i, b1c, b2c, b3c]) + # SAD_m = core.std.Interleave([SAD_f3m, SAD_f2m, SAD_f1m, b, SAD_b1m, SAD_b2m, SAD_b3m]) + elif radius == 4: + c = core.std.Interleave([f4c, f3c, f2c, f1c, i, b1c, b2c, b3c, b4c]) + # SAD_m = core.std.Interleave([SAD_f4m, SAD_f3m, SAD_f2m, SAD_f1m, b, SAD_b1m, SAD_b2m, SAD_b3m, SAD_b4m]) + elif radius == 5: + c = core.std.Interleave([f5c, f4c, f3c, f2c, f1c, i, b1c, b2c, b3c, b4c, b5c]) + # SAD_m = core.std.Interleave([SAD_f5m, SAD_f4m, SAD_f3m, SAD_f2m, SAD_f1m, b, SAD_b1m, SAD_b2m, SAD_b3m, SAD_b4m, SAD_b5m]) + else: + c = core.std.Interleave([f6c, f5c, f4c, f3c, f2c, f1c, i, b1c, b2c, b3c, b4c, b5c, b6c]) + # SAD_m = core.std.Interleave([SAD_f6m, SAD_f5m, SAD_f4m, SAD_f3m, SAD_f2m, SAD_f1m, b, SAD_b1m, SAD_b2m, SAD_b3m, SAD_b4m, SAD_b5m, SAD_b6m]) + + # sm = c.ttmpsm.TTempSmooth(maxr=radius, thresh=[255], mdiff=[1], strength=radius + 1, scthresh=99.9, fp=False, pfclip=SAD_m, planes=planes) + sm = c.ttmpsm.TTempSmooth(maxr=radius, thresh=[255], mdiff=[1], strength=radius + 1, scthresh=99.9, fp=False, planes=planes) + return sm.std.SelectEvery(cycle=radius * 2 + 1, offsets=[radius]) + + ### DENOISING: FIRST PASS + dMVS = d.mv.Super(levels=1, **super_args) + sm = MCTD_TTSM(d, dMVS, thSAD) if useTTmpSm else MCTD_MVD(d, dMVS, thSAD, thSADC) + + if limit <= -1: + smD = core.std.MakeDiff(i, sm, planes=planes) + expr = f'x {neutral} - abs y {neutral} - abs < x y ?' + DD = core.std.Expr([pD, smD], expr=[expr] if chroma or isGray else [expr, '']) + smL = core.std.MakeDiff(i, DD, planes=planes) + elif limit > 0: + expr = f'x y - abs {limit} <= x x y - 0 < y {limit} - y {limit} + ? ?' + smL = core.std.Expr([sm, i], expr=[expr] if chroma or isGray else [expr, '']) + else: + smL = sm + + ### DENOISING: SECOND PASS + if twopass: + smLMVS = smL.mv.Super(levels=1, **super_args) + sm = MCTD_TTSM(smL, smLMVS, thSAD2) if useTTmpSm else MCTD_MVD(smL, smLMVS, thSAD2, thSADC2) + + if limit2 <= -1: + smD = core.std.MakeDiff(i, sm, planes=planes) + expr = f'x {neutral} - abs y {neutral} - abs < x y ?' + DD = core.std.Expr([pD, smD], expr=[expr] if chroma or isGray else [expr, '']) + smL = core.std.MakeDiff(i, DD, planes=planes) + elif limit2 > 0: + expr = f'x y - abs {limit2} <= x x y - 0 < y {limit2} - y {limit2} + ? ?' + smL = core.std.Expr([sm, i], expr=[expr] if chroma or isGray else [expr, '']) + else: + smL = sm + + ### POST-DENOISING: FFT3D + if post <= 0: + smP = smL + else: + smP = smL.fft3dfilter.FFT3DFilter(sigma=post * 0.8, sigma2=post * 0.6, sigma3=post * 0.4, sigma4=post * 0.2, **fft3d_args) + + ### EDGECLEANING + if edgeclean: + mP = AvsPrewitt(mvf.GetPlane(smP, 0)) + mS = mt_expand_multi(mP, sw=ECrad, sh=ECrad).std.Inflate() + mD = core.std.Expr([mS, mP.std.Inflate()], expr=[f'x y - {ECthr} <= 0 x y - ?']).std.Inflate().std.Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1]) + smP = core.std.MaskedMerge(smP, DeHalo_alpha(smP.dfttest.DFTTest(tbsize=1, planes=planes), darkstr=0), mD, planes=planes) + + ### STABILIZING + if stabilize: + # mM = core.std.Merge(mvf.GetPlane(SAD_f1m, 0), mvf.GetPlane(SAD_b1m, 0)).std.Lut(function=lambda x: min(cround(x ** 1.6), peak)) + mE = AvsPrewitt(mvf.GetPlane(smP, 0)).std.Lut(function=lambda x: min(cround(x ** 1.8), peak)).std.Median().std.Inflate() + # mF = core.std.Expr([mM, mE], expr=['x y max']).std.Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1]) + mF = mE.std.Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1]) + TTc = smP.ttmpsm.TTempSmooth(maxr=maxr, mdiff=[255], strength=TTstr, planes=planes) + smP = core.std.MaskedMerge(TTc, smP, mF, planes=planes) + + ### OUTPUT + return smP.std.Crop(**crop_args) + + +################################################################################################ +### ### +### Simple MDegrain Mod - SMDegrain() ### +### ### +### Mod by Dogway - Original idea by Caroliano ### +### ### +### Special Thanks: Sagekilla, Didée, cretindesalpes, Gavino and MVtools people ### +### ### +### v3.1.2d (Dogway's mod) - 21 July 2015 ### +### ### +################################################################################################ +### +### General purpose simple degrain function. Pure temporal denoiser. Basically a wrapper(function)/frontend of mvtools2+mdegrain +### with some added common related options. Goal is accessibility and quality but not targeted to any specific kind of source. +### The reason behind is to keep it simple so aside masktools2 you will only need MVTools2. +### +### Check documentation for deep explanation on settings and defaults. +### VideoHelp thread: (http://forum.videohelp.com/threads/369142) +### +################################################################################################ + +# Globals +bv6 = bv4 = bv3 = bv2 = bv1 = fv1 = fv2 = fv3 = fv4 = fv6 = None + +def SMDegrain(input, tr=2, thSAD=300, thSADC=None, RefineMotion=False, contrasharp=None, CClip=None, interlaced=False, tff=None, plane=4, Globals=0, pel=None, subpixel=2, prefilter=-1, mfilter=None, + blksize=None, overlap=None, search=4, truemotion=None, MVglobal=None, dct=0, limit=255, limitc=None, thSCD1=400, thSCD2=130, chroma=True, hpad=None, vpad=None, Str=1.0, Amp=0.0625): + if not isinstance(input, vs.VideoNode): + raise vs.Error('SMDegrain: this is not a clip') + + if input.format.color_family == vs.GRAY: + plane = 0 + chroma = False + + peak = (1 << input.format.bits_per_sample) - 1 + + # Defaults & Conditionals + thSAD2 = thSAD // 2 + if thSADC is None: + thSADC = thSAD2 + + GlobalR = (Globals == 1) + GlobalO = (Globals >= 3) + if1 = CClip is not None + + if contrasharp is None: + contrasharp = not GlobalO and if1 + + w = input.width + h = input.height + preclip = isinstance(prefilter, vs.VideoNode) + ifC = isinstance(contrasharp, bool) + if0 = contrasharp if ifC else contrasharp > 0 + if4 = w > 1024 or h > 576 + + if pel is None: + pel = 1 if if4 else 2 + if pel < 2: + subpixel = min(subpixel, 2) + pelclip = pel > 1 and subpixel >= 3 + + if blksize is None: + blksize = 16 if if4 else 8 + blk2 = blksize // 2 + if overlap is None: + overlap = blk2 + ovl2 = overlap // 2 + if truemotion is None: + truemotion = not if4 + if MVglobal is None: + MVglobal = truemotion + + planes = [0, 1, 2] if chroma else [0] + plane0 = (plane != 0) + + if hpad is None: + hpad = blksize + if vpad is None: + vpad = blksize + limit = scale(limit, peak) + if limitc is None: + limitc = limit + else: + limitc = scale(limitc, peak) + + # Error Report + if not (ifC or isinstance(contrasharp, int)): + raise vs.Error("SMDegrain: 'contrasharp' only accepts bool and integer inputs") + if if1 and (not isinstance(CClip, vs.VideoNode) or CClip.format.id != input.format.id): + raise vs.Error("SMDegrain: 'CClip' must be the same format as input") + if interlaced and h & 3: + raise vs.Error('SMDegrain: interlaced source requires mod 4 height sizes') + if interlaced and not isinstance(tff, bool): + raise vs.Error("SMDegrain: 'tff' must be set if source is interlaced. Setting tff to true means top field first and false means bottom field first") + if not (isinstance(prefilter, int) or preclip): + raise vs.Error("SMDegrain: 'prefilter' only accepts integer and clip inputs") + if preclip and prefilter.format.id != input.format.id: + raise vs.Error("SMDegrain: 'prefilter' must be the same format as input") + if mfilter is not None and (not isinstance(mfilter, vs.VideoNode) or mfilter.format.id != input.format.id): + raise vs.Error("SMDegrain: 'mfilter' must be the same format as input") + if RefineMotion and blksize < 8: + raise vs.Error('SMDegrain: for RefineMotion you need a blksize of at least 8') + if not chroma and plane != 0: + raise vs.Error('SMDegrain: denoising chroma with luma only vectors is bugged in mvtools and thus unsupported') + + # RefineMotion Variables + if RefineMotion: + halfblksize = blk2 # MRecalculate works with half block size + halfoverlap = overlap if overlap <= 2 else ovl2 + ovl2 % 2 # Halve the overlap to suit the halved block size + halfthSAD = thSAD2 # MRecalculate uses a more strict thSAD, which defaults to 150 (half of function's default of 300) + + # Input preparation for Interlacing + if not interlaced: + inputP = input + else: + inputP = input.std.SeparateFields(tff=tff) + + # Prefilter & Motion Filter + if mfilter is None: + mfilter = inputP + + if not GlobalR: + if preclip: + pref = prefilter + elif prefilter <= -1: + pref = inputP + elif prefilter == 3: + expr = 'x {i} < {peak} x {j} > 0 {peak} x {i} - {peak} {j} {i} - / * - ? ?'.format(i=scale(16, peak), j=scale(75, peak), peak=peak) + pref = core.std.MaskedMerge(inputP.dfttest.DFTTest(tbsize=1, slocation=[0.0,4.0, 0.2,9.0, 1.0,15.0], planes=planes), + inputP, + mvf.GetPlane(inputP, 0).std.Expr(expr=[expr]), + planes=planes) + elif prefilter >= 4: + if chroma: + pref = KNLMeansCL(inputP, d=1, a=1, h=7) + else: + pref = inputP.knlm.KNLMeansCL(d=1, a=1, h=7) + else: + pref = MinBlur(inputP, r=prefilter, planes=planes) + else: + pref = inputP + + # Default Auto-Prefilter - Luma expansion TV->PC (up to 16% more values for motion estimation) + if not GlobalR: + pref = DitherLumaRebuild(pref, s0=Str, c=Amp, chroma=chroma) + + # Subpixel 3 + if pelclip: + import nnedi3_resample as nnrs + cshift = 0.25 if pel == 2 else 0.375 + pclip = nnrs.nnedi3_resample(pref, w * pel, h * pel, src_left=cshift, src_top=cshift, nns=4, mode='znedi3') + if not GlobalR: + pclip2 = nnrs.nnedi3_resample(inputP, w * pel, h * pel, src_left=cshift, src_top=cshift, nns=4, mode='znedi3') + + # Motion vectors search + global bv6, bv4, bv3, bv2, bv1, fv1, fv2, fv3, fv4, fv6 + super_args = dict(hpad=hpad, vpad=vpad, pel=pel) + analyse_args = dict(blksize=blksize, search=search, chroma=chroma, truemotion=truemotion, global_=MVglobal, overlap=overlap, dct=dct) + if RefineMotion: + recalculate_args = dict(thsad=halfthSAD, blksize=halfblksize, search=search, chroma=chroma, truemotion=truemotion, overlap=halfoverlap, dct=dct) + + if pelclip: + super_search = pref.mv.Super(chroma=chroma, rfilter=4, pelclip=pclip, **super_args) + else: + super_search = pref.mv.Super(chroma=chroma, sharp=subpixel, rfilter=4, **super_args) + + if not GlobalR: + if pelclip: + super_render = inputP.mv.Super(levels=1, chroma=plane0, pelclip=pclip2, **super_args) + if RefineMotion: + Recalculate = pref.mv.Super(levels=1, chroma=chroma, pelclip=pclip, **super_args) + else: + super_render = inputP.mv.Super(levels=1, chroma=plane0, sharp=subpixel, **super_args) + if RefineMotion: + Recalculate = pref.mv.Super(levels=1, chroma=chroma, sharp=subpixel, **super_args) + + if interlaced: + if tr > 2: + bv6 = super_search.mv.Analyse(isb=True, delta=6, **analyse_args) + fv6 = super_search.mv.Analyse(isb=False, delta=6, **analyse_args) + if RefineMotion: + bv6 = core.mv.Recalculate(Recalculate, bv6, **recalculate_args) + fv6 = core.mv.Recalculate(Recalculate, fv6, **recalculate_args) + if tr > 1: + bv4 = super_search.mv.Analyse(isb=True, delta=4, **analyse_args) + fv4 = super_search.mv.Analyse(isb=False, delta=4, **analyse_args) + if RefineMotion: + bv4 = core.mv.Recalculate(Recalculate, bv4, **recalculate_args) + fv4 = core.mv.Recalculate(Recalculate, fv4, **recalculate_args) + else: + if tr > 2: + bv3 = super_search.mv.Analyse(isb=True, delta=3, **analyse_args) + fv3 = super_search.mv.Analyse(isb=False, delta=3, **analyse_args) + if RefineMotion: + bv3 = core.mv.Recalculate(Recalculate, bv3, **recalculate_args) + fv3 = core.mv.Recalculate(Recalculate, fv3, **recalculate_args) + bv1 = super_search.mv.Analyse(isb=True, delta=1, **analyse_args) + fv1 = super_search.mv.Analyse(isb=False, delta=1, **analyse_args) + if RefineMotion: + bv1 = core.mv.Recalculate(Recalculate, bv1, **recalculate_args) + fv1 = core.mv.Recalculate(Recalculate, fv1, **recalculate_args) + if interlaced or tr > 1: + bv2 = super_search.mv.Analyse(isb=True, delta=2, **analyse_args) + fv2 = super_search.mv.Analyse(isb=False, delta=2, **analyse_args) + if RefineMotion: + bv2 = core.mv.Recalculate(Recalculate, bv2, **recalculate_args) + fv2 = core.mv.Recalculate(Recalculate, fv2, **recalculate_args) + else: + super_render = super_search + + # Finally, MDegrain + degrain_args = dict(thsad=thSAD, thsadc=thSADC, plane=plane, limit=limit, limitc=limitc, thscd1=thSCD1, thscd2=thSCD2) + if not GlobalO: + if interlaced: + if tr >= 3: + output = core.mv.Degrain3(mfilter, super_render, bv2, fv2, bv4, fv4, bv6, fv6, **degrain_args) + elif tr == 2: + output = core.mv.Degrain2(mfilter, super_render, bv2, fv2, bv4, fv4, **degrain_args) + else: + output = core.mv.Degrain1(mfilter, super_render, bv2, fv2, **degrain_args) + else: + if tr >= 3: + output = core.mv.Degrain3(mfilter, super_render, bv1, fv1, bv2, fv2, bv3, fv3, **degrain_args) + elif tr == 2: + output = core.mv.Degrain2(mfilter, super_render, bv1, fv1, bv2, fv2, **degrain_args) + else: + output = core.mv.Degrain1(mfilter, super_render, bv1, fv1, **degrain_args) + + # Contrasharp (only sharpens luma) + if not GlobalO and if0: + if if1: + if interlaced: + CClip = CClip.std.SeparateFields(tff=tff) + else: + CClip = inputP + + # Output + if not GlobalO: + if if0: + if interlaced: + if ifC: + return Weave(ContraSharpening(output, CClip, planes=planes), tff=tff) + else: + return Weave(LSFmod(output, strength=contrasharp, source=CClip, Lmode=0, soothe=False, defaults='slow'), tff=tff) + elif ifC: + return ContraSharpening(output, CClip, planes=planes) + else: + return LSFmod(output, strength=contrasharp, source=CClip, Lmode=0, soothe=False, defaults='slow') + elif interlaced: + return Weave(output, tff=tff) + else: + return output + else: + return input + + +def STPresso( + clp: vs.VideoNode, + limit: int = 3, + bias: int = 24, + RGmode: Union[int, vs.VideoNode] = 4, + tthr: int = 12, + tlimit: int = 3, + tbias: int = 49, + back: int = 1, + planes: Optional[Union[int, Sequence[int]]] = None, +) -> vs.VideoNode: + """ + Dampen the grain just a little, to keep the original look. + + Parameters: + clp: Clip to process. + + limit: The spatial part won't change a pixel more than this. + + bias: The percentage of the spatial filter that will apply. + + RGmode: The spatial filter is RemoveGrain, this is its mode. It also accepts loading your personal prefiltered clip. + + tthr: Temporal threshold for fluxsmooth. Can be set "a good bit bigger" than usually. + + tlimit: The temporal filter won't change a pixel more than this. + + tbias: The percentage of the temporal filter that will apply. + + back: After all changes have been calculated, reduce all pixel changes by this value. (shift "back" towards original value) + + planes: Specifies which planes will be processed. Any unprocessed planes will be simply copied. + """ + if not isinstance(clp, vs.VideoNode): + raise vs.Error('STPresso: this is not a clip') + + plane_range = range(clp.format.num_planes) + + if planes is None: + planes = list(plane_range) + elif isinstance(planes, int): + planes = [planes] + + bits = get_depth(clp) + limit = scale_value(limit, 8, bits) + tthr = scale_value(tthr, 8, bits) + tlimit = scale_value(tlimit, 8, bits) + back = scale_value(back, 8, bits) + + LIM = cround(limit * 100 / bias - 1) if limit > 0 else cround(scale_value(100 / bias, 8, bits)) + TLIM = cround(tlimit * 100 / tbias - 1) if tlimit > 0 else cround(scale_value(100 / tbias, 8, bits)) + + if limit < 0: + expr = f'x y - abs {LIM} < x x 1 x y - dup abs / * - ?' + else: + expr = f'x y - abs {scale_value(1, 8, bits)} < x x {LIM} + y < x {limit} + x {LIM} - y > x {limit} - x {100 - bias} * y {bias} * + 100 / ? ? ?' + if tlimit < 0: + texpr = f'x y - abs {TLIM} < x x 1 x y - dup abs / * - ?' + else: + texpr = f'x y - abs {scale_value(1, 8, bits)} < x x {TLIM} + y < x {tlimit} + x {TLIM} - y > x {tlimit} - x {100 - tbias} * y {tbias} * + 100 / ? ? ?' + + if isinstance(RGmode, vs.VideoNode): + bzz = RGmode + else: + if RGmode == 4: + bzz = clp.std.Median(planes=planes) + elif RGmode in [11, 12]: + bzz = clp.std.Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1], planes=planes) + elif RGmode == 19: + bzz = clp.std.Convolution(matrix=[1, 1, 1, 1, 0, 1, 1, 1, 1], planes=planes) + elif RGmode == 20: + bzz = clp.std.Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1], planes=planes) + else: + bzz = clp.rgvs.RemoveGrain(mode=RGmode) + + last = core.std.Expr([clp, bzz], expr=[expr if i in planes else '' for i in plane_range]) + + if tthr > 0: + analyse_args = dict(truemotion=False, delta=1, blksize=16, overlap=8) + + mvSuper = bzz.mv.Super(sharp=1) + bv1 = mvSuper.mv.Analyse(isb=True, **analyse_args) + fv1 = mvSuper.mv.Analyse(isb=False, **analyse_args) + bc1 = core.mv.Compensate(bzz, mvSuper, bv1) + fc1 = core.mv.Compensate(bzz, mvSuper, fv1) + + interleave = core.std.Interleave([fc1, bzz, bc1]) + smooth = interleave.flux.SmoothT(temporal_threshold=tthr, planes=planes) + smooth = smooth.std.SelectEvery(cycle=3, offsets=1) + + diff = core.std.MakeDiff(bzz, smooth, planes=planes) + diff = core.std.MakeDiff(last, diff, planes=planes) + last = core.std.Expr([last, diff], expr=[texpr if i in planes else '' for i in plane_range]) + + if back > 0: + expr = f'x {back} + y < x {back} + x {back} - y > x {back} - y ? ?' + last = core.std.Expr([last, clp], expr=[expr if i in planes else '' for i in plane_range]) + + return last + + +# a.k.a. BalanceBordersMod +def bbmod(c, cTop, cBottom, cLeft, cRight, thresh=128, blur=999): + if not isinstance(c, vs.VideoNode): + raise vs.Error('bbmod: this is not a clip') + + if c.format.color_family in [vs.GRAY, vs.RGB]: + raise vs.Error('bbmod: Gray and RGB formats are not supported') + + if thresh <= 0: + raise vs.Error('bbmod: thresh must be greater than 0') + + if blur <= 0: + raise vs.Error('bbmod: blur must be greater than 0') + + neutral = 1 << (c.format.bits_per_sample - 1) + peak = (1 << c.format.bits_per_sample) - 1 + + BicubicResize = partial(core.resize.Bicubic, filter_param_a=1, filter_param_b=0) + + def btb(c, cTop): + cWidth = c.width + cHeight = c.height + cTop = min(cTop, cHeight - 1) + blurWidth = max(8, math.floor(cWidth / blur)) + + c2 = c.resize.Point(cWidth * 2, cHeight * 2) + + last = c2.std.CropAbs(width=cWidth * 2, height=2, top=cTop * 2) + last = last.resize.Point(cWidth * 2, cTop * 2) + referenceBlurChroma = BicubicResize(BicubicResize(last.std.Expr(expr=[f'x {neutral} - abs 2 *', '']), blurWidth * 2, cTop * 2), cWidth * 2, cTop * 2) + referenceBlur = BicubicResize(BicubicResize(last, blurWidth * 2, cTop * 2), cWidth * 2, cTop * 2) + + original = c2.std.CropAbs(width=cWidth * 2, height=cTop * 2) + + last = BicubicResize(original, blurWidth * 2, cTop * 2) + originalBlurChroma = BicubicResize(BicubicResize(last.std.Expr(expr=[f'x {neutral} - abs 2 *', '']), blurWidth * 2, cTop * 2), cWidth * 2, cTop * 2) + originalBlur = BicubicResize(BicubicResize(last, blurWidth * 2, cTop * 2), cWidth * 2, cTop * 2) + + balancedChroma = core.std.Expr([original, originalBlurChroma, referenceBlurChroma], expr=['', f'z y / 8 min 0.4 max x {neutral} - * {neutral} +']) + expr = 'z {i} - y {i} - / 8 min 0.4 max x {i} - * {i} +'.format(i=scale(16, peak)) + balancedLuma = core.std.Expr([balancedChroma, originalBlur, referenceBlur], expr=[expr, 'z y - x +']) + + difference = core.std.MakeDiff(balancedLuma, original) + difference = difference.std.Expr(expr=[f'x {scale(128 + thresh, peak)} min {scale(128 - thresh, peak)} max']) + + last = core.std.MergeDiff(original, difference) + return core.std.StackVertical([last, c2.std.CropAbs(width=cWidth * 2, height=(cHeight - cTop) * 2, top=cTop * 2)]).resize.Point(cWidth, cHeight) + + if cTop > 0: + c = btb(c, cTop) + c = c.std.Transpose().std.FlipHorizontal() + if cLeft > 0: + c = btb(c, cLeft) + c = c.std.Transpose().std.FlipHorizontal() + if cBottom > 0: + c = btb(c, cBottom) + c = c.std.Transpose().std.FlipHorizontal() + if cRight > 0: + c = btb(c, cRight) + return c.std.Transpose().std.FlipHorizontal() + + +# Parameters: +# g1str (float) - [0.0 - ???] strength of grain / for dark areas. Default is 7.0 +# g2str (float) - [0.0 - ???] strength of grain / for midtone areas. Default is 5.0 +# g3str (float) - [0.0 - ???] strength of grain / for bright areas. Default is 3.0 +# g1shrp (int) - [0 - 100] sharpness of grain / for dark areas (NO EFFECT when g1size=1.0 !!). Default is 60 +# g2shrp (int) - [0 - 100] sharpness of grain / for midtone areas (NO EFFECT when g2size=1.0 !!). Default is 66 +# g3shrp (int) - [0 - 100] sharpness of grain / for bright areas (NO EFFECT when g3size=1.0 !!). Default is 80 +# g1size (float) - [0.5 - 4.0] size of grain / for dark areas. Default is 1.5 +# g2size (float) - [0.5 - 4.0] size of grain / for midtone areas. Default is 1.2 +# g3size (float) - [0.5 - 4.0] size of grain / for bright areas. Default is 0.9 +# temp_avg (int) - [0 - 100] percentage of noise's temporal averaging. Default is 0 +# ontop_grain (float) - [0 - ???] additional grain to put on top of prev. generated grain. Default is 0.0 +# seed (int) - specifies a repeatable grain sequence. Set to at least 0 to use. +# th1 (int) - start of dark->midtone mixing zone. Default is 24 +# th2 (int) - end of dark->midtone mixing zone. Default is 56 +# th3 (int) - start of midtone->bright mixing zone. Default is 128 +# th4 (int) - end of midtone->bright mixing zone. Default is 160 +def GrainFactory3(clp, g1str=7.0, g2str=5.0, g3str=3.0, g1shrp=60, g2shrp=66, g3shrp=80, g1size=1.5, g2size=1.2, g3size=0.9, temp_avg=0, ontop_grain=0.0, seed=-1, th1=24, th2=56, th3=128, th4=160): + if not isinstance(clp, vs.VideoNode): + raise vs.Error('GrainFactory3: this is not a clip') + + if clp.format.color_family == vs.RGB: + raise vs.Error('GrainFactory3: RGB format is not supported') + + if clp.format.sample_type == vs.INTEGER: + neutral = 1 << (clp.format.bits_per_sample - 1) + peak = (1 << clp.format.bits_per_sample) - 1 + else: + neutral = 0.0 + peak = 1.0 + + if clp.format.color_family != vs.GRAY: + clp_orig = clp + clp = mvf.GetPlane(clp, 0) + else: + clp_orig = None + + ox = clp.width + oy = clp.height + sx1 = m4(ox / g1size) + sy1 = m4(oy / g1size) + sx1a = m4((ox + sx1) / 2) + sy1a = m4((oy + sy1) / 2) + sx2 = m4(ox / g2size) + sy2 = m4(oy / g2size) + sx2a = m4((ox + sx2) / 2) + sy2a = m4((oy + sy2) / 2) + sx3 = m4(ox / g3size) + sy3 = m4(oy / g3size) + sx3a = m4((ox + sx3) / 2) + sy3a = m4((oy + sy3) / 2) + + b1 = g1shrp / -50 + 1 + b2 = g2shrp / -50 + 1 + b3 = g3shrp / -50 + 1 + b1a = b1 / 2 + b2a = b2 / 2 + b3a = b3 / 2 + c1 = (1 - b1) / 2 + c2 = (1 - b2) / 2 + c3 = (1 - b3) / 2 + c1a = (1 - b1a) / 2 + c2a = (1 - b2a) / 2 + c3a = (1 - b3a) / 2 + tmpavg = temp_avg / 100 + th1 = scale(th1, peak) + th2 = scale(th2, peak) + th3 = scale(th3, peak) + th4 = scale(th4, peak) + + grainlayer1 = clp.std.BlankClip(width=sx1, height=sy1, color=[neutral]).grain.Add(var=g1str, seed=seed) + if g1size != 1 and (sx1 != ox or sy1 != oy): + if g1size > 1.5: + grainlayer1 = grainlayer1.resize.Bicubic(sx1a, sy1a, filter_param_a=b1a, filter_param_b=c1a).resize.Bicubic(ox, oy, filter_param_a=b1a, filter_param_b=c1a) + else: + grainlayer1 = grainlayer1.resize.Bicubic(ox, oy, filter_param_a=b1, filter_param_b=c1) + + grainlayer2 = clp.std.BlankClip(width=sx2, height=sy2, color=[neutral]).grain.Add(var=g2str, seed=seed) + if g2size != 1 and (sx2 != ox or sy2 != oy): + if g2size > 1.5: + grainlayer2 = grainlayer2.resize.Bicubic(sx2a, sy2a, filter_param_a=b2a, filter_param_b=c2a).resize.Bicubic(ox, oy, filter_param_a=b2a, filter_param_b=c2a) + else: + grainlayer2 = grainlayer2.resize.Bicubic(ox, oy, filter_param_a=b2, filter_param_b=c2) + + grainlayer3 = clp.std.BlankClip(width=sx3, height=sy3, color=[neutral]).grain.Add(var=g3str, seed=seed) + if g3size != 1 and (sx3 != ox or sy3 != oy): + if g3size > 1.5: + grainlayer3 = grainlayer3.resize.Bicubic(sx3a, sy3a, filter_param_a=b3a, filter_param_b=c3a).resize.Bicubic(ox, oy, filter_param_a=b3a, filter_param_b=c3a) + else: + grainlayer3 = grainlayer3.resize.Bicubic(ox, oy, filter_param_a=b3, filter_param_b=c3) + + expr1 = f'x {th1} < 0 x {th2} > {peak} {peak} {th2 - th1} / x {th1} - * ? ?' + expr2 = f'x {th3} < 0 x {th4} > {peak} {peak} {th4 - th3} / x {th3} - * ? ?' + grainlayer = core.std.MaskedMerge(core.std.MaskedMerge(grainlayer1, grainlayer2, clp.std.Expr(expr=[expr1])), grainlayer3, clp.std.Expr(expr=[expr2])) + + if temp_avg > 0: + grainlayer = core.std.Merge(grainlayer, AverageFrames(grainlayer, weights=[1] * 3), weight=[tmpavg]) + if ontop_grain > 0: + grainlayer = grainlayer.grain.Add(var=ontop_grain, seed=seed) + + result = core.std.MakeDiff(clp, grainlayer) + + if clp_orig is not None: + result = core.std.ShufflePlanes([result, clp_orig], planes=[0, 1, 2], colorfamily=clp_orig.format.color_family) + return result + + +#------------------------------------------------------------------------------# +# # +# InterFrame 2.8.2 by SubJunk # +# # +# A frame interpolation script that makes accurate estimations # +# about the content of non-existent frames # +# Its main use is to give videos higher framerates like newer TVs do # +#------------------------------------------------------------------------------# +def InterFrame(Input, Preset='Medium', Tuning='Film', NewNum=None, NewDen=1, GPU=False, InputType='2D', OverrideAlgo=None, OverrideArea=None, FrameDouble=False): + if not isinstance(Input, vs.VideoNode): + raise vs.Error('InterFrame: this is not a clip') + + # Validate inputs + Preset = Preset.lower() + Tuning = Tuning.lower() + InputType = InputType.upper() + + if Preset not in ['medium', 'fast', 'faster', 'fastest']: + raise vs.Error(f"InterFrame: '{Preset}' is not a valid preset") + + if Tuning not in ['film', 'smooth', 'animation', 'weak']: + raise vs.Error(f"InterFrame: '{Tuning}' is not a valid tuning") + + if InputType not in ['2D', 'SBS', 'OU', 'HSBS', 'HOU']: + raise vs.Error(f"InterFrame: '{InputType}' is not a valid InputType") + + def InterFrameProcess(clip): + # Create SuperString + if Preset in ['fast', 'faster', 'fastest']: + SuperString = '{pel:1,' + else: + SuperString = '{' + + SuperString += 'gpu:1}' if GPU else 'gpu:0}' + + # Create VectorsString + if Tuning == 'animation' or Preset == 'fastest': + VectorsString = '{block:{w:32,' + elif Preset in ['fast', 'faster'] or not GPU: + VectorsString = '{block:{w:16,' + else: + VectorsString = '{block:{w:8,' + + if Tuning == 'animation' or Preset == 'fastest': + VectorsString += 'overlap:0' + elif Preset == 'faster' and GPU: + VectorsString += 'overlap:1' + else: + VectorsString += 'overlap:2' + + if Tuning == 'animation': + VectorsString += '},main:{search:{coarse:{type:2,' + elif Preset == 'faster': + VectorsString += '},main:{search:{coarse:{' + else: + VectorsString += '},main:{search:{distance:0,coarse:{' + + if Tuning == 'animation': + VectorsString += 'distance:-6,satd:false},distance:0,' + elif Tuning == 'weak': + VectorsString += 'distance:-1,trymany:true,' + else: + VectorsString += 'distance:-10,' + + if Tuning == 'animation' or Preset in ['faster', 'fastest']: + VectorsString += 'bad:{sad:2000}}}}}' + elif Tuning == 'weak': + VectorsString += 'bad:{sad:2000}}}},refine:[{thsad:250,search:{distance:-1,satd:true}}]}' + else: + VectorsString += 'bad:{sad:2000}}}},refine:[{thsad:250}]}' + + # Create SmoothString + if NewNum is not None: + SmoothString = '{rate:{num:' + repr(NewNum) + ',den:' + repr(NewDen) + ',abs:true},' + elif clip.fps_num / clip.fps_den in [15, 25, 30] or FrameDouble: + SmoothString = '{rate:{num:2,den:1,abs:false},' + else: + SmoothString = '{rate:{num:60000,den:1001,abs:true},' + + if OverrideAlgo is not None: + SmoothString += 'algo:' + repr(OverrideAlgo) + ',mask:{cover:80,' + elif Tuning == 'animation': + SmoothString += 'algo:2,mask:{' + elif Tuning == 'smooth': + SmoothString += 'algo:23,mask:{' + else: + SmoothString += 'algo:13,mask:{cover:80,' + + if OverrideArea is not None: + SmoothString += f'area:{OverrideArea}' + elif Tuning == 'smooth': + SmoothString += 'area:150' + else: + SmoothString += 'area:0' + + if Tuning == 'weak': + SmoothString += ',area_sharp:1.2},scene:{blend:true,mode:0,limits:{blocks:50}}}' + else: + SmoothString += ',area_sharp:1.2},scene:{blend:true,mode:0}}' + + # Make interpolation vector clip + Super = clip.svp1.Super(SuperString) + Vectors = core.svp1.Analyse(Super['clip'], Super['data'], clip, VectorsString) + + # Put it together + return core.svp2.SmoothFps(clip, Super['clip'], Super['data'], Vectors['clip'], Vectors['data'], SmoothString) + + # Get either 1 or 2 clips depending on InputType + if InputType == 'SBS': + FirstEye = InterFrameProcess(Input.std.Crop(right=Input.width // 2)) + SecondEye = InterFrameProcess(Input.std.Crop(left=Input.width // 2)) + return core.std.StackHorizontal([FirstEye, SecondEye]) + elif InputType == 'OU': + FirstEye = InterFrameProcess(Input.std.Crop(bottom=Input.height // 2)) + SecondEye = InterFrameProcess(Input.std.Crop(top=Input.height // 2)) + return core.std.StackVertical([FirstEye, SecondEye]) + elif InputType == 'HSBS': + FirstEye = InterFrameProcess(Input.std.Crop(right=Input.width // 2).resize.Spline36(Input.width, Input.height)) + SecondEye = InterFrameProcess(Input.std.Crop(left=Input.width // 2).resize.Spline36(Input.width, Input.height)) + return core.std.StackHorizontal([FirstEye.resize.Spline36(Input.width // 2, Input.height), SecondEye.resize.Spline36(Input.width // 2, Input.height)]) + elif InputType == 'HOU': + FirstEye = InterFrameProcess(Input.std.Crop(bottom=Input.height // 2).resize.Spline36(Input.width, Input.height)) + SecondEye = InterFrameProcess(Input.std.Crop(top=Input.height // 2).resize.Spline36(Input.width, Input.height)) + return core.std.StackVertical([FirstEye.resize.Spline36(Input.width, Input.height // 2), SecondEye.resize.Spline36(Input.width, Input.height // 2)]) + else: + return InterFrameProcess(Input) + + +# column is the column you want to work on. +def FixColumnBrightness(c, column, input_low, input_high, output_low, output_high): + if not isinstance(c, vs.VideoNode): + raise vs.Error('FixColumnBrightness: this is not a clip') + + if c.format.color_family == vs.RGB: + raise vs.Error('FixColumnBrightness: RGB format is not supported') + + peak = (1 << c.format.bits_per_sample) - 1 + + if c.format.color_family != vs.GRAY: + c_orig = c + c = mvf.GetPlane(c, 0) + else: + c_orig = None + + input_low = scale(input_low, peak) + input_high = scale(input_high, peak) + output_low = scale(output_low, peak) + output_high = scale(output_high, peak) + + last = SmoothLevels(c, input_low, 1, input_high, output_low, output_high, Smode=0) + last = last.std.CropAbs(width=1, height=c.height, left=column) + last = Overlay(c, last, x=column) + if c_orig is not None: + last = core.std.ShufflePlanes([last, c_orig], planes=[0, 1, 2], colorfamily=c_orig.format.color_family) + return last + + +# row is the row you want to work on. +def FixRowBrightness(c, row, input_low, input_high, output_low, output_high): + if not isinstance(c, vs.VideoNode): + raise vs.Error('FixRowBrightness: this is not a clip') + + if c.format.color_family == vs.RGB: + raise vs.Error('FixRowBrightness: RGB format is not supported') + + peak = (1 << c.format.bits_per_sample) - 1 + + if c.format.color_family != vs.GRAY: + c_orig = c + c = mvf.GetPlane(c, 0) + else: + c_orig = None + + input_low = scale(input_low, peak) + input_high = scale(input_high, peak) + output_low = scale(output_low, peak) + output_high = scale(output_high, peak) + + last = SmoothLevels(c, input_low, 1, input_high, output_low, output_high, Smode=0) + last = last.std.CropAbs(width=c.width, height=1, top=row) + last = Overlay(c, last, y=row) + if c_orig is not None: + last = core.std.ShufflePlanes([last, c_orig], planes=[0, 1, 2], colorfamily=c_orig.format.color_family) + return last + + +# protect_value determines which pixels wouldn't be affected by the filter. Increasing the value, you protect the pixels with lower luma. +def FixColumnBrightnessProtect(c, column, input_low, input_high, output_low, output_high, protect_value=20): + if not isinstance(c, vs.VideoNode): + raise vs.Error('FixColumnBrightnessProtect: this is not a clip') + + if c.format.color_family == vs.RGB: + raise vs.Error('FixColumnBrightnessProtect: RGB format is not supported') + + peak = (1 << c.format.bits_per_sample) - 1 + + if c.format.color_family != vs.GRAY: + c_orig = c + c = mvf.GetPlane(c, 0) + else: + c_orig = None + + input_low = scale(255 - input_low, peak) + input_high = scale(255 - input_high, peak) + output_low = scale(255 - output_low, peak) + output_high = scale(255 - output_high, peak) + protect_value = scale(protect_value, peak) + + last = SmoothLevels(c.std.Invert(), input_low, 1, input_high, output_low, output_high, protect=protect_value, Smode=0).std.Invert() + last = last.std.CropAbs(width=1, height=c.height, left=column) + last = Overlay(c, last, x=column) + if c_orig is not None: + last = core.std.ShufflePlanes([last, c_orig], planes=[0, 1, 2], colorfamily=c_orig.format.color_family) + return last + + +def FixRowBrightnessProtect(c, row, input_low, input_high, output_low, output_high, protect_value=20): + if not isinstance(c, vs.VideoNode): + raise vs.Error('FixRowBrightnessProtect: this is not a clip') + + if c.format.color_family == vs.RGB: + raise vs.Error('FixRowBrightnessProtect: RGB format is not supported') + + shift = c.format.bits_per_sample - 8 + peak = (1 << c.format.bits_per_sample) - 1 + + if c.format.color_family != vs.GRAY: + c_orig = c + c = mvf.GetPlane(c, 0) + else: + c_orig = None + + input_low = scale(255 - input_low, peak) + input_high = scale(255 - input_high, peak) + output_low = scale(255 - output_low, peak) + output_high = scale(255 - output_high, peak) + protect_value = scale(protect_value, peak) + + last = SmoothLevels(c.std.Invert(), input_low, 1, input_high, output_low, output_high, protect=protect_value, Smode=0).std.Invert() + last = last.std.CropAbs(width=c.width, height=1, top=row) + last = Overlay(c, last, y=row) + if c_orig is not None: + last = core.std.ShufflePlanes([last, c_orig], planes=[0, 1, 2], colorfamily=c_orig.format.color_family) + return last + + +# adj_val should be a number x where -100 < x < 100. This parameter decides +# how much the brightness should be affected. Numbers below 0 will make it darker +# and number above 0 will make it brighter. +# +# prot_val is the protect value. This is what makes it behave differently than the +# normal FixBrightness. Any luma above (255-prot_val) will not be affected which is +# the basic idea of the protect script. +def FixColumnBrightnessProtect2(c, column, adj_val, prot_val=16): + if not isinstance(c, vs.VideoNode): + raise vs.Error('FixColumnBrightnessProtect2: this is not a clip') + + if c.format.color_family == vs.RGB: + raise vs.Error('FixColumnBrightnessProtect2: RGB format is not supported') + + if not (-100 < adj_val < 100): + raise vs.Error('FixColumnBrightnessProtect2: adj_val must be greater than -100 and less than 100') + + peak = (1 << c.format.bits_per_sample) - 1 + + if c.format.color_family != vs.GRAY: + c_orig = c + c = mvf.GetPlane(c, 0) + else: + c_orig = None + + expr = f'x {scale(16, peak)} - {100 - adj_val} / 100 * {scale(16, peak)} + x {scale(255 - prot_val, peak)} - -10 / 0 max 1 min * x x {scale(245 - prot_val, peak)} - 10 / 0 max 1 min * +' + last = c.std.Expr(expr=[expr]) + last = last.std.CropAbs(width=1, height=c.height, left=column) + last = Overlay(c, last, x=column) + if c_orig is not None: + last = core.std.ShufflePlanes([last, c_orig], planes=[0, 1, 2], colorfamily=c_orig.format.color_family) + return last + + +def FixRowBrightnessProtect2(c, row, adj_val, prot_val=16): + if not isinstance(c, vs.VideoNode): + raise vs.Error('FixRowBrightnessProtect2: this is not a clip') + + if c.format.color_family == vs.RGB: + raise vs.Error('FixRowBrightnessProtect2: RGB format is not supported') + + if not (-100 < adj_val < 100): + raise vs.Error('FixRowBrightnessProtect2: adj_val must be greater than -100 and less than 100') + + peak = (1 << c.format.bits_per_sample) - 1 + + if c.format.color_family != vs.GRAY: + c_orig = c + c = mvf.GetPlane(c, 0) + else: + c_orig = None + + expr = f'x {scale(16, peak)} - {100 - adj_val} / 100 * {scale(16, peak)} + x {scale(255 - prot_val, peak)} - -10 / 0 max 1 min * x x {scale(245 - prot_val, peak)} - 10 / 0 max 1 min * +' + last = c.std.Expr(expr=[expr]) + last = last.std.CropAbs(width=c.width, height=1, top=row) + last = Overlay(c, last, y=row) + if c_orig is not None: + last = core.std.ShufflePlanes([last, c_orig], planes=[0, 1, 2], colorfamily=c_orig.format.color_family) + return last + + +######################################################################################### +### ### +### function Smooth Levels : SmoothLevels() ### +### ### +### v1.02 by "LaTo INV." ### +### ### +### 28 January 2009 ### +### ### +######################################################################################### +### +### +### /!\ Needed filters : RGVS, f3kdb +### -------------------- +### +### +### +### +---------+ +### | GENERAL | +### +---------+ +### +### Levels options: +### --------------- +### input_low, gamma, input_high, output_low, output_high [default: 0, 1.0, maximum value of input format, 0, maximum value of input format] +### /!\ The value is not internally normalized on an 8-bit scale, and must be scaled to the bit depth of input format manually by users +### +### chroma [default: 50] +### --------------------- +### 0 = no chroma processing (similar as Ylevels) +### xx = intermediary +### 100 = normal chroma processing (similar as Levels) +### +### limiter [default: 0] +### -------------------- +### 0 = no limiter (similar as Ylevels) +### 1 = input limiter +### 2 = output limiter (similar as Levels: coring=false) +### 3 = input & output limiter (similar as Levels: coring=true) +### +### +### +### +----------+ +### | LIMITING | +### +----------+ +### +### Lmode [default: 0] +### ------------------ +### 0 = no limit +### 1 = limit conversion on dark & bright areas (apply conversion @0% at luma=0 & @100% at luma=Ecenter & @0% at luma=255) +### 2 = limit conversion on dark areas (apply conversion @0% at luma=0 & @100% at luma=255) +### 3 = limit conversion on bright areas (apply conversion @100% at luma=0 & @0% at luma=255) +### +### DarkSTR [default: 100] +### ---------------------- +### Strength for limiting: the higher, the more conversion are reduced on dark areas (for Lmode=1&2) +### +### BrightSTR [default: 100] +### ------------------------ +### Strength for limiting: the higher, the more conversion are reduced on bright areas (for Lmode=1&3) +### +### Ecenter [default: median value of input format] +### ---------------------- +### Center of expression for Lmode=1 +### /!\ The value is not internally normalized on an 8-bit scale, and must be scaled to the bit depth of input format manually by users +### +### protect [default: -1] +### --------------------- +### -1 = protect off +### >=0 = pure black protection +### ---> don't apply conversion on pixels egal or below this value +### (ex: with 16, the black areas like borders and generic are untouched so they don't look washed out) +### /!\ The value is not internally normalized on an 8-bit scale, and must be scaled to the bit depth of input format manually by users +### +### Ecurve [default: 0] +### ------------------- +### Curve used for limit & protect: +### 0 = use sine curve +### 1 = use linear curve +### +### +### +### +-----------+ +### | SMOOTHING | +### +-----------+ +### +### Smode [default: -2] +### ------------------- +### 2 = smooth on, maxdiff must be < to "255/Mfactor" +### 1 = smooth on, maxdiff must be < to "128/Mfactor" +### 0 = smooth off +### -1 = smooth on if maxdiff < "128/Mfactor", else off +### -2 = smooth on if maxdiff < "255/Mfactor", else off +### +### Mfactor [default: 2] +### -------------------- +### The higher, the more precise but the less maxdiff allowed: +### maxdiff=128/Mfactor for Smode1&-1 and maxdiff=255/Mfactor for Smode2&-2 +### +### RGmode [default: 12] +### -------------------- +### In strength order: + 19 > 12 >> 20 > 11 - +### +### useDB [default: false] +### --------------------- +### Use f3kdb on top of removegrain: prevent posterize when doing levels conversion +### +### +######################################################################################### +def SmoothLevels(input, input_low=0, gamma=1.0, input_high=None, output_low=0, output_high=None, chroma=50, limiter=0, Lmode=0, DarkSTR=100, BrightSTR=100, Ecenter=None, protect=-1, Ecurve=0, + Smode=-2, Mfactor=2, RGmode=12, useDB=False): + if not isinstance(input, vs.VideoNode): + raise vs.Error('SmoothLevels: this is not a clip') + + if input.format.color_family == vs.RGB: + raise vs.Error('SmoothLevels: RGB format is not supported') + + isGray = (input.format.color_family == vs.GRAY) + + if input.format.sample_type == vs.INTEGER: + neutral = [1 << (input.format.bits_per_sample - 1)] * 2 + peak = (1 << input.format.bits_per_sample) - 1 + else: + neutral = [0.5, 0.0] + peak = 1.0 + + if chroma <= 0 and not isGray: + input_orig = input + input = mvf.GetPlane(input, 0) + else: + input_orig = None + + if input_high is None: + input_high = peak + + if output_high is None: + output_high = peak + + if Ecenter is None: + Ecenter = neutral[0] + + if gamma <= 0: + raise vs.Error('SmoothLevels: gamma must be greater than 0.0') + + if Ecenter <= 0 or Ecenter >= peak: + raise vs.Error('SmoothLevels: Ecenter must be greater than 0 and less than maximum value of input format') + + if Mfactor <= 0: + raise vs.Error('SmoothLevels: Mfactor must be greater than 0') + + if RGmode == 4: + RemoveGrain = partial(core.std.Median) + elif RGmode in [11, 12]: + RemoveGrain = partial(core.std.Convolution, matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]) + elif RGmode == 19: + RemoveGrain = partial(core.std.Convolution, matrix=[1, 1, 1, 1, 0, 1, 1, 1, 1]) + elif RGmode == 20: + RemoveGrain = partial(core.std.Convolution, matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1]) + else: + RemoveGrain = partial(core.rgvs.RemoveGrain, mode=[RGmode]) + + ### EXPRESSION + exprY = f'x {input_low} - {input_high - input_low + (input_high == input_low)} / {1 / gamma} pow {output_high - output_low} * {output_low} +' + + if chroma > 0 and not isGray: + scaleC = ((output_high - output_low) / (input_high - input_low + (input_high == input_low)) + 100 / chroma - 1) / (100 / chroma) + exprC = f'x {neutral[1]} - {scaleC} * {neutral[1]} +' + + Dstr = DarkSTR / 100 + Bstr = BrightSTR / 100 + + if Lmode <= 0: + exprL = '1' + elif Ecurve <= 0: + if Lmode == 1: + var_d = f'x {Ecenter} /' + var_b = f'{peak} x - {peak} {Ecenter} - /' + exprL = f'x {Ecenter} < ' + sine_expr(var_d) + f' {Dstr} pow x {Ecenter} > ' + sine_expr(var_b) + f' {Bstr} pow 1 ? ?' + elif Lmode == 2: + var_d = f'x {peak} /' + exprL = sine_expr(var_d) + f' {Dstr} pow' + else: + var_b = f'{peak} x - {peak} /' + exprL = sine_expr(var_b) + f' {Bstr} pow' + else: + if Lmode == 1: + exprL = f'x {Ecenter} < x {Ecenter} / abs {Dstr} pow x {Ecenter} > 1 x {Ecenter} - {peak - Ecenter} / abs - {Bstr} pow 1 ? ?' + elif Lmode == 2: + exprL = f'1 x {peak} - {peak} / abs - {Dstr} pow' + else: + exprL = f'x {peak} - {peak} / abs {Bstr} pow' + + if protect <= -1: + exprP = '1' + elif Ecurve <= 0: + var_p = f'x {protect} - {scale(16, peak)} /' + exprP = f'x {protect} <= 0 x {protect + scale(16, peak)} >= 1 ' + sine_expr(var_p) + f' ? ?' + else: + exprP = f'x {protect} <= 0 x {protect + scale(16, peak)} >= 1 x {protect} - {scale(16, peak)} / abs ? ?' + + ### PROCESS + if limiter == 1 or limiter >= 3: + limitI = input.std.Expr(expr=[f'x {input_low} max {input_high} min']) + else: + limitI = input + + expr = exprL + ' ' + exprP + ' * ' + exprY + ' x - * x +' + level = limitI.std.Expr(expr=[expr] if chroma <= 0 or isGray else [expr, exprC]) + diff = core.std.Expr([limitI, level], expr=[f'x y - {Mfactor} * {neutral[1]} +']) + process = RemoveGrain(diff) + if useDB: + process = process.std.Expr(expr=[f'x {neutral[1]} - {Mfactor} / {neutral[1]} +']).f3kdb.Deband(grainy=0, grainc=0, output_depth=input.format.bits_per_sample) + smth = core.std.MakeDiff(limitI, process) + else: + smth = core.std.Expr([limitI, process], expr=[f'x y {neutral[1]} - {Mfactor} / -']) + + level2 = core.std.Expr([limitI, diff], expr=[f'x y {neutral[1]} - {Mfactor} / -']) + diff2 = core.std.Expr([level2, level], expr=[f'x y - {Mfactor} * {neutral[1]} +']) + process2 = RemoveGrain(diff2) + if useDB: + process2 = process2.std.Expr(expr=[f'x {neutral[1]} - {Mfactor} / {neutral[1]} +']).f3kdb.Deband(grainy=0, grainc=0, output_depth=input.format.bits_per_sample) + smth2 = core.std.MakeDiff(smth, process2) + else: + smth2 = core.std.Expr([smth, process2], expr=[f'x y {neutral[1]} - {Mfactor} / -']) + + mask1 = core.std.Expr([limitI, level], expr=[f'x y - abs {neutral[0] / Mfactor} >= {peak} 0 ?']) + mask2 = core.std.Expr([limitI, level], expr=[f'x y - abs {peak / Mfactor} >= {peak} 0 ?']) + + if Smode >= 2: + Slevel = smth2 + elif Smode == 1: + Slevel = smth + elif Smode == -1: + Slevel = core.std.MaskedMerge(smth, level, mask1) + elif Smode <= -2: + Slevel = core.std.MaskedMerge(core.std.MaskedMerge(smth, smth2, mask1), level, mask2) + else: + Slevel = level + + if limiter >= 2: + limitO = Slevel.std.Expr(expr=[f'x {output_low} max {output_high} min']) + else: + limitO = Slevel + + if input_orig is not None: + limitO = core.std.ShufflePlanes([limitO, input_orig], planes=[0, 1, 2], colorfamily=input_orig.format.color_family) + return limitO + + +############################## +# FastLineDarken 1.4x MT MOD # +############################## +# +# Written by Vectrangle (http://forum.doom9.org/showthread.php?t=82125) +# Didée: - Speed Boost, Updated: 11th May 2007 +# Dogway - added protection option. 12-May-2011 +# +# Parameters are: +# strength (integer) - Line darkening amount, 0-256. Default 48. Represents the _maximum_ amount +# that the luma will be reduced by, weaker lines will be reduced by +# proportionately less. +# protection (integer) - Prevents the darkest lines from being darkened. Protection acts as a threshold. +# Values range from 0 (no prot) to ~50 (protect everything) +# luma_cap (integer) - value from 0 (black) to 255 (white), used to stop the darkening +# determination from being 'blinded' by bright pixels, and to stop grey +# lines on white backgrounds being darkened. Any pixels brighter than +# luma_cap are treated as only being as bright as luma_cap. Lowering +# luma_cap tends to reduce line darkening. 255 disables capping. Default 191. +# threshold (integer) - any pixels that were going to be darkened by an amount less than +# threshold will not be touched. setting this to 0 will disable it, setting +# it to 4 (default) is recommended, since often a lot of random pixels are +# marked for very slight darkening and a threshold of about 4 should fix +# them. Note if you set threshold too high, some lines will not be darkened +# thinning (integer) - optional line thinning amount, 0-256. Setting this to 0 will disable it, +# which is gives a _big_ speed increase. Note that thinning the lines will +# inherently darken the remaining pixels in each line a little. Default 0. +def FastLineDarkenMOD(c, strength=48, protection=5, luma_cap=191, threshold=4, thinning=0): + if not isinstance(c, vs.VideoNode): + raise vs.Error('FastLineDarkenMOD: this is not a clip') + + if c.format.color_family == vs.RGB: + raise vs.Error('FastLineDarkenMOD: RGB format is not supported') + + peak = (1 << c.format.bits_per_sample) - 1 if c.format.sample_type == vs.INTEGER else 1.0 + + if c.format.color_family != vs.GRAY: + c_orig = c + c = mvf.GetPlane(c, 0) + else: + c_orig = None + + ## parameters ## + Str = strength / 128 + lum = scale(luma_cap, peak) + thr = scale(threshold, peak) + thn = thinning / 16 + + ## filtering ## + exin = c.std.Maximum(threshold=peak / (protection + 1)).std.Minimum() + thick = core.std.Expr([c, exin], expr=[f'y {lum} < y {lum} ? x {thr} + > x y {lum} < y {lum} ? - 0 ? {Str} * x +']) + if thinning <= 0: + last = thick + else: + diff = core.std.Expr([c, exin], expr=[f'y {lum} < y {lum} ? x {thr} + > x y {lum} < y {lum} ? - 0 ? {scale(127, peak)} +']) + linemask = diff.std.Minimum().std.Expr(expr=[f'x {scale(127, peak)} - {thn} * {peak} +']).std.Convolution(matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1]) + thin = core.std.Expr([c.std.Maximum(), diff], expr=[f'x y {scale(127, peak)} - {Str} 1 + * +']) + last = core.std.MaskedMerge(thin, thick, linemask) + + if c_orig is not None: + last = core.std.ShufflePlanes([last, c_orig], planes=[0, 1, 2], colorfamily=c_orig.format.color_family) + return last + + +##################### +## Toon v0.82 edit ## +##################### +# +# function created by mf +# support by Soulhunter ;-) +# ported to masktools v2 and optimized by Didee (0.82) +# added parameters and smaller changes by MOmonster (0.82 edited) +# +# toon v0.8 is the newest light-weight build of mf´s nice line darken function mf_toon +# +# Parameters: +# str (float) - Strength of the line darken. Default is 1.0 +# l_thr (int) - Lower threshold for the linemask. Default is 2 +# u_thr (int) - Upper threshold for the linemask. Default is 12 +# blur (int) - "blur" parameter of AWarpSharp2. Default is 2 +# depth (int) - "depth" parameter of AWarpSharp2. Default is 32 +def Toon(input, str=1.0, l_thr=2, u_thr=12, blur=2, depth=32): + if not isinstance(input, vs.VideoNode): + raise vs.Error('Toon: this is not a clip') + + if input.format.color_family == vs.RGB: + raise vs.Error('Toon: RGB format is not supported') + + neutral = 1 << (input.format.bits_per_sample - 1) + peak = (1 << input.format.bits_per_sample) - 1 + multiple = peak / 255 + + if input.format.color_family != vs.GRAY: + input_orig = input + input = mvf.GetPlane(input, 0) + else: + input_orig = None + + lthr = neutral + scale(l_thr, peak) + lthr8 = lthr / multiple + uthr = neutral + scale(u_thr, peak) + uthr8 = uthr / multiple + ludiff = u_thr - l_thr + + last = core.std.MakeDiff(input.std.Maximum().std.Minimum(), input) + last = core.std.Expr([last, Padding(last, 6, 6, 6, 6).warp.AWarpSharp2(blur=blur, depth=depth).std.Crop(6, 6, 6, 6)], expr=['x y min']) + expr = f'y {lthr} <= {neutral} y {uthr} >= x {uthr8} y {multiple} / - 128 * x {multiple} / y {multiple} / {lthr8} - * + {ludiff} / {multiple} * ? {neutral} - {str} * {neutral} + ?' + last = core.std.MakeDiff(input, core.std.Expr([last, last.std.Maximum()], expr=[expr])) + + if input_orig is not None: + last = core.std.ShufflePlanes([last, input_orig], planes=[0, 1, 2], colorfamily=input_orig.format.color_family) + return last + + +################################################################################################ +### ### +### LimitedSharpenFaster MOD : function LSFmod() ### +### ### +### Modded Version by LaTo INV. ### +### ### +### v1.9 - 05 October 2009 ### +### ### +################################################################################################ +### +### +--------------+ +### | DEPENDENCIES | +### +--------------+ +### +### -> RGVS +### -> CAS +### +### +### +### +---------+ +### | GENERAL | +### +---------+ +### +### strength [int] +### -------------- +### Strength of the sharpening +### +### Smode [int: 1,2,3] +### ---------------------- +### Sharpen mode: +### =1 : Range sharpening +### =2 : Nonlinear sharpening (corrected version) +### =3 : Contrast Adaptive Sharpening +### +### Smethod [int: 1,2,3] +### -------------------- +### Sharpen method: (only used in Smode=1,2) +### =1 : 3x3 kernel +### =2 : Min/Max +### =3 : Min/Max + 3x3 kernel +### +### kernel [int: 11,12,19,20] +### ------------------------- +### Kernel used in Smethod=1&3 +### In strength order: + 19 > 12 >> 20 > 11 - +### +### +### +### +---------+ +### | SPECIAL | +### +---------+ +### +### preblur [int: 0,1,2,3] +### -------------------------------- +### Mode to avoid noise sharpening & ringing: +### =-1 : No preblur +### = 0 : MinBlur(0) +### = 1 : MinBlur(1) +### = 2 : MinBlur(2) +### = 3 : DFTTest +### +### secure [bool] +### ------------- +### Mode to avoid banding & oil painting (or face wax) effect of sharpening +### +### source [clip] +### ------------- +### If source is defined, LSFmod doesn't sharp more a denoised clip than this source clip +### In this mode, you can safely set Lmode=0 & PP=off +### Usage: denoised.LSFmod(source=source) +### Example: last.FFT3DFilter().LSFmod(source=last,Lmode=0,soft=0) +### +### +### +### +----------------------+ +### | NONLINEAR SHARPENING | +### +----------------------+ +### +### Szrp [int] +### ---------- +### Zero Point: +### - differences below Szrp are amplified (overdrive sharpening) +### - differences above Szrp are reduced (reduced sharpening) +### +### Spwr [int] +### ---------- +### Power: exponent for sharpener +### +### SdmpLo [int] +### ------------ +### Damp Low: reduce sharpening for small changes [0:disable] +### +### SdmpHi [int] +### ------------ +### Damp High: reduce sharpening for big changes [0:disable] +### +### +### +### +----------+ +### | LIMITING | +### +----------+ +### +### Lmode [int: ...,0,1,2,3,4] +### -------------------------- +### Limit mode: +### <0 : Limit with repair (ex: Lmode=-1 --> repair(1), Lmode=-5 --> repair(5)...) +### =0 : No limit +### =1 : Limit to over/undershoot +### =2 : Limit to over/undershoot on edges and no limit on not-edges +### =3 : Limit to zero on edges and to over/undershoot on not-edges +### =4 : Limit to over/undershoot on edges and to over/undershoot2 on not-edges +### +### overshoot [int] +### --------------- +### Limit for pixels that get brighter during sharpening +### +### undershoot [int] +### ---------------- +### Limit for pixels that get darker during sharpening +### +### overshoot2 [int] +### ---------------- +### Same as overshoot, only for Lmode=4 +### +### undershoot2 [int] +### ----------------- +### Same as undershoot, only for Lmode=4 +### +### +### +### +-----------------+ +### | POST-PROCESSING | +### +-----------------+ +### +### soft [int: -2,-1,0...100] +### ------------------------- +### Soft the sharpening effect (-1 = old autocalculate, -2 = new autocalculate) +### +### soothe [bool] +### ------------- +### =True : Enable soothe temporal stabilization +### =False : Disable soothe temporal stabilization +### +### keep [int: 0...100] +### ------------------- +### Minimum percent of the original sharpening to keep (only with soothe=True) +### +### +### +### +-------+ +### | EDGES | +### +-------+ +### +### edgemode [int: -1,0,1,2] +### ------------------------ +### =-1 : Show edgemask +### = 0 : Sharpening all +### = 1 : Sharpening only edges +### = 2 : Sharpening only not-edges +### +### edgemaskHQ [bool] +### ----------------- +### =True : Original edgemask +### =False : Faster edgemask +### +### +### +### +------------+ +### | UPSAMPLING | +### +------------+ +### +### ss_x ; ss_y [float] +### ------------------- +### Supersampling factor (reduce aliasing on edges) +### +### dest_x ; dest_y [int] +### --------------------- +### Output resolution after sharpening (avoid a resizing step) +### +### +### +### +----------+ +### | SETTINGS | +### +----------+ +### +### defaults [string: "old" or "slow" or "fast"] +### -------------------------------------------- +### = "old" : Reset settings to original version (output will be THE SAME AS LSF) +### = "slow" : Enable SLOW modded version settings +### = "fast" : Enable FAST modded version settings +### --> /!\ [default:"fast"] +### +### +### defaults="old" : - strength = 100 +### ---------------- - Smode = 1 +### - Smethod = Smode==1?2:1 +### - kernel = 11 +### +### - preblur = -1 +### - secure = false +### - source = undefined +### +### - Szrp = 16 +### - Spwr = 2 +### - SdmpLo = strength/25 +### - SdmpHi = 0 +### +### - Lmode = 1 +### - overshoot = 1 +### - undershoot = overshoot +### - overshoot2 = overshoot*2 +### - undershoot2 = overshoot2 +### +### - soft = 0 +### - soothe = false +### - keep = 25 +### +### - edgemode = 0 +### - edgemaskHQ = true +### +### - ss_x = Smode==1?1.50:1.25 +### - ss_y = ss_x +### - dest_x = ox +### - dest_y = oy +### +### +### defaults="slow" : - strength = 100 +### ----------------- - Smode = 2 +### - Smethod = 3 +### - kernel = 11 +### +### - preblur = -1 +### - secure = true +### - source = undefined +### +### - Szrp = 16 +### - Spwr = 4 +### - SdmpLo = 4 +### - SdmpHi = 48 +### +### - Lmode = 4 +### - overshoot = strength/100 +### - undershoot = overshoot +### - overshoot2 = overshoot*2 +### - undershoot2 = overshoot2 +### +### - soft = -2 +### - soothe = true +### - keep = 20 +### +### - edgemode = 0 +### - edgemaskHQ = true +### +### - ss_x = Smode==3?1.00:1.50 +### - ss_y = ss_x +### - dest_x = ox +### - dest_y = oy +### +### +### defaults="fast" : - strength = 80 +### ----------------- - Smode = 3 +### - Smethod = 2 +### - kernel = 11 +### +### - preblur = 0 +### - secure = true +### - source = undefined +### +### - Szrp = 16 +### - Spwr = 4 +### - SdmpLo = 4 +### - SdmpHi = 48 +### +### - Lmode = 0 +### - overshoot = strength/100 +### - undershoot = overshoot +### - overshoot2 = overshoot*2 +### - undershoot2 = overshoot2 +### +### - soft = 0 +### - soothe = false +### - keep = 20 +### +### - edgemode = 0 +### - edgemaskHQ = false +### +### - ss_x = Smode==3?1.00:1.25 +### - ss_y = ss_x +### - dest_x = ox +### - dest_y = oy +### +################################################################################################ +def LSFmod(input, strength=None, Smode=None, Smethod=None, kernel=11, preblur=None, secure=None, source=None, Szrp=16, Spwr=None, SdmpLo=None, SdmpHi=None, Lmode=None, overshoot=None, undershoot=None, + overshoot2=None, undershoot2=None, soft=None, soothe=None, keep=None, edgemode=0, edgemaskHQ=None, ss_x=None, ss_y=None, dest_x=None, dest_y=None, defaults='fast'): + if not isinstance(input, vs.VideoNode): + raise vs.Error('LSFmod: this is not a clip') + + if input.format.color_family == vs.RGB: + raise vs.Error('LSFmod: RGB format is not supported') + + if source is not None and (not isinstance(source, vs.VideoNode) or source.format.id != input.format.id): + raise vs.Error("LSFmod: 'source' must be the same format as input") + + isGray = (input.format.color_family == vs.GRAY) + isInteger = (input.format.sample_type == vs.INTEGER) + + if isInteger: + neutral = 1 << (input.format.bits_per_sample - 1) + peak = (1 << input.format.bits_per_sample) - 1 + factor = 1 << (input.format.bits_per_sample - 8) + else: + neutral = 0.0 + peak = 1.0 + factor = 255.0 + + ### DEFAULTS + try: + num = ['old', 'slow', 'fast'].index(defaults.lower()) + except: + raise vs.Error('LSFmod: defaults must be "old" or "slow" or "fast"') + + ox = input.width + oy = input.height + + if strength is None: + strength = [100, 100, 80][num] + if Smode is None: + Smode = [1, 2, 3][num] + if Smethod is None: + Smethod = [2 if Smode == 1 else 1, 3, 2][num] + if preblur is None: + preblur = [-1, -1, 0][num] + if secure is None: + secure = [False, True, True][num] + if Spwr is None: + Spwr = [2, 4, 4][num] + if SdmpLo is None: + SdmpLo = [strength // 25, 4, 4][num] + if SdmpHi is None: + SdmpHi = [0, 48, 48][num] + if Lmode is None: + Lmode = [1, 4, 0][num] + if overshoot is None: + overshoot = [1, strength // 100, strength // 100][num] + if undershoot is None: + undershoot = overshoot + if overshoot2 is None: + overshoot2 = overshoot * 2 + if undershoot2 is None: + undershoot2 = overshoot2 + if soft is None: + soft = [0, -2, 0][num] + if soothe is None: + soothe = [False, True, False][num] + if keep is None: + keep = [25, 20, 20][num] + if edgemaskHQ is None: + edgemaskHQ = [True, True, False][num] + if ss_x is None: + ss_x = [1.5 if Smode == 1 else 1.25, 1.0 if Smode == 3 else 1.5, 1.0 if Smode == 3 else 1.25][num] + if ss_y is None: + ss_y = ss_x + if dest_x is None: + dest_x = ox + if dest_y is None: + dest_y = oy + + if kernel == 4: + RemoveGrain = partial(core.std.Median) + elif kernel in [11, 12]: + RemoveGrain = partial(core.std.Convolution, matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]) + elif kernel == 19: + RemoveGrain = partial(core.std.Convolution, matrix=[1, 1, 1, 1, 0, 1, 1, 1, 1]) + elif kernel == 20: + RemoveGrain = partial(core.std.Convolution, matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1]) + else: + RemoveGrain = partial(core.rgvs.RemoveGrain, mode=[kernel]) + + if soft == -1: + soft = math.sqrt(((ss_x + ss_y) / 2 - 1) * 100) * 10 + elif soft <= -2: + soft = int((1 + 2 / (ss_x + ss_y)) * math.sqrt(strength)) + soft = min(soft, 100) + + xxs = cround(ox * ss_x / 8) * 8 + yys = cround(oy * ss_y / 8) * 8 + + Str = strength / 100 + + ### SHARP + if ss_x > 1 or ss_y > 1: + tmp = input.resize.Spline36(xxs, yys) + else: + tmp = input + + if not isGray: + tmp_orig = tmp + tmp = mvf.GetPlane(tmp, 0) + + if preblur <= -1: + pre = tmp + elif preblur >= 3: + expr = 'x {i} < {peak} x {j} > 0 {peak} x {i} - {peak} {j} {i} - / * - ? ?'.format(i=scale(16, peak), j=scale(75, peak), peak=peak) + pre = core.std.MaskedMerge(tmp.dfttest.DFTTest(tbsize=1, slocation=[0.0,4.0, 0.2,9.0, 1.0,15.0]), tmp, tmp.std.Expr(expr=[expr])) + else: + pre = MinBlur(tmp, r=preblur) + + dark_limit = pre.std.Minimum() + bright_limit = pre.std.Maximum() + + if Smode < 3: + if Smethod <= 1: + method = RemoveGrain(pre) + elif Smethod == 2: + method = core.std.Merge(dark_limit, bright_limit) + else: + method = RemoveGrain(core.std.Merge(dark_limit, bright_limit)) + + if secure: + method = core.std.Expr([method, pre], expr=['x y < x {i} + x y > x {i} - x ? ?'.format(i=scale(1, peak))]) + + if preblur > -1: + method = core.std.MakeDiff(tmp, core.std.MakeDiff(pre, method)) + + if Smode <= 1: + normsharp = core.std.Expr([tmp, method], expr=[f'x x y - {Str} * +']) + else: + tmpScaled = tmp.std.Expr(expr=[f'x {1 / factor if isInteger else factor} *'], format=tmp.format.replace(sample_type=vs.FLOAT, bits_per_sample=32)) + methodScaled = method.std.Expr(expr=[f'x {1 / factor if isInteger else factor} *'], format=method.format.replace(sample_type=vs.FLOAT, bits_per_sample=32)) + expr = f'x y = x x x y - abs {Szrp} / {1 / Spwr} pow {Szrp} * {Str} * x y - dup abs / * x y - dup * {Szrp * Szrp} {SdmpLo} + * x y - dup * {SdmpLo} + {Szrp * Szrp} * / * 1 {SdmpHi} 0 = 0 {(Szrp / SdmpHi) ** 4} ? + 1 {SdmpHi} 0 = 0 x y - abs {SdmpHi} / 4 pow ? + / * + ? {factor if isInteger else 1 / factor} *' + normsharp = core.std.Expr([tmpScaled, methodScaled], expr=[expr], format=tmp.format) + else: + normsharp = pre.cas.CAS(sharpness=min(Str, 1)) + + if secure: + normsharp = core.std.Expr([normsharp, pre], expr=['x y < x {i} + x y > x {i} - x ? ?'.format(i=scale(1, peak))]) + + if preblur > -1: + normsharp = core.std.MakeDiff(tmp, core.std.MakeDiff(pre, normsharp)) + + ### LIMIT + normal = mt_clamp(normsharp, bright_limit, dark_limit, scale(overshoot, peak), scale(undershoot, peak)) + second = mt_clamp(normsharp, bright_limit, dark_limit, scale(overshoot2, peak), scale(undershoot2, peak)) + zero = mt_clamp(normsharp, bright_limit, dark_limit, 0, 0) + + if edgemaskHQ: + edge = tmp.std.Sobel(scale=2) + else: + edge = core.std.Expr([tmp.std.Maximum(), tmp.std.Minimum()], expr=['x y -']) + edge = edge.std.Expr(expr=[f'x {1 / factor if isInteger else factor} * {128 if edgemaskHQ else 32} / 0.86 pow 255 * {factor if isInteger else 1 / factor} *']) + + if Lmode < 0: + limit1 = core.rgvs.Repair(normsharp, tmp, mode=[abs(Lmode)]) + elif Lmode == 0: + limit1 = normsharp + elif Lmode == 1: + limit1 = normal + elif Lmode == 2: + limit1 = core.std.MaskedMerge(normsharp, normal, edge.std.Inflate()) + elif Lmode == 3: + limit1 = core.std.MaskedMerge(normal, zero, edge.std.Inflate()) + else: + limit1 = core.std.MaskedMerge(second, normal, edge.std.Inflate()) + + if edgemode <= 0: + limit2 = limit1 + elif edgemode == 1: + limit2 = core.std.MaskedMerge(tmp, limit1, edge.std.Inflate().std.Inflate().std.Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1])) + else: + limit2 = core.std.MaskedMerge(limit1, tmp, edge.std.Inflate().std.Inflate().std.Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1])) + + ### SOFT + if soft == 0: + PP1 = limit2 + else: + sharpdiff = core.std.MakeDiff(tmp, limit2) + sharpdiff = core.std.Expr([sharpdiff, sharpdiff.std.Convolution(matrix=[1, 1, 1, 1, 0, 1, 1, 1, 1])], expr=[f'x {neutral} - abs y {neutral} - abs > y {soft} * x {100 - soft} * + 100 / x ?']) + PP1 = core.std.MakeDiff(tmp, sharpdiff) + + ### SOOTHE + if soothe: + diff = core.std.MakeDiff(tmp, PP1) + diff = core.std.Expr([diff, AverageFrames(diff, weights=[1] * 3, scenechange=32 / 255)], + expr=[f'x {neutral} - y {neutral} - * 0 < x {neutral} - 100 / {keep} * {neutral} + x {neutral} - abs y {neutral} - abs > x {keep} * y {100 - keep} * + 100 / x ? ?']) + PP2 = core.std.MakeDiff(tmp, diff) + else: + PP2 = PP1 + + ### OUTPUT + if dest_x != ox or dest_y != oy: + if not isGray: + PP2 = core.std.ShufflePlanes([PP2, tmp_orig], planes=[0, 1, 2], colorfamily=input.format.color_family) + out = PP2.resize.Spline36(dest_x, dest_y) + elif ss_x > 1 or ss_y > 1: + out = PP2.resize.Spline36(dest_x, dest_y) + if not isGray: + out = core.std.ShufflePlanes([out, input], planes=[0, 1, 2], colorfamily=input.format.color_family) + elif not isGray: + out = core.std.ShufflePlanes([PP2, input], planes=[0, 1, 2], colorfamily=input.format.color_family) + else: + out = PP2 + + if edgemode <= -1: + return edge.resize.Spline36(dest_x, dest_y, format=input.format) + elif source is not None: + if dest_x != ox or dest_y != oy: + src = source.resize.Spline36(dest_x, dest_y) + In = input.resize.Spline36(dest_x, dest_y) + else: + src = source + In = input + + shrpD = core.std.MakeDiff(In, out, planes=[0]) + expr = f'x {neutral} - abs y {neutral} - abs < x y ?' + shrpL = core.std.Expr([core.rgvs.Repair(shrpD, core.std.MakeDiff(In, src, planes=[0]), mode=[1] if isGray else [1, 0]), shrpD], expr=[expr] if isGray else [expr, '']) + return core.std.MakeDiff(In, shrpL, planes=[0]) + else: + return out + + +def AverageFrames( + clip: vs.VideoNode, weights: Union[float, Sequence[float]], scenechange: Optional[float] = None, planes: Optional[Union[int, Sequence[int]]] = None +) -> vs.VideoNode: + if not isinstance(clip, vs.VideoNode): + raise vs.Error('AverageFrames: this is not a clip') + + if scenechange: + clip = SCDetect(clip, threshold=scenechange) + return clip.std.AverageFrames(weights=weights, scenechange=scenechange, planes=planes) + + +def AvsPrewitt(clip: vs.VideoNode, planes: Optional[Union[int, Sequence[int]]] = None) -> vs.VideoNode: + if not isinstance(clip, vs.VideoNode): + raise vs.Error('AvsPrewitt: this is not a clip') + + plane_range = range(clip.format.num_planes) + + if planes is None: + planes = list(plane_range) + elif isinstance(planes, int): + planes = [planes] + + return core.std.Expr( + [ + clip.std.Convolution(matrix=[1, 1, 0, 1, 0, -1, 0, -1, -1], planes=planes, saturate=False), + clip.std.Convolution(matrix=[1, 1, 1, 0, 0, 0, -1, -1, -1], planes=planes, saturate=False), + clip.std.Convolution(matrix=[1, 0, -1, 1, 0, -1, 1, 0, -1], planes=planes, saturate=False), + clip.std.Convolution(matrix=[0, -1, -1, 1, 0, -1, 1, 1, 0], planes=planes, saturate=False), + ], + expr=['x y max z max a max' if i in planes else '' for i in plane_range], + ) + + +def ChangeFPS(clip: vs.VideoNode, fpsnum: int, fpsden: int = 1) -> vs.VideoNode: + if not isinstance(clip, vs.VideoNode): + raise vs.Error('ChangeFPS: this is not a clip') + + factor = (fpsnum / fpsden) * (clip.fps_den / clip.fps_num) + + def frame_adjuster(n: int) -> vs.VideoNode: + real_n = math.floor(n / factor) + one_frame_clip = clip[real_n] * (len(clip) + 100) + return one_frame_clip + + attribute_clip = clip.std.BlankClip(length=math.floor(len(clip) * factor), fpsnum=fpsnum, fpsden=fpsden) + return attribute_clip.std.FrameEval(eval=frame_adjuster) + + +def Gauss(clip: vs.VideoNode, p: Optional[float] = None, sigma: Optional[float] = None, planes: Optional[Union[int, Sequence[int]]] = None) -> vs.VideoNode: + if not isinstance(clip, vs.VideoNode): + raise vs.Error('Gauss: this is not a clip') + + if p is None and sigma is None: + raise vs.Error('Gauss: must have p or sigma') + + if p is not None and not 0.385 <= p <= 64.921: + raise vs.Error('Gauss: p must be between 0.385 and 64.921 (inclusive)') + + if sigma is not None and not 0.334 <= sigma <= 4.333: + raise vs.Error('Gauss: sigma must be between 0.334 and 4.333 (inclusive)') + + if sigma is None and p is not None: + # Translate AviSynth parameter to standard parameter. + sigma = math.sqrt(1.0 / (2.0 * (p / 10.0) * math.log(2))) + + # 6 * sigma + 1 rule-of-thumb. + taps = int(math.ceil(sigma * 6 + 1)) + if not taps % 2: + taps += 1 + + # Gaussian kernel. + kernel = [] + for x in range(int(math.floor(taps / 2))): + kernel.append(1.0 / (math.sqrt(2.0 * math.pi) * sigma) * math.exp(-(x * x) / (2 * sigma * sigma))) + + # Renormalize to -1023...1023. + for i in range(1, len(kernel)): + kernel[i] *= 1023 / kernel[0] + kernel[0] = 1023 + + # Symmetry. + kernel = kernel[::-1] + kernel[1:] + + return clip.std.Convolution(matrix=kernel, planes=planes, mode='hv') + + +def mt_clamp( + clip: vs.VideoNode, + bright_limit: vs.VideoNode, + dark_limit: vs.VideoNode, + overshoot: int = 0, + undershoot: int = 0, + planes: Optional[Union[int, Sequence[int]]] = None, +) -> vs.VideoNode: + if not (isinstance(clip, vs.VideoNode) and isinstance(bright_limit, vs.VideoNode) and isinstance(dark_limit, vs.VideoNode)): + raise vs.Error('mt_clamp: this is not a clip') + + if bright_limit.format.id != clip.format.id or dark_limit.format.id != clip.format.id: + raise vs.Error('mt_clamp: clips must have the same format') + + plane_range = range(clip.format.num_planes) + + if planes is None: + planes = list(plane_range) + elif isinstance(planes, int): + planes = [planes] + + return core.std.Expr([clip, bright_limit, dark_limit], expr=[f'x y {overshoot} + min z {undershoot} - max' if i in planes else '' for i in plane_range]) + + +def KNLMeansCL( + clip: vs.VideoNode, + d: Optional[int] = None, + a: Optional[int] = None, + s: Optional[int] = None, + h: Optional[float] = None, + wmode: Optional[int] = None, + wref: Optional[float] = None, + device_type: Optional[str] = None, + device_id: Optional[int] = None, +) -> vs.VideoNode: + if not isinstance(clip, vs.VideoNode): + raise vs.Error('KNLMeansCL: this is not a clip') + + if clip.format.color_family != vs.YUV: + raise vs.Error('KNLMeansCL: this wrapper is intended to be used only for YUV format') + + if clip.format.subsampling_w > 0 or clip.format.subsampling_h > 0: + return clip.knlm.KNLMeansCL(d=d, a=a, s=s, h=h, wmode=wmode, wref=wref, device_type=device_type, device_id=device_id).knlm.KNLMeansCL( + d=d, a=a, s=s, h=h, channels='UV', wmode=wmode, wref=wref, device_type=device_type, device_id=device_id + ) + else: + return clip.knlm.KNLMeansCL(d=d, a=a, s=s, h=h, channels='YUV', wmode=wmode, wref=wref, device_type=device_type, device_id=device_id) + + +def Overlay( + base: vs.VideoNode, + overlay: vs.VideoNode, + x: int = 0, + y: int = 0, + mask: Optional[vs.VideoNode] = None, + opacity: float = 1.0, + mode: str = 'normal', + planes: Optional[Union[int, Sequence[int]]] = None, + mask_first_plane: bool = True, +) -> vs.VideoNode: + ''' + Puts clip overlay on top of clip base using different blend modes, and with optional x,y positioning, masking and opacity. + + Parameters: + base: This clip will be the base, determining the size and all other video properties of the result. + + overlay: This is the image that will be placed on top of the base clip. + + x, y: Define the placement of the overlay image on the base clip, in pixels. Can be positive or negative. + + mask: Optional transparency mask. Must be the same size as overlay. Where mask is darker, overlay will be more transparent. + + opacity: Set overlay transparency. The value is from 0.0 to 1.0, where 0.0 is transparent and 1.0 is fully opaque. + This value is multiplied by mask luminance to form the final opacity. + + mode: Defines how your overlay should be blended with your base image. Available blend modes are: + addition, average, burn, darken, difference, divide, dodge, exclusion, extremity, freeze, glow, grainextract, grainmerge, hardlight, hardmix, heat, + lighten, linearlight, multiply, negation, normal, overlay, phoenix, pinlight, reflect, screen, softlight, subtract, vividlight + + planes: Specifies which planes will be processed. Any unprocessed planes will be simply copied. + + mask_first_plane: If true, only the mask's first plane will be used for transparency. + ''' + if not (isinstance(base, vs.VideoNode) and isinstance(overlay, vs.VideoNode)): + raise vs.Error('Overlay: this is not a clip') + + if mask is not None: + if not isinstance(mask, vs.VideoNode): + raise vs.Error('Overlay: mask is not a clip') + + if mask.width != overlay.width or mask.height != overlay.height or get_depth(mask) != get_depth(overlay): + raise vs.Error('Overlay: mask must have the same dimensions and bit depth as overlay') + + if base.format.sample_type == vs.INTEGER: + bits = get_depth(base) + neutral = 1 << (bits - 1) + peak = (1 << bits) - 1 + factor = 1 << bits + else: + neutral = 0.5 + peak = factor = 1.0 + + plane_range = range(base.format.num_planes) + + if planes is None: + planes = list(plane_range) + elif isinstance(planes, int): + planes = [planes] + + if base.format.subsampling_w > 0 or base.format.subsampling_h > 0: + base_orig = base + base = base.resize.Point(format=base.format.replace(subsampling_w=0, subsampling_h=0)) + else: + base_orig = None + + if overlay.format.id != base.format.id: + overlay = overlay.resize.Point(format=base.format) + + if mask is None: + mask = overlay.std.BlankClip(format=overlay.format.replace(color_family=vs.GRAY, subsampling_w=0, subsampling_h=0), color=peak) + elif mask.format.id != overlay.format.id and mask.format.color_family != vs.GRAY: + mask = mask.resize.Point(format=overlay.format, range_s='full') + + opacity = min(max(opacity, 0.0), 1.0) + mode = mode.lower() + + # Calculate padding sizes + l, r = x, base.width - overlay.width - x + t, b = y, base.height - overlay.height - y + + # Split into crop and padding values + cl, pl = min(l, 0) * -1, max(l, 0) + cr, pr = min(r, 0) * -1, max(r, 0) + ct, pt = min(t, 0) * -1, max(t, 0) + cb, pb = min(b, 0) * -1, max(b, 0) + + # Crop and padding + overlay = overlay.std.Crop(left=cl, right=cr, top=ct, bottom=cb) + overlay = overlay.std.AddBorders(left=pl, right=pr, top=pt, bottom=pb) + mask = mask.std.Crop(left=cl, right=cr, top=ct, bottom=cb) + mask = mask.std.AddBorders(left=pl, right=pr, top=pt, bottom=pb, color=[0] * mask.format.num_planes) + + if opacity < 1: + mask = mask.std.Expr(expr=f'x {opacity} *') + + if mode == 'normal': + pass + elif mode == 'addition': + expr = f'x y +' + elif mode == 'average': + expr = f'x y + 2 /' + elif mode == 'burn': + expr = f'x 0 <= x {peak} {peak} y - {factor} * x / - ?' + elif mode == 'darken': + expr = f'x y min' + elif mode == 'difference': + expr = f'x y - abs' + elif mode == 'divide': + expr = f'y 0 <= {peak} {peak} x * y / ?' + elif mode == 'dodge': + expr = f'x {peak} >= x y {factor} * {peak} x - / ?' + elif mode == 'exclusion': + expr = f'x y + 2 x * y * {peak} / -' + elif mode == 'extremity': + expr = f'{peak} x - y - abs' + elif mode == 'freeze': + expr = f'y 0 <= 0 {peak} {peak} x - dup * y / {peak} min - ?' + elif mode == 'glow': + expr = f'x {peak} >= x y y * {peak} x - / ?' + elif mode == 'grainextract': + expr = f'x y - {neutral} +' + elif mode == 'grainmerge': + expr = f'x y + {neutral} -' + elif mode == 'hardlight': + expr = f'y {neutral} < 2 y x * {peak} / * {peak} 2 {peak} y - {peak} x - * {peak} / * - ?' + elif mode == 'hardmix': + expr = f'x {peak} y - < 0 {peak} ?' + elif mode == 'heat': + expr = f'x 0 <= 0 {peak} {peak} y - dup * x / {peak} min - ?' + elif mode == 'lighten': + expr = f'x y max' + elif mode == 'linearlight': + expr = f'y {neutral} < y 2 x * + {peak} - y 2 x {neutral} - * + ?' + elif mode == 'multiply': + expr = f'x y * {peak} /' + elif mode == 'negation': + expr = f'{peak} {peak} x - y - abs -' + elif mode == 'overlay': + expr = f'x {neutral} < 2 x y * {peak} / * {peak} 2 {peak} x - {peak} y - * {peak} / * - ?' + elif mode == 'phoenix': + expr = f'x y min x y max - {peak} +' + elif mode == 'pinlight': + expr = f'y {neutral} < x 2 y * min x 2 y {neutral} - * max ?' + elif mode == 'reflect': + expr = f'y {peak} >= y x x * {peak} y - / ?' + elif mode == 'screen': + expr = f'{peak} {peak} x - {peak} y - * {peak} / -' + elif mode == 'softlight': + expr = f'x {neutral} > y {peak} y - x {neutral} - * {neutral} / 0.5 y {neutral} - abs {peak} / - * + y y {neutral} x - {neutral} / * 0.5 y {neutral} - abs {peak} / - * - ?' + elif mode == 'subtract': + expr = f'x y -' + elif mode == 'vividlight': + expr = f'x {neutral} < x 0 <= 2 x * {peak} {peak} y - {factor} * 2 x * / - ? 2 x {neutral} - * {peak} >= 2 x {neutral} - * y {factor} * {peak} 2 x {neutral} - * - / ? ?' + else: + raise vs.Error('Overlay: invalid mode specified') + + if mode != 'normal': + overlay = core.std.Expr([overlay, base], expr=[expr if i in planes else '' for i in plane_range]) + + # Return padded clip + last = core.std.MaskedMerge(base, overlay, mask, planes=planes, first_plane=mask_first_plane) + if base_orig is not None: + last = last.resize.Point(format=base_orig.format) + return last + + +def Padding(clip: vs.VideoNode, left: int = 0, right: int = 0, top: int = 0, bottom: int = 0) -> vs.VideoNode: + if not isinstance(clip, vs.VideoNode): + raise vs.Error('Padding: this is not a clip') + + if left < 0 or right < 0 or top < 0 or bottom < 0: + raise vs.Error('Padding: border size to pad must not be negative') + + width = clip.width + left + right + height = clip.height + top + bottom + + return clip.resize.Point(width, height, src_left=-left, src_top=-top, src_width=width, src_height=height) + + +def SCDetect(clip: vs.VideoNode, threshold: float = 0.1) -> vs.VideoNode: + def copy_property(n: int, f: vs.VideoFrame) -> vs.VideoFrame: + fout = f[0].copy() + fout.props['_SceneChangePrev'] = f[1].props['_SceneChangePrev'] + fout.props['_SceneChangeNext'] = f[1].props['_SceneChangeNext'] + return fout + + if not isinstance(clip, vs.VideoNode): + raise vs.Error('SCDetect: this is not a clip') + + sc = clip + if clip.format.color_family == vs.RGB: + sc = clip.resize.Point(format=vs.GRAY8, matrix_s='709') + + sc = sc.misc.SCDetect(threshold=threshold) + if clip.format.color_family == vs.RGB: + sc = clip.std.ModifyFrame(clips=[clip, sc], selector=copy_property) + + return sc + + +def Weave(clip: vs.VideoNode, tff: Optional[bool] = None) -> vs.VideoNode: + if not isinstance(clip, vs.VideoNode): + raise vs.Error('Weave: this is not a clip') + + if tff is None: + with clip.get_frame(0) as f: + if f.props.get('_Field') not in [1, 2]: + raise vs.Error('Weave: tff was not specified and field order could not be determined from frame properties') + + return clip.std.DoubleWeave(tff=tff)[::2] + + +def ContraSharpening( + denoised: vs.VideoNode, original: vs.VideoNode, radius: int = 1, rep: int = 1, planes: Optional[Union[int, Sequence[int]]] = None +) -> vs.VideoNode: + ''' + contra-sharpening: sharpen the denoised clip, but don't add more to any pixel than what was removed previously. + + Parameters: + denoised: Denoised clip to sharpen. + + original: Original clip before denoising. + + radius: Spatial radius for contra-sharpening. + + rep: Mode of repair to limit the difference. + + planes: Specifies which planes will be processed. Any unprocessed planes will be simply copied. + By default only luma plane will be processed for non-RGB formats. + ''' + if not (isinstance(denoised, vs.VideoNode) and isinstance(original, vs.VideoNode)): + raise vs.Error('ContraSharpening: this is not a clip') + + if denoised.format.id != original.format.id: + raise vs.Error('ContraSharpening: clips must have the same format') + + neutral = 1 << (get_depth(denoised) - 1) + + plane_range = range(denoised.format.num_planes) + + if planes is None: + planes = [0] if denoised.format.color_family != vs.RGB else [0, 1, 2] + elif isinstance(planes, int): + planes = [planes] + + pad = 2 if radius < 3 else 4 + denoised = Padding(denoised, pad, pad, pad, pad) + original = Padding(original, pad, pad, pad, pad) + + matrix1 = [1, 2, 1, 2, 4, 2, 1, 2, 1] + matrix2 = [1, 1, 1, 1, 1, 1, 1, 1, 1] + + # damp down remaining spots of the denoised clip + s = MinBlur(denoised, radius, planes) + # the difference achieved by the denoising + allD = core.std.MakeDiff(original, denoised, planes=planes) + + RG11 = s.std.Convolution(matrix=matrix1, planes=planes) + if radius >= 2: + RG11 = RG11.std.Convolution(matrix=matrix2, planes=planes) + if radius >= 3: + RG11 = RG11.std.Convolution(matrix=matrix2, planes=planes) + + # the difference of a simple kernel blur + ssD = core.std.MakeDiff(s, RG11, planes=planes) + # limit the difference to the max of what the denoising removed locally + ssDD = core.rgvs.Repair(ssD, allD, mode=[rep if i in planes else 0 for i in plane_range]) + # abs(diff) after limiting may not be bigger than before + ssDD = core.std.Expr([ssDD, ssD], expr=[f'x {neutral} - abs y {neutral} - abs < x y ?' if i in planes else '' for i in plane_range]) + # apply the limited difference (sharpening is just inverse blurring) + last = core.std.MergeDiff(denoised, ssDD, planes=planes) + return last.std.Crop(pad, pad, pad, pad) + + +def MinBlur(clp: vs.VideoNode, r: int = 1, planes: Optional[Union[int, Sequence[int]]] = None) -> vs.VideoNode: + '''Nifty Gauss/Median combination''' + from mvsfunc import LimitFilter + + if not isinstance(clp, vs.VideoNode): + raise vs.Error('MinBlur: this is not a clip') + + plane_range = range(clp.format.num_planes) + + if planes is None: + planes = list(plane_range) + elif isinstance(planes, int): + planes = [planes] + + matrix1 = [1, 2, 1, 2, 4, 2, 1, 2, 1] + matrix2 = [1, 1, 1, 1, 1, 1, 1, 1, 1] + + if r <= 0: + RG11 = sbr(clp, planes=planes) + RG4 = clp.std.Median(planes=planes) + elif r == 1: + RG11 = clp.std.Convolution(matrix=matrix1, planes=planes) + RG4 = clp.std.Median(planes=planes) + elif r == 2: + RG11 = clp.std.Convolution(matrix=matrix1, planes=planes).std.Convolution(matrix=matrix2, planes=planes) + RG4 = clp.ctmf.CTMF(radius=2, planes=planes) + else: + RG11 = clp.std.Convolution(matrix=matrix1, planes=planes).std.Convolution(matrix=matrix2, planes=planes).std.Convolution(matrix=matrix2, planes=planes) + if get_depth(clp) == 16: + s16 = clp + RG4 = depth(clp, 12, dither_type=Dither.NONE).ctmf.CTMF(radius=3, planes=planes) + RG4 = LimitFilter(s16, depth(RG4, 16), thr=0.0625, elast=2, planes=planes) + else: + RG4 = clp.ctmf.CTMF(radius=3, planes=planes) + + return core.std.Expr([clp, RG11, RG4], expr=['x y - x z - * 0 < x x y - abs x z - abs < y z ? ?' if i in planes else '' for i in plane_range]) + + +def sbr(c: vs.VideoNode, r: int = 1, planes: Optional[Union[int, Sequence[int]]] = None) -> vs.VideoNode: + '''make a highpass on a blur's difference (well, kind of that)''' + if not isinstance(c, vs.VideoNode): + raise vs.Error('sbr: this is not a clip') + + neutral = 1 << (get_depth(c) - 1) if c.format.sample_type == vs.INTEGER else 0.0 + + plane_range = range(c.format.num_planes) + + if planes is None: + planes = list(plane_range) + elif isinstance(planes, int): + planes = [planes] + + matrix1 = [1, 2, 1, 2, 4, 2, 1, 2, 1] + matrix2 = [1, 1, 1, 1, 1, 1, 1, 1, 1] + + RG11 = c.std.Convolution(matrix=matrix1, planes=planes) + if r >= 2: + RG11 = RG11.std.Convolution(matrix=matrix2, planes=planes) + if r >= 3: + RG11 = RG11.std.Convolution(matrix=matrix2, planes=planes) + + RG11D = core.std.MakeDiff(c, RG11, planes=planes) + + RG11DS = RG11D.std.Convolution(matrix=matrix1, planes=planes) + if r >= 2: + RG11DS = RG11DS.std.Convolution(matrix=matrix2, planes=planes) + if r >= 3: + RG11DS = RG11DS.std.Convolution(matrix=matrix2, planes=planes) + + RG11DD = core.std.Expr( + [RG11D, RG11DS], + expr=[f'x y - x {neutral} - * 0 < {neutral} x y - abs x {neutral} - abs < x y - {neutral} + x ? ?' if i in planes else '' for i in plane_range], + ) + return core.std.MakeDiff(c, RG11DD, planes=planes) + + +def sbrV(c: vs.VideoNode, r: int = 1, planes: Optional[Union[int, Sequence[int]]] = None) -> vs.VideoNode: + if not isinstance(c, vs.VideoNode): + raise vs.Error('sbrV: this is not a clip') + + neutral = 1 << (get_depth(c) - 1) if c.format.sample_type == vs.INTEGER else 0.0 + + plane_range = range(c.format.num_planes) + + if planes is None: + planes = list(plane_range) + elif isinstance(planes, int): + planes = [planes] + + matrix1 = [1, 2, 1] + matrix2 = [1, 4, 6, 4, 1] + + RG11 = c.std.Convolution(matrix=matrix1, planes=planes, mode='v') + if r >= 2: + RG11 = RG11.std.Convolution(matrix=matrix2, planes=planes, mode='v') + if r >= 3: + RG11 = RG11.std.Convolution(matrix=matrix2, planes=planes, mode='v') + + RG11D = core.std.MakeDiff(c, RG11, planes=planes) + + RG11DS = RG11D.std.Convolution(matrix=matrix1, planes=planes, mode='v') + if r >= 2: + RG11DS = RG11DS.std.Convolution(matrix=matrix2, planes=planes, mode='v') + if r >= 3: + RG11DS = RG11DS.std.Convolution(matrix=matrix2, planes=planes, mode='v') + + RG11DD = core.std.Expr( + [RG11D, RG11DS], + expr=[f'x y - x {neutral} - * 0 < {neutral} x y - abs x {neutral} - abs < x y - {neutral} + x ? ?' if i in planes else '' for i in plane_range], + ) + return core.std.MakeDiff(c, RG11DD, planes=planes) + + +def DitherLumaRebuild(src: vs.VideoNode, s0: float = 2.0, c: float = 0.0625, chroma: bool = True) -> vs.VideoNode: + '''Converts luma (and chroma) to PC levels, and optionally allows tweaking for pumping up the darks. (for the clip to be fed to motion search only)''' + if not isinstance(src, vs.VideoNode): + raise vs.Error('DitherLumaRebuild: this is not a clip') + + if src.format.color_family == vs.RGB: + raise vs.Error('DitherLumaRebuild: RGB format is not supported') + + is_gray = src.format.color_family == vs.GRAY + is_integer = src.format.sample_type == vs.INTEGER + + bits = get_depth(src) + neutral = 1 << (bits - 1) + + k = (s0 - 1) * c + t = f'x {scale_value(16, 8, bits)} - {scale_value(219, 8, bits)} / 0 max 1 min' if is_integer else 'x 0 max 1 min' + e = f'{k} {1 + c} {(1 + c) * c} {t} {c} + / - * {t} 1 {k} - * + ' + (f'{scale_value(256, 8, bits)} *' if is_integer else '') + return src.std.Expr(expr=e if is_gray else [e, f'x {neutral} - 128 * 112 / {neutral} +' if chroma and is_integer else '']) + + +def mt_expand_multi(src: vs.VideoNode, mode: str = 'rectangle', planes: Optional[Union[int, Sequence[int]]] = None, sw: int = 1, sh: int = 1) -> vs.VideoNode: + ''' + Calls std.Maximum multiple times in order to grow the mask from the desired width and height. + + Parameters: + src: Clip to process. + + mode: "rectangle", "ellipse" or "losange". Ellipses are actually combinations of rectangles and losanges and look more like octogons. + Losanges are truncated (not scaled) when sw and sh are not equal. + + planes: Specifies which planes will be processed. Any unprocessed planes will be simply copied. + + sw: Growing shape width. 0 is allowed. + + sh: Growing shape height. 0 is allowed. + ''' + if not isinstance(src, vs.VideoNode): + raise vs.Error('mt_expand_multi: this is not a clip') + + if sw > 0 and sh > 0: + mode_m = [0, 1, 0, 1, 1, 0, 1, 0] if mode == 'losange' or (mode == 'ellipse' and (sw % 3) != 1) else [1, 1, 1, 1, 1, 1, 1, 1] + elif sw > 0: + mode_m = [0, 0, 0, 1, 1, 0, 0, 0] + elif sh > 0: + mode_m = [0, 1, 0, 0, 0, 0, 1, 0] + else: + mode_m = None + + if mode_m is not None: + src = mt_expand_multi(src.std.Maximum(planes=planes, coordinates=mode_m), mode=mode, planes=planes, sw=sw - 1, sh=sh - 1) + return src + + +def mt_inpand_multi(src: vs.VideoNode, mode: str = 'rectangle', planes: Optional[Union[int, Sequence[int]]] = None, sw: int = 1, sh: int = 1) -> vs.VideoNode: + ''' + Calls std.Minimum multiple times in order to shrink the mask from the desired width and height. + + Parameters: + src: Clip to process. + + mode: "rectangle", "ellipse" or "losange". Ellipses are actually combinations of rectangles and losanges and look more like octogons. + Losanges are truncated (not scaled) when sw and sh are not equal. + + planes: Specifies which planes will be processed. Any unprocessed planes will be simply copied. + + sw: Shrinking shape width. 0 is allowed. + + sh: Shrinking shape height. 0 is allowed. + ''' + if not isinstance(src, vs.VideoNode): + raise vs.Error('mt_inpand_multi: this is not a clip') + + if sw > 0 and sh > 0: + mode_m = [0, 1, 0, 1, 1, 0, 1, 0] if mode == 'losange' or (mode == 'ellipse' and (sw % 3) != 1) else [1, 1, 1, 1, 1, 1, 1, 1] + elif sw > 0: + mode_m = [0, 0, 0, 1, 1, 0, 0, 0] + elif sh > 0: + mode_m = [0, 1, 0, 0, 0, 0, 1, 0] + else: + mode_m = None + + if mode_m is not None: + src = mt_inpand_multi(src.std.Minimum(planes=planes, coordinates=mode_m), mode=mode, planes=planes, sw=sw - 1, sh=sh - 1) + return src + + +def mt_inflate_multi(src: vs.VideoNode, planes: Optional[Union[int, Sequence[int]]] = None, radius: int = 1) -> vs.VideoNode: + if not isinstance(src, vs.VideoNode): + raise vs.Error('mt_inflate_multi: this is not a clip') + + for _ in range(radius): + src = src.std.Inflate(planes=planes) + return src + + +def mt_deflate_multi(src: vs.VideoNode, planes: Optional[Union[int, Sequence[int]]] = None, radius: int = 1) -> vs.VideoNode: + if not isinstance(src, vs.VideoNode): + raise vs.Error('mt_deflate_multi: this is not a clip') + + for _ in range(radius): + src = src.std.Deflate(planes=planes) + return src + + +def cround(x: float) -> int: + return math.floor(x + 0.5) if x > 0 else math.ceil(x - 0.5) + + +def m4(x: Union[float, int]) -> int: + return 16 if x < 16 else cround(x / 4) * 4 + + +def scale(value, peak): + return cround(value * peak / 255) if peak != 1 else value / 255 + +# sin(pi x / 2) for -1 < x < 1 using Taylor series +def sine_expr(var): + return f'{-3.5988432352121e-6} {var} * {var} * {0.00016044118478736} + {var} * {var} * {-0.0046817541353187} + {var} * {var} * {0.079692626246167} + {var} * {var} * {-0.64596409750625} + {var} * {var} * {1.5707963267949} + {var} *' diff --git a/Programs/libcrypto-3.dll b/Programs/libcrypto-3.dll new file mode 100644 index 0000000..58e21f3 Binary files /dev/null and b/Programs/libcrypto-3.dll differ diff --git a/Programs/libffi-8.dll b/Programs/libffi-8.dll new file mode 100644 index 0000000..8ebbbe8 Binary files /dev/null and b/Programs/libffi-8.dll differ diff --git a/Programs/libssl-3.dll b/Programs/libssl-3.dll new file mode 100644 index 0000000..b765636 Binary files /dev/null and b/Programs/libssl-3.dll differ diff --git a/Programs/msvcp140.dll b/Programs/msvcp140.dll new file mode 100644 index 0000000..01d749d Binary files /dev/null and b/Programs/msvcp140.dll differ diff --git a/Programs/msvcp140_1.dll b/Programs/msvcp140_1.dll new file mode 100644 index 0000000..493b96c Binary files /dev/null and b/Programs/msvcp140_1.dll differ diff --git a/Programs/msvcp140_2.dll b/Programs/msvcp140_2.dll new file mode 100644 index 0000000..493fd64 Binary files /dev/null and b/Programs/msvcp140_2.dll differ diff --git a/Programs/msvcp140_atomic_wait.dll b/Programs/msvcp140_atomic_wait.dll new file mode 100644 index 0000000..e84b83a Binary files /dev/null and b/Programs/msvcp140_atomic_wait.dll differ diff --git a/Programs/msvcp140_codecvt_ids.dll b/Programs/msvcp140_codecvt_ids.dll new file mode 100644 index 0000000..e5d3011 Binary files /dev/null and b/Programs/msvcp140_codecvt_ids.dll differ diff --git a/Programs/mvsfunc.py b/Programs/mvsfunc.py new file mode 100644 index 0000000..631167e --- /dev/null +++ b/Programs/mvsfunc.py @@ -0,0 +1,3251 @@ +################################################################################################################################ +## mvsfunc - mawen1250's VapourSynth functions +################################################################################################################################ +## Requirments: +## fmtconv +## BM3D +################################################################################################################################ +## Main functions: +## Depth +## ToRGB +## ToYUV +## BM3D +## VFRSplice +################################################################################################################################ +## Runtime functions: +## PlaneStatistics +## PlaneCompare +## ShowAverage +## FilterIf +## FilterCombed +################################################################################################################################ +## Utility functions: +## Min +## Max +## Avg +## MinFilter +## MaxFilter +## LimitFilter +## PointPower +## CheckMatrix +## postfix2infix +################################################################################################################################ +## Frame property functions: +## SetColorSpace +## AssumeFrame +## AssumeTFF +## AssumeBFF +## AssumeField +## AssumeCombed +################################################################################################################################ +## Helper functions: +## CheckVersion +## GetMatrix +## zDepth +## PlaneAverage +## GetPlane +## GrayScale +## Preview +## CheckColorFamily +## RemoveFrameProp +## RegisterFormat +################################################################################################################################ + + +import vapoursynth as vs +import functools +import math +from collections.abc import Sequence +__version__ = '11' + +if not hasattr(vs, 'core'): + core = vs.get_core() +else: + core = vs.core + +################################################################################################################################ + + +VSMaxPlaneNum = 3 + + +################################################################################################################################ + + + + + +################################################################################################################################ +################################################################################################################################ +################################################################################################################################ +## Main functions below +################################################################################################################################ +################################################################################################################################ +################################################################################################################################ + + +################################################################################################################################ +## Main function: Depth() +################################################################################################################################ +## Bit depth conversion with dithering (if needed). +## It's a wrapper for fmtc.bitdepth and zDepth (core.resize/zimg). +## Only constant format is supported, frame properties of the input clip is mostly ignored (only available with zDepth). +################################################################################################################################ +## Basic parameters +## input {clip}: clip to be converted +## can be of YUV/RGB/Gray color family, can be of 8~16 bit integer or 16/32 bit float +## depth {int}: output bit depth, can be 1~16 bit integer or 16/32 bit float +## note that 1~7 bit content is still stored as 8 bit integer format +## default is the same as that of the input clip +## sample {int}: output sample type, can be 0 (vs.INTEGER) or 1 (vs.FLOAT) +## default is the same as that of the input clip +## fulls {bool}: define if input clip is of full range +## default: None, assume True for RGB/YCgCo input, assume False for Gray/YUV input +## fulld {bool}: define if output clip is of full range +## default is the same as "fulls" +################################################################################################################################ +## Advanced parameters +## dither {int|str}: dithering algorithm applied for depth conversion +## - {int}: same as "dmode" in fmtc.bitdepth, will be automatically converted if using zDepth +## - {str}: same as "dither_type" in zDepth, will be automatically converted if using fmtc.bitdepth +## - default: +## - output depth is 32, and conversions without quantization error: 1 | "none" +## - otherwise: 3 | "error_diffusion" +## useZ {bool}: prefer zDepth or fmtc.bitdepth for depth conversion +## When 11,13~15 bit integer or 16 bit float is involved, zDepth is always used. +## - False: prefer fmtc.bitdepth +## - True: prefer zDepth +## default: False +################################################################################################################################ +## Parameters of fmtc.bitdepth +## ampo, ampn, dyn, staticnoise, cpuopt, patsize, tpdfo, tpdfn, corplane: +## same as those in fmtc.bitdepth, ignored when useZ=True +## *NOTE* no positional arguments, only keyword arguments are accepted +################################################################################################################################ +def Depth(input, depth=None, sample=None, fulls=None, fulld=None, + dither=None, useZ=None, **kwargs): + # input clip + clip = input + + if not isinstance(input, vs.VideoNode): + raise type_error('"input" must be a clip!') + + ## Default values for kwargs + if 'ampn' not in kwargs: + kwargs['ampn'] = None + if 'ampo' not in kwargs: + kwargs['ampo'] = None + + # Get properties of input clip + sFormat = input.format + + sColorFamily = sFormat.color_family + CheckColorFamily(sColorFamily) + sIsYUV = sColorFamily == vs.YUV + sIsGRAY = sColorFamily == vs.GRAY + + sbitPS = sFormat.bits_per_sample + sSType = sFormat.sample_type + + if fulls is None: + # If not set, assume limited range for YUV and Gray input + fulls = False if sIsYUV or sIsGRAY else True + elif not isinstance(fulls, int): + raise type_error('"fulls" must be a bool!') + + # Get properties of output clip + lowDepth = False + + if depth is None: + dbitPS = sbitPS + elif not isinstance(depth, int): + raise type_error('"depth" must be an int!') + else: + if depth < 8: + dbitPS = 8 + lowDepth = True + else: + dbitPS = depth + if sample is None: + if depth is None: + dSType = sSType + depth = dbitPS + else: + dSType = vs.FLOAT if dbitPS >= 32 else vs.INTEGER + elif not isinstance(sample, int): + raise type_error('"sample" must be an int!') + elif sample != vs.INTEGER and sample != vs.FLOAT: + raise value_error('"sample" must be either 0 (vs.INTEGER) or 1 (vs.FLOAT)!') + else: + dSType = sample + if depth is None and sSType != vs.FLOAT and sample == vs.FLOAT: + dbitPS = 32 + elif depth is None and sSType != vs.INTEGER and sample == vs.INTEGER: + dbitPS = 16 + if dSType == vs.INTEGER and (dbitPS < 1 or dbitPS > 16): + raise value_error(f'{dbitPS}-bit integer output is not supported!') + if dSType == vs.FLOAT and (dbitPS != 16 and dbitPS != 32): + raise value_error(f'{dbitPS}-bit float output is not supported!') + + if fulld is None: + fulld = fulls + elif not isinstance(fulld, int): + raise type_error('"fulld" must be a bool!') + + # Low-depth support + if lowDepth: + if dither == "none" or dither == 1: + clip = _quantization_conversion(clip, sbitPS, depth, vs.INTEGER, fulls, fulld, False, False, 8, 0) + clip = _quantization_conversion(clip, depth, 8, vs.INTEGER, fulld, fulld, False, False, 8, 0) + return clip + else: + full = fulld + clip = _quantization_conversion(clip, sbitPS, depth, vs.INTEGER, fulls, full, False, False, 16, 1) + sSType = vs.INTEGER + sbitPS = 16 + fulls = False + fulld = False + + # Whether to use zDepth or fmtc.bitdepth for conversion + # When 11,13~15 bit integer or 16 bit float is involved, force using zDepth + if useZ is None: + useZ = False + elif not isinstance(useZ, int): + raise type_error('"useZ" must be a bool!') + if sSType == vs.INTEGER and (sbitPS == 13 or sbitPS == 15): + useZ = True + if dSType == vs.INTEGER and (dbitPS == 11 or 13 <= dbitPS <= 15): + useZ = True + if (sSType == vs.FLOAT and sbitPS < 32) or (dSType == vs.FLOAT and dbitPS < 32): + useZ = True + + # Dithering type + if kwargs['ampn'] is not None and not isinstance(kwargs['ampn'], (int, float)): + raise type_error('"ampn" must be an int or a float!') + + if dither is None: + if dbitPS == 32 or (dbitPS >= sbitPS and fulld == fulls and fulld == False): + dither = "none" if useZ else 1 + else: + dither = "error_diffusion" if useZ else 3 + elif not isinstance(dither, (int, str)): + raise type_error('"dither" must be an int or a str!') + else: + if isinstance(dither, str): + dither = dither.lower() + if dither != "none" and dither != "ordered" and dither != "random" and dither != "error_diffusion": + raise value_error('Unsupported "dither" specified!') + else: + if dither < 0 or dither > 9: + raise value_error('Unsupported "dither" specified!') + if useZ and isinstance(dither, int): + if dither == 0: + dither = "ordered" + elif dither == 1 or dither == 2: + if kwargs['ampn'] is not None and kwargs['ampn'] > 0: + dither = "random" + else: + dither = "none" + else: + dither = "error_diffusion" + elif not useZ and isinstance(dither, str): + if dither == "none": + dither = 1 + elif dither == "ordered": + dither = 0 + elif dither == "random": + if kwargs['ampn'] is None: + dither = 1 + kwargs['ampn'] = 1 + elif kwargs['ampn'] > 0: + dither = 1 + else: + dither = 3 + else: + dither = 3 + + if not useZ: + if kwargs['ampo'] is None: + kwargs['ampo'] = 1.5 if dither == 0 else 1 + elif not isinstance(kwargs['ampo'], (int, float)): + raise type_error('"ampo" must be an int or a float!') + + # Skip processing if not needed + if dSType == sSType and dbitPS == sbitPS and (sSType == vs.FLOAT or fulld == fulls) and not lowDepth: + return clip + + # Apply conversion + if useZ: + clip = zDepth(clip, sample=dSType, depth=dbitPS, range=fulld, range_in=fulls, dither_type=dither) + else: + clip = core.fmtc.bitdepth(clip, bits=dbitPS, flt=dSType, fulls=fulls, fulld=fulld, dmode=dither, **kwargs) + clip = SetColorSpace(clip, ColorRange=0 if fulld else 1) + + # Low-depth support + if lowDepth: + clip = _quantization_conversion(clip, depth, 8, vs.INTEGER, full, full, False, False, 8, 0) + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Main function: ToRGB() +################################################################################################################################ +## A wrapper of fmtconv to convert any color space to full range RGB. +## Thus, if input is limited range RGB, it will be converted to full range. +## If matrix is 10, "2020cl" or "bt2020c", the output is linear RGB. +## Only constant format is supported, frame properties of the input clip is mostly ignored. +## Note that you may get faster speed with core.resize, or not (for now, dither_type='error_diffusion' is slow). +## It's recommended to use Preview() for previewing now. +################################################################################################################################ +## Basic parameters +## input {clip}: clip to be converted +## can be of YUV/RGB/Gray color family, can be of 8-16 bit integer or 16/32 bit float +## matrix {int|str}: color matrix of input clip, only makes sense for YUV input +## decides the conversion coefficients from YUV to RGB +## check GetMatrix() for available values +## default: None, guessed according to the color family and size of input clip +## depth {int}: output bit depth, can be 1-16 bit integer or 16/32 bit float +## note that 1-7 bit content is still stored as 8 bit integer format +## default is the same as that of the input clip +## sample {int}: output sample type, can be 0 (vs.INTEGER) or 1 (vs.FLOAT) +## default is the same as that of the input clip +## full {bool}: define if input clip is of full range +## default: guessed according to the color family of input clip and "matrix" +################################################################################################################################ +## Parameters of resampling +## kernel, taps, a1, a2, cplace: +## used for chroma re-sampling, same as those in fmtc.resample +## default: kernel="bicubic", a1=0, a2=0.5, also known as "Catmull-Rom". +################################################################################################################################ +## Parameters of depth conversion +## dither, useZ, ampo, ampn, dyn, staticnoise, cpuopt, patsize, tpdfo, tpdfn, corplane: +## same as those in Depth() +## *NOTE* no positional arguments, only keyword arguments are accepted +################################################################################################################################ +def ToRGB(input, matrix=None, depth=None, sample=None, full=None, + kernel=None, taps=None, a1=None, a2=None, cplace=None, **kwargs): + # input clip + clip = input + + if not isinstance(input, vs.VideoNode): + raise type_error('"input" must be a clip!') + + # Get string format parameter "matrix" + matrix = GetMatrix(input, matrix, True) + + # Get properties of input clip + sFormat = input.format + + sColorFamily = sFormat.color_family + CheckColorFamily(sColorFamily) + sIsRGB = sColorFamily == vs.RGB + sIsYUV = sColorFamily == vs.YUV + sIsGRAY = sColorFamily == vs.GRAY + + sbitPS = sFormat.bits_per_sample + sSType = sFormat.sample_type + + sHSubS = 1 << sFormat.subsampling_w + sVSubS = 1 << sFormat.subsampling_h + + if full is None: + # If not set, assume limited range for YUV and Gray input + # Assume full range for YCgCo and OPP input + if (sIsGRAY or sIsYUV) and (matrix == "RGB" or matrix == "YCgCo" or matrix == "OPP"): + fulls = True + else: + fulls = False if sIsYUV or sIsGRAY else True + elif not isinstance(full, int): + raise type_error('"full" must be a bool!') + else: + fulls = full + + # Get properties of output clip + if depth is None: + dbitPS = sbitPS + elif not isinstance(depth, int): + raise type_error('"depth" must be an int!') + else: + dbitPS = depth + if sample is None: + if depth is None: + dSType = sSType + else: + dSType = vs.FLOAT if dbitPS >= 32 else vs.INTEGER + elif not isinstance(sample, int): + raise type_error('"sample" must be an int!') + elif sample != vs.INTEGER and sample != vs.FLOAT: + raise value_error('"sample" must be either 0 (vs.INTEGER) or 1 (vs.FLOAT)!') + else: + dSType = sample + if depth is None and sSType != vs.FLOAT and sample == vs.FLOAT: + dbitPS = 32 + elif depth is None and sSType != vs.INTEGER and sample == vs.INTEGER: + dbitPS = 16 + if dSType == vs.INTEGER and (dbitPS < 1 or dbitPS > 16): + raise value_error(f'{dbitPS}-bit integer output is not supported!') + if dSType == vs.FLOAT and (dbitPS != 16 and dbitPS != 32): + raise value_error(f'{dbitPS}-bit float output is not supported!') + + fulld = True + + # Get properties of internal processed clip + pSType = max(sSType, dSType) # If float sample type is involved, then use float for conversion + if pSType == vs.FLOAT: + # For float sample type, only 32-bit is supported by fmtconv + pbitPS = 32 + else: + # Apply conversion in the higher one of input and output bit depth + pbitPS = max(sbitPS, dbitPS) + # For integer sample type, only 8-, 9-, 10-, 12-, 16-bit is supported by fmtc.matrix + if sHSubS != 1 or sVSubS != 1: + # When chroma re-sampling is needed, always process in 16-bit for integer sample type + pbitPS = 16 + elif pbitPS == 11: + pbitPS = 12 + elif pbitPS > 12 and pbitPS < 16: + pbitPS = 16 + + # fmtc.resample parameters + if kernel is None: + kernel = "bicubic" + if a1 is None and a2 is None: + a1 = 0 + a2 = 0.5 + elif not isinstance(kernel, str): + raise type_error('"kernel" must be a str!') + + # Conversion + if sIsRGB: + # Skip matrix conversion for RGB input + # Apply depth conversion for output clip + clip = Depth(clip, dbitPS, dSType, fulls, fulld, **kwargs) + elif sIsGRAY: + # Apply depth conversion for output clip + clip = Depth(clip, dbitPS, dSType, fulls, fulld, **kwargs) + # Shuffle planes for Gray input + clip = core.std.ShufflePlanes([clip,clip,clip], [0,0,0], vs.RGB) + # Set output frame properties + clip = SetColorSpace(clip, Matrix=0) + else: + # Apply chroma up-sampling if needed + if sHSubS != 1 or sVSubS != 1: + clip = core.fmtc.resample(clip, kernel=kernel, taps=taps, a1=a1, a2=a2, css="444", planes=[2,3,3], fulls=fulls, fulld=fulls, cplace=cplace, flt=pSType==vs.FLOAT) + # Apply depth conversion for processed clip + else: + clip = Depth(clip, pbitPS, pSType, fulls, fulls, **kwargs) + # Apply matrix conversion for YUV input + if matrix == "OPP": + clip = core.fmtc.matrix(clip, fulls=fulls, fulld=fulld, coef=[1,1,2/3,0, 1,0,-4/3,0, 1,-1,2/3,0], col_fam=vs.RGB) + clip = SetColorSpace(clip, Matrix=0) + elif matrix == "2020cl": + clip = core.fmtc.matrix2020cl(clip, full=fulls) + else: + clip = core.fmtc.matrix(clip, mat=matrix, fulls=fulls, fulld=fulld, col_fam=vs.RGB) + # Apply depth conversion for output clip + clip = Depth(clip, dbitPS, dSType, fulld, fulld, **kwargs) + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Main function: ToYUV() +################################################################################################################################ +## A wrapper of fmtconv to convert any color space to YUV with/without sub-sampling. +## If input is RGB, it's assumed to be of full range. +## Thus, limited range RGB clip should first be manually converted to full range before calling this function. +## If matrix is 10, "2020cl" or "bt2020c", the input should be linear RGB. +## Only constant format is supported, frame properties of the input clip is mostly ignored. +## Note that you may get faster speed with core.resize, or not (for now, dither_type='error_diffusion' is slow). +################################################################################################################################ +## Basic parameters +## input {clip}: clip to be converted +## can be of YUV/RGB/Gray color family, can be of 8-16 bit integer or 16/32 bit float +## matrix {int|str}: color matrix of output clip +## decides the conversion coefficients from RGB to YUV +## check GetMatrix() for available values +## default: None, guessed according to the color family and size of input clip +## css {str}: chroma sub-sampling of output clip, similar to the one in fmtc.resample +## If two number is defined, then the first is horizontal sub-sampling and the second is vertical sub-sampling. +## For example, "11" is 4:4:4, "21" is 4:2:2, "22" is 4:2:0. +## preset values: +## - "444" | "4:4:4" | "11" +## - "440" | "4:4:0" | "12" +## - "422" | "4:2:2" | "21" +## - "420" | "4:2:0" | "22" +## - "411" | "4:1:1" | "41" +## - "410" | "4:1:0" | "42" +## default: 4:4:4 for RGB/Gray input, same as input is for YUV input +## depth {int}: output bit depth, can be 1-16 bit integer or 16/32 bit float +## note that 1-7 bit content is still stored as 8 bit integer format +## default is the same as that of the input clip +## sample {int}: output sample type, can be 0 (vs.INTEGER) or 1 (vs.FLOAT) +## default is the same as that of the input clip +## full {bool}: define if input/output Gray/YUV clip is of full range +## default: guessed according to the color family of input clip and "matrix" +################################################################################################################################ +## Parameters of resampling +## kernel, taps, a1, a2, cplace: +## used for chroma re-sampling, same as those in fmtc.resample +## default: kernel="bicubic", a1=0, a2=0.5, also known as "Catmull-Rom" +################################################################################################################################ +## Parameters of depth conversion +## dither, useZ, ampo, ampn, dyn, staticnoise, cpuopt, patsize, tpdfo, tpdfn, corplane: +## same as those in Depth() +## *NOTE* no positional arguments, only keyword arguments are accepted +################################################################################################################################ +def ToYUV(input, matrix=None, css=None, depth=None, sample=None, full=None, + kernel=None, taps=None, a1=None, a2=None, cplace=None, **kwargs): + # input clip + clip = input + + if not isinstance(input, vs.VideoNode): + raise type_error('"input" must be a clip!') + + # Get string format parameter "matrix" + matrix = GetMatrix(input, matrix, False) + + # Get properties of input clip + sFormat = input.format + + sColorFamily = sFormat.color_family + CheckColorFamily(sColorFamily) + sIsRGB = sColorFamily == vs.RGB + sIsYUV = sColorFamily == vs.YUV + sIsGRAY = sColorFamily == vs.GRAY + + sbitPS = sFormat.bits_per_sample + sSType = sFormat.sample_type + + sHSubS = 1 << sFormat.subsampling_w + sVSubS = 1 << sFormat.subsampling_h + + if sIsRGB: + # Always assume full range for RGB input + fulls = True + elif full is None: + # If not set, assume limited range for YUV and Gray input + # Assume full range for YCgCo and OPP input + if (sIsGRAY or sIsYUV) and (matrix == "RGB" or matrix == "YCgCo" or matrix == "OPP"): + fulls = True + else: + fulls = False if sIsYUV or sIsGRAY else True + elif not isinstance(full, int): + raise type_error('"full" must be a bool!') + else: + fulls = full + + # Get properties of output clip + if depth is None: + dbitPS = sbitPS + elif not isinstance(depth, int): + raise type_error('"depth" must be an int!') + else: + dbitPS = depth + if sample is None: + if depth is None: + dSType = sSType + else: + dSType = vs.FLOAT if dbitPS >= 32 else vs.INTEGER + elif not isinstance(sample, int): + raise type_error('"sample" must be an int!') + elif sample != vs.INTEGER and sample != vs.FLOAT: + raise value_error('"sample" must be either 0 (vs.INTEGER) or 1 (vs.FLOAT)!') + else: + dSType = sample + if depth is None and sSType != vs.FLOAT and sample == vs.FLOAT: + dbitPS = 32 + elif depth is None and sSType != vs.INTEGER and sample == vs.INTEGER: + dbitPS = 16 + if dSType == vs.INTEGER and (dbitPS < 1 or dbitPS > 16): + raise value_error(f'{dbitPS}-bit integer output is not supported!') + if dSType == vs.FLOAT and (dbitPS != 16 and dbitPS != 32): + raise value_error(f'{dbitPS}-bit float output is not supported!') + + if full is None: + # If not set, assume limited range for YUV and Gray output + # Assume full range for YCgCo and OPP output + if matrix == "RGB" or matrix == "YCgCo" or matrix == "OPP": + fulld = True + else: + fulld = False + elif not isinstance(full, int): + raise type_error('"full" must be a bool!') + else: + fulld = full + + # Chroma sub-sampling parameters + if css is None: + dHSubS = sHSubS + dVSubS = sVSubS + css = f'{dHSubS}{dVSubS}' + elif not isinstance(css, str): + raise type_error('"css" must be a str!') + else: + if css == "444" or css == "4:4:4": + css = "11" + elif css == "440" or css == "4:4:0": + css = "12" + elif css == "422" or css == "4:2:2": + css = "21" + elif css == "420" or css == "4:2:0": + css = "22" + elif css == "411" or css == "4:1:1": + css = "41" + elif css == "410" or css == "4:1:0": + css = "42" + dHSubS = int(css[0]) + dVSubS = int(css[1]) + + # Get properties of internal processed clip + pSType = max(sSType, dSType) # If float sample type is involved, then use float for conversion + if pSType == vs.FLOAT: + # For float sample type, only 32-bit is supported by fmtconv + pbitPS = 32 + else: + # Apply conversion in the higher one of input and output bit depth + pbitPS = max(sbitPS, dbitPS) + # For integer sample type, only 8-, 9-, 10-, 12-, 16-bit is supported by fmtc.matrix + if pbitPS == 11: + pbitPS = 12 + elif pbitPS > 12 and pbitPS < 16: + pbitPS = 16 + if dHSubS != sHSubS or dVSubS != sVSubS: + # When chroma re-sampling is needed, always process in 16-bit for integer sample type + pbitPS = 16 + + # fmtc.resample parameters + if kernel is None: + kernel = "bicubic" + if a1 is None and a2 is None: + a1 = 0 + a2 = 0.5 + elif not isinstance(kernel, str): + raise type_error('"kernel" must be a str!') + + # Conversion + if sIsYUV: + # Skip matrix conversion for YUV input + # Change chroma sub-sampling if needed + if dHSubS != sHSubS or dVSubS != sVSubS: + # Apply depth conversion for processed clip + clip = Depth(clip, pbitPS, pSType, fulls, fulls, **kwargs) + clip = core.fmtc.resample(clip, kernel=kernel, taps=taps, a1=a1, a2=a2, css=css, planes=[2,3,3], fulls=fulls, fulld=fulls, cplace=cplace) + # Apply depth conversion for output clip + clip = Depth(clip, dbitPS, dSType, fulls, fulld, **kwargs) + elif sIsGRAY: + # Apply depth conversion for output clip + clip = Depth(clip, dbitPS, dSType, fulls, fulld, **kwargs) + # Shuffle planes for Gray input + widthc = input.width // dHSubS + heightc = input.height // dVSubS + UV = core.std.BlankClip(clip, width=widthc, height=heightc, + color=1 << (dbitPS - 1) if dSType == vs.INTEGER else 0) + clip = core.std.ShufflePlanes([clip,UV,UV], [0,0,0], vs.YUV) + else: + # Apply depth conversion for processed clip + clip = Depth(clip, pbitPS, pSType, fulls, fulls, **kwargs) + # Apply matrix conversion for RGB input + if matrix == "OPP": + clip = core.fmtc.matrix(clip, fulls=fulls, fulld=fulld, coef=[1/3,1/3,1/3,0, 1/2,0,-1/2,0, 1/4,-1/2,1/4,0], col_fam=vs.YUV) + clip = SetColorSpace(clip, Matrix=2) + elif matrix == "2020cl": + clip = core.fmtc.matrix2020cl(clip, full=fulld) + else: + clip = core.fmtc.matrix(clip, mat=matrix, fulls=fulls, fulld=fulld, col_fam=vs.YUV) + # Change chroma sub-sampling if needed + if dHSubS != sHSubS or dVSubS != sVSubS: + clip = core.fmtc.resample(clip, kernel=kernel, taps=taps, a1=a1, a2=a2, css=css, planes=[2,3,3], fulls=fulld, fulld=fulld, cplace=cplace) + # Apply depth conversion for output clip + clip = Depth(clip, dbitPS, dSType, fulld, fulld, **kwargs) + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Main function: BM3D() +################################################################################################################################ +## A wrap function for easy using of BM3D/V-BM3D denoising filter. +## The BM3D filtering is always done in 16-bit int or 32-bit float opponent (OPP) color space internally. +## It can automatically convert any input color space to OPP and convert it back after filtering. +## Alternatively, you can specify "output" to force outputting RGB or OPP, and "css" to change chroma subsampling. +## For Gray input, no color space conversion is involved, thus "output" and "css" won't take effect. +## You can specify "refine" for any number of final estimate refinements. +################################################################################################################################ +## Basic parameters +## input {clip}: clip to be filtered +## can be of YUV/RGB/Gray color family, can be of 8-16 bit integer or 16/32 bit float +## sigma {float[]}: same as "sigma" in BM3D, used for both basic estimate and final estimate +## the strength of filtering, should be carefully adjusted according to the noise +## set 0 to disable the filtering of corresponding plane +## default: [5.0,5.0,5.0] +## radius1 {int}: temporal radius of basic estimate +## - 0: BM3D (spatial denoising) +## - 1~16: temporal radius of V-BM3D (spatial-temporal denoising) +## default: 0 +## radius2 {int}: temporal radius of final estimate +## default is the same as "radius1" +## profile1 {str}: same as "profile" in BM3D basic estimate +## default: "fast" +## profile2 {str}: same as "profile" in BM3D final estimate +## default is the same as "profile1" +################################################################################################################################ +## Advanced parameters +## refine {int}: refinement times +## - 0: basic estimate only +## - 1: basic estimate + refined with final estimate, the original behavior of BM3D +## - n: basic estimate + refined with final estimate for n times +## each final estimate takes the filtered clip in previous estimate as reference clip to filter the input clip +## default: 1 +## pre {clip} (optional): pre-filtered clip for basic estimate +## must be of the same format and dimension as the input clip +## should be a clip better suited for block-matching than the input clip +## ref {clip} (optional): basic estimate clip +## must be of the same format and dimension as the input clip +## replace the basic estimate of BM3D and serve as the reference clip for final estimate +## psample {int}: internal processed precision +## - 0: 16-bit integer, less accuracy, less memory consumption +## - 1: 32-bit float, more accuracy, more memory consumption +## default: 1 +################################################################################################################################ +## Parameters of input properties +## matrix {int|str}: color matrix of input clip, only makes sense for YUV input +## check GetMatrix() for available values +## default: guessed according to the color family and size of input clip +## full {bool}: define if input clip is of full range +## default: guessed according to the color family of input clip and "matrix" +################################################################################################################################ +## Parameters of output properties +## output {int}: type of output clip, doesn't make sense for Gray input +## - 0: same format as input clip +## - 1: full range RGB (converted from input clip) +## - 2: full range OPP (converted from full range RGB, the color space where the filtering takes place) +## default: 0 +## css {str}: chroma subsampling of output clip, only valid when output=0 and input clip is YUV +## check ToYUV() for available values +## default is the same as that of the input clip +## depth {int}: bit depth of output clip, can be 1-16 for integer or 16/32 for float +## note that 1-7 bit content is still stored as 8 bit integer format +## default is the same as that of the input clip +## sample {int}: sample type of output clip, can be 0 (vs.INTEGER) or 1 (vs.FLOAT) +## default is the same as that of the input clip +################################################################################################################################ +## Parameters of resampling +## cu_kernel, cu_taps, cu_a1, cu_a2, cu_cplace: +## used for chroma up-sampling, same as those in fmtc.resample +## default: kernel="bicubic", a1=0, a2=0.5, also known as "Catmull-Rom" +## cd_kernel, cd_taps, cd_a1, cd_a2, cd_cplace: +## used for chroma down-sampling, same as those in fmtc.resample +## default: kernel="bicubic", a1=0, a2=0.5, also known as "Catmull-Rom" +################################################################################################################################ +## Parameters of BM3D basic estimate +## block_size1, block_step1, group_size1, bm_range1, bm_step1, ps_num1, ps_range1, ps_step1, th_mse1, hard_thr: +## same as those in bm3d.Basic/bm3d.VBasic +################################################################################################################################ +## Parameters of BM3D final estimate +## block_size2, block_step2, group_size2, bm_range2, bm_step2, ps_num2, ps_range2, ps_step2, th_mse2: +## same as those in bm3d.Final/bm3d.VFinal +################################################################################################################################ +## Parameters of depth conversion +## dither, useZ, ampo, ampn, dyn, staticnoise, cpuopt, patsize, tpdfo, tpdfn, corplane: +## same as those in Depth() +## *NOTE* no positional arguments, only keyword arguments are accepted +################################################################################################################################ +def BM3D(input, sigma=None, radius1=None, radius2=None, profile1=None, profile2=None, + refine=None, pre=None, ref=None, psample=None, + matrix=None, full=None, + output=None, css=None, depth=None, sample=None, + cu_kernel=None, cu_taps=None, cu_a1=None, cu_a2=None, cu_cplace=None, + cd_kernel=None, cd_taps=None, cd_a1=None, cd_a2=None, cd_cplace=None, + block_size1=None, block_step1=None, group_size1=None, bm_range1=None, bm_step1=None, ps_num1=None, ps_range1=None, ps_step1=None, th_mse1=None, hard_thr=None, + block_size2=None, block_step2=None, group_size2=None, bm_range2=None, bm_step2=None, ps_num2=None, ps_range2=None, ps_step2=None, th_mse2=None, + **kwargs): + # input clip + clip = input + + if not isinstance(input, vs.VideoNode): + raise type_error('"input" must be a clip!') + + # Get string format parameter "matrix" + matrix = GetMatrix(input, matrix, True) + + # Get properties of input clip + sFormat = input.format + + sColorFamily = sFormat.color_family + CheckColorFamily(sColorFamily) + sIsRGB = sColorFamily == vs.RGB + sIsYUV = sColorFamily == vs.YUV + sIsGRAY = sColorFamily == vs.GRAY + + sbitPS = sFormat.bits_per_sample + sSType = sFormat.sample_type + + sHSubS = 1 << sFormat.subsampling_w + sVSubS = 1 << sFormat.subsampling_h + + if full is None: + # If not set, assume limited range for YUV and Gray input + # Assume full range for YCgCo and OPP input + if (sIsGRAY or sIsYUV) and (matrix == "RGB" or matrix == "YCgCo" or matrix == "OPP"): + fulls = True + else: + fulls = False if sIsYUV or sIsGRAY else True + elif not isinstance(full, int): + raise type_error('"full" must be a bool!') + else: + fulls = full + + # Get properties of internal processed clip + if psample is None: + psample = vs.FLOAT + elif not isinstance(psample, int): + raise type_error('"psample" must be an int!') + elif psample != vs.INTEGER and psample != vs.FLOAT: + raise value_error('"psample" must be either 0 (vs.INTEGER) or 1 (vs.FLOAT)!') + pbitPS = 16 if psample == vs.INTEGER else 32 + pSType = psample + + # Chroma sub-sampling parameters + if css is None: + dHSubS = sHSubS + dVSubS = sVSubS + css = f'{dHSubS}{dVSubS}' + elif not isinstance(css, str): + raise type_error('"css" must be a str!') + else: + if css == "444" or css == "4:4:4": + css = "11" + elif css == "440" or css == "4:4:0": + css = "12" + elif css == "422" or css == "4:2:2": + css = "21" + elif css == "420" or css == "4:2:0": + css = "22" + elif css == "411" or css == "4:1:1": + css = "41" + elif css == "410" or css == "4:1:0": + css = "42" + dHSubS = int(css[0]) + dVSubS = int(css[1]) + + if cu_cplace is not None and cd_cplace is None: + cd_cplace = cu_cplace + + # Parameters processing + if sigma is None: + sigma = [5.0,5.0,5.0] + else: + if isinstance(sigma, int): + sigma = float(sigma) + sigma = [sigma,sigma,sigma] + elif isinstance(sigma, float): + sigma = [sigma,sigma,sigma] + elif isinstance(sigma, list): + while len(sigma) < 3: + sigma.append(sigma[len(sigma) - 1]) + else: + raise type_error('sigma must be a float[] or an int[]!') + if sIsGRAY: + sigma = [sigma[0],0,0] + skip = sigma[0] <= 0 and sigma[1] <= 0 and sigma[2] <= 0 + + if radius1 is None: + radius1 = 0 + elif not isinstance(radius1, int): + raise type_error('"radius1" must be an int!') + elif radius1 < 0: + raise value_error('valid range of "radius1" is [0, +inf)!') + if radius2 is None: + radius2 = radius1 + elif not isinstance(radius2, int): + raise type_error('"radius2" must be an int!') + elif radius2 < 0: + raise value_error('valid range of "radius2" is [0, +inf)!') + + if profile1 is None: + profile1 = "fast" + elif not isinstance(profile1, str): + raise type_error('"profile1" must be a str!') + if profile2 is None: + profile2 = profile1 + elif not isinstance(profile2, str): + raise type_error('"profile2" must be a str!') + + if refine is None: + refine = 1 + elif not isinstance(refine, int): + raise type_error('"refine" must be an int!') + elif refine < 0: + raise value_error('valid range of "refine" is [0, +inf)!') + + if output is None: + output = 0 + elif not isinstance(output, int): + raise type_error('"output" must be an int!') + elif output < 0 or output > 2: + raise value_error('valid values of "output" are 0, 1 and 2!') + + if pre is not None: + if not isinstance(pre, vs.VideoNode): + raise type_error('"pre" must be a clip!') + if pre.format.id != sFormat.id: + raise value_error('clip "pre" must be of the same format as the input clip!') + if pre.width != input.width or pre.height != input.height: + raise value_error('clip "pre" must be of the same size as the input clip!') + + if ref is not None: + if not isinstance(ref, vs.VideoNode): + raise type_error('"ref" must be a clip!') + if ref.format.id != sFormat.id: + raise value_error('clip "ref" must be of the same format as the input clip!') + if ref.width != input.width or ref.height != input.height: + raise value_error('clip "ref" must be of the same size as the input clip!') + + # Get properties of output clip + if depth is None: + if output == 0: + dbitPS = sbitPS + else: + dbitPS = pbitPS + elif not isinstance(depth, int): + raise type_error('"depth" must be an int!') + else: + dbitPS = depth + if sample is None: + if depth is None: + if output == 0: + dSType = sSType + else: + dSType = pSType + else: + dSType = vs.FLOAT if dbitPS >= 32 else vs.INTEGER + elif not isinstance(sample, int): + raise type_error('"sample" must be an int!') + elif sample != vs.INTEGER and sample != vs.FLOAT: + raise value_error('"sample" must be either 0 (vs.INTEGER) or 1 (vs.FLOAT)!') + else: + dSType = sample + if depth is None and sSType != vs.FLOAT and sample == vs.FLOAT: + dbitPS = 32 + elif depth is None and sSType != vs.INTEGER and sample == vs.INTEGER: + dbitPS = 16 + if dSType == vs.INTEGER and (dbitPS < 1 or dbitPS > 16): + raise value_error(f'{dbitPS}-bit integer output is not supported!') + if dSType == vs.FLOAT and (dbitPS != 16 and dbitPS != 32): + raise value_error(f'{dbitPS}-bit float output is not supported!') + + if output == 0: + fulld = fulls + else: + # Always full range output when output=1|output=2 (full range RGB or full range OPP) + fulld = True + + # Convert to processed format + # YUV/RGB input is converted to opponent color space as full range YUV + # Gray input is converted to full range Gray + onlyY = False + if sIsGRAY: + onlyY = True + # Convert Gray input to full range Gray in processed format + clip = Depth(clip, pbitPS, pSType, fulls, True, **kwargs) + if pre is not None: + pre = Depth(pre, pbitPS, pSType, fulls, True, **kwargs) + if ref is not None: + ref = Depth(ref, pbitPS, pSType, fulls, True, **kwargs) + else: + # Convert input to full range RGB + clip = ToRGB(clip, matrix, pbitPS, pSType, fulls, + cu_kernel, cu_taps, cu_a1, cu_a2, cu_cplace, **kwargs) + if pre is not None: + pre = ToRGB(pre, matrix, pbitPS, pSType, fulls, + cu_kernel, cu_taps, cu_a1, cu_a2, cu_cplace, **kwargs) + if ref is not None: + ref = ToRGB(ref, matrix, pbitPS, pSType, fulls, + cu_kernel, cu_taps, cu_a1, cu_a2, cu_cplace, **kwargs) + # Convert full range RGB to full range OPP + clip = ToYUV(clip, "OPP", "444", pbitPS, pSType, True, + cu_kernel, cu_taps, cu_a1, cu_a2, cu_cplace, **kwargs) + if pre is not None: + pre = ToYUV(pre, "OPP", "444", pbitPS, pSType, True, + cu_kernel, cu_taps, cu_a1, cu_a2, cu_cplace, **kwargs) + if ref is not None: + ref = ToYUV(ref, "OPP", "444", pbitPS, pSType, True, + cu_kernel, cu_taps, cu_a1, cu_a2, cu_cplace, **kwargs) + # Convert OPP to Gray if only Y is processed + srcOPP = clip + if sigma[1] <= 0 and sigma[2] <= 0: + onlyY = True + clip = core.std.ShufflePlanes([clip], [0], vs.GRAY) + if pre is not None: + pre = core.std.ShufflePlanes([pre], [0], vs.GRAY) + if ref is not None: + ref = core.std.ShufflePlanes([ref], [0], vs.GRAY) + + # Basic estimate + if ref is not None: + # Use custom basic estimate specified by clip "ref" + flt = ref + elif skip: + flt = clip + elif radius1 < 1: + # Apply BM3D basic estimate + # Optional pre-filtered clip for block-matching can be specified by "pre" + flt = core.bm3d.Basic(clip, ref=pre, profile=profile1, sigma=sigma, + block_size=block_size1, block_step=block_step1, group_size=group_size1, + bm_range=bm_range1, bm_step=bm_step1, th_mse=th_mse1, hard_thr=hard_thr, matrix=100) + else: + # Apply V-BM3D basic estimate + # Optional pre-filtered clip for block-matching can be specified by "pre" + flt = core.bm3d.VBasic(clip, ref=pre, profile=profile1, sigma=sigma, radius=radius1, + block_size=block_size1, block_step=block_step1, group_size=group_size1, + bm_range=bm_range1, bm_step=bm_step1, ps_num=ps_num1, ps_range=ps_range1, ps_step=ps_step1, + th_mse=th_mse1, hard_thr=hard_thr, matrix=100).bm3d.VAggregate(radius=radius1, sample=pSType) + # Shuffle Y plane back if not processed + if not onlyY and sigma[0] <= 0: + flt = core.std.ShufflePlanes([clip,flt,flt], [0,1,2], vs.YUV) + + # Final estimate + for _ in range(0, refine): + if skip: + flt = clip + elif radius2 < 1: + # Apply BM3D final estimate + flt = core.bm3d.Final(clip, ref=flt, profile=profile2, sigma=sigma, + block_size=block_size2, block_step=block_step2, group_size=group_size2, + bm_range=bm_range2, bm_step=bm_step2, th_mse=th_mse2, matrix=100) + else: + # Apply V-BM3D final estimate + flt = core.bm3d.VFinal(clip, ref=flt, profile=profile2, sigma=sigma, radius=radius2, + block_size=block_size2, block_step=block_step2, group_size=group_size2, + bm_range=bm_range2, bm_step=bm_step2, ps_num=ps_num2, ps_range=ps_range2, ps_step=ps_step2, + th_mse=th_mse2, matrix=100).bm3d.VAggregate(radius=radius2, sample=pSType) + # Shuffle Y plane back if not processed + if not onlyY and sigma[0] <= 0: + flt = core.std.ShufflePlanes([clip,flt,flt], [0,1,2], vs.YUV) + + # Convert to output format + if sIsGRAY: + clip = Depth(flt, dbitPS, dSType, True, fulld, **kwargs) + else: + # Shuffle back to YUV if not all planes are processed + if onlyY: + clip = core.std.ShufflePlanes([flt,srcOPP,srcOPP], [0,1,2], vs.YUV) + elif sigma[1] <= 0 or sigma[2] <= 0: + clip = core.std.ShufflePlanes([flt, clip if sigma[1] <= 0 else flt, + clip if sigma[2] <= 0 else flt], [0,1,2], vs.YUV) + else: + clip = flt + # Convert to final output format + if output <= 1: + # Convert full range OPP to full range RGB + clip = ToRGB(clip, "OPP", pbitPS, pSType, True, + cu_kernel, cu_taps, cu_a1, cu_a2, cu_cplace, **kwargs) + if output <= 0 and not sIsRGB: + # Convert full range RGB to YUV + clip = ToYUV(clip, matrix, css, dbitPS, dSType, fulld, + cd_kernel, cd_taps, cd_a1, cd_a2, cd_cplace, **kwargs) + else: + # Depth conversion for RGB or OPP output + clip = Depth(clip, dbitPS, dSType, True, fulld, **kwargs) + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Main function: VFRSplice() +################################################################################################################################ +## Splice multiple clips with different frame rate, and output timecode file. +## Each input clip is of CFR (constant frame rate). +## The output clip is of VFR (variational frame rate). +################################################################################################################################ +## Basic parameters +## clips {clip}: any number of clips to splice +## each clip should be CFR +## tcfile {str}: timecode file output +## default: None +## v2 {bool}: timecode format +## True for v2 output and False for v1 output +## default: True +## precision {int}: precision of time and frame rate +## a decimal number indicating how many digits should be displayed after the decimal point for a fixed-point value +## default: 6 +################################################################################################################################ +def VFRSplice(clips, tcfile=None, v2=None, precision=None): + # Arguments + if isinstance(clips, vs.VideoNode): + clips = [clips] + elif isinstance(clips, Sequence): + for clip in clips: + if not isinstance(clip, vs.VideoNode): + raise type_error('each element in "clips" must be a clip!') + if clip.fps_num == 0 or clip.fps_den == 0: + raise value_error('each clip in "clips" must be CFR!') + else: + raise type_error('"clips" must be a clip or a sequence of clips!') + + if tcfile is not None and not isinstance(tcfile, str): + raise type_error('"tcfile" must be a str!') + + if v2 is None: + v2 = True + elif not isinstance(v2, int): + raise type_error('"v2" must be a bool!') + + if precision is None: + precision = 6 + elif not isinstance(precision, int): + raise type_error('"precision" must be an int!') + + # Fraction to str function + def frac2str(num, den, precision=6): + return f'{num / den : <.{precision}F}' + + # Timecode file + if tcfile is None: + pass + else: + # Get timecode v1 list + cur_frame = 0 + tc_list = [] + index = 0 + for clip in clips: + if index > 0 and clip.fps_num == tc_list[index - 1][2] and clip.fps_den == tc_list[index - 1][3]: + tc_list[index - 1] = (tc_list[index - 1][0], cur_frame + clip.num_frames - 1, clip.fps_num, clip.fps_den) + else: + tc_list.append((cur_frame, cur_frame + clip.num_frames - 1, clip.fps_num, clip.fps_den)) + index += 1 + cur_frame += clip.num_frames + + # Write to timecode file + ofile = open(tcfile, 'w') + if v2: # timecode v2 + olines = ['# timecode format v2\n'] + time = 0 # ms + for tc in tc_list: + frame_duration = 1000 * tc[3] / tc[2] # ms + for _ in range(tc[0], tc[1] + 1): + olines.append(f'{time : <.{precision}F}\n') + time += frame_duration + else: # timecode v1 + olines = [ + '# timecode format v1\n', + f'Assume {frac2str(tc_list[0][2], tc_list[0][3], precision)}\n' + ] + for tc in tc_list: + olines.append(f'{tc[0]},{tc[1]},{frac2str(tc[2], tc[3], precision)}\n') + try: + ofile.writelines(olines) + finally: + ofile.close() + + # Output spliced clip + return core.std.Splice(clips, mismatch=True) +################################################################################################################################ + + + + + +################################################################################################################################ +################################################################################################################################ +################################################################################################################################ +## Runtime functions below +################################################################################################################################ +################################################################################################################################ +################################################################################################################################ + + +################################################################################################################################ +## Runtime function: PlaneStatistics() +################################################################################################################################ +## Calculate statistics of specific plane and store them as frame properties +## All the values are normalized (float that the peak-to-peak value is 1) +## Supported statistics: +## mean: stored as frame property 'PlaneMean' +## mean absolute deviation: stored as frame property 'PlaneMAD' +## variance: stored as frame property 'PlaneVar' +## standard deviation: stored as frame property 'PlaneSTD' +## root mean square: stored as frame property 'PlaneRMS' +################################################################################################################################ +## Basic parameters +## clip {clip}: clip to be evaluated +## can be of YUV/RGB/Gray color family, can be of 8-16 bit integer or 32 bit float +## plane {int}: specify which plane to evaluate +## default: 0 +## mean {bool}: whether to calculate mean +## default: True +## mad {bool}: whether to calculate mean absolute deviation +## default: True +## var {bool}: whether to calculate variance +## default: True +## std {bool}: whether to calculate standard deviation +## default: True +## rms {bool}: whether to calculate root mean square +## default: True +################################################################################################################################ +def PlaneStatistics(clip, plane=None, mean=True, mad=True, var=True, std=True, rms=True): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Get properties of input clip + sFormat = clip.format + + sSType = sFormat.sample_type + sbitPS = sFormat.bits_per_sample + sNumPlanes = sFormat.num_planes + + valueRange = (1 << sbitPS) - 1 if sSType == vs.INTEGER else 1 + + # Parameters + if plane is None: + plane = 0 + elif not isinstance(plane, int): + raise type_error('"plane" must be an int!') + elif plane < 0 or plane > sNumPlanes: + raise value_error(f'valid range of "plane" is [0, {sNumPlanes})!') + + floatFormat = RegisterFormat(vs.GRAY, vs.FLOAT, 32, 0, 0) + floatBlk = core.std.BlankClip(clip, format=floatFormat.id) + + clipPlane = GetPlane(clip, plane) + + # Plane Mean + clip = PlaneAverage(clip, plane, "PlaneMean") + + # Plane MAD (mean absolute deviation) + if mad: + '''# always float precision + def _PlaneADFrame(n, f, clip): + mean = f.props.PlaneMean + scale = 1 / valueRange + expr = f"x {scale} * {mean} - abs" + return core.std.Expr(clip, expr, floatFormat.id) + ADclip = core.std.FrameEval(floatBlk, functools.partial(_PlaneADFrame, clip=clipPlane), clip)''' + if hasattr(core, 'akarin'): + ADclip = core.akarin.Expr([clipPlane, clip], f'x y.PlaneMean {valueRange} * - abs') + else: + def _PlaneADFrame(n, f, clip): + mean = f.props.PlaneMean * valueRange + expr = f"x {mean} - abs" + return core.std.Expr(clip, expr) + ADclip = core.std.FrameEval(clipPlane, functools.partial(_PlaneADFrame, clip=clipPlane), clip) + ADclip = PlaneAverage(ADclip, 0, "PlaneMAD") + + def _PlaneMADTransfer(n, f): + fout = f[0].copy() + fout.props.PlaneMAD = f[1].props.PlaneMAD + return fout + clip = core.std.ModifyFrame(clip, [clip, ADclip], selector=_PlaneMADTransfer) + + # Plane Var (variance) and STD (standard deviation) + if var or std: + if hasattr(core, 'akarin'): + SDclip = core.akarin.Expr([clipPlane, clip], f'x y.PlaneMean {valueRange} * - dup *', format=floatFormat.id) + else: + def _PlaneSDFrame(n, f, clip): + mean = f.props.PlaneMean * valueRange + expr = f"x {mean} - dup *" + return core.std.Expr(clip, expr, floatFormat.id) + SDclip = core.std.FrameEval(floatBlk, functools.partial(_PlaneSDFrame, clip=clipPlane), clip) + SDclip = PlaneAverage(SDclip, 0, "PlaneVar") + + def _PlaneVarSTDTransfer(n, f): + fout = f[0].copy() + if var: + fout.props.PlaneVar = f[1].props.PlaneVar / (valueRange * valueRange) + if std: + fout.props.PlaneSTD = math.sqrt(f[1].props.PlaneVar) / valueRange + return fout + clip = core.std.ModifyFrame(clip, [clip, SDclip], selector=_PlaneVarSTDTransfer) + + # Plane RMS (root mean square) + if rms: + expr = "x x *" + squareClip = core.std.Expr(clipPlane, expr, floatFormat.id) + squareClip = PlaneAverage(squareClip, 0, "PlaneMS") + + def _PlaneRMSTransfer(n, f): + fout = f[0].copy() + fout.props.PlaneRMS = math.sqrt(f[1].props.PlaneMS) / valueRange + return fout + clip = core.std.ModifyFrame(clip, [clip, squareClip], selector=_PlaneRMSTransfer) + + # Delete frame property "PlaneMean" if not needed + if not mean: + clip = RemoveFrameProp(clip, "PlaneMean") + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Runtime function: PlaneCompare() +################################################################################################################################ +## Compare specific plane of 2 clips and store the statistical results as frame properties +## All the values are normalized (float of which the peak-to-peak value is 1) except PSNR +## Supported statistics: +## mean absolute error: stored as frame property 'PlaneMAE', aka L1 distance +## root of mean squared error: stored as frame property 'PlaneRMSE', aka L2 distance(Euclidean distance) +## peak signal-to-noise ratio: stored as frame property 'PlanePSNR', maximum value is 100.0 (when 2 planes are identical) +## covariance: stored as frame property 'PlaneCov' +## correlation: stored as frame property 'PlaneCorr' +################################################################################################################################ +## Basic parameters +## clip1 {clip}: the first clip to be evaluated, will be copied to output +## can be of YUV/RGB/Gray color family, can be of 8-16 bit integer or 32 bit float +## clip2 {clip}: the second clip, to be compared with the first one +## must be of the same format and dimension as the "clip1" +## plane {int}: specify which plane to evaluate +## default: 0 +## mae {bool}: whether to calculate mean absolute error +## default: True +## rmse {bool}: whether to calculate root of mean squared error +## default: True +## psnr {bool}: whether to calculate peak signal-to-noise ratio +## default: True +## cov {bool}: whether to calculate covariance +## default: True +## corr {bool}: whether to calculate correlation +## default: True +################################################################################################################################ +def PlaneCompare(clip1, clip2, plane=None, mae=True, rmse=True, psnr=True, cov=True, corr=True): + # input clip + if not isinstance(clip1, vs.VideoNode): + raise type_error('"clip1" must be a clip!') + if not isinstance(clip2, vs.VideoNode): + raise type_error('"clip2" must be a clip!') + + # Get properties of input clip + sFormat = clip1.format + if sFormat.id != clip2.format.id: + raise value_error('"clip1" and "clip2" must be of the same format!') + if clip1.width != clip2.width or clip1.height != clip2.height: + raise value_error('"clip1" and "clip2" must be of the same width and height!') + + sSType = sFormat.sample_type + sbitPS = sFormat.bits_per_sample + sNumPlanes = sFormat.num_planes + + valueRange = (1 << sbitPS) - 1 if sSType == vs.INTEGER else 1 + + # Parameters + if plane is None: + plane = 0 + elif not isinstance(plane, int): + raise type_error('"plane" must be an int!') + elif plane < 0 or plane > sNumPlanes: + raise value_error(f'valid range of "plane" is [0, {sNumPlanes})!') + + floatFormat = RegisterFormat(vs.GRAY, vs.FLOAT, 32, 0, 0) + floatBlk = core.std.BlankClip(clip1, format=floatFormat.id) + + clip1Plane = GetPlane(clip1, plane) + clip2Plane = GetPlane(clip2, plane) + + # Plane MAE (mean absolute error) + if mae: + expr = "x y - abs" + ADclip = core.std.Expr([clip1Plane, clip2Plane], expr, floatFormat.id) + ADclip = PlaneAverage(ADclip, 0, "PlaneMAE") + + def _PlaneMAETransfer(n, f): + fout = f[0].copy() + fout.props.PlaneMAE = f[1].props.PlaneMAE / valueRange + return fout + clip1 = core.std.ModifyFrame(clip1, [clip1, ADclip], selector=_PlaneMAETransfer) + + # Plane RMSE (root of mean squared error) and PSNR (peak signal-to-noise ratio) + if rmse or psnr: + expr = "x y - dup *" + SDclip = core.std.Expr([clip1Plane, clip2Plane], expr, floatFormat.id) + SDclip = PlaneAverage(SDclip, 0, "PlaneMSE") + + def _PlaneRMSEnPSNRTransfer(n, f): + fout = f[0].copy() + if rmse: + fout.props.PlaneRMSE = math.sqrt(f[1].props.PlaneMSE) / valueRange + if psnr: + fout.props.PlanePSNR = min(10 * math.log(valueRange * valueRange / f[1].props.PlaneMSE, 10), 99.99999999999999) if f[1].props.PlaneMSE > 0 else 100.0 + return fout + clip1 = core.std.ModifyFrame(clip1, [clip1, SDclip], selector=_PlaneRMSEnPSNRTransfer) + + # Plane Cov (covariance) and Corr (correlation) + if cov or corr: + clip1Mean = PlaneAverage(clip1Plane, 0, "PlaneMean") + clip2Mean = PlaneAverage(clip2Plane, 0, "PlaneMean") + + if hasattr(core, 'akarin'): + CoDclip = core.akarin.Expr([clip1Plane, clip1Mean, clip2Plane, clip2Mean], f'x y.PlaneMean {valueRange} * - z a.PlaneMean {valueRange} * - *', format=floatFormat.id) + else: + def _PlaneCoDFrame(n, f, clip1, clip2): + mean1 = f[0].props.PlaneMean * valueRange + mean2 = f[1].props.PlaneMean * valueRange + expr = f"x {mean1} - y {mean2} - *" + return core.std.Expr([clip1, clip2], expr, floatFormat.id) + CoDclip = core.std.FrameEval(floatBlk, functools.partial(_PlaneCoDFrame, clip1=clip1Plane, clip2=clip2Plane), [clip1Mean, clip2Mean]) + + CoDclip = PlaneAverage(CoDclip, 0, "PlaneCov") + clips = [clip1, CoDclip] + + if corr: + + if hasattr(core, 'akarin'): + SDclip1 = core.akarin.Expr([clip1Plane, clip1Mean], f'x y.PlaneMean {valueRange} * - dup *', format=floatFormat.id) + SDclip2 = core.akarin.Expr([clip2Plane, clip2Mean], f'x y.PlaneMean {valueRange} * - dup *', format=floatFormat.id) + else: + def _PlaneSDFrame(n, f, clip): + mean = f.props.PlaneMean * valueRange + expr = f"x {mean} - dup *" + return core.std.Expr(clip, expr, floatFormat.id) + SDclip1 = core.std.FrameEval(floatBlk, functools.partial(_PlaneSDFrame, clip=clip1Plane), clip1Mean) + SDclip2 = core.std.FrameEval(floatBlk, functools.partial(_PlaneSDFrame, clip=clip2Plane), clip2Mean) + + SDclip1 = PlaneAverage(SDclip1, 0, "PlaneVar") + SDclip2 = PlaneAverage(SDclip2, 0, "PlaneVar") + clips.append(SDclip1) + clips.append(SDclip2) + + def _PlaneCovTransfer(n, f): + fout = f[0].copy() + if cov: + fout.props.PlaneCov = f[1].props.PlaneCov / (valueRange * valueRange) + if corr: + std1std2 = math.sqrt(f[2].props.PlaneVar * f[3].props.PlaneVar) + fout.props.PlaneCorr = f[1].props.PlaneCov / std1std2 if std1std2 > 0 else float("inf") + return fout + clip1 = core.std.ModifyFrame(clip1, clips, selector=_PlaneCovTransfer) + + # Output + return clip1 +################################################################################################################################ + + +################################################################################################################################ +## Runtime function: ShowAverage() +################################################################################################################################ +## Display unnormalized average of each plane +################################################################################################################################ +## Basic parameters +## clip {clip}: clip to be evaluated +## can be of YUV/RGB/Gray color family, can be of 8-16 bit integer or 16/32 bit float +################################################################################################################################ +## Advanced parameters +## alignment {int}: same as the one in text.Text() +## default: 7 +################################################################################################################################ +def ShowAverage(clip, alignment=None): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Get properties of input clip + sFormat = clip.format + + sColorFamily = sFormat.color_family + CheckColorFamily(sColorFamily) + sIsYUV = sColorFamily == vs.YUV + + sSType = sFormat.sample_type + sbitPS = sFormat.bits_per_sample + sNumPlanes = sFormat.num_planes + + valueRange = (1 << sbitPS) - 1 if sSType == vs.INTEGER else 1 + offset = [0, -0.5, -0.5] if sSType == vs.FLOAT and sIsYUV else [0, 0, 0] + + # Process and output + def _ShowAverageFrame(n, f): + text = "" + if sNumPlanes == 1: + average = f.props.PlaneAverage * valueRange + offset[0] + text += f"PlaneAverage[{0}]={average}" + else: + for p in range(sNumPlanes): + average = f[p].props.PlaneAverage * valueRange + offset[p] + text += f"PlaneAverage[{p}]={average}\n" + return core.text.Text(clip, text, alignment) + + avg = [] + for p in range(sNumPlanes): + avg.append(PlaneAverage(clip, p)) + + return core.std.FrameEval(clip, _ShowAverageFrame, prop_src=avg) +################################################################################################################################ + + +################################################################################################################################ +## Runtime function: FilterIf() +################################################################################################################################ +## Take the frames from clip "flt" that is marked to be filtered and the ones from clip "src" that is not. +## An arbitrary frame property named "prop_name" from clip "props" is evaluated to determine whether it should be filtered. +################################################################################################################################ +## Basic parameters +## src {clip}: the source clip +## can be of any constant format +## flt {clip}: the filtered clip +## must be of the same format and dimension as "src" +## prop_name {str} (mandatory): the frame property to be evaluated +## for each frame, if this property exists and is True, then take the frame from "flt", otherwise take the one from "src" +## props {clip} (optional): the clip from which the frame property is evaluated +## can be of any format, should have the same number of frames as "src" +## default: None (use "src") +################################################################################################################################ +def FilterIf(src, flt, prop_name, props=None): + # input clip + if not isinstance(src, vs.VideoNode): + raise type_error('"src" must be a clip!') + if not isinstance(flt, vs.VideoNode): + raise type_error('"flt" must be a clip!') + if props is not None and not isinstance(props, vs.VideoNode): + raise type_error('"props" must be a clip!') + + # Get properties of input clip + sFormat = src.format + if sFormat.id != flt.format.id: + raise value_error('"src" and "flt" must be of the same format!') + if src.width != flt.width or src.height != flt.height: + raise value_error('"src" and "flt" must be of the same width and height!') + + if prop_name is None or not isinstance(prop_name, str): + raise type_error('"prop_name" must be specified and must be a str!') + else: + prop_name = _check_arg_prop(prop_name, None, None, 'prop_name') + + if props is None: + props = src + + # FrameEval function + def _FilterIfFrame(n, f): + try: + if f.props.__getattr__(prop_name): + return flt + except KeyError: + pass + return src + + # Process + return core.std.FrameEval(src, _FilterIfFrame, props) +################################################################################################################################ + + +################################################################################################################################ +## Runtime function: FilterCombed() +################################################################################################################################ +## Take the frames from clip "flt" that is marked as combed and the ones from clip "src" that is not. +## The frame property '_Combed' from clip "props" is evaluated to determine whether it's combed. +## This function is an instantiation of FilterIf() +################################################################################################################################ +## Basic parameters +## src {clip}: the source clip +## can be of any constant format +## flt {clip}: the filtered clip (de-interlaced) +## must be of the same format and dimension as "src" +## props {clip} (optional): the clip from which the frame property is evaluated +## can be of any format, should have the same number of frames as "src" +## default: None (use "src") +################################################################################################################################ +def FilterCombed(src, flt, props=None): + clip = FilterIf(src, flt, '_Combed', props) + clip = RemoveFrameProp(clip, '_Combed') + return AssumeFrame(clip) +################################################################################################################################ + + + + + +################################################################################################################################ +################################################################################################################################ +################################################################################################################################ +## Utility functions below +################################################################################################################################ +################################################################################################################################ +################################################################################################################################ + + +################################################################################################################################ +## Utility function: Min() +################################################################################################################################ +## Take 2 clips and return pixel-wise minimum of them. +## With a special mode=2 for difference clip. +################################################################################################################################ +## Basic parameters +## clip1 {clip}: the first clip +## can be of YUV/RGB/Gray color family, can be of 8-16 bit integer or 16/32 bit float +## clip2 {clip}: the second clip +## must be of the same format and dimension as "clip1" +## mode {int[]}: specify processing mode for each plane +## - 0: don't process, copy "clip1" to output +## - 1: normal minimum, output = min(clip1, clip2) +## - 2: difference minimum, output = abs(clip2 - neutral) < abs(clip1 - neutral) ? clip2 : clip1 +## default: [1,1,1] for YUV/RGB input, [1] for Gray input +################################################################################################################################ +## Advanced parameters +## neutral {int|float}: specfy the neutral value used for mode=2 +## default: 1 << (bits_per_sample - 1) for integer input, 0 for float input +################################################################################################################################ +def Min(clip1, clip2, mode=None, neutral=None): + return _operator2(clip1, clip2, mode, neutral, 'Min') +################################################################################################################################ + + +################################################################################################################################ +## Utility function: Max() +################################################################################################################################ +## Take 2 clips and return pixel-wise maximum of them. +## With a special mode=2 for difference clip. +################################################################################################################################ +## Basic parameters +## clip1 {clip}: the first clip +## can be of YUV/RGB/Gray color family, can be of 8-16 bit integer or 16/32 bit float +## clip2 {clip}: the second clip +## must be of the same format and dimension as "clip1" +## mode {int[]}: specify processing mode for each plane +## - 0: don't process, copy "clip1" to output +## - 1: normal maximum, output = max(clip1, clip2) +## - 2: difference maximum, output = abs(clip2 - neutral) > abs(clip1 - neutral) ? clip2 : clip1 +## default: [1,1,1] for YUV/RGB input, [1] for Gray input +################################################################################################################################ +## Advanced parameters +## neutral {int|float}: specfy the neutral value used for mode=2 +## default: 1 << (bits_per_sample - 1) for integer input, 0 for float input +################################################################################################################################ +def Max(clip1, clip2, mode=None, neutral=None): + return _operator2(clip1, clip2, mode, neutral, 'Max') +################################################################################################################################ + + +################################################################################################################################ +## Utility function: Avg() +################################################################################################################################ +## Take 2 clips and return pixel-wise average of them. +################################################################################################################################ +## Basic parameters +## clip1 {clip}: the first clip +## can be of YUV/RGB/Gray color family, can be of 8-16 bit integer or 16/32 bit float +## clip2 {clip}: the second clip +## must be of the same format and dimension as "clip1" +## mode {int[]}: specify processing mode for each plane +## - 0: don't process, copy "clip1" to output +## - 1: average, output = (clip1 + clip2) / 2 +## default: [1,1,1] for YUV/RGB input, [1] for Gray input +################################################################################################################################ +def Avg(clip1, clip2, mode=None): + return _operator2(clip1, clip2, mode, None, 'Avg') +################################################################################################################################ + + +################################################################################################################################ +## Utility function: MinFilter() +################################################################################################################################ +## Apply filtering with minimum difference of the 2 filtered clips. +################################################################################################################################ +## Basic parameters +## src {clip}: source clip +## can be of YUV/RGB/Gray color family, can be of 8-16 bit integer or 16/32 bit float +## flt1 {clip}: filtered clip 1 +## must be of the same format and dimension as "src" +## flt2 {clip}: filtered clip 2 +## must be of the same format and dimension as "src" +## planes {int[]}: specify which planes to process +## unprocessed planes will be copied from "src" +## default: all planes will be processed, [0,1,2] for YUV/RGB input, [0] for Gray input +################################################################################################################################ +def MinFilter(src, flt1, flt2, planes=None): + return _min_max_filter(src, flt1, flt2, planes, 'MinFilter') +################################################################################################################################ + + +################################################################################################################################ +## Utility function: MaxFilter() +################################################################################################################################ +## Apply filtering with maximum difference of the 2 filtered clips. +################################################################################################################################ +## Basic parameters +## src {clip}: source clip +## can be of YUV/RGB/Gray color family, can be of 8-16 bit integer or 16/32 bit float +## flt1 {clip}: filtered clip 1 +## must be of the same format and dimension as "src" +## flt2 {clip}: filtered clip 2 +## must be of the same format and dimension as "src" +## planes {int[]}: specify which planes to process +## unprocessed planes will be copied from "src" +## default: all planes will be processed, [0,1,2] for YUV/RGB input, [0] for Gray input +################################################################################################################################ +def MaxFilter(src, flt1, flt2, planes=None): + return _min_max_filter(src, flt1, flt2, planes, 'MaxFilter') +################################################################################################################################ + + +################################################################################################################################ +## Utility function: LimitFilter() +################################################################################################################################ +## Similar to the AviSynth function Dither_limit_dif16() and HQDeringmod_limit_dif16(). +## It acts as a post-processor, and is very useful to limit the difference of filtering while avoiding artifacts. +## Commonly used cases: +## de-banding +## de-ringing +## de-noising +## sharpening +## combining high precision source with low precision filtering: mvf.LimitFilter(src, flt, thr=1.0, elast=2.0) +################################################################################################################################ +## There are 2 implementations, default one with std.Expr, the other with std.Lut. +## The Expr version supports all mode, while the Lut version doesn't support float input and ref clip. +## Also the Lut version will truncate the filtering diff if it exceeds half the value range(128 for 8-bit, 32768 for 16-bit). +## The Lut version might be faster than Expr version in some cases, for example 8-bit input and brighten_thr != thr. +################################################################################################################################ +## Algorithm for Y/R/G/B plane (for chroma, replace "thr" and "brighten_thr" with "thrc") +## dif = flt - src +## dif_ref = flt - ref +## dif_abs = abs(dif_ref) +## thr_1 = brighten_thr if (dif > 0) else thr +## thr_2 = thr_1 * elast +## +## if dif_abs <= thr_1: +## final = flt +## elif dif_abs >= thr_2: +## final = src +## else: +## final = src + dif * (thr_2 - dif_abs) / (thr_2 - thr_1) +################################################################################################################################ +## Basic parameters +## flt {clip}: filtered clip, to compute the filtering diff +## can be of YUV/RGB/Gray color family, can be of 8-16 bit integer or 16/32 bit float +## src {clip}: source clip, to apply the filtering diff +## must be of the same format and dimension as "flt" +## ref {clip} (optional): reference clip, to compute the weight to be applied on filtering diff +## must be of the same format and dimension as "flt" +## default: None (use "src") +## thr {float}: threshold (8-bit scale) to limit filtering diff +## default: 1.0 +## elast {float}: elasticity of the soft threshold +## default: 2.0 +## planes {int[]}: specify which planes to process +## unprocessed planes will be copied from "flt" +## default: all planes will be processed, [0,1,2] for YUV/RGB input, [0] for Gray input +################################################################################################################################ +## Advanced parameters +## brighten_thr {float}: threshold (8-bit scale) for filtering diff that brightening the image (Y/R/G/B plane) +## set a value different from "thr" is useful to limit the overshoot/undershoot/blurring introduced in sharpening/de-ringing +## default is the same as "thr" +## thrc {float}: threshold (8-bit scale) for chroma (U/V/Co/Cg plane) +## default is the same as "thr" +## force_expr {bool} +## - True: force to use the std.Expr implementation +## - False: use the std.Lut implementation if available +## default: True +################################################################################################################################ +def LimitFilter(flt, src, ref=None, thr=None, elast=None, brighten_thr=None, thrc=None, force_expr=None, planes=None): + # input clip + if not isinstance(flt, vs.VideoNode): + raise type_error('"flt" must be a clip!') + if not isinstance(src, vs.VideoNode): + raise type_error('"src" must be a clip!') + if ref is not None and not isinstance(ref, vs.VideoNode): + raise type_error('"ref" must be a clip!') + + # Get properties of input clip + sFormat = flt.format + if sFormat.id != src.format.id: + raise value_error('"flt" and "src" must be of the same format!') + if flt.width != src.width or flt.height != src.height: + raise value_error('"flt" and "src" must be of the same width and height!') + + if ref is not None: + if sFormat.id != ref.format.id: + raise value_error('"flt" and "ref" must be of the same format!') + if flt.width != ref.width or flt.height != ref.height: + raise value_error('"flt" and "ref" must be of the same width and height!') + + sColorFamily = sFormat.color_family + CheckColorFamily(sColorFamily) + sIsYUV = sColorFamily == vs.YUV + + sSType = sFormat.sample_type + sbitPS = sFormat.bits_per_sample + sNumPlanes = sFormat.num_planes + + # Parameters + if thr is None: + thr = 1.0 + elif isinstance(thr, int) or isinstance(thr, float): + if thr < 0: + raise value_error('valid range of "thr" is [0, +inf)') + else: + raise type_error('"thr" must be an int or a float!') + + if elast is None: + elast = 2.0 + elif isinstance(elast, int) or isinstance(elast, float): + if elast < 1: + raise value_error('valid range of "elast" is [1, +inf)') + else: + raise type_error('"elast" must be an int or a float!') + + if brighten_thr is None: + brighten_thr = thr + elif isinstance(brighten_thr, int) or isinstance(brighten_thr, float): + if brighten_thr < 0: + raise value_error('valid range of "brighten_thr" is [0, +inf)') + else: + raise type_error('"brighten_thr" must be an int or a float!') + + if thrc is None: + thrc = thr + elif isinstance(thrc, int) or isinstance(thrc, float): + if thrc < 0: + raise value_error('valid range of "thrc" is [0, +inf)') + else: + raise type_error('"thrc" must be an int or a float!') + + if force_expr is None: + force_expr = True + elif not isinstance(force_expr, int): + raise type_error('"force_expr" must be a bool!') + if ref is not None or sSType != vs.INTEGER: + force_expr = True + + # planes + process = [0 for i in range(VSMaxPlaneNum)] + + if planes is None: + process = [1 for i in range(VSMaxPlaneNum)] + elif isinstance(planes, int): + if planes < 0 or planes >= VSMaxPlaneNum: + raise value_error(f'valid range of "planes" is [0, {VSMaxPlaneNum})!') + process[planes] = 1 + elif isinstance(planes, Sequence): + for p in planes: + if not isinstance(p, int): + raise type_error('"planes" must be a (sequence of) int!') + elif p < 0 or p >= VSMaxPlaneNum: + raise value_error(f'valid range of "planes" is [0, {VSMaxPlaneNum})!') + process[p] = 1 + else: + raise type_error('"planes" must be a (sequence of) int!') + + # Process + if thr <= 0 and brighten_thr <= 0: + if sIsYUV: + if thrc <= 0: + return src + else: + return src + if thr >= 255 and brighten_thr >= 255: + if sIsYUV: + if thrc >= 255: + return flt + else: + return flt + if thr >= 128 or brighten_thr >= 128: + force_expr = True + + if force_expr: # implementation with std.Expr + valueRange = (1 << sbitPS) - 1 if sSType == vs.INTEGER else 1 + limitExprY = _limit_filter_expr(ref is not None, thr, elast, brighten_thr, valueRange) + limitExprC = _limit_filter_expr(ref is not None, thrc, elast, thrc, valueRange) + expr = [] + for i in range(sNumPlanes): + if process[i]: + if i > 0 and (sIsYUV): + expr.append(limitExprC) + else: + expr.append(limitExprY) + else: + expr.append("") + + if ref is None: + clip = core.std.Expr([flt, src], expr) + else: + clip = core.std.Expr([flt, src, ref], expr) + else: # implementation with std.MakeDiff, std.Lut and std.MergeDiff + diff = core.std.MakeDiff(flt, src, planes=planes) + if sIsYUV: + if process[0]: + diff = _limit_diff_lut(diff, thr, elast, brighten_thr, [0]) + if process[1] or process[2]: + _planes = [] + if process[1]: + _planes.append(1) + if process[2]: + _planes.append(2) + diff = _limit_diff_lut(diff, thrc, elast, thrc, _planes) + else: + diff = _limit_diff_lut(diff, thr, elast, brighten_thr, planes) + clip = core.std.MakeDiff(flt, diff, planes=planes) + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Utility function: PointPower() +################################################################################################################################ +## Up-scaling by a power of 2 with nearest-neighborhood interpolation (point resize) +## Internally it involves std.Transpose, std.Interleave and std.DoubleWeave+std.SelectEvery for the scaling +## It will be faster than point-resizers for pure vertical scaling when the scaling ratio is not too large, especially for 8-bit input +################################################################################################################################ +## Basic parameters +## clip {clip}: clip to be scaled +## can be of any format +## vpow {float}: vertical scaling ratio is 2^vpow +## default: 1 +## hpow {float}: horizontal scaling ratio is 2^hpow +## default: 0 +################################################################################################################################ +def PointPower(clip, vpow=None, hpow=None): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Parameters + if vpow is None: + vpow = 1 + elif not isinstance(vpow, int): + raise type_error('"vpow" must be an int!') + elif vpow < 0: + raise value_error('valid range of "vpow" is [0, +inf)!') + + if hpow is None: + hpow = 0 + elif not isinstance(hpow, int): + raise type_error('"hpow" must be an int!') + elif hpow < 0: + raise value_error('valid range of "hpow" is [0, +inf)!') + + # Process + if hpow > 0: + clip = core.std.Transpose(clip) + for _ in range(hpow): + clip = core.std.Interleave([clip, clip]).std.DoubleWeave(True).std.SelectEvery(2, 0) + clip = core.std.Transpose(clip) + + if vpow > 0: + for _ in range(vpow): + clip = core.std.Interleave([clip, clip]).std.DoubleWeave(True).std.SelectEvery(2, 0) + + # Output + return AssumeFrame(clip) +################################################################################################################################ + + +################################################################################################################################ +## Utility function: CheckMatrix() +################################################################################################################################ +## *** EXPERIMENTAL *** I'm not sure whether it will work or not *** +################################################################################################################################ +## Check whether the input YUV clip matches specific color matrix +## Output is RGB24, out of range pixels will be marked as 255, indicating that the matrix may not be correct +## Additional plane mean values about the out of range pixels will be print on the frame +## Multiple matrices can be specified simultaneously, and multiple results will be stacked vertically +################################################################################################################################ +## Basic parameters +## clip {clip}: clip to evaluate +## must be of YUV color family +## matrices {str[]}: specify a (sequence of) matrix to test +## default: ['601', '709', '2020', '240', 'FCC', 'YCgCo'] +## full {bool}: define if input clip is of full range +## default: False for YUV input +## lower {float}: lower boundary for valid range (inclusive) +## default: -0.02 +## upper {float}: upper boundary for valid range (inclusive) +## default: 1.02 +################################################################################################################################ +def CheckMatrix(clip, matrices=None, full=None, lower=None, upper=None): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Get properties of input clip + sFormat = clip.format + + sColorFamily = sFormat.color_family + CheckColorFamily(sColorFamily, ('YUV')) + + # Parameters + if matrices is None: + matrices = ['601', '709', '2020', '240', 'FCC', 'YCgCo'] + elif isinstance(matrices, str): + matrices = [matrices] + elif not isinstance(matrices, Sequence): + raise type_error('\'matrices\' must be a (sequence of) str!') + + if full is None: + full = False + elif not isinstance(full, int): + raise type_error('\'full\' must be a bool!') + + if lower is None: + lower = -0.02 + elif not (isinstance(lower, float) or isinstance(lower, int)): + raise type_error('\'lower\' must be an int or a float!') + + if upper is None: + upper = 1.02 + elif not (isinstance(upper, float) or isinstance(upper, int)): + raise type_error('\'upper\' must be an int or a float!') + + # Process + clip = ToYUV(clip, css='444', depth=32, full=full) + + props = ['RMean', 'GMean', 'BMean', 'TotalMean'] + def _FrameProps(n, f): + fout = f.copy() + fout.props.__setattr__(props[3], (f.props.__getattr__(props[0]) + f.props.__getattr__(props[1]) + f.props.__getattr__(props[2])) / 3) + return fout + + rgb_clips = [] + for matrix in matrices: + rgb_clip = ToRGB(clip, matrix=matrix) + rgb_clip = rgb_clip.std.Expr(f'x {lower} < 1 x - x {upper} > x 0 ? ?') + rgb_clip = PlaneAverage(rgb_clip, 0, props[0]) + rgb_clip = PlaneAverage(rgb_clip, 1, props[1]) + rgb_clip = PlaneAverage(rgb_clip, 2, props[2]) + rgb_clip = core.std.ModifyFrame(rgb_clip, rgb_clip, selector=_FrameProps) + rgb_clip = Depth(rgb_clip, depth=8, dither='none') + rgb_clip = rgb_clip.text.FrameProps(props, alignment=7) + rgb_clip = rgb_clip.text.Text(matrix, alignment=8) + rgb_clips.append(rgb_clip) + + # Output + return core.std.StackVertical(rgb_clips) +################################################################################################################################ + + +################################################################################################################################ +## Utility function: postfix2infix() +################################################################################################################################ +## Convert postfix expression (used by std.Expr) to infix expression +################################################################################################################################ +## Basic parameters +## expr {str}: the postfix expression to be converted +################################################################################################################################ +def postfix2infix(expr): + op1 = ['exp', 'log', 'sqrt', 'abs', 'not', 'dup'] + op2 = ['+', '-', '*', '/', 'max', 'min', '>', '<', '=', '>=', '<=', 'and', 'or', 'xor', 'swap', 'pow'] + op3 = ['?'] + + def remove_brackets(x): + if x[0] == '(' and x[len(x) - 1] == ')': + p = 1 + for c in x[1:-1]: + if c == '(': + p += 1 + elif c == ')': + p -= 1 + if p == 0: + break + if p == 1: + return x[1:-1] + return x + + if not isinstance(expr, str): + raise type_error('\'expr\' must be a str!') + expr_list = expr.split() + + stack = [] + for item in expr_list: + if op1.count(item) > 0: + try: + operand1 = stack.pop() + except IndexError: + raise value_error('Invalid expression, require operands.') + if item == 'dup': + stack.append(operand1) + stack.append(operand1) + else: + stack.append(f'{item}({remove_brackets(operand1)})') + elif op2.count(item) > 0: + try: + operand2 = stack.pop() + operand1 = stack.pop() + except IndexError: + raise value_error('Invalid expression, require operands.') + stack.append(f'({operand1} {item} {operand2})') + elif op3.count(item) > 0: + try: + operand3 = stack.pop() + operand2 = stack.pop() + operand1 = stack.pop() + except IndexError: + raise value_error('Invalid expression, require operands.') + stack.append(f'({operand1} {item} {operand2} : {operand3})') + else: + stack.append(item) + + if len(stack) > 1: + raise value_error('Invalid expression, require operators.') + return remove_brackets(stack[0]) +################################################################################################################################ + + + + + +################################################################################################################################ +################################################################################################################################ +################################################################################################################################ +## Frame property functions below +################################################################################################################################ +################################################################################################################################ +################################################################################################################################ + + +################################################################################################################################ +## Frame property function: SetColorSpace() +################################################################################################################################ +## Modify the color space related frame properties in the given clip. +## Detailed descriptions of these properties: http://www.vapoursynth.com/doc/apireference.html +################################################################################################################################ +## Parameters +## %Any%: for the property named "_%Any%" +## - None: do nothing +## - True: do nothing +## - False: delete corresponding frame properties if exist +## - {int}: set to this value +################################################################################################################################ +def SetColorSpace(clip, ChromaLocation=None, ColorRange=None, Primaries=None, Matrix=None, Transfer=None): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Modify frame properties + if ChromaLocation is None: + pass + elif isinstance(ChromaLocation, bool): + if ChromaLocation is False: + clip = RemoveFrameProp(clip, '_ChromaLocation') + elif isinstance(ChromaLocation, int): + if ChromaLocation >= 0 and ChromaLocation <=5: + clip = core.std.SetFrameProp(clip, prop='_ChromaLocation', intval=ChromaLocation) + else: + raise value_error('valid range of "ChromaLocation" is [0, 5]!') + else: + raise type_error('"ChromaLocation" must be an int or a bool!') + + if ColorRange is None: + pass + elif isinstance(ColorRange, bool): + if ColorRange is False: + clip = RemoveFrameProp(clip, '_ColorRange') + elif isinstance(ColorRange, int): + if ColorRange >= 0 and ColorRange <=1: + clip = core.std.SetFrameProp(clip, prop='_ColorRange', intval=ColorRange) + else: + raise value_error('valid range of "ColorRange" is [0, 1]!') + else: + raise type_error('"ColorRange" must be an int or a bool!') + + if Primaries is None: + pass + elif isinstance(Primaries, bool): + if Primaries is False: + clip = RemoveFrameProp(clip, '_Primaries') + elif isinstance(Primaries, int): + clip = core.std.SetFrameProp(clip, prop='_Primaries', intval=Primaries) + else: + raise type_error('"Primaries" must be an int or a bool!') + + if Matrix is None: + pass + elif isinstance(Matrix, bool): + if Matrix is False: + clip = RemoveFrameProp(clip, '_Matrix') + elif isinstance(Matrix, int): + clip = core.std.SetFrameProp(clip, prop='_Matrix', intval=Matrix) + else: + raise type_error('"Matrix" must be an int or a bool!') + + if Transfer is None: + pass + elif isinstance(Transfer, bool): + if Transfer is False: + clip = RemoveFrameProp(clip, '_Transfer') + elif isinstance(Transfer, int): + clip = core.std.SetFrameProp(clip, prop='_Transfer', intval=Transfer) + else: + raise type_error('"Transfer" must be an int or a bool!') + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Frame property function: AssumeFrame() +################################################################################################################################ +## Set all the frames in the given clip to be frame-based(progressive). +## It can be used to prevent the field order set in de-interlace filters from being overridden by the frame property '_FieldBased'. +## Also it may be useful to be applied before upscaling or anti-aliasing scripts using EEDI3/nnedi3, etc.(whose field order should be specified explicitly) +################################################################################################################################ +def AssumeFrame(clip): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Modify frame properties + clip = core.std.SetFrameProp(clip, prop='_FieldBased', intval=0) + clip = RemoveFrameProp(clip, '_Field') + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Frame property function: AssumeTFF() +################################################################################################################################ +## Set all the frames in the given clip to be top-field-first(interlaced). +## This frame property will override the field order set in those de-interlace filters. +################################################################################################################################ +def AssumeTFF(clip): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Modify frame properties + clip = core.std.SetFrameProp(clip, prop='_FieldBased', intval=2) + clip = RemoveFrameProp(clip, '_Field') + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Frame property function: AssumeBFF() +################################################################################################################################ +## Set all the frames in the given clip to be bottom-field-first(interlaced). +## This frame property will override the field order set in those de-interlace filters. +################################################################################################################################ +def AssumeBFF(clip): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Modify frame properties + clip = core.std.SetFrameProp(clip, prop='_FieldBased', intval=1) + clip = RemoveFrameProp(clip, '_Field') + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Frame property function: AssumeField() +################################################################################################################################ +## Set all the frames in the given clip to be field-based(derived from interlaced frame). +################################################################################################################################ +## Parameters +## top {bool}: +## - True: top-field-based +## - False: bottom-field-based +################################################################################################################################ +def AssumeField(clip, top): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + if not isinstance(top, int): + raise type_error('"top" must be a bool!') + + # Modify frame properties + clip = RemoveFrameProp(clip, '_FieldBased') + clip = core.std.SetFrameProp(clip, prop='_Field', intval=1 if top else 0) + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Frame property function: AssumeCombed() +################################################################################################################################ +## Set all the frames in the given clip to be combed or not. +################################################################################################################################ +## Parameters +## combed {bool}: +## - None: delete property '_Combed' if exist +## - True: set property '_Combed' to 1 +## - False: set property '_Combed' to 0 +## default: True +################################################################################################################################ +def AssumeCombed(clip, combed=True): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Modify frame properties + if combed is None: + clip = RemoveFrameProp(clip, '_Combed') + elif not isinstance(combed, int): + raise type_error('"combed" must be a bool!') + else: + clip = core.std.SetFrameProp(clip, prop='_Combed', intval=combed) + + # Output + return clip +################################################################################################################################ + + + + + +################################################################################################################################ +################################################################################################################################ +################################################################################################################################ +## Helper functions below +################################################################################################################################ +################################################################################################################################ +################################################################################################################################ + + +################################################################################################################################ +## Helper function: CheckVersion() +################################################################################################################################ +## Check if the version of mvsfunc matches the specified version requirements. +## For example, if you write a script requires at least mvsfunc-r5, use mvf.CheckVersion(5) to make sure r5 or later version is used. +################################################################################################################################ +## Parameters +## version {int} (mandatory): specify the required version number +## less {bool}: if False, raise error when this mvsfunc's version is less than the specified version +## default: False +## equal {bool}: if False, raise error when this mvsfunc's version is equal to the specified version +## default: True +## greater {bool}: if False, raise error when this mvsfunc's version is greater than the specified version +## default: True +################################################################################################################################ +def CheckVersion(version, less=False, equal=True, greater=True): + if not less and __version__ < version: + raise ImportWarning(f'mvsfunc version ({__version__}) is less than the version ({version}) specified!') + if not equal and __version__ == version: + raise ImportWarning(f'mvsfunc version ({__version__}) is equal to the version ({version}) specified!') + if not greater and __version__ > version: + raise ImportWarning(f'mvsfunc version ({__version__}) is greater than the version ({version}) specified!') + + return True +################################################################################################################################ + + +################################################################################################################################ +## Helper function: GetMatrix() +################################################################################################################################ +## Return str or int format parameter "matrix". +################################################################################################################################ +## Parameters +## clip {clip}: the source clip +## matrix {int|str}: explicitly specify matrix in int or str format, not case-sensitive +## - 0 | "RGB" +## - 1 | "709" | "bt709" +## - 2 | "Unspecified": same as not specified (None) +## - 4 | "FCC" +## - 5 | "bt470bg": same as "601" +## - 6 | "601" | "smpte170m" +## - 7 | "240" | "smpte240m" +## - 8 | "YCgCo" | "YCoCg" +## - 9 | "2020" | "bt2020nc" +## - 10 | "2020cl" | "bt2020c" +## - 100 | "OPP" | "opponent": same as the opponent color space used in BM3D denoising filter +## default: guessed according to the color family and size of input clip +## dIsRGB {bool}: specify if the target is RGB +## If source and target are both RGB and "matrix" is not specified, then assume matrix="RGB". +## default: False for RGB input, otherwise True +## id {bool}: +## - False: output matrix name{str} +## - True: output matrix id{int} +## default: False +################################################################################################################################ +def GetMatrix(clip, matrix=None, dIsRGB=None, id=False): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Get properties of input clip + sFormat = clip.format + + sColorFamily = sFormat.color_family + CheckColorFamily(sColorFamily) + sIsRGB = sColorFamily == vs.RGB + + # Get properties of output clip + if dIsRGB is None: + dIsRGB = not sIsRGB + elif not isinstance(dIsRGB, int): + raise type_error('"dIsRGB" must be a bool!') + + # id + if not isinstance(id, int): + raise type_error('"id" must be a bool!') + + # Resolution level + SD = False + UHD = False + + if clip.width <= 1024 and clip.height <= 576: + SD = True + elif clip.width <= 2048 and clip.height <= 1536: + pass # HD + else: + UHD = True + + # Convert to string format + if matrix is None: + matrix = "Unspecified" + elif not isinstance(matrix, (int, str)): + raise type_error('"matrix" must be an int or a str!') + else: + if isinstance(matrix, str): + matrix = matrix.lower() + if matrix == 0 or matrix == "rgb": # GBR + matrix = 0 if id else "RGB" + elif matrix == 1 or matrix == "709" or matrix == "bt709": # bt709 + matrix = 1 if id else "709" + elif matrix == 2 or matrix == "unspecified" or matrix == "unspec": # Unspecified + matrix = 2 if id else "Unspecified" + elif matrix == 4 or matrix == "fcc": # fcc + matrix = 4 if id else "FCC" + elif matrix == 5 or matrix == "bt470bg" or matrix == "470bg": # bt470bg + matrix = 5 if id else "601" + elif matrix == 6 or matrix == "601" or matrix == "smpte170m" or matrix == "170m": # smpte170m + matrix = 6 if id else "601" + elif matrix == 7 or matrix == "240" or matrix == "smpte240m": # smpte240m + matrix = 7 if id else "240" + elif matrix == 8 or matrix == "ycgco" or matrix == "ycocg": # YCgCo + matrix = 8 if id else "YCgCo" + elif matrix == 9 or matrix == "2020" or matrix == "bt2020nc" or matrix == "2020ncl": # bt2020nc + matrix = 9 if id else "2020" + elif matrix == 10 or matrix == "2020cl" or matrix == "bt2020c": # bt2020c + matrix = 10 if id else "2020cl" + elif matrix == 100 or matrix == "opp" or matrix == "opponent": # opponent color space + matrix = 100 if id else "OPP" + else: + raise value_error('Unsupported matrix specified!') + + # If unspecified, automatically determine it based on color family and resolution level + if matrix == 2 or matrix == "Unspecified": + if dIsRGB and sIsRGB: + matrix = 0 if id else "RGB" + else: + matrix = (6 if id else "601") if SD else (9 if id else "2020") if UHD else (1 if id else "709") + + # Output + return matrix +################################################################################################################################ + + +################################################################################################################################ +## Helper function: zDepth() +################################################################################################################################ +## Smart function to utilize zimg depth conversion for both 1.0 and 2.0 API of vszimg as well as core.resize. +## core.resize is preferred now. +################################################################################################################################ +def zDepth(clip, sample=None, depth=None, range=None, range_in=None, dither_type=None, cpu_type=None): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Get properties of input clip + sFormat = clip.format + + # Get properties of output clip + if sample is None: + sample = sFormat.sample_type + elif not isinstance(sample, int): + raise type_error('"sample" must be an int!') + + if depth is None: + depth = sFormat.bits_per_sample + elif not isinstance(depth, int): + raise type_error('"depth" must be an int!') + + format = RegisterFormat(sFormat.color_family, sample, depth, sFormat.subsampling_w, sFormat.subsampling_h) + + # Process + zimgResize = hasattr(core, 'resize') + zimgPlugin = hasattr(core, 'z') + if zimgResize: + # VapourSynth resizer + clip = core.resize.Bicubic(clip, format=format.id, range=range, range_in=range_in, dither_type=dither_type, cpu_type=cpu_type) + elif zimgPlugin and hasattr(core.z, 'Format'): + # vszimg 2.0 + clip = core.z.Format(clip, format=format.id, range=range, range_in=range_in, dither_type=dither_type, cpu_type=cpu_type) + elif zimgPlugin and hasattr(core.z, 'Depth'): + # vszimg 1.0 + clip = core.z.Depth(clip, dither=dither_type, sample=sample, depth=depth, fullrange_in=range_in, fullrange_out=range) + else: + raise attribute_error('no available core.resize or zimg found!') + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Helper function: PlaneAverage() +################################################################################################################################ +## Evaluate normalized average value of the specified plane and store it as a frame property. +## Mainly as a wrap function to support both std.PlaneAverage and std.PlaneStats with the same interface. +################################################################################################################################ +## Parameters +## clip {clip}: the source clip +## can be of any constant format +## plane {int}: the plane to evaluate +## default: 0 +## prop {str}: the frame property name to be written +## default: 'PlaneAverage' +################################################################################################################################ +def PlaneAverage(clip, plane=None, prop=None): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Get properties of input clip + sFormat = clip.format + sNumPlanes = sFormat.num_planes + + # Parameters + if plane is None: + plane = 0 + elif not isinstance(plane, int): + raise type_error('"plane" must be an int!') + elif plane < 0 or plane > sNumPlanes: + raise value_error(f'valid range of "plane" is [0, {sNumPlanes})!') + + if prop is None: + prop = 'PlaneAverage' + elif not isinstance(prop, str): + raise type_error('"prop" must be a str!') + + # Process + if hasattr(core.std, 'PlaneAverage'): + clip = core.std.PlaneAverage(clip, plane=plane, prop=prop) + elif hasattr(core.std, 'PlaneStats'): + clip = core.std.PlaneStats(clip, plane=plane, prop='PlaneStats') + def _PlaneAverageTransfer(n, f): + fout = f.copy() + fout.props.__setattr__(prop, f.props.PlaneStatsAverage) + del fout.props.PlaneStatsAverage + del fout.props.PlaneStatsMinMax + return fout + clip = core.std.ModifyFrame(clip, clip, selector=_PlaneAverageTransfer) + else: + raise attribute_error('no available plane average function found!') + + # output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Helper function: GetPlane() +################################################################################################################################ +## Extract specific plane and store it in a Gray clip. +################################################################################################################################ +## Parameters +## clip {clip}: the source clip +## can be of any constant format +## plane {int}: the plane to extract +## default: 0 +################################################################################################################################ +def GetPlane(clip, plane=None): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Get properties of input clip + sFormat = clip.format + sNumPlanes = sFormat.num_planes + + # Parameters + if plane is None: + plane = 0 + elif not isinstance(plane, int): + raise type_error('"plane" must be an int!') + elif plane < 0 or plane > sNumPlanes: + raise value_error(f'valid range of "plane" is [0, {sNumPlanes})!') + + # Process + return core.std.ShufflePlanes(clip, plane, vs.GRAY) +################################################################################################################################ + + +################################################################################################################################ +## Helper function: GrayScale() +################################################################################################################################ +## Convert the given clip to gray-scale. +################################################################################################################################ +## Parameters +## clip {clip}: the source clip +## can be of any constant format +## matrix {int|str}: for RGB input only, same as the one in ToYUV() +################################################################################################################################ +def GrayScale(clip, matrix=None): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!') + + # Get properties of input clip + sFormat = clip.format + + sColorFamily = sFormat.color_family + CheckColorFamily(sColorFamily) + sIsRGB = sColorFamily == vs.RGB + sIsGRAY = sColorFamily == vs.GRAY + + # Process + if sIsGRAY: + pass + elif sIsRGB: + clip = ToYUV(clip, matrix=matrix, full=True) + clip = core.std.ShufflePlanes(clip, [0,0,0], sColorFamily) + else: + blank = clip.std.BlankClip() + clip = core.std.ShufflePlanes([clip,blank,blank], [0,1,2], sColorFamily) + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Helper function: Preview() +################################################################################################################################ +## Convert the given clip or clips to the same RGB format. +## When multiple clips is given, they will be interleaved together, and resized to the same dimension using "Catmull-Rom". +################################################################################################################################ +## Set "plane" if you want to output a specific plane. +################################################################################################################################ +## matrix, full, dither, kernel, a1, a2 correspond to matrix_in, range_in, dither_type, +## resample_filter_uv, filter_param_a_uv, filter_param_b_uv in resize.Bicubic. +## "matrix" is passed to GetMatrix(id=True) first. +## default dither: random +## default chroma resampler: kernel="bicubic", a1=0, a2=0.5, also known as "Catmull-Rom" +################################################################################################################################ +def Preview(clips, plane=None, matrix=None, full=None, depth=None, + dither=None, kernel=None, a1=None, a2=None): + # input clip + if isinstance(clips, vs.VideoNode): + ref = clips + elif isinstance(clips, Sequence): + for c in clips: + if not isinstance(c, vs.VideoNode): + raise type_error('"clips" must be a clip or a sequence of clips!') + ref = clips[0] + else: + raise type_error('"clips" must be a clip or a sequence of clips!') + + # Get properties of output clip + if depth is None: + depth = 8 + elif not isinstance(depth, int): + raise type_error('"depth" must be an int!') + if depth >= 32: + sample = vs.FLOAT + else: + sample = vs.INTEGER + dFormat = RegisterFormat(vs.RGB, sample, depth, 0, 0).id + + # Parameters + if dither is None: + dither = "random" + if kernel is None: + kernel = "bicubic" + if a1 is None and a2 is None: + a1 = 0 + a2 = 0.5 + + # Conversion + def _Conv(clip): + if plane is not None: + clip = GetPlane(clip, plane) + return core.resize.Bicubic(clip, ref.width, ref.height, format=dFormat, + matrix_in=GetMatrix(clip, matrix, True, True), range_in=full, + filter_param_a=0, filter_param_b=0.5, + resample_filter_uv=kernel, filter_param_a_uv=a1, filter_param_b_uv=a2, + dither_type=dither) + + if isinstance(clips, vs.VideoNode): + clip = _Conv(clips) + elif isinstance(clips, Sequence): + clips = [_Conv(c) for c in clips] + clip = core.std.Interleave(clips) + + # Output + return clip +################################################################################################################################ + + +################################################################################################################################ +## Helper function: CheckColorFamily() +################################################################################################################################ +def CheckColorFamily(color_family, valid_list=None, invalid_list=None): + if valid_list is None: + valid_list = ('RGB', 'YUV', 'GRAY') + if invalid_list is None: + invalid_list = ('COMPAT', 'UNDEFINED') + # check invalid list + for cf in invalid_list: + if color_family == getattr(vs, cf, None): + raise value_error(f'color family *{cf}* is not supported!') + # check valid list + if valid_list: + if color_family not in [getattr(vs, cf, None) for cf in valid_list]: + raise value_error(f'color family not supported, only {valid_list} are accepted') +################################################################################################################################ + + +################################################################################################################################ +## Helper function: RemoveFrameProp() +################################################################################################################################ +def RemoveFrameProp(clip, prop): + if hasattr(core.std, 'RemoveFrameProps'): + # API >= 4 + return core.std.RemoveFrameProps(clip, prop) + return core.std.SetFrameProp(clip, prop, delete=True) +################################################################################################################################ + + +################################################################################################################################ +## Helper function: RegisterFormat() +################################################################################################################################ +def RegisterFormat(color_family, sample_type, bits_per_sample, subsampling_w, subsampling_h): + if hasattr(core, 'query_video_format'): + # API >= 4 + return core.query_video_format(color_family, sample_type, bits_per_sample, subsampling_w, subsampling_h) + return core.register_format(color_family, sample_type, bits_per_sample, subsampling_w, subsampling_h) +################################################################################################################################ + + + + + +################################################################################################################################ +################################################################################################################################ +################################################################################################################################ +## Internal used functions below +################################################################################################################################ +################################################################################################################################ +################################################################################################################################ + + +################################################################################################################################ +def get_func_name(num_of_call_stacks=1): + import inspect + frame = inspect.currentframe() + for _ in range(num_of_call_stacks): + frame = frame.f_back + return frame.f_code.co_name +################################################################################################################################ +def exception(obj1, *args, num_stacks=1): + name = get_func_name(num_stacks + 1) + return Exception(f'[mvsfunc.{name}] {obj1}', *args) +################################################################################################################################ +def type_error(obj1, *args, num_stacks=1): + name = get_func_name(num_stacks + 1) + return TypeError(f'[mvsfunc.{name}] {obj1}', *args) +################################################################################################################################ +def value_error(obj1, *args, num_stacks=1): + name = get_func_name(num_stacks + 1) + return ValueError(f'[mvsfunc.{name}] {obj1}', *args) +################################################################################################################################ +def attribute_error(obj1, *args, num_stacks=1): + name = get_func_name(num_stacks + 1) + return AttributeError(f'[mvsfunc.{name}] {obj1}', *args) +################################################################################################################################ + + +################################################################################################################################ +## Internal used function to calculate quantization parameters +################################################################################################################################ +def _quantization_parameters(sample=None, depth=None, full=None, chroma=None): + qp = {} + + if sample is None: + sample = vs.INTEGER + if depth is None: + depth = 8 + elif depth < 1: + raise value_error('"depth" should not be less than 1!', num_stacks=2) + if full is None: + full = True + if chroma is None: + chroma = False + + lShift = depth - 8 + rShift = 8 - depth + + if sample == vs.INTEGER: + if chroma: + qp['floor'] = 0 if full else 16 << lShift if lShift >= 0 else 16 >> rShift + qp['neutral'] = 128 << lShift if lShift >= 0 else 128 >> rShift + qp['ceil'] = (1 << depth) - 1 if full else 240 << lShift if lShift >= 0 else 240 >> rShift + qp['range'] = qp['ceil'] - qp['floor'] + else: + qp['floor'] = 0 if full else 16 << lShift if lShift >= 0 else 16 >> rShift + qp['neutral'] = qp['floor'] + qp['ceil'] = (1 << depth) - 1 if full else 235 << lShift if lShift >= 0 else 235 >> rShift + qp['range'] = qp['ceil'] - qp['floor'] + elif sample == vs.FLOAT: + if chroma: + qp['floor'] = -0.5 + qp['neutral'] = 0.0 + qp['ceil'] = 0.5 + qp['range'] = qp['ceil'] - qp['floor'] + else: + qp['floor'] = 0.0 + qp['neutral'] = qp['floor'] + qp['ceil'] = 1.0 + qp['range'] = qp['ceil'] - qp['floor'] + else: + raise value_error('Unsupported "sample" specified!', num_stacks=2) + + return qp +################################################################################################################################ + + +################################################################################################################################ +## Internal used function to do quantization conversion with std.Expr +################################################################################################################################ +def _quantization_conversion(clip, depths=None, depthd=None, sample=None, fulls=None, fulld=None, + chroma=None, clamp=None, dbitPS=None, mode=None): + # input clip + if not isinstance(clip, vs.VideoNode): + raise type_error('"clip" must be a clip!', num_stacks=2) + + # Get properties of input clip + sFormat = clip.format + + sColorFamily = sFormat.color_family + CheckColorFamily(sColorFamily) + sIsYUV = sColorFamily == vs.YUV + sIsGRAY = sColorFamily == vs.GRAY + + sbitPS = sFormat.bits_per_sample + sSType = sFormat.sample_type + + if depths is None: + depths = sbitPS + elif not isinstance(depths, int): + raise type_error('"depths" must be an int!', num_stacks=2) + + if fulls is None: + # If not set, assume limited range for YUV and Gray input + fulls = False if sIsYUV or sIsGRAY else True + elif not isinstance(fulls, int): + raise type_error('"fulls" must be a bool!', num_stacks=2) + + if chroma is None: + chroma = False + elif not isinstance(chroma, int): + raise type_error('"chroma" must be a bool!', num_stacks=2) + elif not sIsGRAY: + chroma = False + + # Get properties of output clip + if depthd is None: + pass + elif not isinstance(depthd, int): + raise type_error('"depthd" must be an int!', num_stacks=2) + if sample is None: + if depthd is None: + dSType = sSType + depthd = depths + else: + dSType = vs.FLOAT if dbitPS >= 32 else vs.INTEGER + elif not isinstance(sample, int): + raise type_error('"sample" must be an int!', num_stacks=2) + elif sample != vs.INTEGER and sample != vs.FLOAT: + raise value_error('"sample" must be either 0 (vs.INTEGER) or 1 (vs.FLOAT)!', num_stacks=2) + else: + dSType = sample + if dSType == vs.INTEGER and (dbitPS < 1 or dbitPS > 16): + raise value_error(f'{dbitPS}-bit integer output is not supported!', num_stacks=2) + if dSType == vs.FLOAT and (dbitPS != 16 and dbitPS != 32): + raise value_error(f'{dbitPS}-bit float output is not supported!', num_stacks=2) + + if fulld is None: + fulld = fulls + elif not isinstance(fulld, int): + raise type_error('"fulld" must be a bool!', num_stacks=2) + + if clamp is None: + clamp = dSType == vs.INTEGER + elif not isinstance(clamp, int): + raise type_error('"clamp" must be a bool!', num_stacks=2) + + if dbitPS is None: + if depthd < 8: + dbitPS = 8 + else: + dbitPS = depthd + elif not isinstance(dbitPS, int): + raise type_error('"dbitPS" must be an int!', num_stacks=2) + + if mode is None: + mode = 0 + elif not isinstance(mode, int): + raise type_error('"mode" must be an int!', num_stacks=2) + elif depthd >= 8: + mode = 0 + + dFormat = RegisterFormat(sFormat.color_family, dSType, dbitPS, sFormat.subsampling_w, sFormat.subsampling_h) + + # Expression function + def gen_expr(chroma, mode): + if dSType == vs.INTEGER: + exprLower = 0 + exprUpper = 1 << (dFormat.bytes_per_sample * 8) - 1 + else: + exprLower = float('-inf') + exprUpper = float('inf') + + sQP = _quantization_parameters(sSType, depths, fulls, chroma) + dQP = _quantization_parameters(dSType, depthd, fulld, chroma) + + gain = dQP['range'] / sQP['range'] + offset = dQP['neutral' if chroma else 'floor'] - sQP['neutral' if chroma else 'floor'] * gain + + if mode == 1: + scale = 256 + gain = gain * scale + offset = offset * scale + else: + scale = 1 + + if gain != 1 or offset != 0 or clamp: + expr = " x " + if gain != 1: expr = expr + f" {gain} * " + if offset != 0: expr = expr + f" {offset} + " + if clamp: + if dQP['floor'] * scale > exprLower: expr = expr + f" {dQP['floor'] * scale} max " + if dQP['ceil'] * scale < exprUpper: expr = expr + f" {dQP['ceil'] * scale} min " + else: + expr = "" + + return expr + + # Process + Yexpr = gen_expr(False, mode) + Cexpr = gen_expr(True, mode) + + if sIsYUV: + expr = [Yexpr, Cexpr] + elif sIsGRAY and chroma: + expr = Cexpr + else: + expr = Yexpr + + clip = core.std.Expr(clip, expr, format=dFormat.id) + + # Output + clip = SetColorSpace(clip, ColorRange=0 if fulld else 1) + return clip +################################################################################################################################ + + +################################################################################################################################ +## Internal used function to check the argument for frame property +################################################################################################################################ +def _check_arg_prop(arg, default=None, defaultTrue=None, argName='arg'): + if defaultTrue is None: + defaultTrue = default + + if arg is None: + arg = default + elif isinstance(arg, int): + if arg: + arg = defaultTrue + elif isinstance(arg, str): + if arg: + if not arg.isidentifier(): + raise value_error(f'{argName}="{arg}" is not a valid identifier!', num_stacks=2) + else: + arg = False + else: + raise type_error(f'"{argName}" must be a str or a bool!', num_stacks=2) + + return arg +################################################################################################################################ + + +################################################################################################################################ +## Internal used function for Min(), Max() and Avg() +################################################################################################################################ +def _operator2(clip1, clip2, mode, neutral, name): + # input clip + if not isinstance(clip1, vs.VideoNode): + raise type_error('"clip1" must be a clip!', num_stacks=2) + if not isinstance(clip2, vs.VideoNode): + raise type_error('"clip2" must be a clip!', num_stacks=2) + + # Get properties of input clip + sFormat = clip1.format + if sFormat.id != clip2.format.id: + raise value_error('"clip1" and "clip2" must be of the same format!', num_stacks=2) + if clip1.width != clip2.width or clip1.height != clip2.height: + raise value_error('"clip1" and "clip2" must be of the same width and height!', num_stacks=2) + + sSType = sFormat.sample_type + sbitPS = sFormat.bits_per_sample + sNumPlanes = sFormat.num_planes + + # mode + if mode is None: + mode = [1 for i in range(VSMaxPlaneNum)] + elif isinstance(mode, int): + mode = [mode for i in range(VSMaxPlaneNum)] + elif isinstance(mode, list): + for m in mode: + if not isinstance(m, int): + raise type_error('"mode" must be a (sequence of) int!', num_stacks=2) + while len(mode) < VSMaxPlaneNum: + mode.append(mode[len(mode) - 1]) + else: + raise type_error('"mode" must be a (sequence of) int!', num_stacks=2) + + # neutral + if neutral is None: + neutral = 1 << (sbitPS - 1) if sSType == vs.INTEGER else 0 + elif not (isinstance(neutral, int) or isinstance(neutral, float)): + raise type_error('"neutral" must be an int or a float!', num_stacks=2) + + # Process and output + expr = [] + for i in range(sNumPlanes): + if name == 'Min': + if mode[i] >= 2: + expr.append(f"y {neutral} - abs x {neutral} - abs < y x ?") + elif mode[i] == 1: + expr.append("x y min") + else: + expr.append("") + elif name == 'Max': + if mode[i] >= 2: + expr.append(f"y {neutral} - abs x {neutral} - abs > y x ?") + elif mode[i] == 1: + expr.append("x y max") + else: + expr.append("") + elif name == 'Avg': + if mode[i] >= 1: + expr.append("x y + 2 /") + else: + expr.append("") + else: + raise value_error('Unknown "name" specified!', num_stacks=1) + + return core.std.Expr([clip1, clip2], expr) +################################################################################################################################ + + +################################################################################################################################ +## Internal used function for MinFilter() and MaxFilter() +################################################################################################################################ +def _min_max_filter(src, flt1, flt2, planes, name): + # input clip + if not isinstance(src, vs.VideoNode): + raise type_error('"src" must be a clip!', num_stacks=2) + if not isinstance(flt1, vs.VideoNode): + raise type_error('"flt1" must be a clip!', num_stacks=2) + if not isinstance(flt2, vs.VideoNode): + raise type_error('"flt2" must be a clip!', num_stacks=2) + + # Get properties of input clip + sFormat = src.format + if sFormat.id != flt1.format.id or sFormat.id != flt2.format.id: + raise value_error('"src", "flt1" and "flt2" must be of the same format!', num_stacks=2) + if src.width != flt1.width or src.height != flt1.height or src.width != flt2.width or src.height != flt2.height: + raise value_error('"src", "flt1" and "flt2" must be of the same width and height!', num_stacks=2) + + sNumPlanes = sFormat.num_planes + + # planes + process = [0 for i in range(VSMaxPlaneNum)] + + if planes is None: + process = [1 for i in range(VSMaxPlaneNum)] + elif isinstance(planes, int): + if planes < 0 or planes >= VSMaxPlaneNum: + raise value_error(f'valid range of "planes" is [0, {VSMaxPlaneNum})!', num_stacks=2) + process[planes] = 1 + elif isinstance(planes, Sequence): + for p in planes: + if not isinstance(p, int): + raise type_error('"planes" must be a (sequence of) int!') + elif p < 0 or p >= VSMaxPlaneNum: + raise value_error(f'valid range of "planes" is [0, {VSMaxPlaneNum})!', num_stacks=2) + process[p] = 1 + else: + raise type_error('"planes" must be a (sequence of) int!', num_stacks=2) + + # Process and output + expr = [] + for i in range(sNumPlanes): + if process[i]: + if name == 'MinFilter': + expr.append("x z - abs x y - abs < z y ?") + elif name == 'MaxFilter': + expr.append("x z - abs x y - abs > z y ?") + else: + raise value_error('Unknown "name" specified!', num_stacks=1) + else: + expr.append("") + + return core.std.Expr([src, flt1, flt2], expr) +################################################################################################################################ + + +################################################################################################################################ +## Internal used functions for LimitFilter() +################################################################################################################################ +def _limit_filter_expr(defref, thr, elast, largen_thr, value_range): + flt = " x " + src = " y " + ref = " z " if defref else src + + dif = f" {flt} {src} - " + dif_ref = f" {flt} {ref} - " + dif_abs = dif_ref + " abs " + + thr = thr * value_range / 255 + largen_thr = largen_thr * value_range / 255 + + if thr <= 0 and largen_thr <= 0: + limitExpr = f" {src} " + elif thr >= value_range and largen_thr >= value_range: + limitExpr = "" + else: + if thr <= 0: + limitExpr = f" {src} " + elif thr >= value_range: + limitExpr = f" {flt} " + elif elast <= 1: + limitExpr = f" {dif_abs} {thr} <= {flt} {src} ? " + else: + thr_1 = thr + thr_2 = thr * elast + thr_slope = 1 / (thr_2 - thr_1) + # final = src + dif * (thr_2 - dif_abs) / (thr_2 - thr_1) + limitExpr = f" {src} {dif} {thr_2} {dif_abs} - * {thr_slope} * + " + limitExpr = f" {dif_abs} {thr_1} <= {flt} {dif_abs} {thr_2} >= {src} " + limitExpr + " ? ? " + + if largen_thr != thr: + if largen_thr <= 0: + limitExprLargen = f" {src} " + elif largen_thr >= value_range: + limitExprLargen = f" {flt} " + elif elast <= 1: + limitExprLargen = f" {dif_abs} {largen_thr} <= {flt} {src} ? " + else: + thr_1 = largen_thr + thr_2 = largen_thr * elast + thr_slope = 1 / (thr_2 - thr_1) + # final = src + dif * (thr_2 - dif_abs) / (thr_2 - thr_1) + limitExprLargen = f" {src} {dif} {thr_2} {dif_abs} - * {thr_slope} * + " + limitExprLargen = f" {dif_abs} {thr_1} <= {flt} {dif_abs} {thr_2} >= {src} " + limitExprLargen + " ? ? " + limitExpr = f" {flt} {ref} > " + limitExprLargen + " " + limitExpr + " ? " + + return limitExpr +################################################################################################################################ + + +################################################################################################################################ +## Internal used functions for LimitFilter() +################################################################################################################################ +def _limit_diff_lut(diff, thr, elast, largen_thr, planes): + # input clip + if not isinstance(diff, vs.VideoNode): + raise type_error('"diff" must be a clip!', num_stacks=2) + + # Get properties of input clip + sFormat = diff.format + + sSType = sFormat.sample_type + sbitPS = sFormat.bits_per_sample + + if sSType == vs.INTEGER: + neutral = 1 << (sbitPS - 1) + value_range = (1 << sbitPS) - 1 + else: + neutral = 0 + value_range = 1 + raise value_error('"diff" must be an int!', num_stacks=2) + + # Process + thr = thr * value_range / 255 + largen_thr = largen_thr * value_range / 255 + ''' + # for std.MergeDiff(src, limitedDiff) + if thr <= 0 and largen_thr <= 0: + def limitLut(x): + return neutral + return core.std.Lut(diff, planes=planes, function=limitLut) + elif thr >= value_range / 2 and largen_thr >= value_range / 2: + return diff + elif elast <= 1: + def limitLut(x): + dif = x - neutral + dif_abs = abs(dif) + thr_1 = largen_thr if dif > 0 else thr + return x if dif_abs <= thr_1 else neutral + return core.std.Lut(diff, planes=planes, function=limitLut) + else: + def limitLut(x): + dif = x - neutral + dif_abs = abs(dif) + thr_1 = largen_thr if dif > 0 else thr + thr_2 = thr_1 * elast + thr_slope = 1 / (thr_2 - thr_1) + + if dif_abs <= thr_1: + return x + elif dif_abs >= thr_2: + return neutral + else: + # final = src - dif * ((dif_abs - thr_1) / (thr_2 - thr_1) - 1) + return round(dif * (thr_2 - dif_abs) * thr_slope + neutral) + ''' + # for std.MakeDiff(flt, limitedDiff) + if thr <= 0 and largen_thr <= 0: + return diff + elif thr >= value_range / 2 and largen_thr >= value_range / 2: + def limitLut(x): + return neutral + return core.std.Lut(diff, planes=planes, function=limitLut) + elif elast <= 1: + def limitLut(x): + dif = x - neutral + dif_abs = abs(dif) + thr_1 = largen_thr if dif > 0 else thr + return neutral if dif_abs <= thr_1 else x + return core.std.Lut(diff, planes=planes, function=limitLut) + else: + def limitLut(x): + dif = x - neutral + dif_abs = abs(dif) + thr_1 = largen_thr if dif > 0 else thr + thr_2 = thr_1 * elast + + if dif_abs <= thr_1: + return neutral + elif dif_abs >= thr_2: + return x + else: + # final = flt - dif * (dif_abs - thr_1) / (thr_2 - thr_1) + thr_slope = 1 / (thr_2 - thr_1) + return round(dif * (dif_abs - thr_1) * thr_slope + neutral) + return core.std.Lut(diff, planes=planes, function=limitLut) +################################################################################################################################ diff --git a/Programs/pfm-192-vapoursynth-win.exe b/Programs/pfm-192-vapoursynth-win.exe new file mode 100644 index 0000000..47d9885 Binary files /dev/null and b/Programs/pfm-192-vapoursynth-win.exe differ diff --git a/Programs/portable.vs b/Programs/portable.vs new file mode 100644 index 0000000..e69de29 diff --git a/Programs/python.cat b/Programs/python.cat new file mode 100644 index 0000000..dd361ff Binary files /dev/null and b/Programs/python.cat differ diff --git a/Programs/python.exe b/Programs/python.exe new file mode 100644 index 0000000..da79099 Binary files /dev/null and b/Programs/python.exe differ diff --git a/Programs/python3.dll b/Programs/python3.dll new file mode 100644 index 0000000..06da17b Binary files /dev/null and b/Programs/python3.dll differ diff --git a/Programs/python311._pth b/Programs/python311._pth new file mode 100644 index 0000000..e42d652 --- /dev/null +++ b/Programs/python311._pth @@ -0,0 +1,5 @@ +python311.zip +. + +# Uncomment to run site.main() automatically +#import site diff --git a/Programs/python311.dll b/Programs/python311.dll new file mode 100644 index 0000000..0f449d7 Binary files /dev/null and b/Programs/python311.dll differ diff --git a/Programs/python311.zip b/Programs/python311.zip new file mode 100644 index 0000000..afd180c Binary files /dev/null and b/Programs/python311.zip differ diff --git a/Programs/pythonw.exe b/Programs/pythonw.exe new file mode 100644 index 0000000..88217cc Binary files /dev/null and b/Programs/pythonw.exe differ diff --git a/Programs/readonly.vpy b/Programs/readonly.vpy new file mode 100644 index 0000000..89dff43 --- /dev/null +++ b/Programs/readonly.vpy @@ -0,0 +1,6 @@ +import vapoursynth as vs +core = vs.core + +clip = core.lsmas.LWLibavSource(source="D:/Encode/Church/archive_test/2022-03-20_110000_deinterlaced_0500.mkv") + +clip.set_output(0) \ No newline at end of file diff --git a/Programs/sdk/examples/filter_skeleton.c b/Programs/sdk/examples/filter_skeleton.c new file mode 100644 index 0000000..58fd5fe --- /dev/null +++ b/Programs/sdk/examples/filter_skeleton.c @@ -0,0 +1,58 @@ +////////////////////////////////////////// +// This file contains a simple filter +// skeleton you can use to get started. +// With no changes it simply passes +// frames through. + +#include "VapourSynth4.h" +#include "VSHelper4.h" + +typedef struct { + VSNode *node; + const VSVideoInfo *vi; +} FilterData; + + +static const VSFrame *VS_CC filterGetFrame(int n, int activationReason, void *instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) { + FilterData *d = (FilterData *)instanceData; + + if (activationReason == arInitial) { + vsapi->requestFrameFilter(n, d->node, frameCtx); + } else if (activationReason == arAllFramesReady) { + const VSFrame *frame = vsapi->getFrameFilter(n, d->node, frameCtx); + + /* your code here... */ + + return frame; + } + + return NULL; +} + +static void VS_CC filterFree(void *instanceData, VSCore *core, const VSAPI *vsapi) { + FilterData *d = (FilterData *)instanceData; + vsapi->freeNode(d->node); + free(d); +} + +static void VS_CC filterCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { + FilterData d; + FilterData *data; + + d.node = vsapi->mapGetNode(in, "clip", 0, 0); + d.vi = vsapi->getVideoInfo(d.node); + + data = (FilterData *)malloc(sizeof(d)); + *data = d; + + VSFilterDependency deps[] = {{d.node, rpGeneral}}; /* Depending the the request patterns you may want to change this */ + vsapi->createVideoFilter(out, "Filter", data->vi, filterGetFrame, filterFree, fmParallel, deps, 1, data, core); +} + +////////////////////////////////////////// +// Init + +VS_EXTERNAL_API(void) VapourSynthPluginInit2(VSPlugin *plugin, const VSPLUGINAPI *vspapi) { + vspapi->configPlugin("com.example.filter", "filter", "VapourSynth Filter Skeleton", VS_MAKE_VERSION(1, 0), VAPOURSYNTH_API_VERSION, 0, plugin); + vspapi->registerFunction("Filter", "clip:vnode;", "clip:vnode;", filterCreate, NULL, plugin); +} diff --git a/Programs/sdk/examples/invert_example.c b/Programs/sdk/examples/invert_example.c new file mode 100644 index 0000000..747ba11 --- /dev/null +++ b/Programs/sdk/examples/invert_example.c @@ -0,0 +1,173 @@ +////////////////////////////////////////// +// This file contains a simple invert +// filter that's commented to show +// the basics of the filter api. +// This file may make more sense when +// read from the bottom and up. + +#include +#include "VapourSynth4.h" +#include "VSHelper4.h" + +typedef struct { + VSNode *node; + int enabled; +} InvertData; + +// This is the main function that gets called when a frame should be produced. It will, in most cases, get +// called several times to produce one frame. This state is being kept track of by the value of +// activationReason. The first call to produce a certain frame n is always arInitial. In this state +// you should request all the input frames you need. Always do it in ascending order to play nice with the +// upstream filters. +// Once all frames are ready, the filter will be called with arAllFramesReady. It is now time to +// do the actual processing. +static const VSFrame *VS_CC invertGetFrame(int n, int activationReason, void *instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) { + InvertData *d = (InvertData *)instanceData; + + if (activationReason == arInitial) { + // Request the source frame on the first call + vsapi->requestFrameFilter(n, d->node, frameCtx); + } else if (activationReason == arAllFramesReady) { + const VSFrame *src = vsapi->getFrameFilter(n, d->node, frameCtx); + // The reason we query this on a per frame basis is because we want our filter + // to accept clips with varying dimensions. If we reject such content using d->vi + // would be easier. + const VSVideoFormat *fi = vsapi->getVideoFrameFormat(src); + int height = vsapi->getFrameHeight(src, 0); + int width = vsapi->getFrameWidth(src, 0); + + + // When creating a new frame for output it is VERY EXTREMELY SUPER IMPORTANT to + // supply the "dominant" source frame to copy properties from. Frame props + // are an essential part of the filter chain and you should NEVER break it. + VSFrame *dst = vsapi->newVideoFrame(fi, width, height, src, core); + + // It's processing loop time! + // Loop over all the planes + int plane; + for (plane = 0; plane < fi->numPlanes; plane++) { + const uint8_t *srcp = vsapi->getReadPtr(src, plane); + ptrdiff_t src_stride = vsapi->getStride(src, plane); + uint8_t *dstp = vsapi->getWritePtr(dst, plane); + ptrdiff_t dst_stride = vsapi->getStride(dst, plane); // note that if a frame has the same dimensions and format, the stride is guaranteed to be the same. int dst_stride = src_stride would be fine too in this filter. + // Since planes may be subsampled you have to query the height of them individually + int h = vsapi->getFrameHeight(src, plane); + int y; + int w = vsapi->getFrameWidth(src, plane); + int x; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) + dstp[x] = ~srcp[x]; + + dstp += dst_stride; + srcp += src_stride; + } + } + + // Release the source frame + vsapi->freeFrame(src); + + // A reference is consumed when it is returned, so saving the dst reference somewhere + // and reusing it is not allowed. + return dst; + } + + return NULL; +} + +// Free all allocated data on filter destruction +static void VS_CC invertFree(void *instanceData, VSCore *core, const VSAPI *vsapi) { + InvertData *d = (InvertData *)instanceData; + vsapi->freeNode(d->node); + free(d); +} + +// This function is responsible for validating arguments and creating a new filter +static void VS_CC invertCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { + InvertData d; + InvertData *data; + int err; + + // Get a clip reference from the input arguments. This must be freed later. + d.node = vsapi->mapGetNode(in, "clip", 0, 0); + const VSVideoInfo *vi = vsapi->getVideoInfo(d.node); + + // In this first version we only want to handle 8bit integer formats. Note that + // vi->format can be 0 if the input clip can change format midstream. + if (!vsh_isConstantVideoFormat(vi) || vi->format.sampleType != stInteger || vi->format.bitsPerSample != 8) { + vsapi->mapSetError(out, "Invert: only constant format 8bit integer input supported"); + vsapi->freeNode(d.node); + return; + } + + // If a property read fails for some reason (index out of bounds/wrong type) + // then err will have flags set to indicate why and 0 will be returned. This + // can be very useful to know when having optional arguments. Since we have + // strict checking because of what we wrote in the argument string, the only + // reason this could fail is when the value wasn't set by the user. + // And when it's not set we want it to default to enabled. + d.enabled = !!vsapi->mapGetInt(in, "enable", 0, &err); + if (err) + d.enabled = 1; + + // Let's pretend the only allowed values are 1 or 0... + if (d.enabled < 0 || d.enabled > 1) { + vsapi->mapSetError(out, "Invert: enabled must be 0 or 1"); + vsapi->freeNode(d.node); + return; + } + + // I usually keep the filter data struct on the stack and don't allocate it + // until all the input validation is done. + data = (InvertData *)malloc(sizeof(d)); + *data = d; + + // Creates a new filter and returns a reference to it. Always pass on the in and out + // arguments or unexpected things may happen. The name should be something that's + // easy to connect to the filter, like its function name. + // The three function pointers handle initialization, frame processing and filter destruction. + // The filtermode is very important to get right as it controls how threading of the filter + // is handled. In general you should only use fmParallel whenever possible. This is if you + // need to modify no shared data at all when the filter is running. + // For more complicated filters, fmParallelRequests is usually easier to achieve as it can + // be prefetched in parallel but the actual processing is serialized. + // The others can be considered special cases where fmFrameState is useful to source filters and + // fmUnordered is useful when a filter's state may change even when deciding which frames to + // prefetch (such as a cache filter). + + VSFilterDependency deps[] = {{d.node, rpStrictSpatial}}; + vsapi->createVideoFilter(out, "Invert", vi, invertGetFrame, invertFree, fmParallel, deps, 1, data, core); +} + +////////////////////////////////////////// +// Init + +// This is the entry point that is called when a plugin is loaded. You are only supposed +// to call the two provided functions here. +// configFunc sets the id, namespace, and long name of the plugin (the last 3 arguments +// never need to be changed for a normal plugin). +// +// id: Needs to be a "reverse" url and unique among all plugins. +// It is inspired by how android packages identify themselves. +// If you don't own a domain then make one up that's related +// to the plugin name. +// +// namespace: Should only use [a-z_] and not be too long. +// +// full name: Any name that describes the plugin nicely. +// +// registerFunction is called once for each function you want to register. Function names +// should be CamelCase. The argument string has this format: +// name:type; or name:type:flag1:flag2....; +// All argument name should be lowercase and only use [a-z_]. +// The valid types are int,float,data,clip,frame,func. [] can be appended to allow arrays +// of type to be passed (numbers:int[]) +// The available flags are opt, to make an argument optional, empty, which controls whether +// or not empty arrays are accepted + + +VS_EXTERNAL_API(void) VapourSynthPluginInit2(VSPlugin *plugin, const VSPLUGINAPI *vspapi) { + vspapi->configPlugin("com.example.invert", "invert", "VapourSynth Invert Example", VS_MAKE_VERSION(1, 0), VAPOURSYNTH_API_VERSION, 0, plugin); + vspapi->registerFunction("Filter", "clip:vnode;enabled:int:opt;", "clip:vnode;", invertCreate, NULL, plugin); +} diff --git a/Programs/sdk/examples/vsscript_example.c b/Programs/sdk/examples/vsscript_example.c new file mode 100644 index 0000000..ac53583 --- /dev/null +++ b/Programs/sdk/examples/vsscript_example.c @@ -0,0 +1,116 @@ +/* +* This file is an example on how to use the VSScript part of the VapourSynth API. +* It writes out all the frames of an input script to a file. +* This file may be freely modified/copied/distributed. +* +* For an example of how to use getFrameAsync() see src/vspipe/vspipe.cpp +* It's basically the same as this example but with a callback when the +* processing is done. +*/ + +#include "VSScript4.h" +#include "VSHelper4.h" +#include +#include + + + +int main(int argc, char **argv) { + const VSAPI *vsapi = NULL; + const VSSCRIPTAPI *vssapi = NULL; + VSScript *se = NULL; + FILE *outFile = NULL; + + if (argc != 3) { + fprintf(stderr, "Usage: vsscript_example \n"); + return 1; + } + + // Open the output file for writing + outFile = fopen(argv[2], "wb"); + + if (!outFile) { + fprintf(stderr, "Failed to open output for writing\n"); + return 1; + } + + + // Initialize VSScript and get the api pointer + vssapi = getVSScriptAPI(VSSCRIPT_API_VERSION); + if (!vssapi) { + // VapourSynth probably isn't properly installed at all + fprintf(stderr, "Failed to initialize VSScript library\n"); + return 1; + } + + // Get a pointer to the normal api struct, exists so you don't have to link with the VapourSynth core library + // Failure only happens on very rare API version mismatches and usually doesn't need to be checked + vsapi = vssapi->getVSAPI(VAPOURSYNTH_API_VERSION); + assert(vsapi); + + // This line does the actual script evaluation. If se = NULL it will create a new environment + if (vssapi->evaluateFile(se, argv[1])) { + fprintf(stderr, "Script evaluation failed:\n%s", vssapi->getError(se)); + vssapi->freeScript(se); + return 1; + } + + // Get the clip set as output. It is valid until the out index is re-set/cleared/the script is freed + VSNode *node = vssapi->getOutputNode(se, 0); + if (!node) { + fprintf(stderr, "Failed to retrieve output node\n"); + vssapi->freeScript(se); + return 1; + } + + // Reject hard to handle formats + const VSVideoInfo *vi = vsapi->getVideoInfo(node); + + if (!vsh_isConstantVideoFormat(vi)) { + fprintf(stderr, "Cannot output clips with varying dimensions or format\n"); + vsapi->freeNode(node); + vssapi->freeScript(se); + return 1; + } + + // Output all frames + char errMsg[1024]; + int error = 0; + for (int n = 0; n < vi->numFrames; n++) { + const VSFrame *frame = vsapi->getFrame(n, node, errMsg, sizeof(errMsg)); + + if (!frame) { // Check if an error happened when getting the frame + error = 1; + break; + } + + // Loop over every row of every plane write to the file + for (int p = 0; p < vi->format.numPlanes; p++) { + ptrdiff_t stride = vsapi->getStride(frame, p); + const uint8_t *readPtr = vsapi->getReadPtr(frame, p); + int rowSize = vsapi->getFrameWidth(frame, p) * vi->format.bytesPerSample; + int height = vsapi->getFrameHeight(frame, p); + + for (int y = 0; y < height; y++) { + // You should probably handle any fwrite errors here as well + fwrite(readPtr, rowSize, 1, outFile); + readPtr += stride; + } + } + + vsapi->freeFrame(frame); + } + + // Cleanup + fclose(outFile); + + vsapi->freeNode(node); + vssapi->freeScript(se); + + if (error) { + fprintf(stderr, "%s", errMsg); + return 1; + } + + return 0; +} diff --git a/Programs/sdk/include/VSConstants4.h b/Programs/sdk/include/VSConstants4.h new file mode 100644 index 0000000..b27317d --- /dev/null +++ b/Programs/sdk/include/VSConstants4.h @@ -0,0 +1,93 @@ +/* +* Copyright (c) 2021 Fredrik Mellbin +* +* This file is part of VapourSynth. +* +* VapourSynth is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* VapourSynth is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with VapourSynth; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef VSCONSTANTS4_H +#define VSCONSTANTS4_H + +typedef enum VSColorRange { + VSC_RANGE_FULL = 0, + VSC_RANGE_LIMITED = 1 +} VSColorRange; + +typedef enum VSChromaLocation { + VSC_CHROMA_LEFT = 0, + VSC_CHROMA_CENTER = 1, + VSC_CHROMA_TOP_LEFT = 2, + VSC_CHROMA_TOP = 3, + VSC_CHROMA_BOTTOM_LEFT = 4, + VSC_CHROMA_BOTTOM = 5 +} VSChromaLocation; + +typedef enum VSFieldBased { + VSC_FIELD_PROGRESSIVE = 0, + VSC_FIELD_BOTTOM = 1, + VSC_FIELD_TOP = 2 +} VSFieldBased; + +typedef enum VSMatrixCoefficients { + VSC_MATRIX_RGB = 0, + VSC_MATRIX_BT709 = 1, + VSC_MATRIX_UNSPECIFIED = 2, + VSC_MATRIX_FCC = 4, + VSC_MATRIX_BT470_BG = 5, + VSC_MATRIX_ST170_M = 6, /* Equivalent to 5. */ + VSC_MATRIX_ST240_M = 7, + VSC_MATRIX_YCGCO = 8, + VSC_MATRIX_BT2020_NCL = 9, + VSC_MATRIX_BT2020_CL = 10, + VSC_MATRIX_CHROMATICITY_DERIVED_NCL = 12, + VSC_MATRIX_CHROMATICITY_DERIVED_CL = 13, + VSC_MATRIX_ICTCP = 14 +} VSMatrixCoefficients; + +typedef enum VSTransferCharacteristics { + VSC_TRANSFER_BT709 = 1, + VSC_TRANSFER_UNSPECIFIED = 2, + VSC_TRANSFER_BT470_M = 4, + VSC_TRANSFER_BT470_BG = 5, + VSC_TRANSFER_BT601 = 6, /* Equivalent to 1. */ + VSC_TRANSFER_ST240_M = 7, + VSC_TRANSFER_LINEAR = 8, + VSC_TRANSFER_LOG_100 = 9, + VSC_TRANSFER_LOG_316 = 10, + VSC_TRANSFER_IEC_61966_2_4 = 11, + VSC_TRANSFER_IEC_61966_2_1 = 13, + VSC_TRANSFER_BT2020_10 = 14, /* Equivalent to 1. */ + VSC_TRANSFER_BT2020_12 = 15, /* Equivalent to 1. */ + VSC_TRANSFER_ST2084 = 16, + VSC_TRANSFER_ARIB_B67 = 18 +} VSTransferCharacteristics; + +typedef enum VSColorPrimaries { + VSC_PRIMARIES_BT709 = 1, + VSC_PRIMARIES_UNSPECIFIED = 2, + VSC_PRIMARIES_BT470_M = 4, + VSC_PRIMARIES_BT470_BG = 5, + VSC_PRIMARIES_ST170_M = 6, + VSC_PRIMARIES_ST240_M = 7, /* Equivalent to 6. */ + VSC_PRIMARIES_FILM = 8, + VSC_PRIMARIES_BT2020 = 9, + VSC_PRIMARIES_ST428 = 10, + VSC_PRIMARIES_ST431_2 = 11, + VSC_PRIMARIES_ST432_1 = 12, + VSC_PRIMARIES_EBU3213_E = 22 +} VSColorPrimaries; + +#endif /* VSCONSTANTS4_H */ diff --git a/Programs/sdk/include/VSHelper.h b/Programs/sdk/include/VSHelper.h new file mode 100644 index 0000000..c344577 --- /dev/null +++ b/Programs/sdk/include/VSHelper.h @@ -0,0 +1,174 @@ +/***************************************************************************** +* Copyright (c) 2012-2015 Fredrik Mellbin +* --- Legal stuff --- +* This program is free software. It comes without any warranty, to +* the extent permitted by applicable law. You can redistribute it +* and/or modify it under the terms of the Do What The Fuck You Want +* To Public License, Version 2, as published by Sam Hocevar. See +* http://sam.zoy.org/wtfpl/COPYING for more details. +*****************************************************************************/ + +#ifndef VSHELPER_H +#define VSHELPER_H + +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#endif +#include "VapourSynth.h" + +/* Visual Studio doesn't recognize inline in c mode */ +#if defined(_MSC_VER) && !defined(__cplusplus) +#define inline _inline +#endif + +/* A kinda portable definition of the C99 restrict keyword (or its unofficial C++ equivalent) */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* Available in C99 */ +#define VS_RESTRICT restrict +#elif defined(__cplusplus) || defined(_MSC_VER) /* Almost all relevant C++ compilers support it so just assume it works */ +#define VS_RESTRICT __restrict +#else /* Not supported */ +#define VS_RESTRICT +#endif + +#ifdef _WIN32 +#define VS_ALIGNED_MALLOC(pptr, size, alignment) do { *(pptr) = _aligned_malloc((size), (alignment)); } while (0) +#define VS_ALIGNED_FREE(ptr) do { _aligned_free((ptr)); } while (0) +#else +#define VS_ALIGNED_MALLOC(pptr, size, alignment) do { if(posix_memalign((void**)(pptr), (alignment), (size))) *((void**)pptr) = NULL; } while (0) +#define VS_ALIGNED_FREE(ptr) do { free((ptr)); } while (0) +#endif + +#define VSMAX(a,b) ((a) > (b) ? (a) : (b)) +#define VSMIN(a,b) ((a) > (b) ? (b) : (a)) + +#ifdef __cplusplus +/* A nicer templated malloc for all the C++ users out there */ +#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) +template +#else +template +#endif +static inline T* vs_aligned_malloc(size_t size, size_t alignment) { +#ifdef _WIN32 + return (T*)_aligned_malloc(size, alignment); +#else + void *tmp = NULL; + if (posix_memalign(&tmp, alignment, size)) + tmp = 0; + return (T*)tmp; +#endif +} + +static inline void vs_aligned_free(void *ptr) { + VS_ALIGNED_FREE(ptr); +} +#endif /* __cplusplus */ + +/* convenience function for checking if the format never changes between frames */ +static inline int isConstantFormat(const VSVideoInfo *vi) { + return vi->height > 0 && vi->width > 0 && vi->format; +} + +/* convenience function to check for if two clips have the same format (unknown/changeable will be considered the same too) */ +static inline int isSameFormat(const VSVideoInfo *v1, const VSVideoInfo *v2) { + return v1->height == v2->height && v1->width == v2->width && v1->format == v2->format; +} + +/* multiplies and divides a rational number, such as a frame duration, in place and reduces the result */ +static inline void muldivRational(int64_t *num, int64_t *den, int64_t mul, int64_t div) { + /* do nothing if the rational number is invalid */ + if (!*den) + return; + + /* nobody wants to accidentally divide by zero */ + assert(div); + + int64_t a, b; + *num *= mul; + *den *= div; + a = *num; + b = *den; + while (b != 0) { + int64_t t = a; + a = b; + b = t % b; + } + if (a < 0) + a = -a; + *num /= a; + *den /= a; +} + +/* reduces a rational number */ +static inline void vs_normalizeRational(int64_t *num, int64_t *den) { + muldivRational(num, den, 1, 1); +} + +/* add two rational numbers and reduces the result */ +static inline void vs_addRational(int64_t *num, int64_t *den, int64_t addnum, int64_t addden) { + /* do nothing if the rational number is invalid */ + if (!*den) + return; + + /* nobody wants to accidentally add an invalid rational number */ + assert(addden); + + if (*den == addden) { + *num += addnum; + } else { + int64_t temp = addden; + addnum *= *den; + addden *= *den; + *num *= temp; + *den *= temp; + + *num += addnum; + + vs_normalizeRational(num, den); + } +} + +/* converts an int64 to int with saturation, useful to silence warnings when reading int properties among other things */ +static inline int int64ToIntS(int64_t i) { + if (i > INT_MAX) + return INT_MAX; + else if (i < INT_MIN) + return INT_MIN; + else return (int)i; +} + +static inline void vs_bitblt(void *dstp, int dst_stride, const void *srcp, int src_stride, size_t row_size, size_t height) { + if (height) { + if (src_stride == dst_stride && src_stride == (int)row_size) { + memcpy(dstp, srcp, row_size * height); + } else { + const uint8_t *srcp8 = (const uint8_t *)srcp; + uint8_t *dstp8 = (uint8_t *)dstp; + size_t i; + for (i = 0; i < height; i++) { + memcpy(dstp8, srcp8, row_size); + srcp8 += src_stride; + dstp8 += dst_stride; + } + } + } +} + +/* check if the frame dimensions are valid for a given format */ +/* returns non-zero for valid width and height */ +static inline int areValidDimensions(const VSFormat *fi, int width, int height) { + return !(width % (1 << fi->subSamplingW) || height % (1 << fi->subSamplingH)); +} + +/* Visual Studio doesn't recognize inline in c mode */ +#if defined(_MSC_VER) && !defined(__cplusplus) +#undef inline +#endif + +#endif diff --git a/Programs/sdk/include/VSHelper4.h b/Programs/sdk/include/VSHelper4.h new file mode 100644 index 0000000..0061a2d --- /dev/null +++ b/Programs/sdk/include/VSHelper4.h @@ -0,0 +1,217 @@ +/***************************************************************************** +* Copyright (c) 2012-2020 Fredrik Mellbin +* --- Legal stuff --- +* This program is free software. It comes without any warranty, to +* the extent permitted by applicable law. You can redistribute it +* and/or modify it under the terms of the Do What The Fuck You Want +* To Public License, Version 2, as published by Sam Hocevar. See +* http://sam.zoy.org/wtfpl/COPYING for more details. +*****************************************************************************/ + +#ifndef VSHELPER4_H +#define VSHELPER4_H + +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#endif +#include "VapourSynth4.h" + +#define VSH_STD_PLUGIN_ID "com.vapoursynth.std" +#define VSH_RESIZE_PLUGIN_ID "com.vapoursynth.resize" +#define VSH_TEXT_PLUGIN_ID "com.vapoursynth.text" + +#ifdef __cplusplus +namespace vsh { +#define VSH4_MANGLE_FUNCTION_NAME(name) name +#define VSH4_BOOLEAN_TYPE bool +#else +#define VSH4_MANGLE_FUNCTION_NAME(name) vsh_##name +#define VSH4_BOOLEAN_TYPE int +#endif + +/* Visual Studio doesn't recognize inline in c mode */ +#if defined(_MSC_VER) && !defined(__cplusplus) +#define inline _inline +#endif + +/* A kinda portable definition of the C99 restrict keyword (or its unofficial C++ equivalent) */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* Available in C99 */ +#define VS_RESTRICT restrict +#elif defined(__cplusplus) || defined(_MSC_VER) /* Almost all relevant C++ compilers support it so just assume it works */ +#define VS_RESTRICT __restrict +#else /* Not supported */ +#define VS_RESTRICT +#endif + +#ifdef _WIN32 +#define VSH_ALIGNED_MALLOC(pptr, size, alignment) do { *(pptr) = _aligned_malloc((size), (alignment)); } while (0) +#define VSH_ALIGNED_FREE(ptr) do { _aligned_free((ptr)); } while (0) +#else +#define VSH_ALIGNED_MALLOC(pptr, size, alignment) do { if(posix_memalign((void**)(pptr), (alignment), (size))) *((void**)pptr) = NULL; } while (0) +#define VSH_ALIGNED_FREE(ptr) do { free((ptr)); } while (0) +#endif + +#define VSMAX(a,b) ((a) > (b) ? (a) : (b)) +#define VSMIN(a,b) ((a) > (b) ? (b) : (a)) + +#ifdef __cplusplus +/* A nicer templated malloc for all the C++ users out there */ +#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) +template +#else +template +#endif +static inline T *vsh_aligned_malloc(size_t size, size_t alignment) { +#ifdef _WIN32 + return (T *)_aligned_malloc(size, alignment); +#else + void *tmp = NULL; + if (posix_memalign(&tmp, alignment, size)) + tmp = 0; + return (T *)tmp; +#endif +} + +static inline void vsh_aligned_free(void *ptr) { + VSH_ALIGNED_FREE(ptr); +} +#endif /* __cplusplus */ + +/* convenience function for checking if the format never changes between frames */ +static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(isConstantVideoFormat)(const VSVideoInfo *vi) { + return vi->height > 0 && vi->width > 0 && vi->format.colorFamily != cfUndefined; +} + +/* convenience function to check if two clips have the same format (unknown/changeable will be considered the same too) */ +static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(isSameVideoFormat)(const VSVideoFormat *v1, const VSVideoFormat *v2) { + return v1->colorFamily == v2->colorFamily && v1->sampleType == v2->sampleType && v1->bitsPerSample == v2->bitsPerSample && v1->subSamplingW == v2->subSamplingW && v1->subSamplingH == v2->subSamplingH; +} + +/* convenience function to check if a clip has the same format as a format id */ +static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(isSameVideoPresetFormat)(unsigned presetFormat, const VSVideoFormat *v, VSCore *core, const VSAPI *vsapi) { + return vsapi->queryVideoFormatID(v->colorFamily, v->sampleType, v->bitsPerSample, v->subSamplingW, v->subSamplingH, core) == presetFormat; +} + +/* convenience function to check for if two clips have the same format (but not framerate) while also including width and height (unknown/changeable will be considered the same too) */ +static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(isSameVideoInfo)(const VSVideoInfo *v1, const VSVideoInfo *v2) { + return v1->height == v2->height && v1->width == v2->width && VSH4_MANGLE_FUNCTION_NAME(isSameVideoFormat)(&v1->format, &v2->format); +} + +/* convenience function to check for if two clips have the same format while also including samplerate (unknown/changeable will be considered the same too) */ +static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(isSameAudioFormat)(const VSAudioFormat *a1, const VSAudioFormat *a2) { + return a1->bitsPerSample == a2->bitsPerSample && a1->sampleType == a2->sampleType && a1->channelLayout == a2->channelLayout; +} + +/* convenience function to check for if two clips have the same format while also including samplerate (unknown/changeable will be considered the same too) */ +static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(isSameAudioInfo)(const VSAudioInfo *a1, const VSAudioInfo *a2) { + return a1->sampleRate == a2->sampleRate && VSH4_MANGLE_FUNCTION_NAME(isSameAudioFormat)(&a1->format, &a2->format); +} + +/* multiplies and divides a rational number, such as a frame duration, in place and reduces the result */ +static inline void VSH4_MANGLE_FUNCTION_NAME(muldivRational)(int64_t *num, int64_t *den, int64_t mul, int64_t div) { + /* do nothing if the rational number is invalid */ + if (!*den) + return; + + /* nobody wants to accidentally divide by zero */ + assert(div); + + int64_t a, b; + *num *= mul; + *den *= div; + a = *num; + b = *den; + while (b != 0) { + int64_t t = a; + a = b; + b = t % b; + } + if (a < 0) + a = -a; + *num /= a; + *den /= a; +} + +/* reduces a rational number */ +static inline void VSH4_MANGLE_FUNCTION_NAME(reduceRational)(int64_t *num, int64_t *den) { + VSH4_MANGLE_FUNCTION_NAME(muldivRational)(num, den, 1, 1); +} + +/* add two rational numbers and reduces the result */ +static inline void VSH4_MANGLE_FUNCTION_NAME(addRational)(int64_t *num, int64_t *den, int64_t addnum, int64_t addden) { + /* do nothing if the rational number is invalid */ + if (!*den) + return; + + /* nobody wants to accidentally add an invalid rational number */ + assert(addden); + + if (*den == addden) { + *num += addnum; + } else { + int64_t temp = addden; + addnum *= *den; + addden *= *den; + *num *= temp; + *den *= temp; + + *num += addnum; + + VSH4_MANGLE_FUNCTION_NAME(reduceRational)(num, den); + } +} + +/* converts an int64 to int with saturation, useful to silence warnings when reading int properties among other things */ +static inline int VSH4_MANGLE_FUNCTION_NAME(int64ToIntS)(int64_t i) { + if (i > INT_MAX) + return INT_MAX; + else if (i < INT_MIN) + return INT_MIN; + else return (int)i; +} + +/* converts a double to float with saturation, useful to silence warnings when reading float properties among other things */ +static inline float VSH4_MANGLE_FUNCTION_NAME(doubleToFloatS)(double d) { + return (float)d; +} + +static inline void VSH4_MANGLE_FUNCTION_NAME(bitblt)(void *dstp, ptrdiff_t dst_stride, const void *srcp, ptrdiff_t src_stride, size_t row_size, size_t height) { + if (height) { + if (src_stride == dst_stride && src_stride == (ptrdiff_t)row_size) { + memcpy(dstp, srcp, row_size * height); + } else { + const uint8_t *srcp8 = (const uint8_t *)srcp; + uint8_t *dstp8 = (uint8_t *)dstp; + size_t i; + for (i = 0; i < height; i++) { + memcpy(dstp8, srcp8, row_size); + srcp8 += src_stride; + dstp8 += dst_stride; + } + } + } +} + +/* check if the frame dimensions are valid for a given format */ +/* returns non-zero for valid width and height */ +static inline VSH4_BOOLEAN_TYPE VSH4_MANGLE_FUNCTION_NAME(areValidDimensions)(const VSVideoFormat *fi, int width, int height) { + return !(width % (1 << fi->subSamplingW) || height % (1 << fi->subSamplingH)); +} + +/* Visual Studio doesn't recognize inline in c mode */ +#if defined(_MSC_VER) && !defined(__cplusplus) +#undef inline +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Programs/sdk/include/VSScript.h b/Programs/sdk/include/VSScript.h new file mode 100644 index 0000000..637b592 --- /dev/null +++ b/Programs/sdk/include/VSScript.h @@ -0,0 +1,85 @@ +/* +* Copyright (c) 2013-2018 Fredrik Mellbin +* +* This file is part of VapourSynth. +* +* VapourSynth is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* VapourSynth is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with VapourSynth; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef VSSCRIPT_H +#define VSSCRIPT_H + +#include "VapourSynth.h" + +#define VSSCRIPT_API_MAJOR 3 +#define VSSCRIPT_API_MINOR 2 +#define VSSCRIPT_API_VERSION ((VSSCRIPT_API_MAJOR << 16) | (VSSCRIPT_API_MINOR)) + +/* As of api 3.2 all functions are threadsafe */ + +typedef struct VSScript VSScript; + +typedef enum VSEvalFlags { + efSetWorkingDir = 1, +} VSEvalFlags; + +/* Get the api version */ +VS_API(int) vsscript_getApiVersion(void); /* api 3.1 */ + +/* Initialize the available scripting runtimes, returns zero on failure */ +VS_API(int) vsscript_init(void); + +/* Free all scripting runtimes */ +VS_API(int) vsscript_finalize(void); + +/* +* Pass a pointer to a null handle to create a new one +* The values returned by the query functions are only valid during the lifetime of the VSScript +* scriptFilename is if the error message should reference a certain file, NULL allowed in vsscript_evaluateScript() +* core is to pass in an already created instance so that mixed environments can be used, +* NULL creates a new core that can be fetched with vsscript_getCore() later OR implicitly uses the one associated with an already existing handle when passed +* If efSetWorkingDir is passed to flags the current working directory will be changed to the path of the script +* note that if scriptFilename is NULL in vsscript_evaluateScript() then __file__ won't be set and the working directory won't be changed +* Set efSetWorkingDir to get the default and recommended behavior +*/ +VS_API(int) vsscript_evaluateScript(VSScript **handle, const char *script, const char *scriptFilename, int flags); +/* Convenience version of the above function that loads the script from a file */ +VS_API(int) vsscript_evaluateFile(VSScript **handle, const char *scriptFilename, int flags); +/* Create an empty environment for use in later invocations, mostly useful to set script variables before execution */ +VS_API(int) vsscript_createScript(VSScript **handle); + +VS_API(void) vsscript_freeScript(VSScript *handle); +VS_API(const char *) vsscript_getError(VSScript *handle); +VS_API(int) vsscript_getExitCode(VSScript *handle); +/* The node returned must be freed using freeNode() before calling vsscript_freeScript() */ +VS_API(VSNodeRef *) vsscript_getOutput(VSScript *handle, int index); +/* Both nodes returned must be freed using freeNode() before calling vsscript_freeScript(), the alpha node pointer will only be set if an alpha clip has been set in the script */ +VS_API(VSNodeRef *) vsscript_getOutput2(VSScript *handle, int index, VSNodeRef **alpha); /* api 3.1 */ +/* Unset an output index */ +VS_API(int) vsscript_clearOutput(VSScript *handle, int index); +/* The core is valid as long as the environment exists */ +VS_API(VSCore *) vsscript_getCore(VSScript *handle); +/* Convenience function for retrieving a vsapi pointer */ +VS_API(const VSAPI *) vsscript_getVSApi(void); /* deprecated as of api 3.2 since it's impossible to tell the api version supported */ +VS_API(const VSAPI *) vsscript_getVSApi2(int version); /* api 3.2, generally you should pass VAPOURSYNTH_API_VERSION */ + +/* Variables names that are not set or not of a convertible type will return an error */ +VS_API(int) vsscript_getVariable(VSScript *handle, const char *name, VSMap *dst); +VS_API(int) vsscript_setVariable(VSScript *handle, const VSMap *vars); +VS_API(int) vsscript_clearVariable(VSScript *handle, const char *name); +/* Tries to clear everything set in an environment, normally it is better to simply free an environment completely and create a new one */ +VS_API(void) vsscript_clearEnvironment(VSScript *handle); + +#endif /* VSSCRIPT_H */ diff --git a/Programs/sdk/include/VSScript4.h b/Programs/sdk/include/VSScript4.h new file mode 100644 index 0000000..c59c683 --- /dev/null +++ b/Programs/sdk/include/VSScript4.h @@ -0,0 +1,97 @@ +/* +* Copyright (c) 2013-2020 Fredrik Mellbin +* +* This file is part of VapourSynth. +* +* VapourSynth is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* VapourSynth is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with VapourSynth; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef VSSCRIPT4_H +#define VSSCRIPT4_H + +#include "VapourSynth4.h" + +#define VSSCRIPT_API_MAJOR 4 +#define VSSCRIPT_API_MINOR 1 +#define VSSCRIPT_API_VERSION VS_MAKE_VERSION(VSSCRIPT_API_MAJOR, VSSCRIPT_API_MINOR) + +typedef struct VSScript VSScript; +typedef struct VSSCRIPTAPI VSSCRIPTAPI; + +struct VSSCRIPTAPI { + /* Returns the highest supported VSSCRIPT_API_VERSION */ + int (VS_CC *getAPIVersion)(void) VS_NOEXCEPT; + + /* Convenience function for retrieving a VSAPI pointer without having to use the VapourSynth library. Always pass VAPOURSYNTH_API_VERSION */ + const VSAPI *(VS_CC *getVSAPI)(int version) VS_NOEXCEPT; + + /* + * Providing a pre-created core is useful for setting core creation flags, log callbacks, preload specific plugins and many other things. + * You must create a VSScript object before evaluating a script. Always takes ownership of the core even on failure. Returns NULL on failure. + * Pass NULL to have a core automatically created with the default options. + */ + VSScript *(VS_CC *createScript)(VSCore *core) VS_NOEXCEPT; + + /* The core is valid as long as the environment exists, return NULL on error */ + VSCore *(VS_CC *getCore)(VSScript *handle) VS_NOEXCEPT; + + /* + * Evaluates a script passed in the buffer argument. The scriptFilename is only used for display purposes. in Python + * it means that the main module won't be unnamed in error messages. + * + * Returns 0 on success. + * + * Note that calling any function other than getError() and freeScript() on a VSScript object in the error state + * will result in undefined behavior. + */ + int (VS_CC *evaluateBuffer)(VSScript *handle, const char *buffer, const char *scriptFilename) VS_NOEXCEPT; + + /* Convenience version of the above function that loads the script from scriptFilename and passes as the buffer to evaluateBuffer */ + int (VS_CC *evaluateFile)(VSScript *handle, const char *scriptFilename) VS_NOEXCEPT; + + /* Returns NULL on success, otherwise an error message */ + const char *(VS_CC *getError)(VSScript *handle) VS_NOEXCEPT; + + /* Returns the script's reported exit code */ + int (VS_CC *getExitCode)(VSScript *handle) VS_NOEXCEPT; + + /* Fetches a variable of any VSMap storable type set in a script. It is stored in the key with the same name in dst. Returns 0 on success. */ + int (VS_CC *getVariable)(VSScript *handle, const char *name, VSMap *dst) VS_NOEXCEPT; + + /* Sets all keys in the provided VSMap as variables in the script. Returns 0 on success. */ + int (VS_CC *setVariables)(VSScript *handle, const VSMap *vars) VS_NOEXCEPT; + + /* + * The returned nodes must be freed using freeNode() before calling freeScript() since they may depend on data in the VSScript + * environment. Returns NULL if no node was set as output in the script. Index 0 is used by default in scripts and other + * values are rarely used. + */ + VSNode *(VS_CC *getOutputNode)(VSScript *handle, int index) VS_NOEXCEPT; + VSNode *(VS_CC *getOutputAlphaNode)(VSScript *handle, int index) VS_NOEXCEPT; + int (VS_CC *getAltOutputMode)(VSScript *handle, int index) VS_NOEXCEPT; + + void (VS_CC *freeScript)(VSScript *handle) VS_NOEXCEPT; + + /* + * Set whether or not the working directory is temporarily changed to the same + * location as the script file when evaluateFile is called. Off by default. + */ + void (VS_CC *evalSetWorkingDir)(VSScript *handle, int setCWD) VS_NOEXCEPT; + +}; + +VS_API(const VSSCRIPTAPI *) getVSScriptAPI(int version) VS_NOEXCEPT; + +#endif /* VSSCRIPT4_H */ diff --git a/Programs/sdk/include/VapourSynth.h b/Programs/sdk/include/VapourSynth.h new file mode 100644 index 0000000..cdbecac --- /dev/null +++ b/Programs/sdk/include/VapourSynth.h @@ -0,0 +1,359 @@ +/* +* Copyright (c) 2012-2017 Fredrik Mellbin +* +* This file is part of VapourSynth. +* +* VapourSynth is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* VapourSynth is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with VapourSynth; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef VAPOURSYNTH_H +#define VAPOURSYNTH_H + +#include + +#define VAPOURSYNTH_API_MAJOR 3 +#define VAPOURSYNTH_API_MINOR 6 +#define VAPOURSYNTH_API_VERSION ((VAPOURSYNTH_API_MAJOR << 16) | (VAPOURSYNTH_API_MINOR)) + +/* Convenience for C++ users. */ +#ifdef __cplusplus +# define VS_EXTERN_C extern "C" +# if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) +# define VS_NOEXCEPT noexcept +# else +# define VS_NOEXCEPT +# endif +# if __cplusplus >= 201402L || (defined(_MSC_VER) && _MSC_VER >= 1900) +# define VS_DEPRECATE(REASON) [[deprecated(REASON)]] +# else +# define VS_DEPRECATE(REASON) +# endif +#else +# define VS_EXTERN_C +# define VS_NOEXCEPT +# define VS_DEPRECATE(REASON) +#endif + +#if defined(_WIN32) && !defined(_WIN64) +# define VS_CC __stdcall +#else +# define VS_CC +#endif + +/* And now for some symbol hide-and-seek... */ +#if defined(_WIN32) /* Windows being special */ +# define VS_EXTERNAL_API(ret) VS_EXTERN_C __declspec(dllexport) ret VS_CC +#elif defined(__GNUC__) && __GNUC__ >= 4 +# define VS_EXTERNAL_API(ret) VS_EXTERN_C __attribute__((visibility("default"))) ret VS_CC +#else +# define VS_EXTERNAL_API(ret) VS_EXTERN_C ret VS_CC +#endif + +#if !defined(VS_CORE_EXPORTS) && defined(_WIN32) +# define VS_API(ret) VS_EXTERN_C __declspec(dllimport) ret VS_CC +#else +# define VS_API(ret) VS_EXTERNAL_API(ret) +#endif + +typedef struct VSFrameRef VSFrameRef; +typedef struct VSNodeRef VSNodeRef; +typedef struct VSCore VSCore; +typedef struct VSPlugin VSPlugin; +typedef struct VSNode VSNode; +typedef struct VSFuncRef VSFuncRef; +typedef struct VSMap VSMap; +typedef struct VSAPI VSAPI; +typedef struct VSFrameContext VSFrameContext; + +typedef enum VSColorFamily { + /* all planar formats */ + cmGray = 1000000, + cmRGB = 2000000, + cmYUV = 3000000, + cmYCoCg = 4000000, + /* special for compatibility */ + cmCompat = 9000000 +} VSColorFamily; + +typedef enum VSSampleType { + stInteger = 0, + stFloat = 1 +} VSSampleType; + +/* The +10 is so people won't be using the constants interchangeably "by accident" */ +typedef enum VSPresetFormat { + pfNone = 0, + + pfGray8 = cmGray + 10, + pfGray16, + + pfGrayH, + pfGrayS, + + pfYUV420P8 = cmYUV + 10, + pfYUV422P8, + pfYUV444P8, + pfYUV410P8, + pfYUV411P8, + pfYUV440P8, + + pfYUV420P9, + pfYUV422P9, + pfYUV444P9, + + pfYUV420P10, + pfYUV422P10, + pfYUV444P10, + + pfYUV420P16, + pfYUV422P16, + pfYUV444P16, + + pfYUV444PH, + pfYUV444PS, + + pfYUV420P12, + pfYUV422P12, + pfYUV444P12, + + pfYUV420P14, + pfYUV422P14, + pfYUV444P14, + + pfRGB24 = cmRGB + 10, + pfRGB27, + pfRGB30, + pfRGB48, + + pfRGBH, + pfRGBS, + + /* special for compatibility, if you implement these in any filter I'll personally kill you */ + /* I'll also change their ids around to break your stuff regularly */ + pfCompatBGR32 = cmCompat + 10, + pfCompatYUY2 +} VSPresetFormat; + +typedef enum VSFilterMode { + fmParallel = 100, /* completely parallel execution */ + fmParallelRequests = 200, /* for filters that are serial in nature but can request one or more frames they need in advance */ + fmUnordered = 300, /* for filters that modify their internal state every request */ + fmSerial = 400 /* for source filters and compatibility with other filtering architectures */ +} VSFilterMode; + +typedef struct VSFormat { + char name[32]; + int id; + int colorFamily; /* see VSColorFamily */ + int sampleType; /* see VSSampleType */ + int bitsPerSample; /* number of significant bits */ + int bytesPerSample; /* actual storage is always in a power of 2 and the smallest possible that can fit the number of bits used per sample */ + + int subSamplingW; /* log2 subsampling factor, applied to second and third plane */ + int subSamplingH; + + int numPlanes; /* implicit from colorFamily */ +} VSFormat; + +typedef enum VSNodeFlags { + nfNoCache = 1, + nfIsCache = 2, + nfMakeLinear = 4 /* api 3.3 */ +} VSNodeFlags; + +typedef enum VSPropTypes { + ptUnset = 'u', + ptInt = 'i', + ptFloat = 'f', + ptData = 's', + ptNode = 'c', + ptFrame = 'v', + ptFunction = 'm' +} VSPropTypes; + +typedef enum VSGetPropErrors { + peUnset = 1, + peType = 2, + peIndex = 4 +} VSGetPropErrors; + +typedef enum VSPropAppendMode { + paReplace = 0, + paAppend = 1, + paTouch = 2 +} VSPropAppendMode; + +typedef struct VSCoreInfo { + const char *versionString; + int core; + int api; + int numThreads; + int64_t maxFramebufferSize; + int64_t usedFramebufferSize; +} VSCoreInfo; + +typedef struct VSVideoInfo { + const VSFormat *format; + int64_t fpsNum; + int64_t fpsDen; + int width; + int height; + int numFrames; /* api 3.2 - no longer allowed to be 0 */ + int flags; +} VSVideoInfo; + +typedef enum VSActivationReason { + arInitial = 0, + arFrameReady = 1, + arAllFramesReady = 2, + arError = -1 +} VSActivationReason; + +typedef enum VSMessageType { + mtDebug = 0, + mtWarning = 1, + mtCritical = 2, + mtFatal = 3 +} VSMessageType; + +/* core entry point */ +typedef const VSAPI *(VS_CC *VSGetVapourSynthAPI)(int version); + +/* plugin function and filter typedefs */ +typedef void (VS_CC *VSPublicFunction)(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi); +typedef void (VS_CC *VSRegisterFunction)(const char *name, const char *args, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin); +typedef void (VS_CC *VSConfigPlugin)(const char *identifier, const char *defaultNamespace, const char *name, int apiVersion, int readonly, VSPlugin *plugin); +typedef void (VS_CC *VSInitPlugin)(VSConfigPlugin configFunc, VSRegisterFunction registerFunc, VSPlugin *plugin); +typedef void (VS_CC *VSFreeFuncData)(void *userData); +typedef void (VS_CC *VSFilterInit)(VSMap *in, VSMap *out, void **instanceData, VSNode *node, VSCore *core, const VSAPI *vsapi); +typedef const VSFrameRef *(VS_CC *VSFilterGetFrame)(int n, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi); +typedef void (VS_CC *VSFilterFree)(void *instanceData, VSCore *core, const VSAPI *vsapi); + +/* other */ +typedef void (VS_CC *VSFrameDoneCallback)(void *userData, const VSFrameRef *f, int n, VSNodeRef *, const char *errorMsg); +typedef void (VS_CC *VSMessageHandler)(int msgType, const char *msg, void *userData); +typedef void (VS_CC *VSMessageHandlerFree)(void *userData); + +struct VSAPI { + VSCore *(VS_CC *createCore)(int threads) VS_NOEXCEPT; + void (VS_CC *freeCore)(VSCore *core) VS_NOEXCEPT; + + VS_DEPRECATE("getCoreInfo has been deprecated as of api 3.6, use getCoreInfo2 instead") + const VSCoreInfo *(VS_CC *getCoreInfo)(VSCore *core) VS_NOEXCEPT; + + const VSFrameRef *(VS_CC *cloneFrameRef)(const VSFrameRef *f) VS_NOEXCEPT; + VSNodeRef *(VS_CC *cloneNodeRef)(VSNodeRef *node) VS_NOEXCEPT; + VSFuncRef *(VS_CC *cloneFuncRef)(VSFuncRef *f) VS_NOEXCEPT; + + void (VS_CC *freeFrame)(const VSFrameRef *f) VS_NOEXCEPT; + void (VS_CC *freeNode)(VSNodeRef *node) VS_NOEXCEPT; + void (VS_CC *freeFunc)(VSFuncRef *f) VS_NOEXCEPT; + + VSFrameRef *(VS_CC *newVideoFrame)(const VSFormat *format, int width, int height, const VSFrameRef *propSrc, VSCore *core) VS_NOEXCEPT; + VSFrameRef *(VS_CC *copyFrame)(const VSFrameRef *f, VSCore *core) VS_NOEXCEPT; + void (VS_CC *copyFrameProps)(const VSFrameRef *src, VSFrameRef *dst, VSCore *core) VS_NOEXCEPT; + + void (VS_CC *registerFunction)(const char *name, const char *args, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin) VS_NOEXCEPT; + VSPlugin *(VS_CC *getPluginById)(const char *identifier, VSCore *core) VS_NOEXCEPT; + VSPlugin *(VS_CC *getPluginByNs)(const char *ns, VSCore *core) VS_NOEXCEPT; + VSMap *(VS_CC *getPlugins)(VSCore *core) VS_NOEXCEPT; + VSMap *(VS_CC *getFunctions)(VSPlugin *plugin) VS_NOEXCEPT; + void (VS_CC *createFilter)(const VSMap *in, VSMap *out, const char *name, VSFilterInit init, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, int flags, void *instanceData, VSCore *core) VS_NOEXCEPT; + void (VS_CC *setError)(VSMap *map, const char *errorMessage) VS_NOEXCEPT; /* use to signal errors outside filter getframe functions */ + const char *(VS_CC *getError)(const VSMap *map) VS_NOEXCEPT; /* use to query errors, returns 0 if no error */ + void (VS_CC *setFilterError)(const char *errorMessage, VSFrameContext *frameCtx) VS_NOEXCEPT; /* use to signal errors in the filter getframe function */ + VSMap *(VS_CC *invoke)(VSPlugin *plugin, const char *name, const VSMap *args) VS_NOEXCEPT; + + const VSFormat *(VS_CC *getFormatPreset)(int id, VSCore *core) VS_NOEXCEPT; + const VSFormat *(VS_CC *registerFormat)(int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) VS_NOEXCEPT; + + const VSFrameRef *(VS_CC *getFrame)(int n, VSNodeRef *node, char *errorMsg, int bufSize) VS_NOEXCEPT; /* do never use inside a filter's getframe function, for external applications using the core as a library or for requesting frames in a filter constructor */ + void (VS_CC *getFrameAsync)(int n, VSNodeRef *node, VSFrameDoneCallback callback, void *userData) VS_NOEXCEPT; /* do never use inside a filter's getframe function, for external applications using the core as a library or for requesting frames in a filter constructor */ + const VSFrameRef *(VS_CC *getFrameFilter)(int n, VSNodeRef *node, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ + void (VS_CC *requestFrameFilter)(int n, VSNodeRef *node, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ + void (VS_CC *queryCompletedFrame)(VSNodeRef **node, int *n, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ + void (VS_CC *releaseFrameEarly)(VSNodeRef *node, int n, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ + + int (VS_CC *getStride)(const VSFrameRef *f, int plane) VS_NOEXCEPT; + const uint8_t *(VS_CC *getReadPtr)(const VSFrameRef *f, int plane) VS_NOEXCEPT; + uint8_t *(VS_CC *getWritePtr)(VSFrameRef *f, int plane) VS_NOEXCEPT; + + VSFuncRef *(VS_CC *createFunc)(VSPublicFunction func, void *userData, VSFreeFuncData free, VSCore *core, const VSAPI *vsapi) VS_NOEXCEPT; + void (VS_CC *callFunc)(VSFuncRef *func, const VSMap *in, VSMap *out, VSCore *core, const VSAPI *vsapi) VS_NOEXCEPT; /* core and vsapi arguments are completely ignored, they only remain to preserve ABI */ + + /* property access functions */ + VSMap *(VS_CC *createMap)(void) VS_NOEXCEPT; + void (VS_CC *freeMap)(VSMap *map) VS_NOEXCEPT; + void (VS_CC *clearMap)(VSMap *map) VS_NOEXCEPT; + + const VSVideoInfo *(VS_CC *getVideoInfo)(VSNodeRef *node) VS_NOEXCEPT; + void (VS_CC *setVideoInfo)(const VSVideoInfo *vi, int numOutputs, VSNode *node) VS_NOEXCEPT; + const VSFormat *(VS_CC *getFrameFormat)(const VSFrameRef *f) VS_NOEXCEPT; + int (VS_CC *getFrameWidth)(const VSFrameRef *f, int plane) VS_NOEXCEPT; + int (VS_CC *getFrameHeight)(const VSFrameRef *f, int plane) VS_NOEXCEPT; + const VSMap *(VS_CC *getFramePropsRO)(const VSFrameRef *f) VS_NOEXCEPT; + VSMap *(VS_CC *getFramePropsRW)(VSFrameRef *f) VS_NOEXCEPT; + + int (VS_CC *propNumKeys)(const VSMap *map) VS_NOEXCEPT; + const char *(VS_CC *propGetKey)(const VSMap *map, int index) VS_NOEXCEPT; + int (VS_CC *propNumElements)(const VSMap *map, const char *key) VS_NOEXCEPT; + char (VS_CC *propGetType)(const VSMap *map, const char *key) VS_NOEXCEPT; + + int64_t(VS_CC *propGetInt)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + double(VS_CC *propGetFloat)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + const char *(VS_CC *propGetData)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + int (VS_CC *propGetDataSize)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + VSNodeRef *(VS_CC *propGetNode)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + const VSFrameRef *(VS_CC *propGetFrame)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + VSFuncRef *(VS_CC *propGetFunc)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + + int (VS_CC *propDeleteKey)(VSMap *map, const char *key) VS_NOEXCEPT; + int (VS_CC *propSetInt)(VSMap *map, const char *key, int64_t i, int append) VS_NOEXCEPT; + int (VS_CC *propSetFloat)(VSMap *map, const char *key, double d, int append) VS_NOEXCEPT; + int (VS_CC *propSetData)(VSMap *map, const char *key, const char *data, int size, int append) VS_NOEXCEPT; + int (VS_CC *propSetNode)(VSMap *map, const char *key, VSNodeRef *node, int append) VS_NOEXCEPT; + int (VS_CC *propSetFrame)(VSMap *map, const char *key, const VSFrameRef *f, int append) VS_NOEXCEPT; + int (VS_CC *propSetFunc)(VSMap *map, const char *key, VSFuncRef *func, int append) VS_NOEXCEPT; + + int64_t (VS_CC *setMaxCacheSize)(int64_t bytes, VSCore *core) VS_NOEXCEPT; + int (VS_CC *getOutputIndex)(VSFrameContext *frameCtx) VS_NOEXCEPT; + VSFrameRef *(VS_CC *newVideoFrame2)(const VSFormat *format, int width, int height, const VSFrameRef **planeSrc, const int *planes, const VSFrameRef *propSrc, VSCore *core) VS_NOEXCEPT; + + VS_DEPRECATE("setMessageHandler has been deprecated as of api 3.6, use addMessageHandler and removeMessageHandler instead") + void (VS_CC *setMessageHandler)(VSMessageHandler handler, void *userData) VS_NOEXCEPT; + + int (VS_CC *setThreadCount)(int threads, VSCore *core) VS_NOEXCEPT; + + const char *(VS_CC *getPluginPath)(const VSPlugin *plugin) VS_NOEXCEPT; + + /* api 3.1 */ + const int64_t *(VS_CC *propGetIntArray)(const VSMap *map, const char *key, int *error) VS_NOEXCEPT; + const double *(VS_CC *propGetFloatArray)(const VSMap *map, const char *key, int *error) VS_NOEXCEPT; + + int (VS_CC *propSetIntArray)(VSMap *map, const char *key, const int64_t *i, int size) VS_NOEXCEPT; + int (VS_CC *propSetFloatArray)(VSMap *map, const char *key, const double *d, int size) VS_NOEXCEPT; + + /* api 3.4 */ + void (VS_CC *logMessage)(int msgType, const char *msg) VS_NOEXCEPT; + + /* api 3.6 */ + int (VS_CC *addMessageHandler)(VSMessageHandler handler, VSMessageHandlerFree free, void *userData) VS_NOEXCEPT; + int (VS_CC *removeMessageHandler)(int id) VS_NOEXCEPT; + void (VS_CC *getCoreInfo2)(VSCore *core, VSCoreInfo *info) VS_NOEXCEPT; +}; + +VS_API(const VSAPI *) getVapourSynthAPI(int version) VS_NOEXCEPT; + +#endif /* VAPOURSYNTH_H */ diff --git a/Programs/sdk/include/VapourSynth4.h b/Programs/sdk/include/VapourSynth4.h new file mode 100644 index 0000000..00b2d57 --- /dev/null +++ b/Programs/sdk/include/VapourSynth4.h @@ -0,0 +1,489 @@ +/* +* Copyright (c) 2012-2021 Fredrik Mellbin +* +* This file is part of VapourSynth. +* +* VapourSynth is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* VapourSynth is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with VapourSynth; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef VAPOURSYNTH4_H +#define VAPOURSYNTH4_H + +#include +#include + +#define VS_MAKE_VERSION(major, minor) (((major) << 16) | (minor)) +#define VAPOURSYNTH_API_MAJOR 4 +#define VAPOURSYNTH_API_MINOR 0 +#define VAPOURSYNTH_API_VERSION VS_MAKE_VERSION(VAPOURSYNTH_API_MAJOR, VAPOURSYNTH_API_MINOR) + +#define VS_AUDIO_FRAME_SAMPLES 3072 + +/* Convenience for C++ users. */ +#ifdef __cplusplus +# define VS_EXTERN_C extern "C" +# if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) +# define VS_NOEXCEPT noexcept +# else +# define VS_NOEXCEPT +# endif +#else +# define VS_EXTERN_C +# define VS_NOEXCEPT +#endif + +#if defined(_WIN32) && !defined(_WIN64) +# define VS_CC __stdcall +#else +# define VS_CC +#endif + +/* And now for some symbol hide-and-seek... */ +#if defined(_WIN32) /* Windows being special */ +# define VS_EXTERNAL_API(ret) VS_EXTERN_C __declspec(dllexport) ret VS_CC +#elif defined(__GNUC__) && __GNUC__ >= 4 +# define VS_EXTERNAL_API(ret) VS_EXTERN_C __attribute__((visibility("default"))) ret VS_CC +#else +# define VS_EXTERNAL_API(ret) VS_EXTERN_C ret VS_CC +#endif + +#if !defined(VS_CORE_EXPORTS) && defined(_WIN32) +# define VS_API(ret) VS_EXTERN_C __declspec(dllimport) ret VS_CC +#else +# define VS_API(ret) VS_EXTERNAL_API(ret) +#endif + +typedef struct VSFrame VSFrame; +typedef struct VSNode VSNode; +typedef struct VSCore VSCore; +typedef struct VSPlugin VSPlugin; +typedef struct VSPluginFunction VSPluginFunction; +typedef struct VSFunction VSFunction; +typedef struct VSMap VSMap; +typedef struct VSLogHandle VSLogHandle; +typedef struct VSFrameContext VSFrameContext; +typedef struct VSPLUGINAPI VSPLUGINAPI; +typedef struct VSAPI VSAPI; + +typedef enum VSColorFamily { + cfUndefined = 0, + cfGray = 1, + cfRGB = 2, + cfYUV = 3 +} VSColorFamily; + +typedef enum VSSampleType { + stInteger = 0, + stFloat = 1 +} VSSampleType; + +#define VS_MAKE_VIDEO_ID(colorFamily, sampleType, bitsPerSample, subSamplingW, subSamplingH) ((colorFamily << 28) | (sampleType << 24) | (bitsPerSample << 16) | (subSamplingW << 8) | (subSamplingH << 0)) + +typedef enum VSPresetVideoFormat { + pfNone = 0, + + pfGray8 = VS_MAKE_VIDEO_ID(cfGray, stInteger, 8, 0, 0), + pfGray9 = VS_MAKE_VIDEO_ID(cfGray, stInteger, 9, 0, 0), + pfGray10 = VS_MAKE_VIDEO_ID(cfGray, stInteger, 10, 0, 0), + pfGray12 = VS_MAKE_VIDEO_ID(cfGray, stInteger, 12, 0, 0), + pfGray14 = VS_MAKE_VIDEO_ID(cfGray, stInteger, 14, 0, 0), + pfGray16 = VS_MAKE_VIDEO_ID(cfGray, stInteger, 16, 0, 0), + pfGray32 = VS_MAKE_VIDEO_ID(cfGray, stInteger, 32, 0, 0), + + pfGrayH = VS_MAKE_VIDEO_ID(cfGray, stFloat, 16, 0, 0), + pfGrayS = VS_MAKE_VIDEO_ID(cfGray, stFloat, 32, 0, 0), + + pfYUV410P8 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 8, 2, 2), + pfYUV411P8 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 8, 2, 0), + pfYUV440P8 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 8, 0, 1), + + pfYUV420P8 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 8, 1, 1), + pfYUV422P8 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 8, 1, 0), + pfYUV444P8 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 8, 0, 0), + + pfYUV420P9 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 9, 1, 1), + pfYUV422P9 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 9, 1, 0), + pfYUV444P9 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 9, 0, 0), + + pfYUV420P10 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 10, 1, 1), + pfYUV422P10 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 10, 1, 0), + pfYUV444P10 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 10, 0, 0), + + pfYUV420P12 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 12, 1, 1), + pfYUV422P12 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 12, 1, 0), + pfYUV444P12 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 12, 0, 0), + + pfYUV420P14 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 14, 1, 1), + pfYUV422P14 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 14, 1, 0), + pfYUV444P14 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 14, 0, 0), + + pfYUV420P16 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 16, 1, 1), + pfYUV422P16 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 16, 1, 0), + pfYUV444P16 = VS_MAKE_VIDEO_ID(cfYUV, stInteger, 16, 0, 0), + + pfYUV444PH = VS_MAKE_VIDEO_ID(cfYUV, stFloat, 16, 0, 0), + pfYUV444PS = VS_MAKE_VIDEO_ID(cfYUV, stFloat, 32, 0, 0), + + pfRGB24 = VS_MAKE_VIDEO_ID(cfRGB, stInteger, 8, 0, 0), + pfRGB27 = VS_MAKE_VIDEO_ID(cfRGB, stInteger, 9, 0, 0), + pfRGB30 = VS_MAKE_VIDEO_ID(cfRGB, stInteger, 10, 0, 0), + pfRGB36 = VS_MAKE_VIDEO_ID(cfRGB, stInteger, 12, 0, 0), + pfRGB42 = VS_MAKE_VIDEO_ID(cfRGB, stInteger, 14, 0, 0), + pfRGB48 = VS_MAKE_VIDEO_ID(cfRGB, stInteger, 16, 0, 0), + + pfRGBH = VS_MAKE_VIDEO_ID(cfRGB, stFloat, 16, 0, 0), + pfRGBS = VS_MAKE_VIDEO_ID(cfRGB, stFloat, 32, 0, 0), +} VSPresetVideoFormat; + +#undef VS_MAKE_VIDEO_ID + + +typedef enum VSFilterMode { + fmParallel = 0, /* completely parallel execution */ + fmParallelRequests = 1, /* for filters that are serial in nature but can request one or more frames they need in advance */ + fmUnordered = 2, /* for filters that modify their internal state every request like source filters that read a file */ + fmFrameState = 3 /* DO NOT USE UNLESS ABSOLUTELY NECESSARY, for compatibility with external code that can only keep the processing state of a single frame at a time */ +} VSFilterMode; + +typedef enum VSMediaType { + mtVideo = 1, + mtAudio = 2 +} VSMediaType; + +typedef struct VSVideoFormat { + int colorFamily; /* see VSColorFamily */ + int sampleType; /* see VSSampleType */ + int bitsPerSample; /* number of significant bits */ + int bytesPerSample; /* actual storage is always in a power of 2 and the smallest possible that can fit the number of bits used per sample */ + + int subSamplingW; /* log2 subsampling factor, applied to second and third plane */ + int subSamplingH; /* log2 subsampling factor, applied to second and third plane */ + + int numPlanes; /* implicit from colorFamily */ +} VSVideoFormat; + +typedef enum VSAudioChannels { + acFrontLeft = 0, + acFrontRight = 1, + acFrontCenter = 2, + acLowFrequency = 3, + acBackLeft = 4, + acBackRight = 5, + acFrontLeftOFCenter = 6, + acFrontRightOFCenter = 7, + acBackCenter = 8, + acSideLeft = 9, + acSideRight = 10, + acTopCenter = 11, + acTopFrontLeft = 12, + acTopFrontCenter = 13, + acTopFrontRight = 14, + acTopBackLeft = 15, + acTopBackCenter = 16, + acTopBackRight = 17, + acStereoLeft = 29, + acStereoRight = 30, + acWideLeft = 31, + acWideRight = 32, + acSurroundDirectLeft = 33, + acSurroundDirectRight = 34, + acLowFrequency2 = 35 +} VSAudioChannels; + +typedef struct VSAudioFormat { + int sampleType; + int bitsPerSample; + int bytesPerSample; /* implicit from bitsPerSample */ + int numChannels; /* implicit from channelLayout */ + uint64_t channelLayout; +} VSAudioFormat; + +typedef enum VSPropertyType { + ptUnset = 0, + ptInt = 1, + ptFloat = 2, + ptData = 3, + ptFunction = 4, + ptVideoNode = 5, + ptAudioNode = 6, + ptVideoFrame = 7, + ptAudioFrame = 8 +} VSPropertyType; + +typedef enum VSMapPropertyError { + peSuccess = 0, + peUnset = 1, /* no key exists */ + peType = 2, /* key exists but not of a compatible type */ + peIndex = 4, /* index out of bounds */ + peError = 3 /* map has error state set */ +} VSMapPropertyError; + +typedef enum VSMapAppendMode { + maReplace = 0, + maAppend = 1 +} VSMapAppendMode; + +typedef struct VSCoreInfo { + const char *versionString; + int core; + int api; + int numThreads; + int64_t maxFramebufferSize; + int64_t usedFramebufferSize; +} VSCoreInfo; + +typedef struct VSVideoInfo { + VSVideoFormat format; + int64_t fpsNum; + int64_t fpsDen; + int width; + int height; + int numFrames; +} VSVideoInfo; + +typedef struct VSAudioInfo { + VSAudioFormat format; + int sampleRate; + int64_t numSamples; + int numFrames; /* the total number of audio frames needed to hold numSamples, implicit from numSamples when calling createAudioFilter */ +} VSAudioInfo; + +typedef enum VSActivationReason { + arInitial = 0, + arAllFramesReady = 1, + arError = -1 +} VSActivationReason; + +typedef enum VSMessageType { + mtDebug = 0, + mtInformation = 1, + mtWarning = 2, + mtCritical = 3, + mtFatal = 4 /* also terminates the process, should generally not be used by normal filters */ +} VSMessageType; + +typedef enum VSCoreCreationFlags { + ccfEnableGraphInspection = 1, + ccfDisableAutoLoading = 2, + ccfDisableLibraryUnloading = 4 +} VSCoreCreationFlags; + +typedef enum VSPluginConfigFlags { + pcModifiable = 1 +} VSPluginConfigFlags; + +typedef enum VSDataTypeHint { + dtUnknown = -1, + dtBinary = 0, + dtUtf8 = 1 +} VSDataTypeHint; + +typedef enum VSRequestPattern { + rpGeneral = 0, /* General pattern */ + rpNoFrameReuse = 1, /* When requesting all output frames from the filter no frame will be requested more than once from this input clip, never requests frames beyond the end of the clip */ + rpStrictSpatial = 2 /* Always (and only) requests frame n from input clip when generating output frame n, never requests frames beyond the end of the clip */ +} VSRequestPattern; + +typedef enum VSCacheMode { + cmAuto = -1, + cmForceDisable = 0, + cmForceEnable = 1 +} VSCacheMode; + +/* Core entry point */ +typedef const VSAPI *(VS_CC *VSGetVapourSynthAPI)(int version); + +/* Plugin, function and filter related */ +typedef void (VS_CC *VSPublicFunction)(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi); +typedef void (VS_CC *VSInitPlugin)(VSPlugin *plugin, const VSPLUGINAPI *vspapi); +typedef void (VS_CC *VSFreeFunctionData)(void *userData); +typedef const VSFrame *(VS_CC *VSFilterGetFrame)(int n, int activationReason, void *instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi); +typedef void (VS_CC *VSFilterFree)(void *instanceData, VSCore *core, const VSAPI *vsapi); + +/* Other */ +typedef void (VS_CC *VSFrameDoneCallback)(void *userData, const VSFrame *f, int n, VSNode *node, const char *errorMsg); +typedef void (VS_CC *VSLogHandler)(int msgType, const char *msg, void *userData); +typedef void (VS_CC *VSLogHandlerFree)(void *userData); + +struct VSPLUGINAPI { + int (VS_CC *getAPIVersion)(void) VS_NOEXCEPT; /* returns VAPOURSYNTH_API_VERSION of the library */ + int (VS_CC *configPlugin)(const char *identifier, const char *pluginNamespace, const char *name, int pluginVersion, int apiVersion, int flags, VSPlugin *plugin) VS_NOEXCEPT; /* use the VS_MAKE_VERSION macro for pluginVersion */ + int (VS_CC *registerFunction)(const char *name, const char *args, const char *returnType, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin) VS_NOEXCEPT; /* non-zero return value on success */ +}; + +typedef struct VSFilterDependency { + VSNode *source; + int requestPattern; /* VSRequestPattern */ +} VSFilterDependency; + +struct VSAPI { + /* Audio and video filter related including nodes */ + void (VS_CC *createVideoFilter)(VSMap *out, const char *name, const VSVideoInfo *vi, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core) VS_NOEXCEPT; /* output nodes are appended to the clip key in the out map */ + VSNode *(VS_CC *createVideoFilter2)(const char *name, const VSVideoInfo *vi, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core) VS_NOEXCEPT; /* same as createVideoFilter but returns a pointer to the VSNode directly or NULL on failure */ + void (VS_CC *createAudioFilter)(VSMap *out, const char *name, const VSAudioInfo *ai, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core) VS_NOEXCEPT; /* output nodes are appended to the clip key in the out map */ + VSNode *(VS_CC *createAudioFilter2)(const char *name, const VSAudioInfo *ai, VSFilterGetFrame getFrame, VSFilterFree free, int filterMode, const VSFilterDependency *dependencies, int numDeps, void *instanceData, VSCore *core) VS_NOEXCEPT; /* same as createAudioFilter but returns a pointer to the VSNode directly or NULL on failure */ + int (VS_CC *setLinearFilter)(VSNode *node) VS_NOEXCEPT; /* Use right after create*Filter*, sets the correct cache mode for using the cacheFrame API and returns the recommended upper number of additional frames to cache per request */ + void (VS_CC *setCacheMode)(VSNode *node, int mode) VS_NOEXCEPT; /* VSCacheMode, changing the cache mode also resets all options to their default */ + void (VS_CC *setCacheOptions)(VSNode *node, int fixedSize, int maxSize, int maxHistorySize) VS_NOEXCEPT; /* passing -1 means no change */ + + void (VS_CC *freeNode)(VSNode *node) VS_NOEXCEPT; + VSNode *(VS_CC *addNodeRef)(VSNode *node) VS_NOEXCEPT; + int (VS_CC *getNodeType)(VSNode *node) VS_NOEXCEPT; /* returns VSMediaType */ + const VSVideoInfo *(VS_CC *getVideoInfo)(VSNode *node) VS_NOEXCEPT; + const VSAudioInfo *(VS_CC *getAudioInfo)(VSNode *node) VS_NOEXCEPT; + + /* Frame related functions */ + VSFrame *(VS_CC *newVideoFrame)(const VSVideoFormat *format, int width, int height, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT; + VSFrame *(VS_CC *newVideoFrame2)(const VSVideoFormat *format, int width, int height, const VSFrame **planeSrc, const int *planes, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT; /* same as newVideoFrame but allows the specified planes to be effectively copied from the source frames */ + VSFrame *(VS_CC *newAudioFrame)(const VSAudioFormat *format, int numSamples, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT; + VSFrame *(VS_CC *newAudioFrame2)(const VSAudioFormat *format, int numSamples, const VSFrame **channelSrc, const int *channels, const VSFrame *propSrc, VSCore *core) VS_NOEXCEPT; /* same as newAudioFrame but allows the specified channels to be effectively copied from the source frames */ + void (VS_CC *freeFrame)(const VSFrame *f) VS_NOEXCEPT; + const VSFrame *(VS_CC *addFrameRef)(const VSFrame *f) VS_NOEXCEPT; + VSFrame *(VS_CC *copyFrame)(const VSFrame *f, VSCore *core) VS_NOEXCEPT; + const VSMap *(VS_CC *getFramePropertiesRO)(const VSFrame *f) VS_NOEXCEPT; + VSMap *(VS_CC *getFramePropertiesRW)(VSFrame *f) VS_NOEXCEPT; + + ptrdiff_t (VS_CC *getStride)(const VSFrame *f, int plane) VS_NOEXCEPT; + const uint8_t *(VS_CC *getReadPtr)(const VSFrame *f, int plane) VS_NOEXCEPT; + uint8_t *(VS_CC *getWritePtr)(VSFrame *f, int plane) VS_NOEXCEPT; /* calling this function invalidates previously gotten read pointers to the same frame */ + + const VSVideoFormat *(VS_CC *getVideoFrameFormat)(const VSFrame *f) VS_NOEXCEPT; + const VSAudioFormat *(VS_CC *getAudioFrameFormat)(const VSFrame *f) VS_NOEXCEPT; + int (VS_CC *getFrameType)(const VSFrame *f) VS_NOEXCEPT; /* returns VSMediaType */ + int (VS_CC *getFrameWidth)(const VSFrame *f, int plane) VS_NOEXCEPT; + int (VS_CC *getFrameHeight)(const VSFrame *f, int plane) VS_NOEXCEPT; + int (VS_CC *getFrameLength)(const VSFrame *f) VS_NOEXCEPT; /* returns the number of samples for audio frames */ + + /* General format functions */ + int (VS_CC *getVideoFormatName)(const VSVideoFormat *format, char *buffer) VS_NOEXCEPT; /* up to 32 characters including terminating null may be written to the buffer, non-zero return value on success */ + int (VS_CC *getAudioFormatName)(const VSAudioFormat *format, char *buffer) VS_NOEXCEPT; /* up to 32 characters including terminating null may be written to the buffer, non-zero return value on success */ + int (VS_CC *queryVideoFormat)(VSVideoFormat *format, int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) VS_NOEXCEPT; /* non-zero return value on success */ + int (VS_CC *queryAudioFormat)(VSAudioFormat *format, int sampleType, int bitsPerSample, uint64_t channelLayout, VSCore *core) VS_NOEXCEPT; /* non-zero return value on success */ + uint32_t (VS_CC *queryVideoFormatID)(int colorFamily, int sampleType, int bitsPerSample, int subSamplingW, int subSamplingH, VSCore *core) VS_NOEXCEPT; /* returns 0 on failure */ + int (VS_CC *getVideoFormatByID)(VSVideoFormat *format, uint32_t id, VSCore *core) VS_NOEXCEPT; /* non-zero return value on success */ + + /* Frame request and filter getframe functions */ + const VSFrame *(VS_CC *getFrame)(int n, VSNode *node, char *errorMsg, int bufSize) VS_NOEXCEPT; /* only for external applications using the core as a library or for requesting frames in a filter constructor, do not use inside a filter's getframe function */ + void (VS_CC *getFrameAsync)(int n, VSNode *node, VSFrameDoneCallback callback, void *userData) VS_NOEXCEPT; /* only for external applications using the core as a library or for requesting frames in a filter constructor, do not use inside a filter's getframe function */ + const VSFrame *(VS_CC *getFrameFilter)(int n, VSNode *node, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ + void (VS_CC *requestFrameFilter)(int n, VSNode *node, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function */ + void (VS_CC *releaseFrameEarly)(VSNode *node, int n, VSFrameContext *frameCtx) VS_NOEXCEPT; /* only use inside a filter's getframe function, unless this function is called a requested frame is kept in memory until the end of processing the current frame */ + void (VS_CC *cacheFrame)(const VSFrame *frame, int n, VSFrameContext *frameCtx) VS_NOEXCEPT; /* used to store intermediate frames in cache, useful for filters where random access is slow, must call setLinearFilter on the node before using or the result is undefined */ + void (VS_CC *setFilterError)(const char *errorMessage, VSFrameContext *frameCtx) VS_NOEXCEPT; /* used to signal errors in the filter getframe function */ + + /* External functions */ + VSFunction *(VS_CC *createFunction)(VSPublicFunction func, void *userData, VSFreeFunctionData free, VSCore *core) VS_NOEXCEPT; + void (VS_CC *freeFunction)(VSFunction *f) VS_NOEXCEPT; + VSFunction *(VS_CC *addFunctionRef)(VSFunction *f) VS_NOEXCEPT; + void (VS_CC *callFunction)(VSFunction *func, const VSMap *in, VSMap *out) VS_NOEXCEPT; + + /* Map and property access functions */ + VSMap *(VS_CC *createMap)(void) VS_NOEXCEPT; + void (VS_CC *freeMap)(VSMap *map) VS_NOEXCEPT; + void (VS_CC *clearMap)(VSMap *map) VS_NOEXCEPT; + void (VS_CC *copyMap)(const VSMap *src, VSMap *dst) VS_NOEXCEPT; /* copies all values in src to dst, if a key already exists in dst it's replaced */ + + void (VS_CC *mapSetError)(VSMap *map, const char *errorMessage) VS_NOEXCEPT; /* used to signal errors outside filter getframe function */ + const char *(VS_CC *mapGetError)(const VSMap *map) VS_NOEXCEPT; /* used to query errors, returns 0 if no error */ + + int (VS_CC *mapNumKeys)(const VSMap *map) VS_NOEXCEPT; + const char *(VS_CC *mapGetKey)(const VSMap *map, int index) VS_NOEXCEPT; + int (VS_CC *mapDeleteKey)(VSMap *map, const char *key) VS_NOEXCEPT; + int (VS_CC *mapNumElements)(const VSMap *map, const char *key) VS_NOEXCEPT; /* returns -1 if a key doesn't exist */ + int (VS_CC *mapGetType)(const VSMap *map, const char *key) VS_NOEXCEPT; /* returns VSPropertyType */ + int (VS_CC *mapSetEmpty)(VSMap *map, const char *key, int type) VS_NOEXCEPT; + + int64_t (VS_CC *mapGetInt)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + int (VS_CC *mapGetIntSaturated)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + const int64_t *(VS_CC *mapGetIntArray)(const VSMap *map, const char *key, int *error) VS_NOEXCEPT; + int (VS_CC *mapSetInt)(VSMap *map, const char *key, int64_t i, int append) VS_NOEXCEPT; + int (VS_CC *mapSetIntArray)(VSMap *map, const char *key, const int64_t *i, int size) VS_NOEXCEPT; + + double (VS_CC *mapGetFloat)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + float (VS_CC *mapGetFloatSaturated)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + const double *(VS_CC *mapGetFloatArray)(const VSMap *map, const char *key, int *error) VS_NOEXCEPT; + int (VS_CC *mapSetFloat)(VSMap *map, const char *key, double d, int append) VS_NOEXCEPT; + int (VS_CC *mapSetFloatArray)(VSMap *map, const char *key, const double *d, int size) VS_NOEXCEPT; + + const char *(VS_CC *mapGetData)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + int (VS_CC *mapGetDataSize)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + int (VS_CC *mapGetDataTypeHint)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; /* returns VSDataTypeHint */ + int (VS_CC *mapSetData)(VSMap *map, const char *key, const char *data, int size, int type, int append) VS_NOEXCEPT; + + VSNode *(VS_CC *mapGetNode)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + int (VS_CC *mapSetNode)(VSMap *map, const char *key, VSNode *node, int append) VS_NOEXCEPT; /* returns 0 on success */ + int (VS_CC *mapConsumeNode)(VSMap *map, const char *key, VSNode *node, int append) VS_NOEXCEPT; /* always consumes the reference, even on error */ + + const VSFrame *(VS_CC *mapGetFrame)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + int (VS_CC *mapSetFrame)(VSMap *map, const char *key, const VSFrame *f, int append) VS_NOEXCEPT; /* returns 0 on success */ + int (VS_CC *mapConsumeFrame)(VSMap *map, const char *key, const VSFrame *f, int append) VS_NOEXCEPT; /* always consumes the reference, even on error */ + + VSFunction *(VS_CC *mapGetFunction)(const VSMap *map, const char *key, int index, int *error) VS_NOEXCEPT; + int (VS_CC *mapSetFunction)(VSMap *map, const char *key, VSFunction *func, int append) VS_NOEXCEPT; /* returns 0 on success */ + int (VS_CC *mapConsumeFunction)(VSMap *map, const char *key, VSFunction *func, int append) VS_NOEXCEPT; /* always consumes the reference, even on error */ + + /* Plugin and plugin function related */ + int (VS_CC *registerFunction)(const char *name, const char *args, const char *returnType, VSPublicFunction argsFunc, void *functionData, VSPlugin *plugin) VS_NOEXCEPT; /* non-zero return value on success */ + VSPlugin *(VS_CC *getPluginByID)(const char *identifier, VSCore *core) VS_NOEXCEPT; + VSPlugin *(VS_CC *getPluginByNamespace)(const char *ns, VSCore *core) VS_NOEXCEPT; + VSPlugin *(VS_CC *getNextPlugin)(VSPlugin *plugin, VSCore *core) VS_NOEXCEPT; /* pass NULL to get the first plugin */ + const char *(VS_CC *getPluginName)(VSPlugin *plugin) VS_NOEXCEPT; + const char *(VS_CC *getPluginID)(VSPlugin *plugin) VS_NOEXCEPT; + const char *(VS_CC *getPluginNamespace)(VSPlugin *plugin) VS_NOEXCEPT; + VSPluginFunction *(VS_CC *getNextPluginFunction)(VSPluginFunction *func, VSPlugin *plugin) VS_NOEXCEPT; /* pass NULL to get the first plugin function */ + VSPluginFunction *(VS_CC *getPluginFunctionByName)(const char *name, VSPlugin *plugin) VS_NOEXCEPT; + const char *(VS_CC *getPluginFunctionName)(VSPluginFunction *func) VS_NOEXCEPT; + const char *(VS_CC *getPluginFunctionArguments)(VSPluginFunction *func) VS_NOEXCEPT; /* returns an argument format string */ + const char *(VS_CC *getPluginFunctionReturnType)(VSPluginFunction *func) VS_NOEXCEPT; /* returns an argument format string */ + const char *(VS_CC *getPluginPath)(const VSPlugin *plugin) VS_NOEXCEPT; /* the full path to the loaded library file containing the plugin entry point */ + int (VS_CC *getPluginVersion)(const VSPlugin *plugin) VS_NOEXCEPT; + VSMap *(VS_CC *invoke)(VSPlugin *plugin, const char *name, const VSMap *args) VS_NOEXCEPT; /* user must free the returned VSMap */ + + /* Core and information */ + VSCore *(VS_CC *createCore)(int flags) VS_NOEXCEPT; /* flags uses the VSCoreCreationFlags enum */ + void (VS_CC *freeCore)(VSCore *core) VS_NOEXCEPT; /* only call this function after all node, frame and function references belonging to the core have been freed */ + int64_t(VS_CC *setMaxCacheSize)(int64_t bytes, VSCore *core) VS_NOEXCEPT; /* the total cache size at which vapoursynth more aggressively tries to reclaim memory, it is not a hard limit */ + int (VS_CC *setThreadCount)(int threads, VSCore *core) VS_NOEXCEPT; /* setting threads to 0 means automatic detection */ + void (VS_CC *getCoreInfo)(VSCore *core, VSCoreInfo *info) VS_NOEXCEPT; + int (VS_CC *getAPIVersion)(void) VS_NOEXCEPT; + + /* Message handler */ + void (VS_CC *logMessage)(int msgType, const char *msg, VSCore *core) VS_NOEXCEPT; + VSLogHandle *(VS_CC *addLogHandler)(VSLogHandler handler, VSLogHandlerFree free, void *userData, VSCore *core) VS_NOEXCEPT; /* free and userData can be NULL, returns a handle that can be passed to removeLogHandler */ + int (VS_CC *removeLogHandler)(VSLogHandle *handle, VSCore *core) VS_NOEXCEPT; /* returns non-zero if successfully removed */ + +#ifdef VS_GRAPH_API + /* Graph information */ + + /* + * These functions only exist to retrieve internal details for debug purposes and graph visualization + * They will only only work properly when used on a core created with ccfEnableGraphInspection and are + * not safe to use concurrently with frame requests or other API functions. Because of this they are + * unsuitable for use in plugins and filters. + */ + + const char *(VS_CC *getNodeCreationFunctionName)(VSNode *node, int level) VS_NOEXCEPT; /* level=0 returns the name of the function that created the filter, specifying a higher level will retrieve the function above that invoked it or NULL if a non-existent level is requested */ + const VSMap *(VS_CC *getNodeCreationFunctionArguments)(VSNode *node, int level) VS_NOEXCEPT; /* level=0 returns a copy of the arguments passed to the function that created the filter, returns NULL if a non-existent level is requested */ + const char *(VS_CC *getNodeName)(VSNode *node) VS_NOEXCEPT; /* the name passed to create*Filter */ + int (VS_CC *getNodeFilterMode)(VSNode *node) VS_NOEXCEPT; /* VSFilterMode */ + int64_t (VS_CC *getNodeFilterTime)(VSNode *node) VS_NOEXCEPT; /* time spent processing frames in nanoseconds */ + const VSFilterDependency *(VS_CC *getNodeDependencies)(VSNode *node) VS_NOEXCEPT; + int (VS_CC *getNumNodeDependencies)(VSNode *node) VS_NOEXCEPT; +#endif +}; + +VS_API(const VSAPI *) getVapourSynthAPI(int version) VS_NOEXCEPT; + +#endif /* VAPOURSYNTH4_H */ diff --git a/Programs/sdk/lib32/VSScript.lib b/Programs/sdk/lib32/VSScript.lib new file mode 100644 index 0000000..d87b2e8 Binary files /dev/null and b/Programs/sdk/lib32/VSScript.lib differ diff --git a/Programs/sdk/lib32/VapourSynth.lib b/Programs/sdk/lib32/VapourSynth.lib new file mode 100644 index 0000000..84bf904 Binary files /dev/null and b/Programs/sdk/lib32/VapourSynth.lib differ diff --git a/Programs/setup.py b/Programs/setup.py new file mode 100644 index 0000000..9252560 --- /dev/null +++ b/Programs/setup.py @@ -0,0 +1,93 @@ +# Always prefer setuptools over distutils +from setuptools import setup +from platform import architecture + +import os +from os import path +from pathlib import Path + +self_path = Path(__file__).resolve() +CURRENT_RELEASE = next(path for path in (self_path.with_name('VAPOURSYNTH_VERSION'), *(folder / 'VAPOURSYNTH_VERSION' for folder in self_path.parents)) if path.exists()).read_text('utf8').split(' ')[-1].strip().split('-')[0] + +try: + from wheel.bdist_wheel import bdist_wheel as _bdist_wheel + class bdist_wheel(_bdist_wheel): + def finalize_options(self): + _bdist_wheel.finalize_options(self) + self.root_is_pure = False + + def get_tag(self): + python, abi, plat = _bdist_wheel.get_tag(self) + # We don't contain any python source + python, abi = 'py2.py3', 'none' + return python, abi, plat +except ImportError: + bdist_wheel = None + + +is_win = (architecture()[1] == "WindowsPE") +is_64 = (architecture()[0] == "64bit") +here = path.abspath(path.dirname(__file__)) + +if not is_win: + raise OSError("VapourSynth Portable is currently only supported on Windows Systems.") + +if not os.path.exists(os.path.join(here, "VapourSynth.dll")): + if is_64: + subdir = "buildp64" + else: + subdir = "buildp32" + build_dir = os.path.join(here, subdir) + + if not os.path.exists(os.path.join(build_dir, "VapourSynth.dll")): + raise OSError("Failed to detect VapourSynth-portable build directory.") +else: + subdir = "." + build_dir = here + +if is_64: + plugin_subdir = 'vapoursynth64' +else: + plugin_subdir = 'vapoursynth32' +plugin_dir = os.path.join(subdir, plugin_subdir) + +setup( + name = "VapourSynth-portable", + version=CURRENT_RELEASE, + description = "A frameserver for the 21st century", + url = "http://www.vapoursynth.com/", + download_url = "https://github.com/vapoursynth/vapoursynth", + author = "Fredrik Mellbin", + author_email = "fredrik.mellbin@gmail.com", + + cmdclass={'bdist_wheel': bdist_wheel}, + + packages=[], + install_requires=["vapoursynth==" + CURRENT_RELEASE], + data_files = [ + ("Lib\\site-packages", [ + os.path.join(build_dir, p) + for p in os.listdir(build_dir) + if p.endswith("140.dll") or \ + p.endswith(".vs") + ]), + + ("Scripts", [ + os.path.join(build_dir, "VSPipe.exe"), + os.path.join(build_dir, "VSScript.dll"), + os.path.join(build_dir, "portable.vs") + ]), + + ("Lib\\site-packages\\%s\\coreplugins"%plugin_subdir, [ + os.path.join(plugin_dir, 'coreplugins', p) + for p in os.listdir(os.path.join(plugin_dir, 'coreplugins')) + if p.endswith(".dll") + ]), + + ("Lib\\site-packages\\%s\\plugins"%plugin_subdir, [ + os.path.join(plugin_dir, 'plugins', p) + for p in os.listdir(os.path.join(plugin_dir, 'plugins')) + if p.endswith(".dll") or p.endswith(".keep") + ]) + ] +) diff --git a/Programs/sqlite3.dll b/Programs/sqlite3.dll new file mode 100644 index 0000000..0aa95df Binary files /dev/null and b/Programs/sqlite3.dll differ diff --git a/Programs/template.vpy b/Programs/template.vpy new file mode 100644 index 0000000..ef8c69c --- /dev/null +++ b/Programs/template.vpy @@ -0,0 +1,33 @@ +import vapoursynth as vs +core = vs.core +import havsfunc + +clip = core.lsmas.LWLibavSource(source="[INPUTFILE]") + +clip = havsfunc.QTGMC(Input=clip, Preset="Slow", InputType=0, TFF=True, FPSDivisor=2, TR2=2, Sharpness=0.3, SourceMatch=1, Lossless=2, MatchPreset="Slow", MatchPreset2="Slow") + +clip = core.resize.Spline36(clip, format=vs.YUV420P10) + +compSharp = core.cas.CAS(clip, sharpness=0.2) # Sharpen clip for non-shown motion compensated frames, helps retain higher frequency detail at the expense of denoise strength + +super = core.mv.Super(clip, hpad=16, vpad=16, rfilter=4) # all levels for MAnalyse +superSharp = core.mv.Super(compSharp, hpad=16, vpad=16, rfilter=4) # all levels for MAnalyse + +backward2 = core.mv.Analyse(super, isb=True, blksize=16, overlap=8, delta=2, search=3, dct=6) +backward = core.mv.Analyse(super, isb=True, blksize=16, overlap=8, search=3, dct=6) +forward = core.mv.Analyse(super, isb=False, blksize=16, overlap=8, search=3, dct=6) +forward2 = core.mv.Analyse(super, isb=False, blksize=16, overlap=8, delta=2, search=3, dct=6) + +backward2 = core.mv.Recalculate(super, backward2, blksize=8, overlap=4, search=3, divide=2, dct=6) # Optionally Recalculate for higher consistency / quality +backward = core.mv.Recalculate(super, backward, blksize=8, overlap=4, search=3, divide=2, dct=6) +forward = core.mv.Recalculate(super, forward, blksize=8, overlap=4, search=3, divide=2, dct=6) +forward2 = core.mv.Recalculate(super, forward2, blksize=8, overlap=4, search=3, divide=2, dct=6) + +backward_re2 = core.mv.Finest(backward2) +backward_re = core.mv.Finest(backward) +forward_re = core.mv.Finest(forward) +forward_re2 = core.mv.Finest(forward2) + +clip = core.mv.Degrain2(clip, superSharp, backward_re, forward_re, backward_re2, forward_re2, thsad=220, thscd1=300) + +clip.set_output(0) \ No newline at end of file diff --git a/Programs/test.vpy b/Programs/test.vpy new file mode 100644 index 0000000..aa9f337 --- /dev/null +++ b/Programs/test.vpy @@ -0,0 +1,33 @@ +import vapoursynth as vs +core = vs.core +import havsfunc + +clip = core.lsmas.LWLibavSource(source="D:/Encode/Church/archive_test/2022-03-20_110000_deinterlaced_0500.mkv") + +clip = havsfunc.QTGMC(Input=clip, Preset="Slow", InputType=0, TFF=True, FPSDivisor=2, TR2=2, Sharpness=0.3, SourceMatch=1, Lossless=2, MatchPreset="Slow", MatchPreset2="Slow") + +clip = core.resize.Spline36(clip, format=vs.YUV420P10) + +compSharp = core.cas.CAS(clip, sharpness=0.2) # Sharpen clip for non-shown motion compensated frames, helps retain higher frequency detail at the expense of denoise strength + +super = core.mv.Super(clip, hpad=16, vpad=16, rfilter=4) # all levels for MAnalyse +superSharp = core.mv.Super(compSharp, hpad=16, vpad=16, rfilter=4) # all levels for MAnalyse + +backward2 = core.mv.Analyse(super, isb=True, blksize=16, overlap=8, delta=2, search=3, dct=6) +backward = core.mv.Analyse(super, isb=True, blksize=16, overlap=8, search=3, dct=6) +forward = core.mv.Analyse(super, isb=False, blksize=16, overlap=8, search=3, dct=6) +forward2 = core.mv.Analyse(super, isb=False, blksize=16, overlap=8, delta=2, search=3, dct=6) + +backward2 = core.mv.Recalculate(super, backward2, blksize=8, overlap=4, search=3, divide=2, dct=6) # Optionally Recalculate for higher consistency / quality +backward = core.mv.Recalculate(super, backward, blksize=8, overlap=4, search=3, divide=2, dct=6) +forward = core.mv.Recalculate(super, forward, blksize=8, overlap=4, search=3, divide=2, dct=6) +forward2 = core.mv.Recalculate(super, forward2, blksize=8, overlap=4, search=3, divide=2, dct=6) + +backward_re2 = core.mv.Finest(backward2) +backward_re = core.mv.Finest(backward) +forward_re = core.mv.Finest(forward) +forward_re2 = core.mv.Finest(forward2) + +clip = core.mv.Degrain2(clip, superSharp, backward_re, forward_re, backward_re2, forward_re2, thsad=220, thscd1=300) + +clip.set_output(0) \ No newline at end of file diff --git a/Programs/test_420.vpy b/Programs/test_420.vpy new file mode 100644 index 0000000..aa9f337 --- /dev/null +++ b/Programs/test_420.vpy @@ -0,0 +1,33 @@ +import vapoursynth as vs +core = vs.core +import havsfunc + +clip = core.lsmas.LWLibavSource(source="D:/Encode/Church/archive_test/2022-03-20_110000_deinterlaced_0500.mkv") + +clip = havsfunc.QTGMC(Input=clip, Preset="Slow", InputType=0, TFF=True, FPSDivisor=2, TR2=2, Sharpness=0.3, SourceMatch=1, Lossless=2, MatchPreset="Slow", MatchPreset2="Slow") + +clip = core.resize.Spline36(clip, format=vs.YUV420P10) + +compSharp = core.cas.CAS(clip, sharpness=0.2) # Sharpen clip for non-shown motion compensated frames, helps retain higher frequency detail at the expense of denoise strength + +super = core.mv.Super(clip, hpad=16, vpad=16, rfilter=4) # all levels for MAnalyse +superSharp = core.mv.Super(compSharp, hpad=16, vpad=16, rfilter=4) # all levels for MAnalyse + +backward2 = core.mv.Analyse(super, isb=True, blksize=16, overlap=8, delta=2, search=3, dct=6) +backward = core.mv.Analyse(super, isb=True, blksize=16, overlap=8, search=3, dct=6) +forward = core.mv.Analyse(super, isb=False, blksize=16, overlap=8, search=3, dct=6) +forward2 = core.mv.Analyse(super, isb=False, blksize=16, overlap=8, delta=2, search=3, dct=6) + +backward2 = core.mv.Recalculate(super, backward2, blksize=8, overlap=4, search=3, divide=2, dct=6) # Optionally Recalculate for higher consistency / quality +backward = core.mv.Recalculate(super, backward, blksize=8, overlap=4, search=3, divide=2, dct=6) +forward = core.mv.Recalculate(super, forward, blksize=8, overlap=4, search=3, divide=2, dct=6) +forward2 = core.mv.Recalculate(super, forward2, blksize=8, overlap=4, search=3, divide=2, dct=6) + +backward_re2 = core.mv.Finest(backward2) +backward_re = core.mv.Finest(backward) +forward_re = core.mv.Finest(forward) +forward_re2 = core.mv.Finest(forward2) + +clip = core.mv.Degrain2(clip, superSharp, backward_re, forward_re, backward_re2, forward_re2, thsad=220, thscd1=300) + +clip.set_output(0) \ No newline at end of file diff --git a/Programs/vapoursynth64/coreplugins/AvsCompat.dll b/Programs/vapoursynth64/coreplugins/AvsCompat.dll new file mode 100644 index 0000000..54e7381 Binary files /dev/null and b/Programs/vapoursynth64/coreplugins/AvsCompat.dll differ diff --git a/Programs/vapoursynth64/coreplugins/LSMASHSource.dll b/Programs/vapoursynth64/coreplugins/LSMASHSource.dll new file mode 100644 index 0000000..8238faa Binary files /dev/null and b/Programs/vapoursynth64/coreplugins/LSMASHSource.dll differ diff --git a/Programs/vapoursynth64/coreplugins/MiscFilters.dll b/Programs/vapoursynth64/coreplugins/MiscFilters.dll new file mode 100644 index 0000000..01dce0b Binary files /dev/null and b/Programs/vapoursynth64/coreplugins/MiscFilters.dll differ diff --git a/Programs/vapoursynth64/coreplugins/RemoveGrainVS.dll b/Programs/vapoursynth64/coreplugins/RemoveGrainVS.dll new file mode 100644 index 0000000..378afb9 Binary files /dev/null and b/Programs/vapoursynth64/coreplugins/RemoveGrainVS.dll differ diff --git a/Programs/vapoursynth64/plugins/.keep b/Programs/vapoursynth64/plugins/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Programs/vapoursynth64/plugins/CAS.dll b/Programs/vapoursynth64/plugins/CAS.dll new file mode 100644 index 0000000..cf84cb6 Binary files /dev/null and b/Programs/vapoursynth64/plugins/CAS.dll differ diff --git a/Programs/vapoursynth64/plugins/EEDI3m.dll b/Programs/vapoursynth64/plugins/EEDI3m.dll new file mode 100644 index 0000000..04433f1 Binary files /dev/null and b/Programs/vapoursynth64/plugins/EEDI3m.dll differ diff --git a/Programs/vapoursynth64/plugins/NNEDI3CL.dll b/Programs/vapoursynth64/plugins/NNEDI3CL.dll new file mode 100644 index 0000000..1a79fdf Binary files /dev/null and b/Programs/vapoursynth64/plugins/NNEDI3CL.dll differ diff --git a/Programs/vapoursynth64/plugins/libmvtools.dll b/Programs/vapoursynth64/plugins/libmvtools.dll new file mode 100644 index 0000000..cbe54da Binary files /dev/null and b/Programs/vapoursynth64/plugins/libmvtools.dll differ diff --git a/Programs/vapoursynth64/plugins/nnedi3_weights.bin b/Programs/vapoursynth64/plugins/nnedi3_weights.bin new file mode 100644 index 0000000..936760e Binary files /dev/null and b/Programs/vapoursynth64/plugins/nnedi3_weights.bin differ diff --git a/Programs/vapoursynth64/plugins/vsznedi3.dll b/Programs/vapoursynth64/plugins/vsznedi3.dll new file mode 100644 index 0000000..60e8239 Binary files /dev/null and b/Programs/vapoursynth64/plugins/vsznedi3.dll differ diff --git a/Programs/vccorlib140.dll b/Programs/vccorlib140.dll new file mode 100644 index 0000000..6c4109b Binary files /dev/null and b/Programs/vccorlib140.dll differ diff --git a/Programs/vcruntime140.dll b/Programs/vcruntime140.dll new file mode 100644 index 0000000..edba548 Binary files /dev/null and b/Programs/vcruntime140.dll differ diff --git a/Programs/vcruntime140_1.dll b/Programs/vcruntime140_1.dll new file mode 100644 index 0000000..6091fbf Binary files /dev/null and b/Programs/vcruntime140_1.dll differ diff --git a/Programs/vs-detect-python.bat b/Programs/vs-detect-python.bat new file mode 100644 index 0000000..8bc5824 --- /dev/null +++ b/Programs/vs-detect-python.bat @@ -0,0 +1,20 @@ +@echo off + +IF EXIST "Python311.dll" ( + ECHO Python 3.11 detected + GOTO end +) + +IF EXIST "Python38.dll" ( + ECHO Python 3.8 detected + ECHO Switching to 3.8 support... + COPY /Y "VSScriptPython38.dll" "VSScript.dll" + ECHO Done + GOTO end +) + +ECHO Neither Python 3.11 nor Python 3.8 is supported +GOTO end + +:end +pause \ No newline at end of file diff --git a/Programs/vsgenstubs.py b/Programs/vsgenstubs.py new file mode 100644 index 0000000..d627b94 --- /dev/null +++ b/Programs/vsgenstubs.py @@ -0,0 +1,8 @@ +import sys +import os + +sys.path.append(os.path.dirname(__file__)) + +from vsgenstubs4 import main + +main() diff --git a/Programs/vsgenstubs4/__init__.py b/Programs/vsgenstubs4/__init__.py new file mode 100644 index 0000000..89b035c --- /dev/null +++ b/Programs/vsgenstubs4/__init__.py @@ -0,0 +1 @@ +from .init import main # noqa: F401 diff --git a/Programs/vsgenstubs4/__main__.py b/Programs/vsgenstubs4/__main__.py new file mode 100644 index 0000000..b171473 --- /dev/null +++ b/Programs/vsgenstubs4/__main__.py @@ -0,0 +1,3 @@ +from .init import sys, main + +main(sys.argv[1:]) diff --git a/Programs/vsgenstubs4/_vapoursynth.part.pyi b/Programs/vsgenstubs4/_vapoursynth.part.pyi new file mode 100644 index 0000000..5eaeba6 --- /dev/null +++ b/Programs/vsgenstubs4/_vapoursynth.part.pyi @@ -0,0 +1,1202 @@ +# Stop pep8 from complaining (hopefully) +# NOQA + +# Ignore Flake Warnings +# flake8: noqa + +# Ignore coverage +# (No coverage) + +# From https://gist.github.com/pylover/7870c235867cf22817ac5b096defb768 +# noinspection PyPep8 +# noinspection PyPep8Naming +# noinspection PyTypeChecker +# noinspection PyAbstractClass +# noinspection PyArgumentEqualDefault +# noinspection PyArgumentList +# noinspection PyAssignmentToLoopOrWithParameter +# noinspection PyAttributeOutsideInit +# noinspection PyAugmentAssignment +# noinspection PyBroadException +# noinspection PyByteLiteral +# noinspection PyCallByClass +# noinspection PyChainedComparsons +# noinspection PyClassHasNoInit +# noinspection PyClassicStyleClass +# noinspection PyComparisonWithNone +# noinspection PyCompatibility +# noinspection PyDecorator +# noinspection PyDefaultArgument +# noinspection PyDictCreation +# noinspection PyDictDuplicateKeys +# noinspection PyDocstringTypes +# noinspection PyExceptClausesOrder +# noinspection PyExceptionInheritance +# noinspection PyFromFutureImport +# noinspection PyGlobalUndefined +# noinspection PyIncorrectDocstring +# noinspection PyInitNewSignature +# noinspection PyInterpreter +# noinspection PyListCreation +# noinspection PyMandatoryEncoding +# noinspection PyMethodFirstArgAssignment +# noinspection PyMethodMayBeStatic +# noinspection PyMethodOverriding +# noinspection PyMethodParameters +# noinspection PyMissingConstructor +# noinspection PyMissingOrEmptyDocstring +# noinspection PyNestedDecorators +# noinspection PynonAsciiChar +# noinspection PyNoneFunctionAssignment +# noinspection PyOldStyleClasses +# noinspection PyPackageRequirements +# noinspection PyPropertyAccess +# noinspection PyPropertyDefinition +# noinspection PyProtectedMember +# noinspection PyRaisingNewStyleClass +# noinspection PyRedeclaration +# noinspection PyRedundantParentheses +# noinspection PySetFunctionToLiteral +# noinspection PySimplifyBooleanCheck +# noinspection PySingleQuotedDocstring +# noinspection PyStatementEffect +# noinspection PyStringException +# noinspection PyStringFormat +# noinspection PySuperArguments +# noinspection PyTrailingSemicolon +# noinspection PyTupleAssignmentBalance +# noinspection PyTupleItemAssignment +# noinspection PyUnboundLocalVariable +# noinspection PyUnnecessaryBackslash +# noinspection PyUnreachableCode +# noinspection PyUnresolvedReferences +# noinspection PyUnusedLocal +# noinspection ReturnValueFromInit + + +from abc import abstractmethod +from ctypes import c_void_p +from enum import IntEnum +from fractions import Fraction +from inspect import Signature +from types import MappingProxyType, TracebackType +from typing import ( + TYPE_CHECKING, Any, BinaryIO, Callable, ContextManager, Dict, Generic, Iterator, Literal, MutableMapping, + NamedTuple, NoReturn, Protocol, Sequence, Tuple, Type, TypedDict, TypeVar, Union, overload, runtime_checkable +) +from weakref import ReferenceType + +__all__ = [ + # Versioning + '__version__', '__api_version__', 'PluginVersion', + + # Enums and constants + 'MessageType', + 'MESSAGE_TYPE_DEBUG', 'MESSAGE_TYPE_INFORMATION', 'MESSAGE_TYPE_WARNING', + 'MESSAGE_TYPE_CRITICAL', 'MESSAGE_TYPE_FATAL', + + 'FilterMode', + 'fmParallel', 'fmParallelRequests', 'fmUnordered', 'fmFrameState', + + 'CoreCreationFlags', + 'ccfEnableGraphInspection', 'ccfDisableAutoLoading', 'ccfDisableLibraryUnloading', + + 'MediaType', + 'VIDEO', 'AUDIO', + + 'ColorFamily', + 'UNDEFINED', 'GRAY', 'RGB', 'YUV', + + 'ColorRange', + 'RANGE_FULL', 'RANGE_LIMITED', + + 'SampleType', + 'INTEGER', 'FLOAT', + + 'PresetVideoFormat', + 'GRAY', + 'GRAY8', 'GRAY9', 'GRAY10', 'GRAY12', 'GRAY14', 'GRAY16', 'GRAY32', 'GRAYH', 'GRAYS', + 'RGB', + 'RGB24', 'RGB27', 'RGB30', 'RGB36', 'RGB42', 'RGB48', 'RGBH', 'RGBS', + 'YUV', + 'YUV410P8', + 'YUV411P8', + 'YUV420P8', 'YUV420P9', 'YUV420P10', 'YUV420P12', 'YUV420P14', 'YUV420P16', + 'YUV422P8', 'YUV422P9', 'YUV422P10', 'YUV422P12', 'YUV422P14', 'YUV422P16', + 'YUV440P8', + 'YUV444P8', 'YUV444P9', 'YUV444P10', 'YUV444P12', 'YUV444P14', 'YUV444P16', 'YUV444PH', 'YUV444PS', + 'NONE', + + 'AudioChannels', + 'FRONT_LEFT', 'FRONT_RIGHT', 'FRONT_CENTER', + 'BACK_LEFT', 'BACK_RIGHT', 'BACK_CENTER', + 'SIDE_LEFT', 'SIDE_RIGHT', + 'TOP_CENTER', + + 'TOP_FRONT_LEFT', 'TOP_FRONT_RIGHT', 'TOP_FRONT_CENTER', + 'TOP_BACK_LEFT', 'TOP_BACK_RIGHT', 'TOP_BACK_CENTER', + + 'WIDE_LEFT', 'WIDE_RIGHT', + + 'SURROUND_DIRECT_LEFT', 'SURROUND_DIRECT_RIGHT', + + 'FRONT_LEFT_OF_CENTER', 'FRONT_RIGHT_OF_CENTER', + + 'STEREO_LEFT', 'STEREO_RIGHT', + + 'LOW_FREQUENCY', 'LOW_FREQUENCY2', + + 'ChromaLocation', + 'CHROMA_TOP_LEFT', 'CHROMA_TOP', + 'CHROMA_LEFT', 'CHROMA_CENTER', + 'CHROMA_BOTTOM_LEFT', 'CHROMA_BOTTOM', + + 'FieldBased', + 'FIELD_PROGRESSIVE', 'FIELD_TOP', 'FIELD_BOTTOM', + + 'MatrixCoefficients', + 'MATRIX_RGB', 'MATRIX_BT709', 'MATRIX_UNSPECIFIED', 'MATRIX_FCC', + 'MATRIX_BT470_BG', 'MATRIX_ST170_M', 'MATRIX_ST240_M', 'MATRIX_YCGCO', 'MATRIX_BT2020_NCL', 'MATRIX_BT2020_CL', + 'MATRIX_CHROMATICITY_DERIVED_NCL', 'MATRIX_CHROMATICITY_DERIVED_CL', 'MATRIX_ICTCP', + + 'TransferCharacteristics', + 'TRANSFER_BT709', 'TRANSFER_UNSPECIFIED', 'TRANSFER_BT470_M', 'TRANSFER_BT470_BG', 'TRANSFER_BT601', + 'TRANSFER_ST240_M', 'TRANSFER_LINEAR', 'TRANSFER_LOG_100', 'TRANSFER_LOG_316', 'TRANSFER_IEC_61966_2_4', + 'TRANSFER_IEC_61966_2_1', 'TRANSFER_BT2020_10', 'TRANSFER_BT2020_12', 'TRANSFER_ST2084', 'TRANSFER_ARIB_B67', + + 'ColorPrimaries', 'PRIMARIES_BT709', 'PRIMARIES_UNSPECIFIED', + 'PRIMARIES_BT470_M', 'PRIMARIES_BT470_BG', 'PRIMARIES_ST170_M', 'PRIMARIES_ST240_M', 'PRIMARIES_FILM', + 'PRIMARIES_BT2020', 'PRIMARIES_ST428', 'PRIMARIES_ST431_2', 'PRIMARIES_ST432_1', 'PRIMARIES_EBU3213_E', + + # Environment SubSystem + 'Environment', 'EnvironmentData', + + 'EnvironmentPolicy', + + 'EnvironmentPolicyAPI', + 'register_policy', 'has_policy', + 'register_on_destroy', 'unregister_on_destroy', + + 'get_current_environment', + + 'VideoOutputTuple', + 'clear_output', 'clear_outputs', 'get_outputs', 'get_output', + + # Logging + 'LogHandle', 'Error', + + # Functions + 'FuncData', 'Func', 'FramePtr', + 'Plugin', 'Function', + + # Formats + 'VideoFormat', 'ChannelLayout', + + # Frames + 'RawFrame', 'VideoFrame', 'AudioFrame', + 'FrameProps', + + # Nodes + 'RawNode', 'VideoNode', 'AudioNode', + + 'Core', '_CoreProxy', 'core', + + # Inspection API [UNSTABLE API] + # '_try_enable_introspection' +] + + +### +# Typing + +T = TypeVar('T') +S = TypeVar('S') + +SingleAndSequence = Union[T, Sequence[T]] + + +@runtime_checkable +class SupportsString(Protocol): + @abstractmethod + def __str__(self) -> str: + ... + + +DataType = Union[str, bytes, bytearray, SupportsString] + +_VapourSynthMapValue = Union[ + SingleAndSequence[int], + SingleAndSequence[float], + SingleAndSequence[DataType], + SingleAndSequence['VideoNode'], + SingleAndSequence['VideoFrame'], + SingleAndSequence['AudioNode'], + SingleAndSequence['AudioFrame'], + SingleAndSequence['VSMapValueCallback[Any]'] +] + +BoundVSMapValue = TypeVar('BoundVSMapValue', bound=_VapourSynthMapValue) + +VSMapValueCallback = Callable[..., BoundVSMapValue] + + +class _Future(Generic[T]): + def set_result(self, value: T) -> None: ... + + def set_exception(self, exception: BaseException) -> None: ... + + def result(self) -> T: ... + + def exception(self) -> Union[NoReturn, None]: ... + +### +# Typed dicts + + +class _VideoFormatInfo(TypedDict): + id: int + name: str + color_family: 'ColorFamily' + sample_type: 'SampleType' + bits_per_sample: int + bytes_per_sample: int + subsampling_w: int + subsampling_h: int + num_planes: int + + +### +# VapourSynth Versioning + + +class VapourSynthVersion(NamedTuple): + release_major: int + release_minor: int + + +class VapourSynthAPIVersion(NamedTuple): + api_major: int + api_minor: int + + +__version__: VapourSynthVersion +__api_version__: VapourSynthAPIVersion + + +### +# Plugin Versioning + + +class PluginVersion(NamedTuple): + major: int + minor: int + + +### +# VapourSynth Enums and Constants + + +class MessageType(IntEnum): + MESSAGE_TYPE_DEBUG: 'MessageType' + MESSAGE_TYPE_INFORMATION: 'MessageType' + MESSAGE_TYPE_WARNING: 'MessageType' + MESSAGE_TYPE_CRITICAL: 'MessageType' + MESSAGE_TYPE_FATAL: 'MessageType' + + +MESSAGE_TYPE_DEBUG: Literal[MessageType.MESSAGE_TYPE_DEBUG] +MESSAGE_TYPE_INFORMATION: Literal[MessageType.MESSAGE_TYPE_INFORMATION] +MESSAGE_TYPE_WARNING: Literal[MessageType.MESSAGE_TYPE_WARNING] +MESSAGE_TYPE_CRITICAL: Literal[MessageType.MESSAGE_TYPE_CRITICAL] +MESSAGE_TYPE_FATAL: Literal[MessageType.MESSAGE_TYPE_FATAL] + + +class FilterMode(IntEnum): + fmParallel: 'FilterMode' + fmParallelRequests: 'FilterMode' + fmUnordered: 'FilterMode' + fmFrameState: 'FilterMode' + + +fmParallel: Literal[FilterMode.fmParallel] +fmParallelRequests: Literal[FilterMode.fmParallelRequests] +fmUnordered: Literal[FilterMode.fmUnordered] +fmFrameState: Literal[FilterMode.fmFrameState] + + +class CoreCreationFlags(IntEnum): + ccfEnableGraphInspection: 'CoreCreationFlags' + ccfDisableAutoLoading: 'CoreCreationFlags' + ccfDisableLibraryUnloading: 'CoreCreationFlags' + + +ccfEnableGraphInspection: Literal[CoreCreationFlags.ccfEnableGraphInspection] +ccfDisableAutoLoading: Literal[CoreCreationFlags.ccfDisableAutoLoading] +ccfDisableLibraryUnloading: Literal[CoreCreationFlags.ccfDisableLibraryUnloading] + + +class MediaType(IntEnum): + VIDEO: 'MediaType' + AUDIO: 'MediaType' + + +VIDEO: Literal[MediaType.VIDEO] +AUDIO: Literal[MediaType.AUDIO] + + +class ColorFamily(IntEnum): + UNDEFINED: 'ColorFamily' + GRAY: 'ColorFamily' + RGB: 'ColorFamily' + YUV: 'ColorFamily' + + +UNDEFINED: Literal[ColorFamily.UNDEFINED] +GRAY: Literal[ColorFamily.GRAY] +RGB: Literal[ColorFamily.RGB] +YUV: Literal[ColorFamily.YUV] + + +class ColorRange(IntEnum): + RANGE_FULL: 'ColorRange' + RANGE_LIMITED: 'ColorRange' + + +RANGE_FULL: Literal[ColorRange.RANGE_FULL] +RANGE_LIMITED: Literal[ColorRange.RANGE_LIMITED] + + +class SampleType(IntEnum): + INTEGER: 'SampleType' + FLOAT: 'SampleType' + + +INTEGER: Literal[SampleType.INTEGER] +FLOAT: Literal[SampleType.FLOAT] + + +class PresetVideoFormat(IntEnum): + NONE: 'PresetVideoFormat' + + GRAY8: 'PresetVideoFormat' + GRAY9: 'PresetVideoFormat' + GRAY10: 'PresetVideoFormat' + GRAY12: 'PresetVideoFormat' + GRAY14: 'PresetVideoFormat' + GRAY16: 'PresetVideoFormat' + GRAY32: 'PresetVideoFormat' + + GRAYH: 'PresetVideoFormat' + GRAYS: 'PresetVideoFormat' + + YUV420P8: 'PresetVideoFormat' + YUV422P8: 'PresetVideoFormat' + YUV444P8: 'PresetVideoFormat' + YUV410P8: 'PresetVideoFormat' + YUV411P8: 'PresetVideoFormat' + YUV440P8: 'PresetVideoFormat' + + YUV420P9: 'PresetVideoFormat' + YUV422P9: 'PresetVideoFormat' + YUV444P9: 'PresetVideoFormat' + + YUV420P10: 'PresetVideoFormat' + YUV422P10: 'PresetVideoFormat' + YUV444P10: 'PresetVideoFormat' + + YUV420P12: 'PresetVideoFormat' + YUV422P12: 'PresetVideoFormat' + YUV444P12: 'PresetVideoFormat' + + YUV420P14: 'PresetVideoFormat' + YUV422P14: 'PresetVideoFormat' + YUV444P14: 'PresetVideoFormat' + + YUV420P16: 'PresetVideoFormat' + YUV422P16: 'PresetVideoFormat' + YUV444P16: 'PresetVideoFormat' + + YUV444PH: 'PresetVideoFormat' + YUV444PS: 'PresetVideoFormat' + + RGB24: 'PresetVideoFormat' + RGB27: 'PresetVideoFormat' + RGB30: 'PresetVideoFormat' + RGB36: 'PresetVideoFormat' + RGB42: 'PresetVideoFormat' + RGB48: 'PresetVideoFormat' + + RGBH: 'PresetVideoFormat' + RGBS: 'PresetVideoFormat' + + +NONE: Literal[PresetVideoFormat.NONE] + +GRAY8: Literal[PresetVideoFormat.GRAY8] +GRAY9: Literal[PresetVideoFormat.GRAY9] +GRAY10: Literal[PresetVideoFormat.GRAY10] +GRAY12: Literal[PresetVideoFormat.GRAY12] +GRAY14: Literal[PresetVideoFormat.GRAY14] +GRAY16: Literal[PresetVideoFormat.GRAY16] +GRAY32: Literal[PresetVideoFormat.GRAY32] + +GRAYH: Literal[PresetVideoFormat.GRAYH] +GRAYS: Literal[PresetVideoFormat.GRAYS] + +YUV420P8: Literal[PresetVideoFormat.YUV420P8] +YUV422P8: Literal[PresetVideoFormat.YUV422P8] +YUV444P8: Literal[PresetVideoFormat.YUV444P8] +YUV410P8: Literal[PresetVideoFormat.YUV410P8] +YUV411P8: Literal[PresetVideoFormat.YUV411P8] +YUV440P8: Literal[PresetVideoFormat.YUV440P8] + +YUV420P9: Literal[PresetVideoFormat.YUV420P9] +YUV422P9: Literal[PresetVideoFormat.YUV422P9] +YUV444P9: Literal[PresetVideoFormat.YUV444P9] + +YUV420P10: Literal[PresetVideoFormat.YUV420P10] +YUV422P10: Literal[PresetVideoFormat.YUV422P10] +YUV444P10: Literal[PresetVideoFormat.YUV444P10] + +YUV420P12: Literal[PresetVideoFormat.YUV420P12] +YUV422P12: Literal[PresetVideoFormat.YUV422P12] +YUV444P12: Literal[PresetVideoFormat.YUV444P12] + +YUV420P14: Literal[PresetVideoFormat.YUV420P14] +YUV422P14: Literal[PresetVideoFormat.YUV422P14] +YUV444P14: Literal[PresetVideoFormat.YUV444P14] + +YUV420P16: Literal[PresetVideoFormat.YUV420P16] +YUV422P16: Literal[PresetVideoFormat.YUV422P16] +YUV444P16: Literal[PresetVideoFormat.YUV444P16] + +YUV444PH: Literal[PresetVideoFormat.YUV444PH] +YUV444PS: Literal[PresetVideoFormat.YUV444PS] + +RGB24: Literal[PresetVideoFormat.RGB24] +RGB27: Literal[PresetVideoFormat.RGB27] +RGB30: Literal[PresetVideoFormat.RGB30] +RGB36: Literal[PresetVideoFormat.RGB36] +RGB42: Literal[PresetVideoFormat.RGB42] +RGB48: Literal[PresetVideoFormat.RGB48] + +RGBH: Literal[PresetVideoFormat.RGBH] +RGBS: Literal[PresetVideoFormat.RGBS] + + +class AudioChannels(IntEnum): + FRONT_LEFT: 'AudioChannels' + FRONT_RIGHT: 'AudioChannels' + FRONT_CENTER: 'AudioChannels' + LOW_FREQUENCY: 'AudioChannels' + BACK_LEFT: 'AudioChannels' + BACK_RIGHT: 'AudioChannels' + FRONT_LEFT_OF_CENTER: 'AudioChannels' + FRONT_RIGHT_OF_CENTER: 'AudioChannels' + BACK_CENTER: 'AudioChannels' + SIDE_LEFT: 'AudioChannels' + SIDE_RIGHT: 'AudioChannels' + TOP_CENTER: 'AudioChannels' + TOP_FRONT_LEFT: 'AudioChannels' + TOP_FRONT_CENTER: 'AudioChannels' + TOP_FRONT_RIGHT: 'AudioChannels' + TOP_BACK_LEFT: 'AudioChannels' + TOP_BACK_CENTER: 'AudioChannels' + TOP_BACK_RIGHT: 'AudioChannels' + STEREO_LEFT: 'AudioChannels' + STEREO_RIGHT: 'AudioChannels' + WIDE_LEFT: 'AudioChannels' + WIDE_RIGHT: 'AudioChannels' + SURROUND_DIRECT_LEFT: 'AudioChannels' + SURROUND_DIRECT_RIGHT: 'AudioChannels' + LOW_FREQUENCY2: 'AudioChannels' + + +FRONT_LEFT: Literal[AudioChannels.FRONT_LEFT] +FRONT_RIGHT: Literal[AudioChannels.FRONT_RIGHT] +FRONT_CENTER: Literal[AudioChannels.FRONT_CENTER] +LOW_FREQUENCY: Literal[AudioChannels.LOW_FREQUENCY] +BACK_LEFT: Literal[AudioChannels.BACK_LEFT] +BACK_RIGHT: Literal[AudioChannels.BACK_RIGHT] +FRONT_LEFT_OF_CENTER: Literal[AudioChannels.FRONT_LEFT_OF_CENTER] +FRONT_RIGHT_OF_CENTER: Literal[AudioChannels.FRONT_RIGHT_OF_CENTER] +BACK_CENTER: Literal[AudioChannels.BACK_CENTER] +SIDE_LEFT: Literal[AudioChannels.SIDE_LEFT] +SIDE_RIGHT: Literal[AudioChannels.SIDE_RIGHT] +TOP_CENTER: Literal[AudioChannels.TOP_CENTER] +TOP_FRONT_LEFT: Literal[AudioChannels.TOP_FRONT_LEFT] +TOP_FRONT_CENTER: Literal[AudioChannels.TOP_FRONT_CENTER] +TOP_FRONT_RIGHT: Literal[AudioChannels.TOP_FRONT_RIGHT] +TOP_BACK_LEFT: Literal[AudioChannels.TOP_BACK_LEFT] +TOP_BACK_CENTER: Literal[AudioChannels.TOP_BACK_CENTER] +TOP_BACK_RIGHT: Literal[AudioChannels.TOP_BACK_RIGHT] +STEREO_LEFT: Literal[AudioChannels.STEREO_LEFT] +STEREO_RIGHT: Literal[AudioChannels.STEREO_RIGHT] +WIDE_LEFT: Literal[AudioChannels.WIDE_LEFT] +WIDE_RIGHT: Literal[AudioChannels.WIDE_RIGHT] +SURROUND_DIRECT_LEFT: Literal[AudioChannels.SURROUND_DIRECT_LEFT] +SURROUND_DIRECT_RIGHT: Literal[AudioChannels.SURROUND_DIRECT_RIGHT] +LOW_FREQUENCY2: Literal[AudioChannels.LOW_FREQUENCY2] + + +class ChromaLocation(IntEnum): + CHROMA_LEFT: 'ChromaLocation' + CHROMA_CENTER: 'ChromaLocation' + CHROMA_TOP_LEFT: 'ChromaLocation' + CHROMA_TOP: 'ChromaLocation' + CHROMA_BOTTOM_LEFT: 'ChromaLocation' + CHROMA_BOTTOM: 'ChromaLocation' + + +CHROMA_LEFT: Literal[ChromaLocation.CHROMA_LEFT] +CHROMA_CENTER: Literal[ChromaLocation.CHROMA_CENTER] +CHROMA_TOP_LEFT: Literal[ChromaLocation.CHROMA_TOP_LEFT] +CHROMA_TOP: Literal[ChromaLocation.CHROMA_TOP] +CHROMA_BOTTOM_LEFT: Literal[ChromaLocation.CHROMA_BOTTOM_LEFT] +CHROMA_BOTTOM: Literal[ChromaLocation.CHROMA_BOTTOM] + + +class FieldBased(IntEnum): + FIELD_PROGRESSIVE: 'FieldBased' + FIELD_TOP: 'FieldBased' + FIELD_BOTTOM: 'FieldBased' + + +FIELD_PROGRESSIVE: Literal[FieldBased.FIELD_PROGRESSIVE] +FIELD_TOP: Literal[FieldBased.FIELD_TOP] +FIELD_BOTTOM: Literal[FieldBased.FIELD_BOTTOM] + + +class MatrixCoefficients(IntEnum): + MATRIX_RGB: 'MatrixCoefficients' + MATRIX_BT709: 'MatrixCoefficients' + MATRIX_UNSPECIFIED: 'MatrixCoefficients' + MATRIX_FCC: 'MatrixCoefficients' + MATRIX_BT470_BG: 'MatrixCoefficients' + MATRIX_ST170_M: 'MatrixCoefficients' + MATRIX_ST240_M: 'MatrixCoefficients' + MATRIX_YCGCO: 'MatrixCoefficients' + MATRIX_BT2020_NCL: 'MatrixCoefficients' + MATRIX_BT2020_CL: 'MatrixCoefficients' + MATRIX_CHROMATICITY_DERIVED_NCL: 'MatrixCoefficients' + MATRIX_CHROMATICITY_DERIVED_CL: 'MatrixCoefficients' + MATRIX_ICTCP: 'MatrixCoefficients' + + +MATRIX_RGB: Literal[MatrixCoefficients.MATRIX_RGB] +MATRIX_BT709: Literal[MatrixCoefficients.MATRIX_BT709] +MATRIX_UNSPECIFIED: Literal[MatrixCoefficients.MATRIX_UNSPECIFIED] +MATRIX_FCC: Literal[MatrixCoefficients.MATRIX_FCC] +MATRIX_BT470_BG: Literal[MatrixCoefficients.MATRIX_BT470_BG] +MATRIX_ST170_M: Literal[MatrixCoefficients.MATRIX_ST170_M] +MATRIX_ST240_M: Literal[MatrixCoefficients.MATRIX_ST240_M] +MATRIX_YCGCO: Literal[MatrixCoefficients.MATRIX_YCGCO] +MATRIX_BT2020_NCL: Literal[MatrixCoefficients.MATRIX_BT2020_NCL] +MATRIX_BT2020_CL: Literal[MatrixCoefficients.MATRIX_BT2020_CL] +MATRIX_CHROMATICITY_DERIVED_NCL: Literal[MatrixCoefficients.MATRIX_CHROMATICITY_DERIVED_NCL] +MATRIX_CHROMATICITY_DERIVED_CL: Literal[MatrixCoefficients.MATRIX_CHROMATICITY_DERIVED_CL] +MATRIX_ICTCP: Literal[MatrixCoefficients.MATRIX_ICTCP] + + +class TransferCharacteristics(IntEnum): + TRANSFER_BT709: 'TransferCharacteristics' + TRANSFER_UNSPECIFIED: 'TransferCharacteristics' + TRANSFER_BT470_M: 'TransferCharacteristics' + TRANSFER_BT470_BG: 'TransferCharacteristics' + TRANSFER_BT601: 'TransferCharacteristics' + TRANSFER_ST240_M: 'TransferCharacteristics' + TRANSFER_LINEAR: 'TransferCharacteristics' + TRANSFER_LOG_100: 'TransferCharacteristics' + TRANSFER_LOG_316: 'TransferCharacteristics' + TRANSFER_IEC_61966_2_4: 'TransferCharacteristics' + TRANSFER_IEC_61966_2_1: 'TransferCharacteristics' + TRANSFER_BT2020_10: 'TransferCharacteristics' + TRANSFER_BT2020_12: 'TransferCharacteristics' + TRANSFER_ST2084: 'TransferCharacteristics' + TRANSFER_ARIB_B67: 'TransferCharacteristics' + + +TRANSFER_BT709: Literal[TransferCharacteristics.TRANSFER_BT709] +TRANSFER_UNSPECIFIED: Literal[TransferCharacteristics.TRANSFER_UNSPECIFIED] +TRANSFER_BT470_M: Literal[TransferCharacteristics.TRANSFER_BT470_M] +TRANSFER_BT470_BG: Literal[TransferCharacteristics.TRANSFER_BT470_BG] +TRANSFER_BT601: Literal[TransferCharacteristics.TRANSFER_BT601] +TRANSFER_ST240_M: Literal[TransferCharacteristics.TRANSFER_ST240_M] +TRANSFER_LINEAR: Literal[TransferCharacteristics.TRANSFER_LINEAR] +TRANSFER_LOG_100: Literal[TransferCharacteristics.TRANSFER_LOG_100] +TRANSFER_LOG_316: Literal[TransferCharacteristics.TRANSFER_LOG_316] +TRANSFER_IEC_61966_2_4: Literal[TransferCharacteristics.TRANSFER_IEC_61966_2_4] +TRANSFER_IEC_61966_2_1: Literal[TransferCharacteristics.TRANSFER_IEC_61966_2_1] +TRANSFER_BT2020_10: Literal[TransferCharacteristics.TRANSFER_BT2020_10] +TRANSFER_BT2020_12: Literal[TransferCharacteristics.TRANSFER_BT2020_12] +TRANSFER_ST2084: Literal[TransferCharacteristics.TRANSFER_ST2084] +TRANSFER_ARIB_B67: Literal[TransferCharacteristics.TRANSFER_ARIB_B67] + + +class ColorPrimaries(IntEnum): + PRIMARIES_BT709: 'ColorPrimaries' + PRIMARIES_UNSPECIFIED: 'ColorPrimaries' + PRIMARIES_BT470_M: 'ColorPrimaries' + PRIMARIES_BT470_BG: 'ColorPrimaries' + PRIMARIES_ST170_M: 'ColorPrimaries' + PRIMARIES_ST240_M: 'ColorPrimaries' + PRIMARIES_FILM: 'ColorPrimaries' + PRIMARIES_BT2020: 'ColorPrimaries' + PRIMARIES_ST428: 'ColorPrimaries' + PRIMARIES_ST431_2: 'ColorPrimaries' + PRIMARIES_ST432_1: 'ColorPrimaries' + PRIMARIES_EBU3213_E: 'ColorPrimaries' + + +PRIMARIES_BT709: Literal[ColorPrimaries.PRIMARIES_BT709] +PRIMARIES_UNSPECIFIED: Literal[ColorPrimaries.PRIMARIES_UNSPECIFIED] +PRIMARIES_BT470_M: Literal[ColorPrimaries.PRIMARIES_BT470_M] +PRIMARIES_BT470_BG: Literal[ColorPrimaries.PRIMARIES_BT470_BG] +PRIMARIES_ST170_M: Literal[ColorPrimaries.PRIMARIES_ST170_M] +PRIMARIES_ST240_M: Literal[ColorPrimaries.PRIMARIES_ST240_M] +PRIMARIES_FILM: Literal[ColorPrimaries.PRIMARIES_FILM] +PRIMARIES_BT2020: Literal[ColorPrimaries.PRIMARIES_BT2020] +PRIMARIES_ST428: Literal[ColorPrimaries.PRIMARIES_ST428] +PRIMARIES_ST431_2: Literal[ColorPrimaries.PRIMARIES_ST431_2] +PRIMARIES_ST432_1: Literal[ColorPrimaries.PRIMARIES_ST432_1] +PRIMARIES_EBU3213_E: Literal[ColorPrimaries.PRIMARIES_EBU3213_E] + + +### +# VapourSynth Environment SubSystem + + +class EnvironmentData: + def __init__(self) -> NoReturn: ... + + +class EnvironmentPolicy: + def on_policy_registered(self, special_api: 'EnvironmentPolicyAPI') -> None: ... + + def on_policy_cleared(self) -> None: ... + + @abstractmethod + def get_current_environment(self) -> Union[EnvironmentData, None]: ... + + @abstractmethod + def set_environment(self, environment: Union[EnvironmentData, None]) -> Union[EnvironmentData, None]: ... + + def is_alive(self, environment: EnvironmentData) -> bool: ... + + +class EnvironmentPolicyAPI: + def __init__(self) -> NoReturn: ... + + def wrap_environment(self, environment_data: EnvironmentData) -> 'Environment': ... + + def create_environment(self, flags: int = 0) -> EnvironmentData: ... + + def set_logger(self, env: EnvironmentData, logger: Callable[[int, str], None]) -> None: ... + + def get_vapoursynth_api(self, version: int) -> c_void_p: ... + + def get_core_ptr(self, environment_data: EnvironmentData) -> c_void_p: ... + + def destroy_environment(self, env: EnvironmentData) -> None: ... + + def unregister_policy(self) -> None: ... + + +def register_policy(policy: EnvironmentPolicy) -> None: + ... + + +if not TYPE_CHECKING: + def _try_enable_introspection(version: int = None): ... + + +def has_policy() -> bool: + ... + + +def register_on_destroy(callback: Callable[..., None]) -> None: + ... + + +def unregister_on_destroy(callback: Callable[..., None]) -> None: + ... + + +class Environment: + env: ReferenceType[EnvironmentData] + + def __init__(self) -> NoReturn: ... + + @property + def alive(self) -> bool: ... + + @property + def single(self) -> bool: ... + + @classmethod + def is_single(cls) -> bool: ... + + @property + def env_id(self) -> int: ... + + @property + def active(self) -> bool: ... + + def copy(self) -> 'Environment': ... + + def use(self) -> ContextManager[None]: ... + + def __eq__(self, other: 'Environment') -> bool: ... # type: ignore[override] + + def __repr__(self) -> str: ... + + +def get_current_environment() -> Environment: + ... + + +class Local: + def __getattr__(self, key: str) -> Any: ... + + # Even though object does have set/del methods, typecheckers will treat them differently + # when they are not explicit; for example by raising a member not found warning. + + def __setattr__(self, key: str, value: Any) -> None: ... + + def __delattr__(self, key: str) -> None: ... + + +class VideoOutputTuple(NamedTuple): + clip: 'VideoNode' + alpha: Union['VideoNode', None] + alt_output: Literal[0, 1, 2] + + +class Error(Exception): + ... + + +def clear_output(index: int = 0) -> None: + ... + + +def clear_outputs() -> None: + ... + + +def get_outputs() -> MappingProxyType[int, Union[VideoOutputTuple, 'AudioNode']]: + ... + + +def get_output(index: int = 0) -> Union[VideoOutputTuple, 'AudioNode']: + ... + + +class FuncData: + def __init__(self) -> NoReturn: ... + + def __call__(self, **kwargs: _VapourSynthMapValue) -> _VapourSynthMapValue: ... + + +class Func: + def __init__(self) -> NoReturn: ... + + def __call__(self, **kwargs: _VapourSynthMapValue) -> _VapourSynthMapValue: ... + + +class FramePtr: + def __init__(self) -> NoReturn: ... + + +class VideoFormat: + id: int + name: str + color_family: ColorFamily + sample_type: SampleType + bits_per_sample: int + bytes_per_sample: int + subsampling_w: int + subsampling_h: int + num_planes: int + + def __init__(self) -> NoReturn: ... + + def _as_dict(self) -> _VideoFormatInfo: ... + + def replace( + self, *, + color_family: Union[ColorFamily, None] = None, + sample_type: Union[SampleType, None] = None, + bits_per_sample: Union[int, None] = None, + subsampling_w: Union[int, None] = None, + subsampling_h: Union[int, None] = None + ) -> 'VideoFormat': ... + + @overload + def __eq__(self, other: 'VideoFormat') -> bool: ... # type: ignore[misc] + + @overload + def __eq__(self, other: Any) -> Literal[False]: ... + + +class FrameProps(MutableMapping[str, _VapourSynthMapValue]): + def __init__(self) -> NoReturn: ... + + def setdefault( + self, key: str, default: _VapourSynthMapValue = 0 + ) -> _VapourSynthMapValue: ... + + def copy(self) -> MutableMapping[str, _VapourSynthMapValue]: ... + + # Since we're inheriting from the MutableMapping abstract class, + # we *have* to specify that we have indeed created these methods. + # If we don't, mypy will complain that we're working with abstract methods. + + def __setattr__(self, name: str, value: _VapourSynthMapValue) -> None: ... + + def __getattr__(self, name: str) -> _VapourSynthMapValue: ... + + def __delattr__(self, name: str) -> None: ... + + def __setitem__(self, name: str, value: _VapourSynthMapValue) -> None: ... + + def __getitem__(self, name: str) -> _VapourSynthMapValue: ... + + def __delitem__(self, name: str) -> None: ... + + def __iter__(self) -> Iterator[str]: ... + + def __len__(self) -> int: ... + + +class ChannelLayout(int): + def __init__(self) -> NoReturn: ... + + def __contains__(self, layout: AudioChannels) -> bool: ... + + def __iter__(self) -> Iterator[AudioChannels]: ... + + @overload + def __eq__(self, other: 'ChannelLayout') -> bool: ... # type: ignore[misc] + + @overload + def __eq__(self, other: Any) -> Literal[False]: ... + + def __len__(self) -> int: ... + + +class audio_view(memoryview): # type: ignore[misc] + @property + def shape(self) -> tuple[int]: ... + + @property + def strides(self) -> tuple[int]: ... + + @property + def ndim(self) -> Literal[1]: ... + + @property + def obj(self) -> FramePtr: ... # type: ignore[override] + + def __getitem__(self, index: int) -> int | float: ... # type: ignore[override] + + def __setitem__(self, index: int, other: int | float) -> None: ... # type: ignore[override] + + def tolist(self) -> list[int | float]: ... # type: ignore[override] + + +class video_view(memoryview): # type: ignore[misc] + @property + def shape(self) -> tuple[int, int]: ... + + @property + def strides(self) -> tuple[int, int]: ... + + @property + def ndim(self) -> Literal[2]: ... + + @property + def obj(self) -> FramePtr: ... # type: ignore[override] + + def __getitem__(self, index: Tuple[int, int]) -> int | float: ... # type: ignore[override] + + def __setitem__(self, index: Tuple[int, int], other: int | float) -> None: ... # type: ignore[override] + + def tolist(self) -> list[int | float]: ... # type: ignore[override] + + +class RawFrame: + def __init__(self) -> NoReturn: ... + + @property + def closed(self) -> bool: ... + + def close(self) -> None: ... + + def copy(self: 'SelfFrame') -> 'SelfFrame': ... + + @property + def props(self) -> FrameProps: ... + + @props.setter + def props(self, new_props: MappingProxyType[str, _VapourSynthMapValue]) -> None: ... + + def get_write_ptr(self, plane: int) -> c_void_p: ... + + def get_read_ptr(self, plane: int) -> c_void_p: ... + + def get_stride(self, plane: int) -> int: ... + + @property + def readonly(self) -> bool: ... + + def __enter__(self: 'SelfFrame') -> 'SelfFrame': ... + + def __exit__( + self, exc_type: Union[Type[BaseException], None], + exc_value: Union[BaseException, None], + traceback: Union[TracebackType, None], /, + ) -> Union[bool, None]: ... + + def __getitem__(self, index: int) -> memoryview: ... + + def __len__(self) -> int: ... + + +SelfFrame = TypeVar('SelfFrame', bound=RawFrame) + + +class VideoFrame(RawFrame): + format: VideoFormat + width: int + height: int + + def readchunks(self) -> Iterator[video_view]: ... + + def __getitem__(self, index: int) -> video_view: ... + + +class AudioFrame(RawFrame): + sample_type: SampleType + bits_per_sample: int + bytes_per_sample: int + channel_layout: int + num_channels: int + + @property + def channels(self) -> ChannelLayout: ... + + def __getitem__(self, index: int) -> audio_view: ... + +#include + + +class RawNode: + def __init__(self) -> NoReturn: ... + + def get_frame(self, n: int) -> RawFrame: ... + + @overload + def get_frame_async(self, n: int, cb: None = None) -> _Future[RawFrame]: ... + + @overload + def get_frame_async(self, n: int, cb: Callable[[Union[RawFrame, None], Union[Exception, None]], None]) -> None: ... + + def frames( + self, prefetch: Union[int, None] = None, backlog: Union[int, None] = None, close: bool = False + ) -> Iterator[RawFrame]: ... + + def set_output(self, index: int = 0) -> None: ... + + def is_inspectable(self, version: Union[int, None] = None) -> bool: ... + + if not TYPE_CHECKING: + @property + def _node_name(self) -> str: ... + + @property + def _name(self) -> str: ... + + @property + def _inputs(self) -> Dict[str, _VapourSynthMapValue]: ... + + @property + def _timings(self) -> int: ... + + @property + def _mode(self) -> FilterMode: ... + + @property + def _dependencies(self): ... + + @overload + def __eq__(self: 'SelfRawNode', other: 'SelfRawNode', /) -> bool: ... # type: ignore[misc] + + @overload + def __eq__(self, other: Any, /) -> Literal[False]: ... + + def __add__(self: 'SelfRawNode', other: 'SelfRawNode', /) -> 'SelfRawNode': ... + + def __radd__(self: 'SelfRawNode', other: 'SelfRawNode', /) -> 'SelfRawNode': ... + + def __mul__(self: 'SelfRawNode', other: int) -> 'SelfRawNode': ... + + def __rmul__(self: 'SelfRawNode', other: int) -> 'SelfRawNode': ... + + def __getitem__(self: 'SelfRawNode', index: Union[int, slice], /) -> 'SelfRawNode': ... + + def __len__(self) -> int: ... + + +SelfRawNode = TypeVar('SelfRawNode', bound=RawNode) + + +class VideoNode(RawNode): + format: Union[VideoFormat, None] + + width: int + height: int + + fps_num: int + fps_den: int + + fps: Fraction + + num_frames: int + + def set_output( + self, index: int = 0, alpha: Union['VideoNode', None] = None, alt_output: Literal[0, 1, 2] = 0 + ) -> None: ... + + def output( + self, fileobj: BinaryIO, y4m: bool = False, progress_update: Callable[[int, int], None] | None = None, + prefetch: int = 0, backlog: int = -1 + ) -> None: ... + + def get_frame(self, n: int) -> VideoFrame: ... + + @overload # type: ignore[override] + def get_frame_async(self, n: int, cb: None = None) -> _Future[VideoFrame]: ... + + @overload + def get_frame_async(self, n: int, cb: Callable[[Union[VideoFrame, None], Union[Exception, None]], None]) -> None: ... + + def frames( + self, prefetch: Union[int, None] = None, backlog: Union[int, None] = None, close: bool = False + ) -> Iterator[VideoFrame]: ... + +#include + + +class AudioNode(RawNode): + sample_type: SampleType + bits_per_sample: int + bytes_per_sample: int + + channel_layout: int + num_channels: int + + sample_rate: int + num_samples: int + + num_frames: int + + @property + def channels(self) -> ChannelLayout: ... + + def get_frame(self, n: int) -> AudioFrame: ... + + @overload # type: ignore[override] + def get_frame_async(self, n: int, cb: None = None) -> _Future[AudioFrame]: ... + + @overload + def get_frame_async(self, n: int, cb: Callable[[Union[AudioFrame, None], Union[Exception, None]], None]) -> None: ... + + def frames( + self, prefetch: Union[int, None] = None, backlog: Union[int, None] = None, close: bool = False + ) -> Iterator[AudioFrame]: ... + +#include + + +class LogHandle: + def __init__(self) -> NoReturn: ... + + +class Function: + plugin: 'Plugin' + name: str + signature: str + return_signature: str + + def __init__(self) -> NoReturn: ... + + def __call__(self, *args: _VapourSynthMapValue, **kwargs: _VapourSynthMapValue) -> _VapourSynthMapValue: ... + + @property + def __signature__(self) -> Signature: ... + + +class Plugin: + identifier: str + namespace: str + name: str + + def __init__(self) -> NoReturn: ... + + def __getattr__(self, name: str) -> Function: ... + + def functions(self) -> Iterator[Function]: ... + + @property + def version(self) -> PluginVersion: ... + + +class Core: + def __init__(self) -> NoReturn: ... + + @property + def num_threads(self) -> int: ... + + @num_threads.setter + def num_threads(self) -> None: ... + + @property + def max_cache_size(self) -> int: ... + + @max_cache_size.setter + def max_cache_size(self) -> None: ... + + @property + def flags(self) -> int: ... + + def plugins(self) -> Iterator[Plugin]: ... + + def query_video_format( + self, color_family: ColorFamily, sample_type: SampleType, bits_per_sample: int, subsampling_w: int = 0, + subsampling_h: int = 0 + ) -> VideoFormat: ... + + def get_video_format(self, id: Union[VideoFormat, int, PresetVideoFormat]) -> VideoFormat: ... + + def create_video_frame(self, format: VideoFormat, width: int, height: int) -> VideoFrame: ... + + def log_message(self, message_type: MessageType, message: str) -> None: ... + + def add_log_handler(self, handler_func: Callable[[MessageType, str], None]) -> LogHandle: ... + + def remove_log_handler(self, handle: LogHandle) -> None: ... + + def version(self) -> str: ... + + def version_number(self) -> int: ... + +#include + + +class _CoreProxy(Core): + @property + def core(self) -> Core: ... + + +core: _CoreProxy diff --git a/Programs/vsgenstubs4/init.py b/Programs/vsgenstubs4/init.py new file mode 100644 index 0000000..729eef3 --- /dev/null +++ b/Programs/vsgenstubs4/init.py @@ -0,0 +1,613 @@ +import re +import sys +from abc import abstractmethod +from argparse import ArgumentParser, Namespace +from inspect import Parameter, Signature +from itertools import chain +from keyword import kwlist as reserved_keywords +from os import SEEK_END, listdir, makedirs, path +from os.path import join as join_path +from pathlib import Path +from typing import ( + Any, Callable, Dict, Iterable, Iterator, List, NamedTuple, Optional, Protocol, Sequence, Tuple, TypedDict, TypeVar, + Union, cast, runtime_checkable +) + +import vapoursynth as vs + +__all__ = [ + 'main' +] + +T = TypeVar('T') +CoreLike = Union[vs.Core, vs.RawNode] + +SingleAndSequence = Union[T, Sequence[T]] + + +@runtime_checkable +class SupportsString(Protocol): + @abstractmethod + def __str__(self) -> str: + ... + + +DataType = Union[str, bytes, bytearray, SupportsString] + +_VapourSynthMapValue = Union[ + SingleAndSequence[int], + SingleAndSequence[float], + SingleAndSequence[DataType], + SingleAndSequence[vs.VideoNode], + SingleAndSequence[vs.VideoFrame], + SingleAndSequence[vs.AudioNode], + SingleAndSequence[vs.AudioFrame], + SingleAndSequence['VSMapValueCallback[Any]'] +] + +BoundVSMapValue = TypeVar('BoundVSMapValue', bound=_VapourSynthMapValue) + +VSMapValueCallback = Callable[..., BoundVSMapValue] + + +vs_value_type = '_VapourSynthMapValue' +site_package_dirname = 'vapoursynth-stubs' + +parser = ArgumentParser() +parser.add_argument( + "plugins", + type=str, nargs="*", + help="Only generate stubs for and inject specified plugin namespaces, " + "append these if the stubs file already exists." +) +parser.add_argument( + "--exclude-plugin", "-r", + metavar="VS_EXCL_PLUGIN", action="append", help="Remove selected plugin from new stubs, " + "or remove from existing stubs." +) +parser.add_argument( + "--load-plugin", "-p", + metavar="VS_PLUGIN", action="append", help="Load non-auto-loaded VapourSynth plugin." +) +parser.add_argument( + '--avs-plugin', action='append', help='Manually load AviSynth plugin.' +) +parser.add_argument( + '--output', '-o', default='@', + help="Where to output the file. Can be a full file path or directory." + "The special value '-' means output to stdout. " + "The spcial value '@' will install it as a stub-package inside site-packages." +) +parser.add_argument( + '--pyi-template', + default=join_path(path.dirname(__file__), '_vapoursynth.part.pyi'), + help='Don\'t use unless you know what you are doing.' +) +parser.add_argument( + '--force', '-f', + action='store_true', + help='Force rewrite of the file.' +) + + +def indent(strings: Iterable[str], spaces: int = 4) -> str: + return '\n'.join(' ' * spaces + line for line in strings) + + +anonymous_signature = Signature( + [ + Parameter('args', Parameter.VAR_POSITIONAL, annotation=vs_value_type), + Parameter('kwargs', Parameter.VAR_KEYWORD, annotation=vs_value_type) + ], + return_annotation=vs.VideoNode +) + +sig_excepted_errors_list = [TypeError, ValueError] + +if vs.__version__[0] < 60: + sig_excepted_errors_list.append(IndexError) + # it tried to delete the bound value even if the signature didn't have any + # eg Version functions, their plugin is bound but the function hasn't got any params + # https://github.com/vapoursynth/vapoursynth/pull/898 + + +sig_excepted_errors = tuple(sig_excepted_errors_list) + +types = { + 'int', 'float', 'DataType', + 'RawNode', + 'VideoNode', 'AudioNode', + 'RawFrame', + 'VideoFrame', 'AudioFrame' +} + + +def load_plugins(args: Namespace) -> vs.Core: + def _check_plugin(path: str) -> str: + pathl = Path(path).absolute() + + if not pathl.exists(): + raise ValueError(f'Plugin "{path}" was not found!') + + return str(pathl) + + if args.load_plugin: + for plugin in args.load_plugin: + vs.core.std.LoadPlugin(_check_plugin(plugin)) + + if args.avs_plugin: + if hasattr(vs.core, 'avs'): + for plugin in args.avs_plugin: + vs.core.avs.LoadPlugin(_check_plugin(plugin)) + else: + raise AttributeError('Core is missing avs plugin!') + + return vs.core.core + + +def clean_signature(signature: Any) -> str: + signature = str(signature) + + # Clean up the type annotations so that they are valid python syntax. + signature = signature.replace('typing.', '') + signature = signature.replace('vapoursynth.', '').replace('vs.', '') + signature = signature.replace('VideoNode', "'VideoNode'").replace('VideoFrame', "'VideoFrame'") + signature = signature.replace('AudioNode', "'AudioNode'").replace('AudioFrame', "'AudioFrame'") + signature = signature.replace('NoneType', 'None') + signature = signature.replace('str, bytes, bytearray', 'DataType') + + for t in types: + for t_ in {t, f"'{t}'"}: + signature = signature.replace(f'Union[{t_}]', f'{t_}') + signature = signature.replace(f'Union[{t_}, None]', f'Optional[{t_}]') + signature = signature.replace(f'Union[{t_}, Sequence[{t_}]]', f'SingleAndSequence[{t_}]') + signature = signature.replace( + f'Union[{t_}, Sequence[{t_}], None]', f'Optional[SingleAndSequence[{t}]]' + ) + + callback_type = 'VSMapValueCallback[_VapourSynthMapValue]' + + # Make Callable definitions sensible + signature = signature.replace('Union[Func, Callable]', callback_type) + signature = signature.replace('Union[Func, Callable, None]', f'Optional[{callback_type}]') + + # Replace the keywords with valid values + for kw in reserved_keywords: + signature = signature.replace(f' {kw}:', f' {kw}_:') + + return signature + + +def get_complex_signature(signature: TypedDict) -> Tuple[str, str]: + dict_name = signature.__name__ # type: ignore + + def _sanitize_type(value: Any) -> str: + if isinstance(value, type): + return str(value.__name__) + return str(value) + + dict_signature = ', '.join( + f'"{name}": {_sanitize_type(value)}' for name, value in signature.__annotations__.items() + ) + + dict_signature = '{' + dict_signature + '}' + + return dict_name, clean_signature(f'TypedDict("{dict_name}", {dict_signature})') + + +def retrieve_func_sigs( + core: Union[vs.Core, vs.RawNode], namespace: str +) -> Iterator[Tuple[str, Union[None, Tuple[str, str]]]]: + plugin = cast(vs.Plugin, getattr(core, namespace)) + + ordered_functions = sorted(plugin.functions(), key=lambda x: x.name.lower()) + + for func in ordered_functions: + signature_base = anonymous_signature + + if func.name in dir(plugin): + try: + signature_base = Signature.from_callable( + cast(vs.Function, getattr(plugin, func.name)), follow_wrapped=True + ) + except sig_excepted_errors: + if isinstance(core, vs.RawNode): + signature_base.replace(return_annotation=core.__class__) + + complex_signature = None + + rann = signature_base.return_annotation + if isinstance(rann, type) and issubclass(rann, dict): + complex_signature = get_complex_signature(rann) + signature_base = signature_base.replace(return_annotation=complex_signature[0]) + elif rann in {Any, Optional[Any]}: + signature_base = signature_base.replace(return_annotation=vs.VideoNode) + + signature = clean_signature(signature_base) + + # Remove anonymous Anys + signature = signature.replace(' **kwargs: Any', f' **kwargs: {vs_value_type}') + + # Add a self. + signature = signature.replace('(', '(self, ').replace(', )', ')') + + yield f' def {func.name}{signature}: ...', complex_signature + + +class BoundSignature: + def __init__(self, namespace: str, cores: Iterable[CoreLike]) -> None: + self.namespace = namespace + self.cores = cores + + def __iter__(self) -> Iterator[Tuple[str, Iterator[Tuple[str, Tuple[str, str] | None]]]]: + for core in self.cores: + signatures = retrieve_func_sigs(core, self.namespace) + + try: + signature = next(signatures) + except StopIteration: + continue + + yield core.__class__.__name__, chain.from_iterable(([signature], signatures)) + + +class PluginMeta(NamedTuple): + name: str + description: str + bound: BoundSignature + + @classmethod + def from_namespace(cls, namespace: str, cores: Sequence[CoreLike]) -> 'PluginMeta': + try: + plugin = cast(vs.Plugin, getattr(cores[0], namespace)) + except BaseException: + raise ValueError(f'Invalid namespace! Plugin not found: "{namespace}"') + + return PluginMeta( + plugin.namespace, plugin.name, BoundSignature(plugin.namespace, cores) + ) + + def _str_(self, kind: str, __x: Tuple[object, ...]) -> bool: + return getattr(str, kind)(self.name.lower(), str(__x[0]).lower()) + + def __gt__(self, x: 'PluginMeta', /) -> bool: return self._str_('__gt__', x) # type: ignore[override] + def __lt__(self, x: 'PluginMeta', /) -> bool: return self._str_('__lt__', x) # type: ignore[override] + def __ge__(self, x: 'PluginMeta', /) -> bool: return self._str_('__ge__', x) # type: ignore[override] + def __le__(self, x: 'PluginMeta', /) -> bool: return self._str_('__le__', x) # type: ignore[override] + def __eq__(self, x: 'PluginMeta', /) -> bool: return self._str_('__eq__', x) # type: ignore[override] + def __ne__(self, x: 'PluginMeta', /) -> bool: return self._str_('__ne__', x) # type: ignore[override] + + +def retrieve_plugins( + args: Namespace, core: vs.Core, cores: Iterable[CoreLike] +) -> Iterator[PluginMeta]: + lower_plugins = list(map(str.lower, args.plugins)) if args.plugins else [] + + if lower_plugins: + find_plugins = lower_plugins.copy() + + for p in core.plugins(): + ns_lower = p.namespace.lower() + + if ns_lower in find_plugins: + find_plugins.remove(ns_lower) + + if find_plugins: + missing_plugins = ', '.join(find_plugins) + + raise ModuleNotFoundError( + 'Can\'t generate stubs for specific plugins, these are missing in your installation:' + f'\n\t"{missing_plugins}"' + ) + + for p in core.plugins(): + if lower_plugins and (p.namespace.lower() not in lower_plugins): + continue + + yield PluginMeta(p.namespace, p.name, BoundSignature(p.namespace, cores)) + + +implementation_start = '# implementation' +implementation_end = '# end implementation' + + +class Implementation(NamedTuple): + plugin: PluginMeta + content: List[str] + + @classmethod + def from_namespace(cls, namespace: str, cores: Sequence[CoreLike]) -> 'Implementation': + return Implementation(PluginMeta.from_namespace(namespace, cores), []) + + @staticmethod + def get_name(plugin: PluginMeta, core_name: str, /) -> str: + return f'_Plugin_{plugin.name}_{core_name}_Bound' + + def __gt__(self, x: 'Implementation', /) -> bool: return self.plugin.__gt__(x.plugin) # type: ignore[override] + def __lt__(self, x: 'Implementation', /) -> bool: return self.plugin.__lt__(x.plugin) # type: ignore[override] + def __ge__(self, x: 'Implementation', /) -> bool: return self.plugin.__ge__(x.plugin) # type: ignore[override] + def __le__(self, x: 'Implementation', /) -> bool: return self.plugin.__le__(x.plugin) # type: ignore[override] + def __eq__(self, x: 'Implementation', /) -> bool: return self.plugin.__eq__(x.plugin) # type: ignore[override] + def __ne__(self, x: 'Implementation', /) -> bool: return self.plugin.__ne__(x.plugin) # type: ignore[override] + + +def get_implementation_content(plugin: PluginMeta) -> Iterator[str]: + body: List[str] = [] + + complex_types: Dict[str, str] = {} + + for core_name, signatures in plugin.bound: + function_signatures: List[str] = [] + + for signature, complex_type in signatures: + function_signatures.append(str(signature)) + + if complex_type: + type_name, type_definition = complex_type + complex_types |= {type_name: (f'{type_name} = {type_definition}')} + + body.extend([ + '', + f"class {Implementation.get_name(plugin, core_name)}(Plugin):", + ' """' + f'This class implements the module definitions for the "{plugin.name}" VapourSynth plugin.' + '\\n\\n*This class cannot be imported.*' + '"""', + '\n'.join(function_signatures), + ]) + + if complex_types: + body.insert(0, '\n'.join(['', *complex_types.values(), ''])) + + return iter(body) + + +def make_implementations(plugins: Iterable[PluginMeta]) -> Iterator[Implementation]: + for plugin in plugins: + content = chain.from_iterable([ + ['', f"{implementation_start}: {plugin.name}"], + get_implementation_content(plugin), + ['', implementation_end, ''] + ]) + + yield Implementation(plugin, list(content)) + + +instance_start = '# instance_bound_' +instance_end = '# end instance' + +instance_bound_pattern = re.compile(fr"^{instance_start}([^:]+): (.+)") + + +class Instance(NamedTuple): + plugin: PluginMeta + core_name: str + definition: List[str] + + @classmethod + def from_namespace(cls, namespace: str, core_name: str, cores: Sequence[CoreLike]) -> 'Instance': + return Instance(PluginMeta.from_namespace(namespace, cores), core_name, []) + + @staticmethod + def get_head(plugin: PluginMeta, core_name: str) -> str: + return f"{instance_start}{core_name}: {plugin.name}" + + def __gt__(self, x: 'Instance', /) -> bool: return self.plugin.__gt__(x.plugin) # type: ignore[override] + def __lt__(self, x: 'Instance', /) -> bool: return self.plugin.__lt__(x.plugin) # type: ignore[override] + def __ge__(self, x: 'Instance', /) -> bool: return self.plugin.__ge__(x.plugin) # type: ignore[override] + def __le__(self, x: 'Instance', /) -> bool: return self.plugin.__le__(x.plugin) # type: ignore[override] + def __eq__(self, x: 'Instance', /) -> bool: return self.plugin.__eq__(x.plugin) # type: ignore[override] + def __ne__(self, x: 'Instance', /) -> bool: return self.plugin.__ne__(x.plugin) # type: ignore[override] + + +def make_instances(plugins: Iterable[PluginMeta]) -> Iterator[Instance]: + for plugin in plugins: + for core_name, _ in plugin.bound: + definition = [ + Instance.get_head(plugin, core_name), + "@property", + f"def {plugin.name}(self) -> {Implementation.get_name(plugin, core_name)}:", + f' """{plugin.description}"""', + instance_end, + ] + yield Instance(plugin, core_name, definition) + + +def locate_or_create_stub_file() -> str: + site_package_dir = path.dirname(vs.__file__) + stub_dir = join_path(site_package_dir, site_package_dirname) + + if not path.exists(stub_dir): + makedirs(stub_dir) + + output_path = join_path(stub_dir, '__init__.pyi') + + for iname in listdir(site_package_dir): + if iname.startswith('VapourSynth-') and iname.endswith('.dist-info'): + break + else: + return output_path + + with open(join_path(site_package_dir, iname, 'RECORD'), 'a+', newline='') as f: + f.seek(0) + + contents = f.read() + + if '__init__.pyi' not in contents: + f.seek(0, SEEK_END) + + if not contents.endswith('\n'): + f.write('\n') + + f.write(f'{site_package_dirname}/__init__.pyi,,\n') + + return output_path + + +def generate_template( + args: Namespace, cores: Sequence[CoreLike], + implementations: List[Implementation], instances: List[Instance], + existing_stubs: Union[Path, None] = None +) -> str: + template = Path(args.pyi_template).read_text() + + if args.plugins and existing_stubs: + existing_implementations = get_existing_implementations(existing_stubs, cores) + existing_instances = get_existing_instances(existing_stubs, cores) + + selected_implementations = [impl.plugin.name for impl in implementations] + selected_instances = [inst.core_name for inst in instances] + + missing_impl = {*existing_implementations} - {*selected_implementations} + + total_core_names = {*existing_instances, *selected_instances} + + implementations.extend([ + existing_implementations[name] for name in missing_impl + ]) + + instances.extend([ + impl[inst_name] + for impl in [ + existing_instances[core_name] for core_name in total_core_names + if core_name in existing_instances + ] + for inst_name in missing_impl + if inst_name in impl + ]) + + if args.exclude_plugin and existing_stubs: + implementations = [x for x in implementations if x.plugin.name not in args.exclude_plugin] + instances = [x for x in instances if x.plugin.name not in args.exclude_plugin] + + implementations = sorted(implementations) + instances = sorted(instances) + + implementation_inject = indent('\n'.join(x.content) for x in implementations) + + template = template.replace('#include ', implementation_inject) + + for core in cores: + this_core_name = core.__class__.__name__ + + this_core_template = '\n'.join( + indent(definition) for _, core_name, definition in instances if core_name == this_core_name + ) + + template = template.replace(f'#include ', this_core_template) + + return template + + +def output_stubs( + args: Namespace, cores: Sequence[CoreLike], implementations: List[Implementation], instances: List[Instance] +) -> None: + existing_stubs: Union[Path, None] = None + + stubs_path = str(args.output) + + if stubs_path == '@' or not stubs_path: + stubs_path = locate_or_create_stub_file() + + stubs = Path(stubs_path) + + if stubs_path != '-': + if not stubs.is_absolute(): + if not stubs.parent: + stubs = stubs.cwd() / stubs + stubs = stubs.absolute() + + if not stubs.suffix: + if stubs.name.lower() == 'vapoursynth': + stubs /= '__init__.pyi' + else: + stubs /= 'vapoursynth.pyi' + + existing_stubs = stubs if stubs.exists() and stubs.is_file() else None + + if existing_stubs and args.force: + existing_stubs.unlink(True) + existing_stubs.touch() + else: + makedirs(stubs.parent, exist_ok=True) + + template = generate_template(args, cores, implementations, instances, existing_stubs) + + out_file = sys.stdout if stubs_path == '-' else open(str(stubs), 'w') + + with out_file: + out_file.write(template) + out_file.flush() + + +def get_existing_implementations(path: Union[str, Path], cores: Sequence[CoreLike]) -> Dict[str, Implementation]: + result: Dict[str, Implementation] = {} + + with open(path, "r") as f: + plugin_name: Optional[str] = None + + for orig_line in f: + line = orig_line.strip() + + if line.startswith(implementation_start): + plugin_name = line[len(implementation_start) + 1:].strip() + result[plugin_name] = Implementation.from_namespace(plugin_name, cores) + + if plugin_name: + result[plugin_name].content.append(orig_line.rstrip()) + + if line.startswith(implementation_end): + plugin_name = None + + return result + + +def get_existing_instances(path: Union[str, Path], cores: Sequence[CoreLike]) -> Dict[str, Dict[str, Instance]]: + result: Dict[str, Dict[str, Instance]] = {} + + with open(path, "r") as f: + core_name: str = '' + plugin_name: Optional[str] = None + + for orig_line in f: + line = orig_line.strip() + + if line.startswith(instance_start): + core_name, plugin_name = instance_bound_pattern.findall(line)[0] + + assert plugin_name + + if core_name not in result: + result[core_name] = {} + + if plugin_name not in result[core_name]: + result[core_name][plugin_name] = Instance.from_namespace( + plugin_name, core_name, cores + ) + + if plugin_name: + result[core_name][plugin_name].definition.append(orig_line.rstrip()[4:]) + + if line.startswith(instance_end): + plugin_name = None + + return result + + +def main(argv: List[str] = sys.argv[1:]): + args = parser.parse_args(args=argv) + + core = load_plugins(args) + + cores: List[CoreLike] = [core, core.std.BlankClip(), core.std.BlankAudio()] + + signatures = list(retrieve_plugins(args, core, cores)) + + implementations = make_implementations(signatures) + instances = make_instances(signatures) + + output_stubs(args, cores, list(implementations), list(instances)) + + +if __name__ == '__main__': + main() diff --git a/Programs/vsrepo.py b/Programs/vsrepo.py new file mode 100644 index 0000000..df1dd41 --- /dev/null +++ b/Programs/vsrepo.py @@ -0,0 +1,929 @@ +## MIT License +## +## Copyright (c) 2018-2020 Fredrik Mellbin +## +## Permission is hereby granted, free of charge, to any person obtaining a copy +## of this software and associated documentation files (the "Software"), to deal +## in the Software without restriction, including without limitation the rights +## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +## copies of the Software, and to permit persons to whom the Software is +## furnished to do so, subject to the following conditions: +## +## The above copyright notice and this permission notice shall be included in all +## copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +## SOFTWARE. + +import argparse +import base64 +import binascii +import csv +import email.utils +import glob +import hashlib +import importlib.util as imputil +import io +import json +import os +import os.path +import re +import subprocess +import sys +import tempfile +import urllib.request +import zipfile +from typing import Iterator, List, MutableMapping, Optional, Tuple + +try: + import winreg +except ImportError: + print('{} is only supported on Windows.'.format(__file__)) + sys.exit(1) + +try: + import tqdm # type: ignore +except ImportError: + pass + +bundled_api3_plugins = ['com.vapoursynth.avisource', 'com.vapoursynth.eedi3', 'com.vapoursynth.imwri', 'com.vapoursynth.misc', 'com.vapoursynth.morpho', 'com.vapoursynth.removegrainvs', 'com.vapoursynth.subtext', 'com.vapoursynth.vinverse', 'org.ivtc.v', 'com.nodame.histogram'] + + +def is_venv() -> bool: + return hasattr(sys, "real_prefix") or (hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix) + + +def detect_vapoursynth_installation() -> str: + try: + spec = imputil.find_spec("vapoursynth") + if spec is None: + raise ModuleNotFoundError() + except (ValueError, ModuleNotFoundError): + print("Could not detect vapoursynth.") + sys.exit(1) + + if not spec.has_location: + try: + import vapoursynth + except ImportError: + print("The vapoursynth-module could not be found or imported.") + else: + return vapoursynth.__file__ + if spec.origin is None: + print("VapourSynth's origin could not be determined.") + sys.exit(1) + return spec.origin + + +def is_sitepackage_install_portable() -> bool: + if args.portable: + return False + + vapoursynth_path = detect_vapoursynth_installation() + return os.path.exists(os.path.join(os.path.dirname(vapoursynth_path), 'portable.vs')) + +def is_sitepackage_install() -> bool: + if args.portable: + return False + + vapoursynth_path = detect_vapoursynth_installation() + base_path = os.path.dirname(vapoursynth_path) + + # We reside in a venv. + if is_venv(): + # VapourSynth has not been installed as a package. + # Assume no site-package install + if len(glob.glob(os.path.join(base_path, 'VapourSynth-*.dist-info'))) == 0: + return False + + if os.path.exists(os.path.join(base_path, "portable.vs")): + return True + + # Assume this is not a global install. + return False + + # We do not reside in a venv. + else: + # pip install vapoursynth-portable + # Install all packages to site-packages and treat them as packages. + if len(glob.glob(os.path.join(base_path, 'VapourSynth_portable-*.dist-info'))) > 0: + return True + + # This is a portable installation, this cannot be a site-package install. + if os.path.exists(os.path.join(base_path, "portable.vs")): + return False + + # This is a global install. Install dist-info files. + return True + +def get_vs_installation_site() -> str: + if is_venv(): + try: + return os.path.dirname(detect_vapoursynth_installation()) + except ImportError: + import setuptools + return os.path.dirname(os.path.dirname(setuptools.__file__)) + + import site + return site.getusersitepackages() + + +is_64bits: bool = sys.maxsize > 2**32 + +parser = argparse.ArgumentParser(description='A simple VapourSynth package manager') +parser.add_argument('operation', choices=['install', 'update', 'upgrade', 'upgrade-all', 'uninstall', 'installed', 'available', 'paths', "genstubs", "gendistinfo"]) +parser.add_argument('package', nargs='*', help='identifier, namespace or module to install, upgrade or uninstall') +parser.add_argument('-f', action='store_true', dest='force', help='force upgrade for packages where the current version is unknown') +parser.add_argument('-p', action='store_true', dest='portable', help='use paths suitable for portable installs') +parser.add_argument('-d', action='store_true', dest='skip_deps', help='skip installing dependencies') +parser.add_argument('-t', choices=['win32', 'win64'], default='win64' if is_64bits else 'win32', dest='target', help='binaries to install, defaults to python\'s architecture') +parser.add_argument('-b', dest='binary_path', help='custom binary install path') +parser.add_argument('-s', dest='script_path', help='custom script install path') +args = parser.parse_args() + +is_64bits = args.target == 'win64' + +file_dirname: str = os.path.dirname(os.path.abspath(__file__)) + +# VSRepo is installed to the site-packages. +if os.path.abspath(file_dirname).startswith(os.path.abspath(sys.prefix)): + file_dirname = os.getcwd() + +if args.portable: + plugin32_path = os.path.join(file_dirname, 'vapoursynth32', 'plugins') + plugin64_path = os.path.join(file_dirname, 'vapoursynth64', 'plugins') +elif is_sitepackage_install_portable(): + vapoursynth_path = detect_vapoursynth_installation() + base_path = os.path.dirname(vapoursynth_path) + plugin32_path = os.path.join(base_path, 'vapoursynth32', 'plugins') + plugin64_path = os.path.join(base_path, 'vapoursynth64', 'plugins') + del vapoursynth_path +else: + pluginparent = [str(os.getenv("APPDATA")), 'VapourSynth'] + plugin32_path = os.path.join(*pluginparent, 'plugins32') + plugin64_path = os.path.join(*pluginparent, 'plugins64') + +if (args.operation in ['install', 'upgrade', 'uninstall']) and ((args.package is None) or len(args.package) == 0): + print('Package argument required for install, upgrade and uninstall operations') + sys.exit(1) + +package_json_path = os.path.join(file_dirname, 'vspackages3.json') if args.portable else os.path.join(*pluginparent, 'vsrepo', 'vspackages3.json') + +if is_sitepackage_install(): + if is_venv(): + try: + import setuptools + site_package_dir: Optional[str] = os.path.dirname(os.path.dirname(setuptools.__file__)) + del setuptools + except ImportError: + site_package_dir = None + else: + import site + site_package_dir = site.getusersitepackages() +else: + site_package_dir = None + +py_script_path: str = file_dirname if args.portable else (site_package_dir if site_package_dir is not None else get_vs_installation_site()) +if args.script_path is not None: + py_script_path = args.script_path + + +plugin_path: str = plugin64_path if is_64bits else plugin32_path +if args.binary_path is not None: + plugin_path = args.binary_path + +os.makedirs(py_script_path, exist_ok=True) +os.makedirs(plugin_path, exist_ok=True) +os.makedirs(os.path.dirname(package_json_path), exist_ok=True) + + +cmd7zip_path: str = os.path.join(file_dirname, '7z.exe') +if not os.path.isfile(cmd7zip_path): + try: + with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\7-Zip', reserved=0, access=winreg.KEY_READ) as regkey: + cmd7zip_path = os.path.join(winreg.QueryValueEx(regkey, 'Path')[0], '7z.exe') + except: + cmd7zip_path = '7z.exe' + +installed_packages: MutableMapping = {} +download_cache: MutableMapping = {} + +def fetch_ur1(url: str, desc: Optional[str] = None) -> bytearray: + with urllib.request.urlopen(url) as urlreq: + if ('tqdm' in sys.modules) and (urlreq.headers['content-length'] is not None): + size = int(urlreq.headers['content-length']) + remaining = size + data = bytearray() + with tqdm.tqdm(total=size, unit='B', unit_scale=True, unit_divisor=1024, desc=desc) as t: + while remaining > 0: + blocksize = min(remaining, 1024*128) + data.extend(urlreq.read(blocksize)) + remaining = remaining - blocksize + t.update(blocksize) + return data + else: + print('Fetching: ' + url) + return urlreq.read() + +def fetch_url_cached(url: str, desc: str = "") -> bytearray: + data = download_cache.get(url, None) + if data is None: + data = fetch_ur1(url, desc) + download_cache[url] = data + return data + +package_print_string = "{:25s} {:15s} {:11s} {:11s} {:s}" + +package_list: Optional[MutableMapping] = None +try: + with open(package_json_path, 'r', encoding='utf-8') as pl: + package_list = json.load(pl) + if package_list is None: + raise ValueError() + if package_list['file-format'] != 3: + print('Package definition format is {} but only version 3 is supported'.format(package_list['file-format'])) + raise ValueError() + package_list = package_list.get('packages') +except (OSError, FileExistsError, ValueError): + pass + +def check_hash(data: bytes, ref_hash: str) -> Tuple[bool, str, str]: + data_hash = hashlib.sha256(data).hexdigest() + return (data_hash == ref_hash, data_hash, ref_hash) + +def get_bin_name(p: MutableMapping): + if p['type'] == 'PyScript': + return 'script' + if p['type'] == 'PyWheel': + return 'wheel' + elif p['type'] == 'VSPlugin': + if is_64bits: + return 'win64' + else: + return 'win32' + else: + raise ValueError('Unknown install type') + +def get_install_path(p: MutableMapping) -> str: + if p['type'] == 'PyScript' or p['type'] == 'PyWheel': + return py_script_path + elif p['type'] == 'VSPlugin': + return plugin_path + else: + raise ValueError('Unknown install type') + +def get_package_from_id(id: str, required: bool = False) -> Optional[MutableMapping]: + if package_list is None: + return None + for p in package_list: + if p['identifier'] == id: + return p + if required: + raise ValueError(f'No package with the identifier {id} found') + return None + +def get_package_from_plugin_name(name: str, required: bool = False) -> Optional[MutableMapping]: + if package_list is None: + return None + for p in package_list: + if p['name'].casefold() == name.casefold(): + return p + if required: + raise ValueError(f'No package with the name {name} found') + return None + +def get_package_from_namespace(namespace: str, required: bool = False) -> Optional[MutableMapping]: + if package_list is None: + return None + for p in package_list: + if 'namespace' in p: + if p['namespace'] == namespace: + return p + if required: + raise ValueError(f'No package with the namespace {namespace} found') + return None + +def get_package_from_modulename(modulename: str, required: bool = False) -> Optional[MutableMapping]: + if package_list is None: + return None + for p in package_list: + if 'modulename' in p: + if p['modulename'] == modulename: + return p + if required: + raise ValueError(f'No package with the modulename {modulename} found') + return None + +def get_package_from_name(name: str) -> MutableMapping: + p = get_package_from_id(name) + if p is None: + p = get_package_from_namespace(name) + if p is None: + p = get_package_from_modulename(name) + if p is None: + p = get_package_from_plugin_name(name) + if p is None: + raise ValueError(f'Package {name} not found') + return p + +def is_package_installed(id: str) -> bool: + return id in installed_packages + +def is_package_upgradable(id: str, force: bool) -> bool: + pkg = get_package_from_id(id, True) + if pkg is None: + return False + lastest_installable = get_latest_installable_release(pkg) + if force: + return (is_package_installed(id) and (lastest_installable is not None) and (installed_packages[id] != lastest_installable['version'])) + else: + return (is_package_installed(id) and (lastest_installable is not None) and (installed_packages[id] != 'Unknown') and (installed_packages[id] != lastest_installable['version'])) + +def get_python_package_name(pkg: MutableMapping) -> str: + if "wheelname" in pkg: + return pkg["wheelname"].replace(".", "_").replace(" ", "_").replace("(", "_").replace(")", "") + else: + return pkg["name"].replace(".", "_").replace(" ", "_").replace("(", "_").replace(")", "") + +def find_dist_version(pkg: MutableMapping, path: Optional[str]) -> Optional[str]: + if path is None: + return None + + name = get_python_package_name(pkg) + versions: List[str] = [] + + for targetname in os.listdir(path): + if (targetname.startswith(f"{name}-") and targetname.endswith(".dist-info")): + # only bother with dist-info dirs that actually have a usable record in case a package uninstall failed to delete the dir + if os.path.isfile(os.path.join(path, targetname, 'RECORD')): + versions.append(targetname[len(name)+1:-10]) + + versions.sort(reverse=True) + return versions[0] if len(versions) > 0 else None + +def detect_installed_packages() -> None: + if package_list is not None: + for p in package_list: + dest_path = get_install_path(p) + if p['type'] == 'PyWheel': + version = find_dist_version(p, dest_path) + if version is not None: + installed_packages[p['identifier']] = version + else: + for v in p['releases']: + matched = True + exists = True + bin_name = get_bin_name(p) + if bin_name in v: + for f in v[bin_name]['files']: + try: + with open(os.path.join(dest_path, f), 'rb') as fh: + if not check_hash(fh.read(), v[bin_name]['files'][f][1])[0]: + matched = False + except FileNotFoundError: + exists = False + matched = False + if matched: + installed_packages[p['identifier']] = v['version'] + break + elif exists: + installed_packages[p['identifier']] = 'Unknown' + else: + print('No valid package definitions found. Run update command first!') + sys.exit(1) + +def print_package_status(p: MutableMapping) -> None: + lastest_installable = get_latest_installable_release(p) + name = p['name'] + if is_package_upgradable(p['identifier'], False): + name = '*' + name + elif is_package_upgradable(p['identifier'], True): + name = '+' + name + print(package_print_string.format(name, p['namespace'] if p['type'] == 'VSPlugin' else p['modulename'], installed_packages.get(p['identifier'], ""), lastest_installable.get('version') if lastest_installable is not None else '', p['identifier'])) + +def list_installed_packages() -> None: + print(package_print_string.format('Name', 'Namespace', 'Installed', 'Latest', 'Identifier')) + for id in installed_packages: + pkg = get_package_from_id(id, True) + if pkg is not None: + print_package_status(pkg) + +def list_available_packages() -> None: + print(package_print_string.format('Name', 'Namespace', 'Installed', 'Latest', 'Identifier')) + if package_list is None: + print("Nothing available to list, please try updating first.") + return + for p in package_list: + print_package_status(p) + +def get_latest_installable_release_with_index(p: MutableMapping) -> Tuple[int, Optional[MutableMapping]]: + max_api = get_vapoursynth_api_version() + package_api: int = 3 + if 'api' in p: + package_api = int(p['api']) + bin_name = get_bin_name(p) + for idx, rel in enumerate(p['releases']): + if not isinstance(rel, MutableMapping): + continue + if bin_name in rel: + bin_api: int = package_api + if 'api' in rel[bin_name]: + bin_api = int(rel[bin_name]['api']) + if bin_api <= max_api and bin_api >= 3: + return (idx, rel) + return (-1, None) + +def get_latest_installable_release(p: MutableMapping) -> Optional[MutableMapping]: + return get_latest_installable_release_with_index(p)[1] + +def can_install(p: MutableMapping) -> bool: + return get_latest_installable_release(p) is not None + + +def make_pyversion(version: str, index: int) -> str: + PEP440REGEX = re.compile(r"(\d+!)?\d+(\.\d+)*((?:a|b|rc)\d+)?(\.post\d+)?(\.dev\d+)?(\+[a-zA-Z0-9]+)?") + + version = version.lower().replace("-", ".") + + if version.startswith("rev"): + return make_pyversion(version[3:], index) + + elif version.startswith("release_"): + return make_pyversion(version[8:], index) + + elif version.startswith("r") or version.startswith("v"): + return make_pyversion(version[1:], index) + + elif version.startswith("test"): + return make_pyversion(version[4:], index) + + elif version.startswith("git:"): + version = version[4:] + return f"{index}+{version}" + + elif PEP440REGEX.match(version): + return version + + else: + return str(index) + + +def rmdir(path: str) -> None: + for path, _, fnames in os.walk(path, topdown=False): + for fname in fnames: + os.remove(os.path.join(path, fname)) + os.rmdir(path) + +# Annotated as Iterator due to https://docs.python.org/3/library/typing.html#typing.Generator +# See the portion about only yielding values, it's an alternative to Generator[str, None, None] +def find_dist_dirs(name: str, path: Optional[str] = site_package_dir) -> Iterator[str]: + if path is None: + return + + for targetname in os.listdir(path): + if not (targetname.startswith(f"{name}-") and targetname.endswith(".dist-info")): + continue + yield os.path.join(path, targetname) + + +def remove_package_meta(pkg: MutableMapping) -> None: + if site_package_dir is None: + return + + name = get_python_package_name(pkg) + + for dist_dir in find_dist_dirs(name): + rmdir(dist_dir) + + +def install_package_meta(files: List[Tuple[str, str, str]], pkg: MutableMapping, rel: MutableMapping, index: int) -> None: + if site_package_dir is None: + return + + name = get_python_package_name(pkg) + + version = make_pyversion(rel["version"], index) + dist_dir = os.path.join(site_package_dir, f"{name}-{version}.dist-info") + + remove_package_meta(pkg) + + os.mkdir(dist_dir) + with open(os.path.join(dist_dir, "INSTALLER"), "w") as f: + files.append((os.path.join(dist_dir, "INSTALLER"), "" ,"")) + f.write("vsrepo") + with open(os.path.join(dist_dir, "METADATA"), "w") as f: + files.append((os.path.join(dist_dir, "METADATA"), "" ,"")) + f.write(f"""Metadata-Version: 2.1 +Name: {name} +Version: {version} +Summary: {pkg.get('description', name)} +Platform: All""") + + with open(os.path.join(dist_dir, "RECORD"), "w", newline="") as f: + files.append((os.path.join(dist_dir, "RECORD"), "", "")) + w = csv.writer(f) + for filename, sha256hex, length in files: + if sha256hex: + sha256hex = "sha256=" + base64.urlsafe_b64encode(binascii.unhexlify(sha256hex.encode("ascii"))).rstrip(b"=").decode("ascii") + try: + filename = os.path.relpath(filename, site_package_dir) + except ValueError: + pass + w.writerow([filename, sha256hex, length]) + + +def install_files(p: MutableMapping) -> Tuple[int, int]: + err = (0, 1) + dest_path = get_install_path(p) + bin_name = get_bin_name(p) + idx, install_rel = get_latest_installable_release_with_index(p) + if install_rel is None: + return err + url = install_rel[bin_name]['url'] + data: Optional[bytearray] = None + try: + data = fetch_url_cached(url, p['name'] + ' ' + install_rel['version']) + except: + print('Failed to download ' + p['name'] + ' ' + install_rel['version'] + ', skipping installation and moving on') + return err + + files: List[Tuple[str, str, str]] = [] + + if bin_name == 'wheel': + try: + hash_result = check_hash(data, install_rel[bin_name]['hash']) + if not hash_result[0]: + raise ValueError('Hash mismatch for ' + url + ' got ' + hash_result[1] + ' but expected ' + hash_result[2]) + with zipfile.ZipFile(io.BytesIO(data), 'r') as zf: + basename: Optional[str] = None + for fn in zf.namelist(): + if fn.endswith('.dist-info/WHEEL'): + basename = fn[:-len('.dist-info/WHEEL')] + break + if basename is None: + raise Exception('Wheel: failed to determine package base name') + for fn in zf.namelist(): + if fn.startswith(basename + '.data'): + raise Exception('Wheel: .data dir mapping not supported') + wheelfile = zf.read(basename + '.dist-info/WHEEL').decode().splitlines() + wheeldict = {} + for line in wheelfile: + tmp = line.split(': ', 2) + if len(tmp) == 2: + wheeldict[tmp[0]] = tmp[1] + if wheeldict['Wheel-Version'] != '1.0': + raise Exception('Wheel: only version 1.0 supported') + if wheeldict['Root-Is-Purelib'] != 'true': + raise Exception('Wheel: only purelib root supported') + zf.extractall(path=dest_path) + with open(os.path.join(dest_path, basename + '.dist-info', 'INSTALLER'), mode='w') as f: + f.write("vsrepo") + with open(os.path.join(dest_path, basename + '.dist-info', 'RECORD')) as f: + contents = f.read() + with open(os.path.join(dest_path, basename + '.dist-info', 'RECORD'), mode='a') as f: + if not contents.endswith("\n"): + f.write("\n") + f.write(basename + '.dist-info/INSTALLER,,\n') + except BaseException as e: + print('Failed to decompress ' + p['name'] + ' ' + install_rel['version'] + ' with error: ' + str(e) + ', skipping installation and moving on') + return err + else: + single_file: Optional[Tuple[str, str, str]] = None + if len(install_rel[bin_name]['files']) == 1: + for key in install_rel[bin_name]['files']: + single_file = (key, install_rel[bin_name]['files'][key][0], install_rel[bin_name]['files'][key][1]) + if (single_file is not None) and (single_file[1] == url.rsplit('/', 2)[-1]): + install_fn = single_file[0] + hash_result = check_hash(data, single_file[2]) + if not hash_result[0]: + raise Exception('Hash mismatch for ' + install_fn + ' got ' + hash_result[1] + ' but expected ' + hash_result[2]) + uninstall_files(p) + os.makedirs(os.path.join(dest_path, os.path.split(install_fn)[0]), exist_ok=True) + with open(os.path.join(dest_path, install_fn), 'wb') as outfile: + files.append((os.path.join(dest_path, install_fn), single_file[2], str(len(data)))) + outfile.write(data) + else: + tffd, tfpath = tempfile.mkstemp(prefix='vsm') + with open(tffd, mode='wb') as tf: + tf.write(data) + result_cache = {} + for install_fn in install_rel[bin_name]['files']: + fn_props = install_rel[bin_name]['files'][install_fn] + result = subprocess.run([cmd7zip_path, "e", "-so", tfpath, fn_props[0]], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + result.check_returncode() + hash_result = check_hash(result.stdout, fn_props[1]) + if not hash_result[0]: + raise Exception('Hash mismatch for ' + install_fn + ' got ' + hash_result[1] + ' but expected ' + hash_result[2]) + result_cache[install_fn] = (result.stdout, fn_props[1]) + uninstall_files(p) + for install_fn in install_rel[bin_name]['files']: + os.makedirs(os.path.join(dest_path, os.path.split(install_fn)[0]), exist_ok=True) + with open(os.path.join(dest_path, install_fn), 'wb') as outfile: + files.append((os.path.join(dest_path, install_fn), str(result_cache[install_fn][1]), str(len(result_cache[install_fn][0])))) + outfile.write(result_cache[install_fn][0]) + os.remove(tfpath) + + install_package_meta(files, p, install_rel, idx) + + installed_packages[p['identifier']] = install_rel['version'] + print('Successfully installed ' + p['name'] + ' ' + install_rel['version']) + return (1, 0) + +def install_package(name: str) -> Tuple[int, int, int]: + p = get_package_from_name(name) + if get_vapoursynth_api_version() <= 3: + if p['identifier'] in bundled_api3_plugins: + print('Binaries are already bundled for ' + p['name'] + ', skipping installation') + return (0, 0, 0) + if can_install(p): + inst = (0, 0, 0) + if not args.skip_deps: + if 'dependencies' in p: + for dep in p['dependencies']: + if not isinstance(dep, str): + continue + res = install_package(dep) + inst = (inst[0], inst[1] + res[0] + res[1], inst[2] + res[2]) + if not is_package_installed(p['identifier']): + fres = install_files(p) + inst = (inst[0] + fres[0], inst[1], inst[2] + fres[1]) + return inst + else: + print('No binaries available for ' + args.target + ' in package ' + p['name'] + ', skipping installation') + return (0, 0, 1) + +def upgrade_files(p: MutableMapping) -> Tuple[int, int, int]: + if can_install(p): + inst = (0, 0, 0) + if 'dependencies' in p: + for dep in p['dependencies']: + if not is_package_installed(dep): + res = install_package(dep) + inst = (inst[0], inst[1] + res[0] + res[1], inst[2] + res[2]) + fres = install_files(p) + return (inst[0] + fres[0], inst[1], inst[2] + fres[1]) + else: + print('No binaries available for ' + args.target + ' in package ' + p['name'] + ', skipping installation') + return (0, 0, 1) + +def upgrade_package(name, force) -> Tuple[int, int, int]: + inst = (0, 0, 0) + p = get_package_from_name(name) + if not is_package_installed(p['identifier']): + print('Package ' + p['name'] + ' not installed, can\'t upgrade') + elif is_package_upgradable(p['identifier'], force): + res = upgrade_files(p) + return (res[0], 0, res[1]) + elif not is_package_upgradable(p['identifier'], True): + print('Package ' + p['name'] + ' not upgraded, latest version installed') + else: + print('Package ' + p['name'] + ' not upgraded, unknown version must use -f to force replacement') + return inst + +def upgrade_all_packages(force: bool) -> Tuple[int, int, int]: + inst = (0, 0, 0) + installed_ids: List[str] = list(installed_packages.keys()) + for id in installed_ids: + if is_package_upgradable(id, force): + pkg = get_package_from_id(id, True) + if pkg is None: + return inst + res = upgrade_files(pkg) + inst = (inst[0] + res[0], inst[1] + res[1], inst[2] + res[2]) + return inst + +def uninstall_files(p: MutableMapping) -> None: + dest_path = get_install_path(p) + bin_name = get_bin_name(p) + + if p['type'] == 'PyWheel': + files: List[str] = [] + pyname = get_python_package_name(p) + for dist_dir in find_dist_dirs(pyname, dest_path): + with open(os.path.join(dest_path, dist_dir, 'RECORD'), mode='r') as rec: + lines = rec.read().splitlines() + for line in lines: + tmp = line.split(',') + if len(tmp) > 0 and len(tmp[0]) > 0: + files.append(tmp[0]) + print(files) + for f in files: + try: + os.remove(os.path.join(dest_path, f)) + except BaseException as e: + print('File removal error: ' + str(e)) + for dist_dir in find_dist_dirs(pyname, dest_path): + rmdir(dist_dir) + else: + installed_rel: Optional[MutableMapping] = None + if p['identifier'] in installed_packages: + for rel in p['releases']: + if rel['version'] == installed_packages[p['identifier']]: + installed_rel = rel + break + if installed_rel is not None: + for f in installed_rel[bin_name]['files']: + os.remove(os.path.join(dest_path, f)) + + remove_package_meta(p) + +def uninstall_package(name: str) -> Tuple[int, int]: + p = get_package_from_name(name) + if is_package_installed(p['identifier']): + if installed_packages[p['identifier']] == 'Unknown': + print('Can\'t uninstall unknown version of package: ' + p['name']) + return (0, 0) + else: + uninstall_files(p) + print('Uninstalled package: ' + p['name'] + ' ' + installed_packages[p['identifier']]) + return (1, 0) + else: + print('No files installed for ' + p['name'] + ', skipping uninstall') + return (0, 0) + +def update_package_definition(url: str) -> None: + localmtimeval = 0.0 + try: + localmtimeval = os.path.getmtime(package_json_path) + except: + pass + localmtime = email.utils.formatdate(localmtimeval + 10, usegmt=True) + req_obj = urllib.request.Request(url, headers={ 'If-Modified-Since': localmtime, 'User-Agent': 'VSRepo' }) + try: + with urllib.request.urlopen(req_obj) as urlreq: + remote_modtime = email.utils.mktime_tz(email.utils.parsedate_tz(urlreq.info()['Last-Modified'])) + data = urlreq.read() + with zipfile.ZipFile(io.BytesIO(data), 'r') as zf: + with zf.open('vspackages3.json') as pkgfile: + with open(package_json_path, 'wb') as dstfile: + dstfile.write(pkgfile.read()) + os.utime(package_json_path, times=(remote_modtime, remote_modtime)) + except urllib.error.HTTPError as httperr: + if httperr.code == 304: + print('Local definitions already up to date: ' + email.utils.formatdate(localmtimeval, usegmt=True)) + else: + raise + else: + print('Local definitions updated to: ' + email.utils.formatdate(remote_modtime, usegmt=True)) + + +def get_vapoursynth_version() -> int: + try: + import vapoursynth + except ImportError: + return 1 + + if hasattr(vapoursynth, "__version__"): + return vapoursynth.__version__[0] + return vapoursynth.core.version_number() + +def get_vapoursynth_api_version() -> int: + try: + import vapoursynth + except ImportError: + return 1 + + if hasattr(vapoursynth, "__api_version__"): + return vapoursynth.__api_version__[0] + # assume lowest widespread api version, will probably error out somewhere else + return 3 + + +def update_genstubs() -> None: + sys.path.append(os.path.dirname(__file__)) + + from vsgenstubs4 import main as genstubs4 + + print("Updating VapourSynth stubs") + + genstubs4([]) + +def rebuild_distinfo() -> None: + print("Rebuilding dist-info dirs for other python package installers") + for pkg_id, pkg_ver in installed_packages.items(): + pkg = get_package_from_id(pkg_id) + if pkg is None: + continue + if pkg['type'] == 'PyWheel': + continue + + for idx, rel in enumerate(pkg["releases"]): + if rel["version"] == pkg_ver: + break + else: + remove_package_meta(pkg) + continue + + dest_path = get_install_path(pkg) + bin_name = get_bin_name(pkg) + files = [ + (os.path.join(dest_path, fn), fd[1], str(os.stat(os.path.join(dest_path, fn)).st_size)) + for fn, fd in rel[bin_name]["files"].items() + ] + + install_package_meta(files, pkg, rel, idx) + + +def print_paths(): + print('Paths:') + print('Definitions: ' + package_json_path) + print('Binaries: ' + plugin_path) + print('Scripts: ' + py_script_path) + + if site_package_dir is not None: + print("Dist-Infos: " + site_package_dir) + else: + print("Dist-Infos: ") + +if args.operation != 'update' and package_list is None: + print('Failed to open vspackages3.json. Run update command.') + sys.exit(1) + +for name in args.package: + try: + assert isinstance(name, str) + get_package_from_name(name) + except Exception as e: + print(e) + sys.exit(1) + +if args.operation == 'install': + detect_installed_packages() + rebuild_distinfo() + + inst = (0, 0, 0) + for name in args.package: + res = install_package(name) + inst = (inst[0] + res[0], inst[1] + res[1], inst[2] + res[2]) + + update_genstubs() + + if (inst[0] == 0) and (inst[1] == 0): + print('Nothing done') + elif (inst[0] > 0) and (inst[1] == 0): + print('{} {} installed'.format(inst[0], 'package' if inst[0] == 1 else 'packages')) + elif (inst[0] == 0) and (inst[1] > 0): + print('{} missing {} installed'.format(inst[1], 'dependency' if inst[1] == 1 else 'dependencies')) + else: + print('{} {} and {} additional {} installed'.format(inst[0], 'package' if inst[0] == 1 else 'packages', inst[1], 'dependency' if inst[1] == 1 else 'dependencies')) + if (inst[2] > 0): + print('{} {} failed'.format(inst[2], 'package' if inst[0] == 1 else 'packages')) +elif args.operation in ('upgrade', 'upgrade-all'): + detect_installed_packages() + rebuild_distinfo() + + inst = (0, 0, 0) + if args.operation == 'upgrade-all': + inst = upgrade_all_packages(args.force) + else: + for name in args.package: + res = upgrade_package(name, args.force) + inst = (inst[0] + res[0], inst[1] + res[1], inst[2] + res[2]) + + update_genstubs() + + if (inst[0] == 0) and (inst[1] == 0): + print('Nothing done') + elif (inst[0] > 0) and (inst[1] == 0): + print('{} {} upgraded'.format(inst[0], 'package' if inst[0] == 1 else 'packages')) + elif (inst[0] == 0) and (inst[1] > 0): + print('{} missing {} installed'.format(inst[1], 'dependency' if inst[1] == 1 else 'dependencies')) + else: + print('{} {} upgraded and {} additional {} installed'.format(inst[0], 'package' if inst[0] == 1 else 'packages', inst[1], 'dependency' if inst[1] == 1 else 'dependencies')) + if (inst[2] > 0): + print('{} {} failed'.format(inst[2], 'package' if inst[0] == 1 else 'packages')) +elif args.operation == 'uninstall': + detect_installed_packages() + uninst = (0, 0) + for name in args.package: + uninst_res = uninstall_package(name) + uninst = (uninst[0] + uninst_res[0], uninst[1] + uninst_res[1]) + if uninst[0] == 0: + print('No packages uninstalled') + else: + print('{} {} uninstalled'.format(uninst[0], 'package' if uninst[0] == 1 else 'packages')) + update_genstubs() +elif args.operation == 'installed': + detect_installed_packages() + list_installed_packages() +elif args.operation == 'available': + detect_installed_packages() + list_available_packages() +elif args.operation == 'update': + update_package_definition('http://www.vapoursynth.com/vsrepo/vspackages3.zip') +elif args.operation == 'paths': + print_paths() +elif args.operation == "genstubs": + update_genstubs() +elif args.operation == "gendistinfo": + detect_installed_packages() + rebuild_distinfo() + + +def noop(): + pass diff --git a/Programs/vsutil/__init__.py b/Programs/vsutil/__init__.py new file mode 100644 index 0000000..3e14a77 --- /dev/null +++ b/Programs/vsutil/__init__.py @@ -0,0 +1,21 @@ +""" +VSUtil. A collection of general-purpose VapourSynth functions to be reused in modules and scripts. +""" + +# export all public function directly +from .clips import * +from .func import * +from .info import * +from .types import * + +# for wildcard imports +_mods = ['clips', 'func', 'info', 'types'] + +__all__ = [] +for _pkg in _mods: + __all__ += __import__(__name__ + '.' + _pkg, fromlist=_mods).__all__ + +try: + from ._metadata import __author__, __version__ +except ImportError: + __author__ = __version__ = 'unknown' diff --git a/Programs/vsutil/_metadata.py b/Programs/vsutil/_metadata.py new file mode 100644 index 0000000..07f0b18 --- /dev/null +++ b/Programs/vsutil/_metadata.py @@ -0,0 +1,2 @@ +__author__ = 'kageru ' +__version__ = '0.8.0' diff --git a/Programs/vsutil/clips.py b/Programs/vsutil/clips.py new file mode 100644 index 0000000..4fe0954 --- /dev/null +++ b/Programs/vsutil/clips.py @@ -0,0 +1,231 @@ +""" +Functions that modify/return a clip. +""" +__all__ = ['depth', 'frame2clip', 'get_y', 'insert_clip', 'join', 'plane', 'split'] + +from typing import Any, List, Optional, Sequence, Union, cast + +import vapoursynth as vs + +from . import func, info, types + +core = vs.core + + +@func.disallow_variable_format +def depth(clip: vs.VideoNode, + bitdepth: int, + /, + sample_type: Optional[Union[int, vs.SampleType]] = None, + *, + range: Optional[Union[int, types.Range]] = None, + range_in: Optional[Union[int, types.Range]] = None, + dither_type: Optional[Union[types.Dither, str]] = None, + ) -> vs.VideoNode: + """A bit depth converter only using ``vapoursynth.core.resize()`` and ``vapoursynth.Format.replace()``. + By default, outputs ``vapoursynth.FLOAT`` sample type for 32-bit and ``vapoursynth.INTEGER`` for anything else. + + >>> src_8 = vs.core.std.BlankClip(format=vs.YUV420P8) + >>> src_10 = depth(src_8, 10) + >>> src_10.format.name + 'YUV420P10' + + >>> src2_10 = vs.core.std.BlankClip(format=vs.RGB30) + >>> src2_8 = depth(src2_10, 8, dither_type=Dither.RANDOM) # override default dither behavior + >>> src2_8.format.name + 'RGB24' + + :param clip: Input clip. + :param bitdepth: Desired `bits_per_sample` of output clip. + :param sample_type: Desired `sample_type` of output clip. Allows overriding default float/integer behavior. + Accepts ``vapoursynth.SampleType`` enums ``vapoursynth.INTEGER`` and ``vapoursynth.FLOAT`` + or their values, ``0`` and ``1`` respectively. + :param range: Output pixel range (defaults to input `clip`'s range). See :class:`Range`. + :param range_in: Input pixel range (defaults to input `clip`'s range). See :class:`Range`. + :param dither_type: Dithering algorithm. Allows overriding default dithering behavior. See :class:`Dither`. + + Defaults to :attr:`Dither.ERROR_DIFFUSION`, or Floyd-Steinberg error diffusion, when downsampling, + converting between ranges, or upsampling full range input. + Defaults to :attr:`Dither.NONE`, or round to nearest, otherwise. + See `_should_dither()` comments for more information. + + :return: Converted clip with desired bit depth and sample type. ``ColorFamily`` will be same as input. + """ + sample_type = types.resolve_enum(vs.SampleType, sample_type, 'sample_type', depth) + range = types.resolve_enum(types.Range, range, 'range', depth) + range_in = types.resolve_enum(types.Range, range_in, 'range_in', depth) + dither_type = types.resolve_enum(types.Dither, dither_type, 'dither_type', depth) + + curr_depth = info.get_depth(clip) + sample_type = func.fallback(sample_type, vs.FLOAT if bitdepth == 32 else vs.INTEGER) + + if (curr_depth, clip.format.sample_type, range_in) == (bitdepth, sample_type, range): + return clip + + should_dither = _should_dither(curr_depth, bitdepth, range_in, range, clip.format.sample_type, sample_type) + dither_type = func.fallback(dither_type, types.Dither.ERROR_DIFFUSION if should_dither else types.Dither.NONE) + + new_format = clip.format.replace(bits_per_sample=bitdepth, sample_type=sample_type).id + + return clip.resize.Point(format=new_format, range=range, range_in=range_in, dither_type=dither_type) + + +_unused: Any = [] + + +def frame2clip(frame: vs.VideoFrame, /, *, enforce_cache=_unused) -> vs.VideoNode: + """Converts a VapourSynth frame to a clip. + + :param frame: The frame to convert. + :param enforce_cache: Forcibly add a cache, even if the ``vapoursynth`` module has this feature disabled. + + :return: A one-frame clip that yields the `frame` passed to the function. + """ + if enforce_cache is not _unused: + import warnings + warnings.warn("enforce_cache is deprecated.", DeprecationWarning) + + bc = core.std.BlankClip( + width=frame.width, + height=frame.height, + length=1, + fpsnum=1, + fpsden=1, + format=frame.format.id + ) + frame = frame.copy() + result = bc.std.ModifyFrame([bc], lambda n, f: frame.copy()) + return result + + +@func.disallow_variable_format +def get_y(clip: vs.VideoNode, /) -> vs.VideoNode: + """Helper to get the luma plane of a clip. + + If passed a single-plane ``vapoursynth.GRAY`` clip, :func:`plane` will assume it to `be` the luma plane + itself and returns the `clip` (no-op). + + :param clip: Input clip. + + :return: Luma plane of the input `clip`. Will return the input `clip` if it is a single-plane grayscale clip. + """ + if clip.format.color_family not in (vs.YUV, vs.GRAY): + raise ValueError('The clip must have a luma plane.') + return plane(clip, 0) + + +def insert_clip(clip: vs.VideoNode, /, insert: vs.VideoNode, start_frame: int) -> vs.VideoNode: + """Convenience method to insert a shorter clip into a longer one. + + The `insert` clip cannot go beyond the last frame of the source `clip` or an exception is raised. + The `insert` clip frames replace the `clip` frames, unlike a normal splice-in. + + :param clip: Longer clip to insert shorter clip into. + :param insert: Insert clip. + :param start_frame: First frame of the longer `clip` to replace. + + :return: Longer clip with frames replaced by the shorter clip. + """ + if start_frame == 0: + return insert + clip[insert.num_frames:] + pre = clip[:start_frame] + frame_after_insert = start_frame + insert.num_frames + if frame_after_insert > clip.num_frames: + raise ValueError('Inserted clip is too long.') + if frame_after_insert == clip.num_frames: + return pre + insert + post = clip[start_frame + insert.num_frames:] + return pre + insert + post + + +def join(planes: Sequence[vs.VideoNode], family: vs.ColorFamily = vs.YUV) -> vs.VideoNode: + """Joins the supplied sequence of planes into a single VideoNode (defaults to YUV). + + >>> planes = [Y, U, V] + >>> clip_YUV = join(planes) + >>> plane = core.std.BlankClip(format=vs.GRAY8) + >>> clip_GRAY = join([plane], family=vs.GRAY) + + :param planes: Sequence of one-plane ``vapoursynth.GRAY`` clips to merge. + :param family: Output color family. + + :return: Merged clip of the supplied `planes`. + """ + return planes[0] if len(planes) == 1 and family == vs.GRAY \ + else core.std.ShufflePlanes(planes, [0, 0, 0], family) + + +@func.disallow_variable_format +def plane(clip: vs.VideoNode, planeno: int, /) -> vs.VideoNode: + """Extracts the plane with the given index from the input clip. + + If given a one-plane clip and ``planeno=0``, returns `clip` (no-op). + + >>> src = vs.core.std.BlankClip(format=vs.YUV420P8) + >>> V = plane(src, 2) + + :param clip: The clip to extract the plane from. + :param planeno: The index of which plane to extract. + + :return: A grayscale clip that only contains the given plane. + """ + if clip.format.num_planes == 1 and planeno == 0: + return clip + return core.std.ShufflePlanes(clip, planeno, vs.GRAY) + + +@func.disallow_variable_format +def split(clip: vs.VideoNode, /) -> List[vs.VideoNode]: + """Returns a list of planes (VideoNodes) from the given input clip. + + >>> src = vs.core.std.BlankClip(format=vs.RGB27) + >>> R, G, B = split(src) + >>> src2 = vs.core.std.BlankClip(format=vs.GRAY8) + >>> split(src2) + [] # always returns a list, even if single plane + + :param clip: Input clip. + + :return: List of planes from the input `clip`. + """ + return [clip] if clip.format.num_planes == 1 else cast(List[vs.VideoNode], clip.std.SplitPlanes()) + + +def _should_dither(in_bits: int, + out_bits: int, + in_range: Optional[types.Range] = None, + out_range: Optional[types.Range] = None, + in_sample_type: Optional[vs.SampleType] = None, + out_sample_type: Optional[vs.SampleType] = None, + ) -> bool: + """ + Determines whether dithering is needed for a given depth/range/sample_type conversion. + + If an input range is specified, and output range *should* be specified otherwise it assumes a range conversion. + + For an explanation of when dithering is needed: + - Dithering is NEVER needed if the conversion results in a float sample type. + - Dithering is ALWAYS needed for a range conversion (i.e. full to limited or vice-versa). + - Dithering is ALWAYS needed to convert a float sample type to an integer sample type. + - Dithering is needed when upsampling full range content with the exception of 8 -> 16 bit upsampling, + as this is simply (0-255) * 257 -> (0-65535). + - Dithering is needed when downsampling limited or full range. + + Dithering is theoretically needed when converting from an integer depth greater than 10 to half float, + despite the higher bit depth, but zimg's internal resampler currently does not dither for float output. + """ + out_sample_type = func.fallback(out_sample_type, vs.FLOAT if out_bits == 32 else vs.INTEGER) + in_sample_type = func.fallback(in_sample_type, vs.FLOAT if in_bits == 32 else vs.INTEGER) + + if out_sample_type == vs.FLOAT: + return False + + range_conversion = in_range != out_range + float_to_int = in_sample_type == vs.FLOAT + upsampling = in_bits < out_bits + downsampling = in_bits > out_bits + + return bool(range_conversion + or float_to_int + or (in_range == types.Range.FULL and upsampling and (in_bits, out_bits) != (8, 16)) + or downsampling) diff --git a/Programs/vsutil/func.py b/Programs/vsutil/func.py new file mode 100644 index 0000000..379ab4b --- /dev/null +++ b/Programs/vsutil/func.py @@ -0,0 +1,142 @@ +from __future__ import annotations +""" +Decorators and non-VapourSynth-related functions. +""" +__all__ = [ + # decorators + 'disallow_variable_format', 'disallow_variable_resolution', + # misc non-vapoursynth related + 'fallback', 'iterate', +] + +import inspect +from functools import partial, wraps +from typing import Union, Any, TypeVar, Callable, cast, overload, Optional + +import vapoursynth as vs + +F = TypeVar('F', bound=Callable) +T = TypeVar('T') +R = TypeVar('R') + + +def _check_variable( + function: F, vname: str, only_first: bool, check_func: Callable[[vs.VideoNode], bool] +) -> Any: + def _check(x: Any) -> bool: + return isinstance(x, vs.VideoNode) and check_func(x) + + @wraps(function) + def _wrapper(*args: Any, **kwargs: Any) -> Any: + for obj in args[:1] if only_first else [*args, *kwargs.values()]: + if _check(obj): + raise ValueError( + f"{function.__name__}: 'Variable-{vname} clips not supported.'" + ) + + if not only_first: + for name, param in inspect.signature(function).parameters.items(): + if param.default is not inspect.Parameter.empty and _check(param.default): + raise ValueError( + f"{function.__name__}: 'Variable-{vname} clip not allowed in default argument `{name}`.'" + ) + + return function(*args, **kwargs) + + return cast(F, _wrapper) + + +@overload +def disallow_variable_format(*, only_first: bool = False) -> Callable[[F], F]: + ... + + +@overload +def disallow_variable_format(function: F | None = None, /) -> F: + ... + + +def disallow_variable_format(function: F | None = None, /, *, only_first: bool = False) -> Callable[[F], F] | F: + """Function decorator that raises an exception if input clips have variable format. + :param function: Function to wrap. + :param only_first: Whether to check only the first argument or not. + + :return: Wrapped function. + """ + + if function is None: + return cast(Callable[[F], F], partial(disallow_variable_format, only_first=only_first)) + + assert function + + return _check_variable( + function, 'format', only_first, lambda x: x.format is None + ) + + +@overload +def disallow_variable_resolution(*, only_first: bool = False) -> Callable[[F], F]: + ... + + +@overload +def disallow_variable_resolution(function: F | None = None, /) -> F: + ... + + +def disallow_variable_resolution(function: F | None = None, /, *, only_first: bool = False) -> Callable[[F], F] | F: + """Function decorator that raises an exception if input clips have variable resolution. + :param function: Function to wrap. + :param only_first: Whether to check only the first argument or not. + + :return: Wrapped function. + """ + + if function is None: + return cast(Callable[[F], F], partial(disallow_variable_resolution, only_first=only_first)) + + assert function + + return _check_variable( + function, 'format', only_first, lambda x: not all({x.width, x.height}) + ) + + +def fallback(value: Optional[T], fallback_value: T) -> T: + """Utility function that returns a value or a fallback if the value is ``None``. + + >>> fallback(5, 6) + 5 + >>> fallback(None, 6) + 6 + + :param value: Argument that can be ``None``. + :param fallback_value: Fallback value that is returned if `value` is ``None``. + + :return: The input `value` or `fallback_value` if `value` is ``None``. + """ + return fallback_value if value is None else value + + +def iterate(base: T, function: Callable[[Union[T, R]], R], count: int) -> Union[T, R]: + """Utility function that executes a given function a given number of times. + + >>> def double(x): + ... return x * 2 + ... + >>> iterate(5, double, 2) + 20 + + :param base: Initial value. + :param function: Function to execute. + :param count: Number of times to execute `function`. + + :return: `function`'s output after repeating `count` number of times. + """ + if count < 0: + raise ValueError('Count cannot be negative.') + + v: Union[T, R] = base + for _ in range(count): + v = function(v) + return v diff --git a/Programs/vsutil/info.py b/Programs/vsutil/info.py new file mode 100644 index 0000000..aaae411 --- /dev/null +++ b/Programs/vsutil/info.py @@ -0,0 +1,244 @@ +""" +Functions that give information about clips or mathematical helpers. +""" +__all__ = ['get_depth', 'get_plane_size', 'get_subsampling', 'get_w', 'is_image', 'scale_value', 'get_lowest_value', 'get_neutral_value', 'get_peak_value'] + +from mimetypes import types_map +from os import path +from typing import Optional, Tuple, TypeVar, Union + +import vapoursynth as vs + +from . import func, types + +core = vs.core + +R = TypeVar('R') +T = TypeVar('T') + + +@func.disallow_variable_format +def get_depth(clip: vs.VideoNode, /) -> int: + """Returns the bit depth of a VideoNode as an integer. + + >>> src = vs.core.std.BlankClip(format=vs.YUV420P10) + >>> get_depth(src) + 10 + + :param clip: Input clip. + + :return: Bit depth of the input `clip`. + """ + return clip.format.bits_per_sample + + +def get_plane_size(frame: Union[vs.VideoFrame, vs.VideoNode], /, planeno: int) -> Tuple[int, int]: + """Calculates the dimensions (width, height) of the desired plane. + + >>> src = vs.core.std.BlankClip(width=1920, height=1080, format=vs.YUV420P8) + >>> get_plane_size(src, 0) + (1920, 1080) + >>> get_plane_size(src, 1) + (960, 540) + + :param frame: Can be a clip or frame. + :param planeno: The desired plane's index. + + :return: Tuple of width and height of the desired plane. + """ + # Add additional checks on VideoNodes as their size and format can be variable. + if isinstance(frame, vs.VideoNode): + if frame.width == 0: + raise ValueError('Cannot calculate plane size of variable size clip. Pass a frame instead.') + if frame.format is None: + raise ValueError('Cannot calculate plane size of variable format clip. Pass a frame instead.') + + width, height = frame.width, frame.height + if planeno != 0: + width >>= frame.format.subsampling_w + height >>= frame.format.subsampling_h + return width, height + + +@func.disallow_variable_format +def get_subsampling(clip: vs.VideoNode, /) -> Union[None, str]: + """Returns the subsampling of a VideoNode in human-readable format. + Returns ``None`` for formats without subsampling. + + >>> src1 = vs.core.std.BlankClip(format=vs.YUV420P8) + >>> get_subsampling(src1) + '420' + >>> src_rgb = vs.core.std.BlankClip(format=vs.RGB30) + >>> get_subsampling(src_rgb) is None + True + + :param clip: Input clip. + + :return: Subsampling of the input `clip` as a string (i.e. ``'420'``) or ``None``. + """ + if clip.format.color_family != vs.YUV: + return None + if clip.format.subsampling_w == 1 and clip.format.subsampling_h == 1: + return '420' + elif clip.format.subsampling_w == 1 and clip.format.subsampling_h == 0: + return '422' + elif clip.format.subsampling_w == 0 and clip.format.subsampling_h == 0: + return '444' + elif clip.format.subsampling_w == 2 and clip.format.subsampling_h == 2: + return '410' + elif clip.format.subsampling_w == 2 and clip.format.subsampling_h == 0: + return '411' + elif clip.format.subsampling_w == 0 and clip.format.subsampling_h == 1: + return '440' + else: + raise ValueError('Unknown subsampling.') + + +def get_w(height: int, aspect_ratio: float = 16 / 9, *, only_even: bool = True) -> int: + """Calculates the width for a clip with the given height and aspect ratio. + + >>> get_w(720) + 1280 + >>> get_w(480) + 854 + + :param height: Input height. + :param aspect_ratio: Aspect ratio for the calculation. (Default: ``16/9``) + :param only_even: Will return the nearest even integer. + ``True`` by default because it imitates the math behind most standard resolutions + (e.g. 854x480). + + :return: Calculated width based on input `height`. + """ + width = height * aspect_ratio + if only_even: + return round(width / 2) * 2 + return round(width) + + +def is_image(filename: str, /) -> bool: + """Returns ``True`` if the filename refers to an image. + + :param filename: String representing a path to a file. + + :return: ``True`` if the `filename` is a path to an image file, otherwise ``False``. + """ + return types_map.get(path.splitext(filename)[-1], '').startswith('image/') + + +def scale_value(value: Union[int, float], + input_depth: int, + output_depth: int, + range_in: Union[int, types.Range] = 0, + range: Optional[Union[int, types.Range]] = None, + scale_offsets: bool = False, + chroma: bool = False, + ) -> Union[int, float]: + """Scales a given numeric value between bit depths, sample types, and/or ranges. + + >>> scale_value(16, 8, 32, range_in=Range.LIMITED) + 0.0730593607305936 + >>> scale_value(16, 8, 32, range_in=Range.LIMITED, scale_offsets=True) + 0.0 + >>> scale_value(16, 8, 32, range_in=Range.LIMITED, scale_offsets=True, chroma=True) + -0.5 + + :param value: Numeric value to be scaled. + :param input_depth: Bit depth of the `value` parameter. Use ``32`` for float sample type. + :param output_depth: Bit depth to scale the input `value` to. + :param range_in: Pixel range of the input `value`. No clamping is performed. See :class:`Range`. + :param range: Pixel range of the output `value`. No clamping is performed. See :class:`Range`. + :param scale_offsets: Whether or not to apply YUV offsets to float chroma and/or TV range integer values. + (When scaling a TV range value of ``16`` to float, setting this to ``True`` will return ``0.0`` + rather than ``0.073059...``) + :param chroma: Whether or not to treat values as chroma instead of luma. + + :return: Scaled numeric value. + """ + range_in = types.resolve_enum(types.Range, range_in, 'range_in', scale_value) + range = types.resolve_enum(types.Range, range, 'range', scale_value) + range = func.fallback(range, range_in) + + if input_depth == 32: + range_in = 1 + + if output_depth == 32: + range = 1 + + def peak_pixel_value(bits: int, range_: Union[int, types.Range], chroma_: bool) -> int: + """ + _ + """ + if bits == 32: + return 1 + if range_: + return (1 << bits) - 1 + return (224 if chroma_ else 219) << (bits - 8) + + input_peak = peak_pixel_value(input_depth, range_in, chroma) + + output_peak = peak_pixel_value(output_depth, range, chroma) + + if input_depth == output_depth and range_in == range: + return value + + if scale_offsets: + if output_depth == 32 and chroma: + value -= 128 << (input_depth - 8) + elif range and not range_in: + value -= 16 << (input_depth - 8) + + value *= output_peak / input_peak + + if scale_offsets: + if input_depth == 32 and chroma: + value += 128 << (output_depth - 8) + elif range_in and not range: + value += 16 << (output_depth - 8) + + return value + + +@func.disallow_variable_format +def get_lowest_value(clip: vs.VideoNode, chroma: bool = False) -> float: + """Returns the lowest possible value for the combination + of the plane type and bit depth/type of the clip as float. + + :param clip: Input clip. + :param chroma: Whether to get luma (default) or chroma plane value. + + :return: Lowest possible value. + """ + is_float = clip.format.sample_type == vs.FLOAT + + return -0.5 if chroma and is_float else 0. + + +@func.disallow_variable_format +def get_neutral_value(clip: vs.VideoNode, chroma: bool = False) -> float: + """Returns the neutral value for the combination + of the plane type and bit depth/type of the clip as float. + + :param clip: Input clip. + :param chroma: Whether to get luma (default) or chroma plane value. + + :return: Neutral value. + """ + is_float = clip.format.sample_type == vs.FLOAT + + return (0. if chroma else 0.5) if is_float else float(1 << (get_depth(clip) - 1)) + + +@func.disallow_variable_format +def get_peak_value(clip: vs.VideoNode, chroma: bool = False) -> float: + """Returns the highest possible value for the combination + of the plane type and bit depth/type of the clip as float. + + :param clip: Input clip. + :param chroma: Whether to get luma (default) or chroma plane value. + + :return: Highest possible value. + """ + is_float = clip.format.sample_type == vs.FLOAT + + return (0.5 if chroma else 1.) if is_float else (1 << get_depth(clip)) - 1. diff --git a/Programs/vsutil/py.typed b/Programs/vsutil/py.typed new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Programs/vsutil/py.typed @@ -0,0 +1 @@ + diff --git a/Programs/vsutil/types.py b/Programs/vsutil/types.py new file mode 100644 index 0000000..f531b10 --- /dev/null +++ b/Programs/vsutil/types.py @@ -0,0 +1,89 @@ +""" +Enums and related functions. +""" +__all__ = ['Dither', 'Range', 'EXPR_VARS', 'resolve_enum'] + +# this file only depends on the stdlib and should stay that way +from enum import Enum +from typing import Any, Callable, Optional, Type, TypeVar, Union + +E = TypeVar('E', bound=Enum) + + +class _NoSubmoduleRepr: + def __repr__(self): + """Removes submodule name from standard repr, helpful since we re-export everything at the top-level.""" + return '<%s.%s.%s: %r>' % (self.__module__.split('.')[0], self.__class__.__name__, self.name, self.value) + + +class Dither(_NoSubmoduleRepr, str, Enum): + """ + Enum for `zimg_dither_type_e`. + """ + NONE = 'none' + """Round to nearest.""" + ORDERED = 'ordered' + """Bayer patterned dither.""" + RANDOM = 'random' + """Pseudo-random noise of magnitude 0.5.""" + ERROR_DIFFUSION = 'error_diffusion' + """Floyd-Steinberg error diffusion.""" + + +class Range(_NoSubmoduleRepr, int, Enum): + """ + Enum for `zimg_pixel_range_e`. + """ + LIMITED = 0 + """Studio (TV) legal range, 16-235 in 8 bits.""" + FULL = 1 + """Full (PC) dynamic range, 0-255 in 8 bits.""" + + +EXPR_VARS: str = 'xyzabcdefghijklmnopqrstuvw' +""" +This constant contains a list of all variables that can appear inside an expr-string ordered +by assignment. So the first clip will have the name *EXPR_VARS[0]*, the second one will +have the name *EXPR_VARS[1]*, and so on. + +This can be used to automatically generate expr-strings. +""" + + +def _readable_enums(enum: Type[Enum]) -> str: + """ + Returns a list of all possible values in `enum`. + Since VapourSynth imported enums don't carry the correct module name, use a special case for them. + """ + if 'importlib' in enum.__module__: + return ', '.join([f'' for i in enum]) + else: + return ', '.join([repr(i) for i in enum]) + + +def resolve_enum(enum: Type[E], value: Any, var_name: str, fn: Optional[Callable] = None) -> Union[E, None]: + """ + Attempts to evaluate `value` in `enum` if value is not ``None``, otherwise returns ``None``. + + >>> def my_fn(family: Optional[int]): + ... return resolve_enum(vs.ColorFamily, family, 'family', my_fn) + >>> my_fn(None) + None + >>> my_fn(3) + + >>> my_fn(9) + ValueError: my_fn: family must be in , , ... + + :param enum: Enumeration, i.e. ``vapoursynth.ColorFamily``. + :param value: Value to check. Can be ``None``. + :param var_name: User-provided parameter name that needs to be checked. + :param fn: Function that should be causing the exception (used for error message only). + + :return: The enum member or ``None``. + """ + if value is None: + return None + try: + return enum(value) + except ValueError: + raise ValueError(f"{fn.__name__ + ': ' if fn else ''}{var_name} must be in {_readable_enums(enum)}.") from None