Channel Streaming
How Hephaestus actually serves a live channel to viewers, why two viewers of the same channel could end up watching different moments of it, and the one setting that guarantees they won't.
The Two Buckets #
Every viewer of a live channel is capability-matched into one of two independent encodes Hephaestus runs for that channel. Which one a given viewer lands on is resolved automatically per-viewer (declared codec/resolution support) — there's nothing to pick as a viewer.
| Direct Stream | Transcode | |
|---|---|---|
| What happens | Video is copied byte-for-byte from the source file (-c:v copy) — no re-encode |
Video is fully re-encoded to your configured resolution/bitrate |
| CPU/GPU cost | Minimal — no video encode at all | A real encode per channel |
| Resolution/bitrate control | None — always the source's own | Full control (see Transcode Quality) |
| Loudness normalization | Yes (audio is always re-encoded, even here) | Yes |
| Schedule drift correction | Coarse — can only skip ahead at the next item transition, never mid-item | Smooth — a small, continuous speed nudge closes drift over an item's whole runtime |
| Eligibility | Only when a viewer's declared capabilities already support the source's video codec/resolution, and the source isn't variable-frame-rate | Always available — the universal fallback |
A channel with direct-stream enabled can have both encodes running at once — some viewers on direct stream, others on transcode, for the exact same nominal channel — Hephaestus doesn't pick one for the whole channel, it picks per viewer.
Schedule Drift & How Each Bucket Corrects It #
A live channel simulates broadcast TV: Kairos computes what should be airing at any given wall-clock moment, and Hephaestus's encode is supposed to match that exactly. In practice it drifts slightly — every item transition costs a little real time to spin up the next encode, decode/output can hiccup under load, and none of that is perfectly zero. Left uncorrected, a channel would slowly fall behind its own schedule.
Transcode corrects this the smooth way: when a real re-encode is already happening, ffmpeg's own timing filter can play an item very slightly faster or slower (never more than a barely-perceptible couple of percent) so a whole item plays start-to-finish exactly on schedule by the time it ends.
Direct stream can't do this at all — a byte-for-byte copy has no filter graph to retime anything through. It can only ever land on the mathematically-correct position when a new item starts (skipping ahead into it if the channel has fallen behind), then rides through that entire item at normal speed with no further correction until the next transition.
Always Transcode #
A per-channel toggle (Channel editor → Transcode Quality → Always transcode (disable direct stream)) that removes direct stream from the equation for that channel entirely — every viewer, regardless of what their device can decode natively, gets the transcode bucket.
The tradeoff is real: every channel now costs a real video encode instead of a free byte copy, so this uses meaningfully more CPU/GPU per active channel. For a channel where hardware headroom is tight and the occasional coarse correction at a scene/episode boundary is an acceptable tradeoff, leaving direct stream enabled (the default) is still a reasonable choice.
Transcode Quality Settings #
Also in the channel editor's Transcode Quality section — these only affect the transcode bucket (direct stream, by definition, always uses the source's own resolution/bitrate).
| Setting | Effect |
|---|---|
| Max Resolution | Scales down only, never upscales — useful for capping bandwidth on a channel built from mixed-resolution sources without hurting your best material. |
| Video Bitrate Cap | 0 = quality-based (CRF/CQ) encoding with no cap; set a value to bound bandwidth
(e.g. 3000 for ~3 Mbps).
|
| Audio Bitrate | Applies to the audio encode on both buckets — direct stream's audio is always re-encoded too, for loudness normalization (see above). |
Audio/Subtitle Language (in the channel editor's own section, alongside these) pick which embedded track Hephaestus maps when a file has more than one — this applies to both buckets identically.