Professional GStreamer-based broadcast playout system (channel-in-a-box) for Linux β with an HTML5 web interface, oGraf graphics engine, and plugin system.
Pipeline Controller is a complete broadcast playout system built on the open-source framework GStreamer. It enables professional on-air operations through a modern, fully browser-based web interface β designed for 24/7 channel-in-a-box operations.

- π¬ dynamic configureable amount of independent media players (MXF, MP4, MOV, TS, β¦)
- ποΈ Master pipeline with compositor, video switcher, and audio mixing
- π Flexible audio routing with multiple groups, channel matrices, and 5.1 upmix
- π EBU R128 loudness normalization per audio group
- β¨ oGraf HTML5 graphics engine (EBU standard) via Puppeteer/Chromium with templates
- π Playlist engine with transitions (cut, v-fade, cut-fade, fade-cut, X-fade) and event children
- π§© Asset Panel for one-click commercial breaks with auto-return (interrupt / break / live modes)
- β±οΈ Counter Strip showing all time-critical events of the current hour at a glance
- ποΈ Voiceover engine with fade-in/out and program ducking
- π Plugin system running in isolated worker threads (crash-safe playout)
- π Optional Bearer-token authentication with role-based access (admin/editor/grafiker/viewer)
- π Full REST API, SSE event stream, and HTTPS support
- π PTP clock support (IEEE 1588 / SMPTE 2110) and DST-safe scheduling
- π Bilingual UI (English / German) with light/dark mode
- πΊ Multi-channel supervisor β run several independent channels/playlists per host (e.g. a main channel + a sign-language variant), each with its own data dir/port, with a central dashboard
- π ChannelBus cross-channel triggers β send NEXT/NEXT_LIVE/JUMP/CUT commands between channels (or hosts), including playlist-item-bound trigger children with frame-accurate pre-roll
- π² DVE / Squeeze β squeeze the program/live video into a positioned box (or squeeze an image/oGraf overlay over full-screen video), with green-screen auto-detection and chroma-key transparency for frame graphics
- π€ Additional outputs β any number of extra downconverted network outputs (RTMP/SRT/UDP/file) or DeckLink SDI/HDMI hardware sinks, independent of the main program path
- π‘ DMF/MXL live sources β EBU/AMWA Media eXchange Layer shared-memory flows as live sources (real
mxlsrc/mxlsinkGStreamer plugin), with in-UI feed discovery/selection - πΊ SCTE-35 splice cue generator β generate SCTE-35
splice_insert/splice_nullas MPEG-TS/UDP, triggered by playlist events, classification (commercial/promo),block_start/block_endevents, or manual cue from the UI β οΈ Transition timing validation β automatic warnings when clips are too short for configured crossfade/fade transitions (πβ badge on playlist event + toast in editor)- π Audio Preset Resilience β automatic fallback when a clip has fewer audio channels than the selected preset requires: static pre-cue check (before playout) and live EBU-silence detection (during playout, hot-swap without interruption). Global fallback chain + optional per-event override, both configurable via an interactive drag-and-drop chip builder in the UI
- π Per-Track Audio Silence Fallback β when a specific audio group (e.g. 5.1 surround) is detected silent while a fallback group (e.g. stereo program) carries signal, only that group's routing matrix is hot-patched without affecting other groups. Automatic up-/downmix (LoRo / LtRt / sum) when channel counts differ. Restores to the original preset matrix when audio returns
- ποΈ Stream Deck WebHID β direct hardware button surface control from the browser (Chrome/Edge, no drivers needed). Fully dynamic pages for playlist control, live source switching, asset playback, oGraf take/takeout, SCTE-35 cues, and branding selection. Plugin-extensible: any plugin can register its own Stream Deck page
Native Node.js installation β no AppImage required:
# On a target machine: download & install
tar -xzf PipelineController-1.0.1.tar.gz
cd PipelineController-1.0.1
bash install.sh # β οΈ never with sudo!
# Start
bash ~/pipeline-controller/start.sh
# or as systemd user-service (if enabled during install)
systemctl --user start pipeline-controllerThe installer verifies Node.js β₯ 18, all required GStreamer plugins (intervideosrc, interaudiosrc, compositor, β¦), installs missing dependencies via apt-get, sets up runtime directories, and configures settings.json paths correctly for the target machine.
chmod +x PipelineController-x86_64.AppImage
# IMPORTANT: extract the AppImage (do not run it directly!)
./PipelineController-x86_64.AppImage --appimage-extract
cd squashfs-root
./AppRun
β οΈ Important: The AppImage must be extracted β the oGraf graphics engine (Puppeteer/Chromium) requires access to the real filesystem and cannot run from a FUSE-mounted AppImage.
# Node.js β₯ 18 required
nvm install 20 && nvm use 20
sudo apt install build-essential libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
gstreamer1.0-{tools,plugins-base,plugins-good,plugins-bad,plugins-ugly,libav,x,alsa,gl} \
pulseaudio
npm install
node server.jsThen open in your browser: http://localhost:3000
node supervisor.js channels.jsonOpens a dashboard at http://localhost:3099 listing all configured channels, each running as its own isolated server.js process (own port, own data dir). See Multi-Channel Operation in the manual.
| Component | Requirement |
|---|---|
| Operating System | Linux x86_64, kernel β₯ 5.4 (Debian 12 / Ubuntu 22.04 recommended) |
| Node.js | β₯ 18 |
| GStreamer | β₯ 1.22 (with plugins-bad for intervideosrc, compositor, β¦) |
| X11 display | Required for ximagesink (use fakesink for headless) |
| Audio | PulseAudio (recommended) or ALSA |
| Python 3 | Only required for the Marina Sync plugin |
| RAM | β₯ 2 GB (4 GB recommended) |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Web UI (HTML5 SPA Β· DE / EN) β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β REST + SSE (HTTP / HTTPS)
ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββ
β Node.js Server (server.js) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Playlist Engine β Graphics Engine β Voiceover β β
β β Audio Router β Plugin Host β Media Lib β β
β β Auth + Roles β User Log β Asset Engine β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β gst-kit (native bindings)
ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββ
β GStreamer Pipelines β
β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββββ β
β β Player 1 β β Player 2 β β Player 3 βββ Master β β
β ββββββββββββ ββββββββββββ ββββββββββββ β Pipeline β β
β β (Compositor)β β
β ββββββββββββββββββββ β + Switcher β β
β β oGraf (Chromium) βββββββββββββββββββββββββ + AudioMix β β
β ββββββββββββββββββββ βββββββ¬βββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββΌβββββββββββ
βΌ
Video Sink + Audio Sinks
Auto-generated graph of the running master pipeline (compositor, video switcher, audio mixer/router, sinks):
Pipeline Controller is built on the EBU oGraf standard for HTML5 broadcast graphics.
Graphics can pull live data from the playlist using a powerful variable syntax β automatically resolved when the graphic appears on screen:
{{next[class(movie)]:title}} β next movie's title
{{next[title(News)]:starttime|unixms}} β countdown target as Unix ms
{{current:classifcolor}} β dynamic accent color
{{next2[class(movie)]:starttime|HH:MM}} β 2nd next movie's start time
Numeric formats (unix, unixms, countdown, countdownms) return real JS numbers β perfect for template fields of type integer or number. An interactive {{β¦}}-builder is available in the UI for every text/number field.
See the manual for the full syntax.
Plugins run in isolated worker threads β a plugin crash has no impact on the running playout.
| Plugin | Description | Default |
|---|---|---|
| π File Transfer Manager | Automatic FTP/FTPS/local transfer & cache management | β enabled |
| ποΈ Broadcast Controller | Control external routers (SW-P-08, EVS Cerebrum, HTTP, TCP) | disabled |
| πΊ SCTE-35 Cue Generator | Generate SCTE-35 splice cues as MPEG-TS/UDP from playlist events, classifications, or manual trigger | disabled |
| π₯οΈ Marina Sync | Auto-sync playlist from Pebble Beach Marina (.mpl watchfolder, on-air resume) |
disabled |
| π‘ SNMP Monitor | Monitor broadcast devices via SNMP v1/v2c/v3 | disabled |
| π¬ Subtitle FAB | Live subtitle control via FAB Subtitle Server | disabled |
Custom plugins can be developed in just a few lines of code β see plugin development in the manual.
Optional role-based access control with Bearer tokens. Disabled by default β enable it under Settings β Users when the system is reachable from untrusted networks.
| Role | Access |
|---|---|
admin |
Full access β user management, all settings, plugins |
editor |
Playlist control, media library, plugin management |
grafiker |
Graphics only (oGraf templates, take/out, hotkeys) |
viewer |
Read-only β live state, SSE stream, no actions |
All login, logout, and write operations are logged to a JSONL audit log (configurable path). Passwords are stored as SHA-256 hashes.
Full control via HTTP β for example:
# Start the master pipeline
curl -X POST http://localhost:3000/api/master/start
# Cue a clip
curl -X POST http://localhost:3000/api/player/1/cue \
-H "Content-Type: application/json" \
-d '{"file":"news.mxf","som":"00:00:00:00","eom":"00:05:30:00"}'
# Show a graphic
curl -X POST http://localhost:3000/api/grafik/show \
-H "Content-Type: application/json" \
-d '{"template":"lower-third","data":{"headline":"Max Mustermann"}}'Real-time updates via Server-Sent Events:
const es = new EventSource('http://localhost:3000/events');
es.addEventListener('audio-level', e => {
const { levels } = JSON.parse(e.data);
// levels: { "pgm-stereo": { rms: -18.5, peak: -14.2 }, ... }
});Full API reference: Manual β REST API
Enable HTTPS as a parallel server port via settings.json or environment variables:
HTTPS_KEY=/path/to/key.pem \
HTTPS_CERT=/path/to/cert.pem \
HTTPS_PORT=3443 \
node server.jsThe plain HTTP port stays active in parallel (useful for local access).
pipeline-controller/
βββ server.js # Main server (one process = one channel)
βββ supervisor.js # Multi-channel supervisor + dashboard
βββ channels.json # Multi-channel config (id/dataDir/port per channel)
βββ ui.html # Web interface (SPA)
βββ settings.json # Settings (auto-generated)
βββ audio_config.json # Audio groups + presets + clock
βββ plugins.json # Plugin configurations
βββ users.json # Users (SHA-256 password hashes)
βββ lib/ # Backend modules
β βββ MasterPipeline.js
β βββ PlayerPipeline.js
β βββ AudioRouter.js
β βββ PlaylistEngine.js
β βββ GrafixEngine.js
β βββ VoiceoverEngine.js
β βββ ChannelBus.js # Cross-channel/cross-host trigger bus
β βββ OutputEngine.js # Additional downconvert/Cleanfeed/DeckLink outputs
β βββ GreenZoneDetect.js # Green-screen box detection + chroma-key transparency
β βββ MxlSource.js # DMF/MXL flow discovery (mxl-info wrapper)
β βββ ...
βββ releases/ # Build artifacts (AppImage, tar.gz) β git-ignored, distributed via GitHub Releases
βββ plugins/ # Plugin system
β βββ broadcast-controller/
β βββ file-transfer-manager/
β βββ marina-sync/
β βββ scte35/
β βββ ...
βββ scripts/
β βββ install-mxl.sh # Builds libmxl + gst-mxl-rs (mxlsrc/mxlsink) from source
βββ env/mxl.env # DMF/MXL plugin paths (auto-generated by install-mxl.sh)
βββ templates/grafik/ # oGraf templates
βββ media/ # Media files
βββ playlists/ # Saved playlists
βββ images/ # Still images
βββ channelbranding/ # Branding overlays
βββ asrun/ # As-run logs (daily, txt)
- π Full manual β Installation, configuration, API
- π¬ Getting started
- π¦ Installer package (recommended)
- π HTTPS / TLS setup
- πΊ Multi-channel operation & supervisor dashboard
- π ChannelBus cross-channel triggers
- π₯ User management & roles
- β¨οΈ Keyboard shortcuts
- π Audio configuration
- π¨ Creating oGraf templates
- π oGraf playlist variables
- π² DVE / Squeeze
- π€ Additional outputs (Downconvert / Cleanfeed / DeckLink)
- π‘ DMF/MXL live sources
- πΊ SCTE-35 cue generator plugin
- π Audio Preset Resilience (fallback chain)
- π§© Asset Panel & auto-return
- β±οΈ Counter Strip
- π Daylight Saving Time behavior
- π Developing your own plugins
- π Troubleshooting
| Component | Version | License |
|---|---|---|
| GStreamer | 1.22+ | LGPL 2.0+ |
| Node.js | 18+ | MIT |
| Puppeteer | 24+ | Apache 2.0 |
| gst-kit | 0.2.5+ | MIT |
| basic-ftp | latest | MIT |
| EBU oGraf | v1 | Open Standard |
gst-plugins-bad and gst-plugins-ugly include decoders for partly license-restricted formats (H.264, MPEG-2, AC-3, DTS). For commercial use with these codecs, licensing fees may apply. For testing and non-commercial use, the open-source implementations may be used freely.
Please file issues via GitHub Issues. For bug reports, please include:
- Linux distribution & version
- GStreamer version (
gst-launch-1.0 --version) - Node.js version (
node --version) - Output of
GST_DEBUG=*:2 node server.js 2> gst_debug.log - Relevant parts of
settings.json(paths, video/audio sinks)
The foundation (GStreamer, Node.js, Chromium, npm packages) is open source. The application-specific code is released under the terms defined in the LICENSE file.
Pipeline Controller
Broadcast Playout System Β· GStreamer 1.22+ Β· Node.js 18+ Β· EBU oGraf
24/7 channel-in-a-box Β· Linux Β· Open-Source-based




