Skip to content

VHS Processing

vhs-service contains two worker modules for an analogue-video workflow:

  1. vhs-decode turns an RF capture into time-base-corrected data and sidecars.
  2. tbc-decode turns those artifacts into a viewable video file.

Exactly one module runs in each process, selected by the command's positional service token.

Stage 1: RF capture to TBC

The vhs_decode job requires:

FieldMeaning
input_sourceRF capture URI, such as .ldf, .lds, .flac, .s16, or .u8.
output_sourceDestination for the decoded .tbc file.
sidecar_output_sourceDestination for the .tbc.json metadata sidecar.
chroma_output_sourceOptional _chroma.tbc destination for Y/C-separated formats.

The following vhs_decode parameters decode an NTSC VHS RF capture and write the TBC artifacts locally:

json
{
  "input_source": "rsync://capture@host/rf/tape.ldf",
  "output_source": "file:///work/tape.tbc",
  "sidecar_output_source": "file:///work/tape.tbc.json",
  "tape_format": "vhs",
  "video_system": "ntsc",
  "tape_speed": "SP"
}

Supported tape formats are vhs, svhs, umatic, umatic_hi, betamax, betamax_hifi, video8, hi8, and edit_betacam. Video systems are pal, pal-m, ntsc, ntsc-j, and mesecam; tape speeds are SP, LP, EP, ELP, and VP.

Optional controls cover sample frequency, threads, frame/sample ranges, level detection, sharpness, chroma filtering, dropout detection, clamping, and an advanced params file. The service-published JSON Schema is the authoritative field list.

Stage 2: TBC to video

The tbc_decode job requires:

FieldMeaning
input_source.tbc luma or combined capture.
sidecar_sourceMatching .tbc.json metadata.
output_sourceDestination video URI.

chroma_source is optional for composite captures and needed for Y/C-separated captures.

The following tbc_decode parameters convert the staged artifacts to an FFV1 video file:

json
{
  "input_source": "file:///work/tape.tbc",
  "sidecar_source": "file:///work/tape.tbc.json",
  "chroma_source": "file:///work/tape_chroma.tbc",
  "output_source": "s3://archive/tape.mkv",
  "profile": "ffv1",
  "pixel_format": "yuv422",
  "bit_depth": "10bit",
  "field_order": "tff"
}

Output controls include video system, chroma decoder, profile/container, pixel format, bit depth, field order, anamorphic mode, luma-only mode, two-step export, metadata export, audio tracks, hardware acceleration, and an advanced configuration file.

Key enums include:

  • chroma decoder: MONO, PAL2D, TRANSFORM2D, TRANSFORM3D, NTSC2D;
  • pixel format: gray, yuv420, yuv422, yuv444;
  • bit depth: 8bit, 10bit, 16bit;
  • field order: auto, tff, bff, prog.

Starting modules

Use serve, worker, or hybrid with one service token:

bash
vhs-service hybrid vhs-decode
vhs-service hybrid tbc-decode

The development tasks use separate containers:

bash
mise run dev:vhs-decode-service
mise run dev:tbc-service

Configuration lives under services.vhs-decode and services.tbc-decode in vhs-service/config.yaml. Each section has its own service ID, database, Kafka topic, consumer group, River limits, health interval, and gRPC address.

Resource planning

The default configuration runs one River worker per process with a 60-minute timeout. RF and TBC artifacts are large, so place worker staging storage on a volume with enough free space for inputs, sidecars, temporary output, and final output.

Released under the MIT License.