GhostStream
Open-Source Video Transcoding Server
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
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 + public models/contracts
pip install "ghoststream[server]" # Add the server runtime dependencies
python -m ghoststream requires the server extra (or the full repo requirements.txt). pip install ghoststream by itself is the GhostHub/client SDK install.
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, install the Python dependencies before running the server or tests:
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
GhostStream consumes Specter through the specter-runtime Python package instead of a vendored submodule.
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.
Release files for ghoststream 1.2.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ghoststream-1.2.6.tar.gz | 117.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ghoststream-1.2.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 241.7 kB
Release files / ghoststream-1.2.6.tar.gz
| Download URL | ghoststream-1.2.6.tar.gz |
|---|---|
| Size | 117.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9616b6827b21d3b688897ccfb3c84ea66c408bbc6c481995a84ab5bb558868bf
|
|
BLAKE2b-256 checksum How to use checksums |
cbcd56b53e703965342bf0ba4ff17bb2f6154974218d5508d5f160b9ae0f82f2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Release files / ghoststream-1.2.6-py3-none-any.whl
| Download URL | ghoststream-1.2.6-py3-none-any.whl |
|---|---|
| Size | 124.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
21f7f5b361184a748acb43c5175df7366cac0051c1ac0d681d6d7e9d2d4f58f1
|
|
BLAKE2b-256 checksum How to use checksums |
0aa7dfd1ce6779b45a865672ee1a2a7988b543be6097cbdcd1825d1f73a6b247
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|