Skip to main content

Open Source Cross-Platform Transcoding Service & SDK

Project description

GhostStream

Open-Source Video Transcoding Server

License: MIT Python 3.10+ Platform

GhostStream is a hardware-accelerated video transcoding server with automatic GPU detection, adaptive bitrate streaming, and minimal configuration. It serves as the transcoding backend for GhostHub but can be used standalone. It is designed for local-machine and LAN use, not direct public internet exposure.

Quick Start

Pre-built Binaries

Platform Download Run
Windows GhostStream.exe Double-click
Linux GhostStream-Linux chmod +x && ./GhostStream-Linux
macOS GhostStream-macOS chmod +x && ./GhostStream-macOS

Requires FFmpeg. On startup, GhostStream launches the Textual dashboard by default and will show install instructions if FFmpeg is missing.

From Source

git clone https://github.com/BleedingXiko/GhostStream.git
cd GhostStream
git submodule update --init --recursive
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install -r requirements.txt
.venv/bin/python -m ghoststream

That creates a local development virtualenv in .venv, installs the server dependencies, and starts the Specter-native GhostStream runtime with the TUI dashboard by default.

If you prefer to stay inside the activated shell, this is equivalent:

python -m ghoststream

Headless / Containers

Use --server-only when you want the API/HLS engine without the dashboard:

.venv/bin/python -m ghoststream --server-only

That mode is ideal for Docker, CI smoke tests, browser example serving, SSH sessions, and other environments where a terminal UI is not practical. GhostStream is intended to stay on your machine or trusted LAN even in headless mode.

SDK Installation

Python:

pip install ghoststream              # SDK only (lightweight)
pip install ghoststream[server]      # Full server runtime, including Specter prerequisites

JavaScript/TypeScript:

npm install ghoststream-sdk

Usage

Python SDK (recommended):

from ghoststream import GhostStreamClient, TranscodeStatus

client = GhostStreamClient(manual_server="localhost:8765")

# Synchronous (Flask/gevent compatible)
job = client.transcode(source="https://example.com/video.mp4", resolution="720p")
print(f"Stream URL: {job.stream_url}")

JavaScript/TypeScript:

import { GhostStreamClient } from 'ghoststream-sdk';

const client = new GhostStreamClient('localhost:8765');
const job = await client.transcode({ source: 'https://example.com/video.mp4', resolution: '720p' });
console.log(`Stream URL: ${job.streamUrl}`);

curl:

curl -X POST http://localhost:8765/api/transcode/start \
  -H "Content-Type: application/json" \
  -d '{"source": "https://example.com/video.mp4", "mode": "stream"}'

See the examples/ directory for additional usage examples.

Features

  • HLS Streaming - Real-time transcoding with immediate playback
  • Adaptive Bitrate (ABR) - Multiple quality variants for bandwidth adaptation
  • Subtitle Muxing - Native WebVTT subtitle support in HLS streams
  • HDR to SDR - Automatic tone mapping for HDR content
  • Codec Support - H.264, H.265/HEVC, VP9, AV1
  • Batch Processing - Queue multiple files with optional two-pass encoding
  • Hardware Acceleration - NVIDIA NVENC, Intel QuickSync, AMD AMF, Apple VideoToolbox
  • Automatic Fallback - Falls back to software encoding if hardware fails

Supported Hardware Encoders

Platform Encoder Detection
NVIDIA NVENC Automatic via nvidia-smi
Intel QuickSync Automatic via VA-API
AMD AMF/VCE Automatic
Apple VideoToolbox Native macOS support
CPU libx264/libx265 Always available

API Reference

Endpoints

Method Endpoint Description
POST /api/transcode/start Start a transcoding job
GET /api/transcode/{id}/status Get job status & progress
POST /api/transcode/{id}/cancel Cancel a job
DELETE /api/transcode/{id} Delete job & cleanup
GET /api/health Health check
GET /api/capabilities Hardware & codec info
WS /ws/progress Real-time progress via WebSocket

Start Transcode Request

{
  "source": "https://example.com/video.mp4",
  "mode": "stream",           // "stream", "abr", or "batch"
  "output": {
    "resolution": "720p",     // "4k", "1080p", "720p", "480p", "original"
    "video_codec": "h264",    // "h264", "h265", "vp9", "av1"
    "audio_codec": "aac",     // "aac", "opus", "copy"
    "hw_accel": "auto"        // "auto", "nvenc", "qsv", "software"
  },
  "start_time": 0,            // Seek to position (seconds)
  "subtitles": [              // Optional: Subtitle tracks to mux
    {
      "url": "https://example.com/subtitle.vtt",
      "label": "English",
      "language": "en",
      "default": true
    }
  ]
}

Response

{
  "job_id": "abc-123",
  "status": "processing",
  "stream_url": "http://localhost:8765/stream/abc-123/master.m3u8?gst=eyJ...",
  "control_token": "eyJ...",
  "progress": 0
}

Use the returned control_token on protected job endpoints:

curl http://localhost:8765/api/transcode/abc-123/status \
  -H "X-GhostStream-Control-Token: eyJ..."

