Skip to content

ktauchathuranga/sstv

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SSTV - Slow Scan Television Encoder

Rust License: MIT

Rust implementation of an SSTV (Slow Scan Television) audio encoder. This tool converts images to audio signals that can be transmitted over radio and decoded by SSTV receivers worldwide.

Sample decoded APT signal

Features

  • 12 SSTV Modes: Martin 1/2, Scottie 1/2/DX, Robot 36/72, PD 120/180/290, BW 8/12
  • Real-time Audio Playback: Stream directly to your sound card
  • WAV File Export: Generate standard WAV files for later transmission
  • Automatic Image Resizing: Lanczos3 resampling for optimal quality
  • Sample Rate Independent: Works with 44.1kHz, 48kHz, or any sample rate
  • Library + CLI: Use as a library in your projects or as a command-line tool

Installation

From Source

git clone https://github.com/ktauchathuranga/sstv.git
cd sstv
cargo build --release

The binary will be available at ./target/release/sstv

Usage

Basic Usage

# Generate SSTV audio and play through speakers
sstv input.jpg

# Save to WAV file
sstv input.jpg output.wav

# Specify mode and sample rate
sstv input.jpg output.wav -m scottie1 -s 48000

# Save without playing
sstv input.jpg output.wav --no-play

Generate All Modes

# Generate WAV files for all supported SSTV modes
for mode in martin1 martin2 scottie1 scottie2 scottiedx robot36 robot72 pd120 pd180 pd290 bw8 bw12; do
  echo "Generating $mode..."
  sstv input.jpg output_${mode}.wav -m $mode --no-play
done

Available Options

USAGE:
    sstv [OPTIONS] <INPUT> [OUTPUT]

ARGS:
    <INPUT>     Input image file (PNG, JPEG, etc.)
    [OUTPUT]    Output WAV file (optional, plays audio if omitted)

OPTIONS:
    -m, --mode <MODE>           SSTV mode [default: martin1]
    -s, --sample-rate <RATE>    Audio sample rate [default: 48000]
    --no-play                   Don't play audio
    -h, --help                  Print help information
    -V, --version               Print version information

Supported Modes

Mode VIS Code Resolution Time Color Space
martin1 0xAC 320×256 114.3s RGB (GBR)
martin2 0x28 320×256 58.1s RGB (GBR)
scottie1 0x3C 320×256 109.6s RGB (GBR)
scottie2 0xB8 320×256 71.1s RGB (GBR)
scottiedx 0xCC 320×256 268.9s RGB (GBR)
robot36 0x88 320×240 36.0s YUV
robot72 0x0C 320×240 72.0s YUV
pd120 0x5F 640×496 126.1s YUV
pd180 0x60 640×496 187.1s YUV
pd290 0xDE 800×616 288.7s YUV
bw8 0x82 160×120 8.0s Grayscale
bw12 0x86 160×120 12.0s Grayscale

Technical Documentation

How SSTV Works

SSTV (Slow Scan Television) is a method of transmitting still images over radio using audio frequency modulation. Unlike fast-scan television (broadcast TV), SSTV transmits one frame over several seconds to minutes, allowing it to fit within the narrow bandwidth of amateur radio voice channels (approximately 3 kHz).

Frequency Modulation Encoding

SSTV uses Frequency Modulation (FM) within the audio band to encode image brightness:

┌─────────────────────────────────────────────────────────────┐
│                    SSTV Frequency Mapping                   │
├─────────────────────────────────────────────────────────────┤
│  Signal Type        │  Frequency (Hz)  │  Purpose           │
├─────────────────────┼──────────────────┼────────────────────┤
│  Sync Pulse         │     1200         │  Line/frame sync   │
│  Black Level        │     1500         │  Minimum brightness│
│  White Level        │     2300         │  Maximum brightness│
│  VIS Bit 1          │     1100         │  Logic high        │
│  VIS Bit 0          │     1300         │  Logic low         │
└─────────────────────┴──────────────────┴────────────────────┘

The relationship between pixel brightness and frequency is linear:

frequency = 1500 + (pixel_value × 800 / 255)

Where pixel_value ranges from 0 (black) to 255 (white).

Signal Structure

Every SSTV transmission follows this structure:

