# VapourSynth

Canonical URL: https://encode.wiki/tools/filtering/vapoursynth/
Content version: ca42e61ede0a24f789d7287a0001244ad22f4abf
Status: current
License: CC BY-SA 4.0
Checksum (SHA-256): 86701458ce76914f1387ecfebc0716d45cdc0f928e5cb9540e2a136383b1a742

> **Repository:** [vapoursynth/vapoursynth](https://github.com/vapoursynth/vapoursynth). A video processing framework with simplicity in mind. Latest release: [R81](https://github.com/vapoursynth/vapoursynth/releases/tag/R81), Oct 4, 2026. Last commit: Oct 7, 2026. License: LGPL-2.1. Stars: 2,108.

VapourSynth is a video filtering framework driven by Python scripts. A script describes a chain of filters; a program such as `vspipe`, an encoder or a previewer then requests frames from it. It is not an encoder or a player, and it has no GUI of its own. It is where most of the encoding community's filtering work happens, because it is scriptable, fast, and has a large plugin ecosystem. The older [AviSynth](https://avisynth.nl/index.php/Main_Page) does the same job, and plenty of people still use it, but the filters this section describes are VapourSynth's.

Scripts are plain Python, and you don't need to know much Python to write them.

## Install

On any platform with Python 3.12 or newer, `pip install vapoursynth` followed by `vapoursynth config` installs the core and `vspipe`. On Windows the official installer or the portable package are alternatives; most Linux distributions also package it.

Plugins and script collections come from several places. The simplest route for the filters on these pages is [vs-jetpack](https://github.com/Jaded-Encoding-Thaumaturgy/vs-jetpack), a collection of Python modules (`vstools`, `vskernels`, `vsdenoise`, `vsdeband`, `vsdehalo`, `vsaa`, `vsdeinterlace`, `vsscale`, `vssource`, `vsmasktools` and others) whose extras also install the native plugins they call as wheels:

```sh
pip install "vsjetpack[full]" --extra-index-url https://jaded-encoding-thaumaturgy.github.io/vs-wheels/simple
```

> **Caution.**
>
> vapoursynth-mvutensils 10 (8 October 2026) removed arguments that vs-jetpack 2.2.6 still passes, so `QTempGaussMC` and `mc_degrain` fail with `AnalyseMany: Function does not take argument(s) named fields`. Until vs-jetpack catches up, add `"vapoursynth-mvutensils<10"` to the install command.
Not every plugin has a wheel for every platform; for the rest use [VSRepo](https://github.com/vapoursynth/vsrepo) (`pip install vsrepo`, then `vsrepo install <plugin>`), your distribution's packages, or build from source. vs-jetpack replaces the older collections: the standalone `vs-tools`/`vs-dehalo` repositories are deprecated, and `havsfunc` has dropped nearly all its functions, QTGMC included, in favour of vs-jetpack.

## Previewing

You'll want to see frames while tuning. [VSView](https://jaded-encoding-thaumaturgy.github.io/vs-view/) (`pip install vsview`, then `vsview script.vpy`) is the current JET previewer and replaces vs-preview, whose repository is now archived. [VapourSynth Editor](https://github.com/YomikoR/VapourSynth-Editor) bundles a code editor with a previewer, which is the easiest start for newcomers. A previewer also lets you compare before/after at the same frame number, which is how filter settings should be judged.

## Loading a source

A script has to load a video through a source plugin:

| Plugin                                                                                  | Notes                                                                                                                                                                   |
| --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [BestSource](https://github.com/vapoursynth/bestsource) (`bs`)                          | Frame-accurate for every format, including awkward seeking. The first load decodes the whole file to build an index, then it is cached. VC-1 cannot be seeked reliably. |
| [L-SMASH-Works](https://github.com/HomeOfAviSynthPlusEvolution/L-SMASH-Works) (`lsmas`) | Fast and usually reliable for MP4, MKV and TS. Can return wrong frames after seeking in some inputs (VC-1 is the classic case).                                         |
| [ffms2](https://github.com/FFMS/ffms2) (`ffms2`)                                        | FFmpeg-based; a good fallback if L-SMASH-Works has trouble with a file.                                                                                                 |

```python
import vapoursynth as vs
core = vs.core

clip = core.bs.VideoSource("input.mkv")
# or: core.lsmas.LWLibavSource("input.mkv"), core.ffms2.Source("input.mkv")
clip.set_output()
```

If seeking is unreliable for a source and you need random access, for example because you're splitting it for [Av1an](/tools/utilities/av1an/), encode it to a lossless intermediate first. The latest Av1an release can't load VapourSynth R73 or newer; see the [Av1an page](/tools/utilities/av1an/) for what to use instead.

With vs-jetpack, `vssource` wraps all three (`BestSource`, `LSMAS`, `FFMS2`) and also converts bit depth and fills in colour properties; see [basics](/tools/filtering/basics/#starting-script). BestSource keeps its index in a cache directory (`~/bsindex` on Linux unless `XDG_CACHE_HOME` is set); `cachemode=3` writes it next to the source instead. L-SMASH-Works and ffms2 write theirs next to the source by default.

## Getting frames out

`vspipe` renders a script's output. Most encoders read Y4M from a pipe:

```sh
vspipe -c y4m script.vpy - | x264 --demuxer y4m --crf 18 -o output.mkv -
vspipe -c y4m script.vpy - | SvtAv1EncApp -i stdin --crf 30 --preset 6 -b output.ivf
vspipe -c y4m script.vpy - | x265 --y4m --crf 20 -o output.hevc -
vspipe -c y4m script.vpy - | ffmpeg -f yuv4mpegpipe -i - -c:v libsvtav1 -crf 30 output.mkv
```

Y4M carries the resolution, frame rate and pixel format, so the encoder needs no extra arguments. It does not carry audio, and vspipe does not give you a muxed file: encode video, then mux with the audio and subtitles from the source (see [audio and subtitles](/guides/audio-and-subtitles/)).

Useful `vspipe` options:

| Option          | Use                                                                                                       |
| --------------- | --------------------------------------------------------------------------------------------------------- |
| `--info`        | Print the output's resolution, frame rate and format without rendering. Run this after changing a script. |
| `-s N`, `-e N`  | Render only a frame range; the end frame is inclusive. Good for test encodes.                             |
| `-a key=value`  | Pass a value (a string) into the script as a global variable.                                             |
| `-o N`          | Select which `set_output(N)` clip to render.                                                              |
| `-p`            | Show progress on stderr.                                                                                  |
| `-t FILE`       | Write a timecodes v2 file, needed to keep timing for variable frame rate sources.                         |
| `--filter-time` | Report how long each filter took, to find the slow one.                                                   |

Filters that use a lot of memory or threads can bring a machine down on a long encode. Cap the cache and thread count in the script with `core.max_cache_size` and `core.num_threads`, and render a short range first.

## Related pages

- [Basics of filtering](/tools/filtering/basics/)
- [FFmpeg](/tools/utilities/ffmpeg/)
- [Av1an](/tools/utilities/av1an/)
- [SVT-AV1](/tools/software-encoders/svt-av1/)