Use the returned stream_url as-is in players and web clients. GhostStream embeds the stream token there and propagates it through HLS playlists and segment URLs. The gst=... query parameter is that stream capability token. It authorizes playlist, segment, and download access for that job, so clients should preserve it exactly as returned.

Examples

File Description
demo.py Basic demo with auto-play
demo.html Browser-based demo
minimal.py Minimal Python example
quickstart.py Interactive examples
curl_examples.md HTTP/curl commands
web_player.html Full-featured web player

Running HTML Examples

The HTML examples must be served over HTTP due to browser CORS restrictions:

# 1. Start GhostStream
.venv/bin/python -m ghoststream --server-only

# 2. In another terminal, serve the examples
cd examples
.venv/bin/python -m http.server 8080

# 3. Open in browser
#    http://localhost:8080/demo.html
#    http://localhost:8080/web_player.html

If your virtualenv is already activated, plain python -m ghoststream --server-only and python -m http.server 8080 are equivalent.

Configuration

Create ghoststream.yaml to customize (optional):

server:
  host: 0.0.0.0  # Bind on all local interfaces; use only on trusted networks
  port: 8765

transcoding:
  max_concurrent_jobs: 2
  segment_duration: 4
  tone_map_hdr: true
  retry_count: 3

hardware:
  prefer_hw_accel: true
  fallback_to_software: true

GhostHub Integration

GhostStream serves as the transcoding backend for GhostHub.

Architecture

┌─────────────────────────────────┐      ┌─────────────────────────────────┐
│        Raspberry Pi             │      │         Your PC                 │
│  ┌───────────────────────────┐  │      │  ┌───────────────────────────┐  │
│  │       GhostHub            │  │ WiFi │  │      GhostStream          │  │
│  │    (Media Server)         │◄─┼──────┼─►│   (GPU Transcoder)        │  │
│  └───────────────────────────┘  │      │  └───────────────────────────┘  │
└─────────────────────────────────┘      └─────────────────────────────────┘
  • Auto-Discovery: GhostStream advertises via mDNS (_ghoststream._tcp.local)
  • On-Demand: Transcoding occurs only when requested
  • Local Network: No internet connection required

Python SDK

pip install ghoststream
from ghoststream import GhostStreamClient, TranscodeStatus

# Auto-discover on network
client = GhostStreamClient()
client.start_discovery()

# Or connect directly
client = GhostStreamClient(manual_server="192.168.1.100:8765")

# Synchronous API (Flask/gevent compatible)
job = client.transcode(
    source="http://pi:5000/media/video.mkv",
    resolution="1080p"
)
if job.status != TranscodeStatus.ERROR:
    print(job.stream_url)

Progress Updates

# Python SDK: poll synchronously
job = client.get_job_status("job-123")
print(job.progress, job.status.value)
// Browser / JS clients can use /ws/progress directly
{"type": "subscribe", "job_ids": ["job-123"], "control_token": "token-from-start-response"}

{"type": "progress", "job_id": "job-123", "data": {"progress": 45.2}}
{"type": "status_change", "job_id": "job-123", "data": {"status": "ready"}}

For multi-job filtered subscriptions, send a job_tokens object keyed by job ID instead of a single control_token.

Contributing

After cloning, initialize the Specter submodule before running the server or tests:

git submodule update --init --recursive

The ghoststream/specter directory is sourced from BleedingXiko/SPECTER. If you need to make changes inside the submodule:

  1. Commit and push from within ghoststream/specter.
  2. Return to the GhostStream repo and commit the updated submodule pointer.

That keeps GhostStream pinned to an explicit Specter revision while still letting contributors iterate on both projects.

Contributions are welcome. See CONTRIBUTING.md for guidelines.

# Development setup
git clone https://github.com/BleedingXiko/GhostStream.git
cd GhostStream
python -m venv .venv && source .venv/bin/activate  # or .venv\Scripts\activate on Windows
pip install -r requirements.txt
.venv/bin/python -m ghoststream --log-level DEBUG

License

MIT License - see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ghoststream-1.2.3.tar.gz (152.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ghoststream-1.2.3-py3-none-any.whl (176.9 kB view details)

Uploaded Python 3

File details

Details for the file ghoststream-1.2.3.tar.gz.

File metadata

  • Download URL: ghoststream-1.2.3.tar.gz
  • Upload date:
  • Size: 152.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for ghoststream-1.2.3.tar.gz
Algorithm Hash digest
SHA256 d0d4c2b78b9af3b2769147fcfb55c5f7d11aa4dce1d4fabff830e390646f8ef9
MD5 3768aad0ec5c4014a883142af0655155
BLAKE2b-256 274de49a31e0cbf0f04a1410f3ac8026d60a339337cf3e8f8bb6b43514a21133

See more details on using hashes here.

File details

Details for the file ghoststream-1.2.3-py3-none-any.whl.

File metadata

  • Download URL: ghoststream-1.2.3-py3-none-any.whl
  • Upload date:
  • Size: 176.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for ghoststream-1.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 c64e9232c9b6f364ebbde55bb69ea1c59a33a7c2920831334dc381b51b62204d
MD5 b01f04a5bad120bc702bae669097d5f0
BLAKE2b-256 897696e2dbcc1a2b9e296eda847069f17f6d7275c84ca1a733eb2f4babe0a51a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page