┌──────────────────────────────────────────────────────────────────────────┐
│                         SSTV Transmission Structure                      │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────┐  ┌─────────┐  ┌──────────────────────────────────────────┐  │
│  │Preamble │→ │VIS Code │→ │              Image Data                  │  │
│  │ ~1.4s   │  │ ~0.3s   │  │         (mode-dependent)                 │  │
│  └─────────┘  └─────────┘  └──────────────────────────────────────────┘  │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘

VIS Code (Vertical Interval Signaling)

The VIS code identifies the SSTV mode being transmitted. It allows receivers to automatically detect and configure themselves for the incoming image format.

VIS Transmission Format

┌────────────────────────────────────────────────────────────────────────┐
│                           VIS Code Structure                           │
├────────────────────────────────────────────────────────────────────────┤
│                                                                        │
│  ┌──────────┐ ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌─────────────────┐ │
│  │  Leader  │→│  Break  │→│  Leader  │→│Start Bit│→│   8 Data Bits   │ │
│  │ 300ms    │ │  10ms   │ │  300ms   │ │  30ms   │ │  30ms × 8       │ │
│  │ 1900 Hz  │ │ 1200 Hz │ │ 1900 Hz  │ │ 1200 Hz │ │ 1100/1300 Hz    │ │
│  └──────────┘ └─────────┘ └──────────┘ └─────────┘ └─────────────────┘ │
│                                                         │              │
│                                                         ↓              │
│  ┌─────────┐                                      ┌─────────┐          │
│  │Stop Bit │←─────────────────────────────────────│ Parity  │          │
│  │  30ms   │                                      │ (bit 7) │          │
│  │ 1200 Hz │                                      └─────────┘          │
│  └─────────┘                                                           │
│                                                                        │
└────────────────────────────────────────────────────────────────────────┘

VIS Code Bit Encoding

  • Logic 1: 1100 Hz for 30ms
  • Logic 0: 1300 Hz for 30ms
  • Bit Order: LSB first

Example: Martin 1 (VIS = 0xAC = 10101100 binary)

Start → 0 → 0 → 1 → 1 → 0 → 1 → 0 → 1 → Stop
      1300 1300 1100 1100 1300 1100 1300 1100

FM Synthesis Implementation

This encoder uses a phase accumulator approach for generating FM audio, ensuring sample-rate independence and smooth frequency transitions:

// Phase accumulator formula (from QSSTV synthes.cpp)
fn next_sample(&mut self, freq: f64) -> f64 {
    let phase_increment = (freq / sample_rate) * SINE_TABLE_LEN;
    self.phase = (self.phase + phase_increment) % SINE_TABLE_LEN;
    self.sine_table[self.phase as usize]
}

Timing Precision

To maintain accurate timing across different sample rates, the encoder uses an adjustment accumulator:

// Duration adjustment for precise timing
let num_samples = ((duration + adjust) * sample_rate + 0.5) as usize;
adjust += duration - (num_samples as f64 / sample_rate);

This ensures that timing errors don't accumulate over the transmission.


Library Usage

Add to your Cargo.toml:

[dependencies]
libsstv = { path = "path/to/libsstv" }

Example

use libsstv::{Encoder, ImageData, Mode, RgbPixel};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create test image (320x256 for Martin 1)
    let pixels: Vec<RgbPixel> = (0..320*256)
        .map(|i| RgbPixel::new((i % 256) as u8, 128, 64))
        .collect();
    let image = ImageData::new(320, 256, pixels);

    // Create encoder for Martin 1 at 48kHz
    let mut encoder = Encoder::new(Mode::Martin1, 48000)?;

    // Encode to audio samples
    let samples = encoder.encode(&image)?;

    // Convert to i16 for WAV output
    let i16_samples = Encoder::samples_to_i16(&samples);

    println!("Generated {} samples", i16_samples.len());
    Ok(())
}

Testing with SSTV Decoders

Generated WAV files can be decoded with:

  • QSSTV (Linux) - The reference implementation
  • MMSSTV (Windows) - Popular Windows decoder
  • Robot36 (Android) - Mobile decoder app
  • CQ SSTV (iOS) - iPhone/iPad decoder

License

MIT License - See LICENSE for details.

About

SSTV Encoder

Topics

Resources

License

Stars

5 stars

Watchers

0 watching

Forks

Sponsor this project

 

Packages

 
 
 

Contributors

Languages