tape-decode
September 7, 2026 ยท View on GitHub
A decoder for analog videotape tape formats, written in Rust. Ported from the vhs-decode project, with a cut off at commit fe3f6099.
GUI
Installation
You can install for Windows / MacOS / Linux for x86 and ARM64 via self-contained binary releases here
For x86-64, ensure you use the correct one for your CPU feature level.
Use nightly Rust for new feature testing builds.
From source
RUSTFLAGS="-C target-cpu=native" cargo build --release
Usage
tape-decode --help
Decode Launcher GUI (decode-rust-gui)
The repository includes a Qt6 launcher (decode.py + decode_launcher.py) modeled after the vhs-decode Decode Launcher and wired to tape-decode.
Run from source
python3 -m venv .venv-launcher
source .venv-launcher/bin/activate
python -m pip install -r requirements-launcher.txt
python decode.py
If your distro uses an externally-managed Python environment (PEP 668), use this venv flow instead of installing launcher dependencies into system Python.
The launcher defaults to guided tape-decode decode command creation (profile/output/frequency/threads), and can also run list-profiles, compare, and write-profile in a terminal.
CLI passthrough via dispatcher
decode.py also forwards normal CLI args directly to tape-decode:
python3 decode.py decode --profile PAL_VHS --luma-out out.tbc capture.flac
Build/package notes
- Windows EXE launcher bundle:
scripts/ci/build-windows-decode-bin.py - macOS app bundle launcher:
scripts/ci/build-macos-decode-bin.py - Linux launcher binary for AppImage staging:
scripts/ci/build-linux-decode-bin.py - Shared Git version resolver (MISRC-style):
scripts/ci/git-version.sh
Linux local packaging sequence (matching CI workflow):
cargo build --release --target x86_64-unknown-linux-gnu --bin tape-decode
source .venv-launcher/bin/activate
python -m pip install pyinstaller -r requirements-launcher.txt
TAPE_DECODE_BIN=target/x86_64-unknown-linux-gnu/release/tape-decode \
python scripts/ci/build-linux-decode-bin.py
For Linux arm64 local builds, replace x86_64-unknown-linux-gnu with aarch64-unknown-linux-gnu in both commands.
GitHub Actions release formatting now mirrors MISRC:
workflow_dispatchsupportscreate_releaseandrelease_taginputs.- Artifact names are versioned and architecture-scoped:
decode-rust-gui-linux_<version>_<arch>.zip/.AppImagedecode-rust-gui-windows_<version>_<arch>.exe/.zipdecode-rust-gui-macos_<version>_<arch>.dmg/.zip
- Version is resolved from tags (
v*) orscripts/ci/git-version.shfallback (dev-<sha>style).
For release artifacts, trigger:
.github/workflows/build_windows_decode.yml.github/workflows/build_macos_decode.yml.github/workflows/build_linux_decode.yml
Examples
List available profiles
tape-decode list-profiles
Output:
405_BETAMAX
819_QUADRUPLEX
MESECAM_VHS
...
Decode a 40 MHz PAL VHS tape from capture.flac
tape-decode decode \
--luma-out decoded.tbc \
--chroma-out decoded_chroma.tbc \
--metadata-out decoded.tbc.json \
--profile PAL_VHS \
--frequency 40 \
--input-format flac \
capture.flac
Decode a 16 MHZ NTSC VHS tape from capture.u8, with 16 threads and 60 field per-thread offset
tape-decode decode \
--luma-out decoded.tbc \
--chroma-out decoded_chroma.tbc \
--metadata-out decoded.tbc.json \
--profile NTSC_VHS \
--frequency 16 \
--mt-threads 16 \
--mt-distance-size 60 \
capture.u8
Livestream 40 MHz PAL VHS from /dev/cxadc0
cat /dev/cxadc0 \
| tape-decode decode \
--luma-out - \
--profile PAL_VHS \
--frequency 40 \
--mt-threads 16 \
--mt-distance-size 60 \
- \
| ffmpeg \
-f rawvideo \
-pixel_format gray16le \
-video_size 1135x626 \
-r 25 \
-i - \
-f yuv4mpegpipe \
-filter:v "format=yuv444p" \
- \
| mpv -
Using in your project
The tape-decode crate hosting the main decoder can be used as a library in your Rust project. You can also use a cdylib to call the decoder from other languages.
License
This project is based on vhs-decode, which is licensed under GPL-3.0. The Rust port is also licensed under GPL-3.0. See COPYING for details.