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.
| 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.
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 ghoststreamThat 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 ghoststreamUse --server-only when you want the API/HLS engine without the dashboard:
.venv/bin/python -m ghoststream --server-onlyThat 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.
Python:
pip install ghoststream # SDK + public models/contracts
pip install "ghoststream[server]" # Add the server runtime dependenciespython -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-sdkPython 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.
- 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
| 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 |
| 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 |
{
"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
}
]
}{
"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.
| 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 |
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.htmlIf your virtualenv is already activated, plain python -m ghoststream --server-only and python -m http.server 8080 are equivalent.
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: trueGhostStream serves as the transcoding backend for GhostHub.
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ 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
pip install ghoststreamfrom 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)# 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.
After cloning, initialize the Specter submodule before running the server or tests:
git submodule update --init --recursiveThe ghoststream/specter directory is sourced from BleedingXiko/SPECTER. If you need to make changes inside the submodule:
- Commit and push from within
ghoststream/specter. - 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 DEBUGMIT License - see LICENSE for details.