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

image

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_dispatch supports create_release and release_tag inputs.
  • Artifact names are versioned and architecture-scoped:
    • decode-rust-gui-linux_<version>_<arch>.zip / .AppImage
    • decode-rust-gui-windows_<version>_<arch>.exe / .zip
    • decode-rust-gui-macos_<version>_<arch>.dmg / .zip
  • Version is resolved from tags (v*) or scripts/ci/git-version.sh fallback (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.