qast / docs
Site Docs Home

Architecture

qast is built around a single pipeline that normalizes any input into a continuous, TV-compatible stream. This page covers the key stages, design decisions, and protocol internals.

Pipeline overview

[Source] → [Resolve] → [Transcode] → [TS Rewrite] → [Mux] → [Buffer] → [HTTP] → [TV]

Stage 1: Source resolution

The source parser (qast/source.py) classifies each input and routes it appropriately:

Stage 2: Transcoding

Every input is transcoded to a universal format via ffmpeg:

ParameterValue
Video codecH.264 Main profile
Resolution1920x1080 @ 30fps
Presetultrafast
Bitrate5 Mbps
GOP60 frames (2 seconds)
Audio codecAAC stereo, 44.1 kHz, 128 kbps
ContainerMPEG-TS (stdout)

The always-transcode design trades CPU for zero compatibility issues. Every TV that supports H.264 Main (which is all of them) will play the output.

Stage 3: PTS/DTS rewriting

The TS rewriter (qast/pipeline/tsrewrite.py) processes 188-byte MPEG-TS packets and rewrites PTS, DTS, and PCR timestamps for continuity. This ensures seamless transitions between queue items — the TV sees one unbroken stream even when the underlying source changes.

Timestamps use 90 kHz integer ticks (no floating point) to avoid drift.

Stage 4: Container muxing

Stage 5: Ring buffer

The ring buffer (qast/pipeline/ringbuf.py) is an in-memory circular buffer with time-based flow control:

Stage 6: HTTP server

A ThreadingHTTPServer streams the buffer contents to the TV over HTTP. It handles:

Device discovery

Discovery runs in parallel across all protocols:

ProtocolMethodDetails
DLNASSDPUDP multicast to 239.255.255.250:1900
RokuSSDPSame multicast, filtered by Roku service type
ChromecastmDNS/DNS-SDMulticast to 224.0.0.251:5353 via pychromecast

Results are deduplicated and sorted alphabetically. Adaptive timeout learning (qast/tuning.py) tracks consecutive discovery failures and extends timeouts dynamically.

Protocol casting

DLNA

SOAP/UPnP: SetAVTransportURI followed by Play. Polling monitors playback state.

Chromecast

Protobuf over TLS via pychromecast. Media controller launches a default media receiver that loads the HTTP stream URL.

Roku

HTTP POST to the ECP endpoint. Requires the free Media Assistant channel (ID 782875) to be installed on the Roku device.

YouTube DASH handling

By default, qast selects separate video and audio DASH streams for higher quality. The audio stream is downloaded to a temp file (~1–2 MB) to work around an ffmpeg HTTP multi-input bug. If the audio download fails, qast automatically falls back to a muxed stream.

Design decisions

Source reference

Created by Rich LeGrand · MIT License