vapoursynth-analog
August 24, 2026 · View on GitHub
VapourSynth source and filters plugin for working with digitized analog video and signals.
See documentation for full details including API reference.
What it does
- Decodes 4𝑓𝑠𝑐-sampled captures to 32-bit float clips: time-base-corrected
.tbcfiles from ld-decode and vhs-decode, and the newer CVBS format (.cvbs, or.cvbsy/.cvbscfor separated luma/chroma). NTSC (Comb), PAL (Transform/PalColour), SECAM, and neural-network composite decoders are available, the last running on CPU, GPU, or Apple Neural Engine. - Handles dropouts three ways: correction during decode, from the capture itself or from additional captures of the same content; annotation as frame properties that survive trimming and splicing; and a mask clip for your own repair filters.
- Modernizes colorimetry: analog-era primaries and transfer characteristics to BT.709, sRGB, BT.2020 SDR or BT.2100 PQ/HLG in one color-managed step, on any clip, whether a fresh decode or a conventional capture.
- Adjusts chroma gain in analog terms: a gain on the color-difference signals, not the saturation axis of an HSV model.
- Turns SECAM's 4:4:0 lattice into a conventional raster, by resampling or delay-line fill.
High-level Python API
If installed as a Python distribution (e.g. with pip or uv), the vsanalog
Python module wraps the plugin's lower-level API with a type-hinted interface
that loads the plugin automatically. vsanalog.decode_4fsc_video(…) is the
starting point, returning 32-bit float clips: YUV444PS (default), RGBS
(color_family="rgb"), GRAYS (color_family="gray"), or YUV440PS for
SECAM.
Example:
import vapoursynth as vs
import vsanalog
import vsdeinterlace # from vsjetpack
src = vsanalog.decode_4fsc_video(
'./Sources/my_home_video.tbc',
'./Sources/my_home_movie_chroma.tbc',
decoder='ntsc3d'
)
deinterlaced = vsdeinterlace.QTempGaussMC().deinterlace(src)
modern = vsanalog.modernize_chromaticity(
deinterlaced,
primaries_in_s='ntsc-1953',
output_preset='hdtv'
)
universal = modern.resize.Spline36(
format=vs.YUV420P8,
chromaloc=vs.CHROMA_LEFT,
dither_type='random'
)
universal.set_output(0)
The source decode and color conversion above use vsanalog; the rest are ordinary VapourSynth or 3rd-party modules. The Recipes page has complete scripts for cropping out caption data, inverting telecine, CRT-style interlaced display, deinterlacing, and denoising.
Low-level VapourSynth Plugin API
Whether installed as a Python distribution or if the plugin library is dropped
in a VapourSynth plugins directory, the plugin exposes a namespace named
analog available on the vapoursynth.core object. It carries the natively
implemented functions decode_4fsc_video, create_dropouts_mask,
modernize_chromaticity, amplify_chroma, and set_log_level. Low-level API
example:
from vapoursynth import core
src = core.analog.decode_4fsc_video(
'my_big_production.tbc',
dropout_correct=True
)
SECAM helpers and dropout_spans are Python-side conveniences available only
through the higher-level vsanalog module.
Layout
| Directory | Description |
|---|---|
src/ | C++ VapourSynth plugin source (plugin entrypoint + libchromadec wrapper) |
python/ | Python package (vsanalog) with type-hinted wrapper and PyInstaller hooks |
subprojects/ | Meson wrap for libchromadec |
tools/ | NN model manifest + fetch/convert helpers used at build time |
docs/ | Sphinx documentation source |
Installing
The simplest way to install is via pip into a Python environment such as a venv:
pip install vsanalog
This installs both the native plugin and a Python module with type-hinted
wrappers like vsanalog.decode_4fsc_video. The plugin is automatically loaded
when you use the Python module.
Alternatively, obtain or
build
the plugin for your operating system and place vsanalog.dll, vsanalog.dylib,
or vsanalog.so into your VapourSynth plugins directory. The released plugin
binaries need only VapourSynth (>= R55): libchromadec, its SQLite, and FFTW
are linked into the plugin. The standalone plugin differs from the wheel in two
ways: neural-network decoders are only available on macOS (thanks to native
CoreML), and no model weights are bundled, so neural decoding through them
takes a model_path you supply.
GPU-accelerated neural decoding
The PyPI wheels run neural decoders on CPU (Linux), on any DX12 GPU via DirectML with CPU fallback (Windows), or on Apple CoreML (macOS). The remaining GPU-execution-provider wheels are too large for PyPI and are published on the project's own package index, one channel per vendor runtime: TensorRT/CUDA (Nvidia) for Linux and Windows, MIGraphX (AMD) for Linux. Add the channel for yours as an extra index:
pip install vsanalog --extra-index-url https://py.justinarthur.com/cu13/ # CUDA 13
pip install vsanalog --extra-index-url https://py.justinarthur.com/cu12/ # CUDA 12 (pre-Turing cards)
pip install vsanalog --extra-index-url https://py.justinarthur.com/rocm7/ # MIGraphX on ROCm 7
vsanalog[tensorrt] on a CUDA channel pulls in the matching TensorRT and
CUDA libraries from PyPI as a convenience (vsanalog[cuda] for the CUDA
runtime alone). These would be needed if you didn't already have them
installed environment-wide. See the
installation guide for details.
Implementation Notes
Signal decoding functionality comes from libchromadec, a C-ABI library started from the original ld-chroma-decoder. It's pulled in as a Meson git wrap and linked statically, along with the trimmed SQLite it bundles, so this plugin has no Qt or system-SQLite dependency at all. libchromadec supplies the composite separation/transformation decoders (NTSC/PAL/SECAM/mono), the CVBS and TBC readers, dropout masks and corrections, and the neural-network decoders.
To ease legal distribution, this project is available under the GPL 3 or later license, matching libchromadec and its inherited ld-decode history.
Machine learning models have been employed at times in the development of this plugin.
Alternatives
- jsaowji’s ldzeug2 is an excellent
alternative VapourSynth video source for TBC files that pioneered the neural
network approaches to separating composited luma and chroma components.
vapoursynth-analog now exposes those models too (via libchromadec's
ldzeug2_color_cnn/ldzeug2_luma_sepdecoders). ldzeug2 moves more 4𝑓𝑠𝑐 processing to the Python domain for flexible scripting; it focuses on composite NTSC, ST 170, and Japan format signals. - ifb's vapoursynth-composite can take decodes, conventional captures, and BT.601-sampled sources like DV and DVD back into digitized composite form for analog-domain repairs and improvements.
- tbc-tools comes with an
ld-chroma-decodertool to decode TBC files to component R′G′B′ or Y′ C′b C′r stream output for use in command line workflows and anld-dropout-correcttool for generating a pre-corrected intermediate based on upstream dropout detection. Split from the original ld-decode project's tools dir. - tbc-video-export is a convenient wrapper around ld-chroma-decoder and ffmpeg for producing digital video files from TBC files. It’s handy if you need to deliver a lossless interlaced intermediate to someone else for filtering or color grading.
- decode-orc helps orchestrate processing and filtration of TBC/CVBS signal data, providing a filter graph like VapourSynth's but in a closer-to-analog space. Also provides a plugin API and an R′G′B′ or Y′ C′b C′r output sink with similar code heritage as libchromadec's.