---
title: OTT-Dienst
url: https://doc.pstreamer.tv/de/manual/ott.html
lang: de
product: Perfect Streamer
version: 1.13.3.445
---

# OTT-Dienst

Liefert Streams über HTTP-basierte Protokolle — **HLS** (über MPEG-TS), **MPEG-DASH** und **Low-Latency HLS** (über CMAF — fragmentiertes MP4, seit Version 1.13) sowie **MPEG-TS over HTTP**. Unterstützt werden HTTPS (SSL) und HTTP/3 (QUIC). Die Auslieferung wird auf der Registerkarte **OTT** der **Stream**-Einstellungen aktiviert.

Die Verbindungs-URLs haben das Format:

- [http://host:port/http/stream/login/password](http://host:port/http/stream/login/password) — Autorisierung per Login und Passwort
- [http://host:port/http/stream/login](http://host:port/http/stream/login) — Autorisierung per Login (Token)
- [http://host:port/http/stream/](http://host:port/http/stream/) — Autorisierung per IP

**host** und **port** werden in den **http server**-Einstellungen festgelegt.

**stream** — **ID** des Streams. Nicht zu verwechseln mit der Reihenfolge in der Stream-Liste. Die **ID** wird im Kopf der Stream-Statistikseite und in der Spalte *ID* der Stream-Liste angezeigt; sie wird bei der Stream-Erstellung festgelegt und ändert sich nie.

Analog für **HLS**, **DASH** und **Low-Latency HLS** (die letzten beiden — nur im *OTT/HLS/LL-HLS/LL-Dash*, siehe unten):

- [http://host:port/hls/stream/login/password](http://host:port/hls/stream/login/password)
- [http://host:port/hls/stream/login](http://host:port/hls/stream/login)
- [http://host:port/hls/stream/](http://host:port/hls/stream/)
- [http://host:port/dash/stream/login/password](http://host:port/dash/stream/login/password)
- [http://host:port/dash/stream/login](http://host:port/dash/stream/login)
- [http://host:port/dash/stream/](http://host:port/dash/stream/)
- [http://host:port/llhls/stream/login/password](http://host:port/llhls/stream/login/password)
- [http://host:port/llhls/stream/login](http://host:port/llhls/stream/login)
- [http://host:port/llhls/stream/](http://host:port/llhls/stream/)

Auf der Stream-Statistik-Seite werden die URLs der verbundenen Protokolle (als Vorlage) und ihr aktueller Status angezeigt. Nicht autorisierter Zugriff ist verboten — Clients müssen in **Peers** eingetragen sein.

Für **HLS** und **DASH** sind in der URL zusätzliche Parameter verfügbar (optional):

[URL]?a=1&s=40&m=40&v=5&h3=1

- **a**: 1 — absoluter Pfad in der Playlist, 0 — relativer Pfad (Standard).
- **s**: Länge der dynamischen Playlist (Sekunden), Standard 40 s.
- **m**: Mindestlänge der dynamischen Playlist (s); Standard 40 s. Maximale Länge der dynamischen Playlist 60 s. Liegt die aktuelle Chunk-Buffer-Größe unter der im Request geforderten Mindestgröße, wird HTTP 404 zurückgegeben. So startet HLS stets mit einem gefüllten Chunk-Buffer auf dem Server.
- **v**: die in der Playlist ausgegebene HLS-Protokollversion. Standardmäßig hängt der Wert vom HLS-Modus ab (siehe unten): *OTT/HLS* und *OTT/HLS/LL-HLS/LL-Dash* — *6*, *Peering/HLS* — *3*. Ein expliziter Wert in der URL überschreibt den Standard. Ein Wechsel der Version kann für die Kompatibilität mit einem bestimmten HLS-Client erforderlich sein.
- **h3**: Opt-in für HTTP/3 (QUIC) für diese OTT-Sitzung. Veranlasst den Server, im Response einen `Alt-Svc`-Header auszugeben; ein kompatibler Player / Browser wechselt daraufhin auf QUIC. Siehe Abschnitt HTTP/3 (QUIC) weiter unten.

Für die Kompatibilität mit einigen HLS-Clients kann der Dateiname index.m3u8 an die URL angehängt werden, z. B. [http://host:port/hls/stream/login/password/index.m3u8](http://host:port/hls/stream/login/password/index.m3u8).

Der Auslieferungsmodus wird über die Stream-Einstellung *OTT HLS* festgelegt (Registerkarte **OTT**): *Peering/HLS*, *OTT/HLS* oder *OTT/HLS/LL-HLS/LL-Dash*.

*Peering/HLS* — ein Modus mit einfacher Aufteilung in Segmente (Chunks). Empfohlen für das Peering (die Distribution) von Streams. Es wird nur **HLS** über MPEG-TS (`/hls`) ausgeliefert. Standardmäßig wird die Playlist als *EXT-X-VERSION:3* ausgegeben, um mit Peer-Clients kompatibel zu sein.

*OTT/HLS* — ein Modus mit einer Segmentaufteilung, die auf einen schnellen Player-Start beim OTT-Broadcasting optimiert ist. In diesem Modus ist die CPU-Last höher; er wird für das Broadcasting empfohlen. Es wird **HLS** über MPEG-TS (`/hls`) ausgeliefert. Standardmäßig wird die Playlist als *EXT-X-VERSION:6* mit *EXT-X-INDEPENDENT-SEGMENTS* und dem Attribut *CHARACTERISTICS* in *EXT-X-MEDIA TYPE=SUBTITLES* ausgegeben (Apple HLS, hls.js, Safari, dash.js/Shaka). Benötigt ein bestimmter Client einen früheren Wert, setzen Sie ihn über den Query-Parameter `?v=` (siehe die Parameterliste oben).

*OTT/HLS/LL-HLS/LL-Dash* — ein Auslieferungsmodus über **CMAF** (fragmentiertes MP4, *fMP4*; seit Version 1.13). Der Stream erzeugt fMP4-Segmente (`.m4s` + gemeinsame `init.mp4`, `mimeType="video/mp4"`), auf deren Basis ausgeliefert werden:

- **MPEG-DASH** unter `/dash` — jetzt über CMAF und **nicht** über MPEG-TS;
- **Low-Latency HLS** unter `/llhls` (siehe Low-Latency HLS unten);
- bei aktivierter Stream-Einstellung *Enable TS Chunk* (Standard *true*) — zusätzlich Legacy-**HLS** über MPEG-TS (`/hls`), wie im *OTT/HLS*; bei *false* werden nur fMP4-Segmente ausgeliefert, was Festplatte und CPU schont.

Die **HLS**-Playlist im *OTT/HLS/LL-HLS/LL-Dash* ist standardmäßig ebenfalls *EXT-X-VERSION:6*.

> **Bemerkung**
>
> **MPEG-DASH** und **Low-Latency HLS** sind nur im *OTT/HLS/LL-HLS/LL-Dash* verfügbar. Im *OTT/HLS* und *Peering/HLS* wird ausschließlich **HLS** über MPEG-TS ausgeliefert.

Für den HTTP-Server kann SSL (HTTPS) aktiviert werden — in den Server-Einstellungen.

**Chunk Min Interval und Chunk Max Interval**

Im OTT-Modus wird der Stream auf PAT/PMT/SPS/PPS/IFrame analysiert, und die Chunks werden nach dem Kriterium des schnellen Player-Starts geschnitten. Die Analyse beginnt bei *min interval*, und falls die Daten aus irgendeinem Grund nicht gefunden werden, wird der Chunk bei *max interval* zwangsweise geschnitten.

**GOP-aligned segments**

Im *OTT/HLS* richtet der Segmenter die Chunk-Grenzen an Random-Access-Punkten aus und unterscheidet zwischen *IDR* und einem gewöhnlichen *I-frame*. Sendet die Quelle mit *closed-GOP* (IDR vorhanden), beginnt jedes *.ts*-TS-Segment garantiert mit *SPS / PPS / IDR* (bei HEVC — zusätzlich *VPS*) — einem echten Einstiegspunkt, an dem der Player den Stream öffnet. Ist die Quelle *open-GOP* / ohne IDR, dient der nächstgelegene I-frame als Grenze (das bisherige Verhalten). Der Segmenter schneidet den „Schwanz“ des vorherigen GOP — die *P / B*-Slices — aus dem Fenster zwischen dem führenden PAT und dem ersten SPS des Chunks heraus. Das:

- beseitigt das anfängliche Schwarzbild beim Start einer VOD-Sitzung (`?t=` / `?epg=`) in *hls.js*, *Safari* und *VLC*: der MSE-Decoder erhält das korrekte Header-Set der NAL-Einheiten bereits im ersten Segment und startet sofort;
- bringt die Ausgabe in Übereinstimmung mit *HLS RFC 8216 §3* („Each Media Segment MUST contain a SPS and a PPS that decode its first Access Unit“);
- macht die *EXT-X-INDEPENDENT-SEGMENTS*-Erklärung in einer *EXT-X-VERSION:6*-Playlist korrekt.

Steuerung über die Stream-Einstellung *gop-aligned-segment* (Standard *true*). Wirkt nur bei *HLS = OTT/HLS*: im *Peering/HLS* und bei MPTS-Streams bleibt das Verhalten unverändert. PSI (PAT / PMT) und Audio bleiben vollständig erhalten; einziger Nebeneffekt ist ein einbildiger *continuity_counter*-Sprung auf der Video-PID an der Grenze zweier benachbarter Chunks, was für HLS / DASH MSE eine legitime Decode-Boundary ist.

Bei der Ausrichtung an Einstiegspunkten kann die tatsächliche Chunk-Dauer über *Chunk Min Interval* hinaus aufgerundet werden. Daher spiegelt der Wert *EXT-X-TARGETDURATION* in der Live-Playlist die **maximale tatsächliche** Segmentdauer wider (Abschnitt 4.3.3.1 von *RFC 8216*) statt des konfigurierten Minimums. Das hält das Manifest innerhalb des Standards: *hls.js* und kompatible Player verkürzen das Aktualisierungsintervall der Playlist nicht und lösen keine falschen *bufferStalledError* aus.

**Low-Latency HLS (/llhls)**

Im *OTT/HLS/LL-HLS/LL-Dash* steht neben `/dash` ein separater **Low-Latency HLS**-Endpoint zur Verfügung — Auslieferung mit reduzierter Latenz auf denselben CMAF-fMP4-Segmenten:

- [http://host:port/llhls/stream/login/password](http://host:port/llhls/stream/login/password)
- [http://host:port/llhls/stream/login](http://host:port/llhls/stream/login)
- [http://host:port/llhls/stream/](http://host:port/llhls/stream/)

Die Medien-Playlist wird in *partielle Segmente* (*parts*, `#EXT-X-PART`-Direktiven) aufgeteilt: Der Player beginnt die Wiedergabe, ohne auf das fertige vollständige Segment zu warten. Verwendet werden ein blockierendes Neuladen der Playlist (der Server hält die Anfrage zurück, bis der nächste part bereit ist) und der Preload-Hinweis `#EXT-X-PRELOAD-HINT`.

Die Ziel-Dauer eines part wird über die Stream-Einstellung *Part Target Duration* festgelegt (ms; Standard 500, Bereich 100–5000). Der Wert wird im laufenden Betrieb übernommen, ohne den Stream neu zu starten, und muss kleiner als *Chunk Min Interval* sein.

**HLS / DASH / LL-HLS Adaptive Multistream**

HLS Adaptive Multistream wird seit Version 1.10 unterstützt, DASH Adaptive Multistream seit Version 1.12 (seit Version 1.13 — über CMAF), Low-Latency HLS Adaptive seit Version 1.13.

Für adaptive Streams wird eine separate Playlist konfiguriert. Dazu ist Folgendes nötig:

- OTT-Auslieferung bei den Streams aktivieren, die in die adaptive Playlist aufgenommen werden: *OTT/HLS* — für adaptives **HLS** über MPEG-TS; *OTT/HLS/LL-HLS/LL-Dash* — für adaptives **DASH** / **Low-Latency HLS** über CMAF.
- Im Hauptmenü erscheint ein Bereich für adaptive Streams. Dort muss ein Stream hinzugefügt und alle Streams angegeben werden, die in diese Playlist aufgenommen werden sollen.
- Für Streams kann ein Bitrate-Parameter gesetzt werden. Standardmäßig ist er 0 — die Bitrate wird aus dem gemessenen Wert übernommen; andernfalls kann sie explizit gesetzt werden.

Für adaptive Playlists gilt eine andere URL:

- [http://host:port/hls/adaptive/stream/login/password](http://host:port/hls/adaptive/stream/login/password)
- [http://host:port/hls/adaptive/stream/login](http://host:port/hls/adaptive/stream/login)
- [http://host:port/hls/adaptive/stream/](http://host:port/hls/adaptive/stream/)
- [http://host:port/dash/adaptive/stream/login/password](http://host:port/dash/adaptive/stream/login/password)
- [http://host:port/dash/adaptive/stream/login](http://host:port/dash/adaptive/stream/login)
- [http://host:port/dash/adaptive/stream/](http://host:port/dash/adaptive/stream/)
- [http://host:port/llhls/adaptive/stream/login/password](http://host:port/llhls/adaptive/stream/login/password)
- [http://host:port/llhls/adaptive/stream/login](http://host:port/llhls/adaptive/stream/login)
- [http://host:port/llhls/adaptive/stream/](http://host:port/llhls/adaptive/stream/)

Peers (Clients) können — wie bei normalen Streams — Zugriffsbeschränkungen auf adaptive Streams haben. Eine Berechtigung für einen adaptiven Stream schließt die Berechtigung für alle enthaltenen Substreams ein.

# HTTP/3 (QUIC)

Seit Version 1.13.1.438 enthält **Perfect Streamer** einen integrierten **HTTP/3**-Server für die OTT-Auslieferung von HLS, MPEG-DASH und Low-Latency HLS über **QUIC** (RFC 9000 + RFC 9114). Der Stack ist **ngtcp2** (QUIC v1) + **nghttp3** (HTTP/3 frame layer); die TLS-Infrastruktur verwendet dasselbe Zertifikat wie der HTTPS-Listener.

QUIC bedient ausschließlich OTT-Routen:

- `/` — Root-Redirect,
- `/hls/...`, `/dash/...` und `/llhls/...` — Master-Playlists / MPD,
- `/h<sessID>/...` — Per-Session-URL (Media-Playlists, Segmente, VTT),
- `/http/<stream>/...` — Raw-MPEG-TS über HTTP.

Low-Latency HLS und DASH werden über QUIC inkrementell (chunked) ausgeliefert: *parts* gehen an den Client, sobald sie bereit sind, ohne auf das vollständige Segment zu warten.

Administrative Pfade (`/data`, `/config`, `/xmltv`, `/db/`, `/login`, `/logout`, `/restart`) liefern über QUIC **404** — die Admin-API verbleibt auf HTTPS / HTTP-TCP. Dies ist eine bewusste Einschränkung zur Reduzierung der Angriffsfläche des QUIC-Listeners.

## Aktivierung

Die QUIC-Einstellungen befinden sich im Abschnitt **Configuration / HTTP server** (Knoten `/config/http-server`):

- **HTTP/3 Enable** (`http3-enable`) — globales Flag zur Aktivierung des QUIC-Listeners. Standardwert: **off**. Die Aktivierung öffnet einen UDP-Socket an `http3-port`; die Deaktivierung schließt ihn.
- **HTTP/3 Port** (`http3-port`) — UDP-Port des QUIC-Listeners. Standardwert: **43984**. QUIC läuft auf UDP, HTTPS auf TCP; die Ports können übereinstimmen oder abweichen — ein Konflikt zwischen ihnen besteht nicht.
- **HTTP/3 0-RTT Enable** (`http3-zero-rtt-enable`) — erlaubt den 0-RTT-Handshake (RFC 9001 §4.6.1) bei wiederaufgenommenen Verbindungen desselben Clients. Reduziert die Start-Latenz; das Replay-Risiko ist bei nicht idempotenten Anfragen zu berücksichtigen (für rein lesende OTT-Last unbedenklich). Standardwert: **on**.

Konfigurationsänderungen werden im laufenden Betrieb angewendet, ohne Neustart des Dienstes.

Zertifikat und Schlüssel werden vom HTTPS-Listener übernommen — es gibt keine separate Zertifikatskonfiguration für HTTP/3. Ist HTTPS nicht konfiguriert (`ssl-enable=false`), liefert die Aktivierung von HTTP/3 nichts — der Handshake scheitert.

## Der Parameter `?h3` — Opt-in pro Sitzung

Ein Browser verbindet sich nicht direkt mit einem HTTP/3-Endpunkt — er geht zunächst über HTTPS/TCP, empfängt im Response den Header `Alt-Svc: h3=":<port>"; ma=86400` (RFC 7838) und schaltet erst nachfolgende Anfragen an diesen Origin auf QUIC um.

In Perfect Streamer ist die Ausgabe von `Alt-Svc` ein **Opt-in pro OTT-Sitzung**. Der Server kündigt QUIC nicht jedem Client unterschiedslos an: Der Client muss HTTP/3 explizit über den Query-Parameter `?h3` auf der HLS-/DASH-Master-URL anfordern.

| Wert in der URL | Opt-in-Wert | `Alt-Svc` im Response |
| --- | --- | --- |
| Parameter fehlt | off (default) | nein |
| `?h3` (ohne Wert) | on | ja |
| `?h3=1`, `?h3=on`, `?h3=yes`, `?h3=true` | on | ja |
| `?h3=0`, `?h3=off`, `?h3=no`, `?h3=false` | explicit off | nein (wie bei fehlend) |

Sobald der Client die Session-URL `/h<sess>/...` erhalten hat, wird das `wantH3`-Flag in der Sitzung gespeichert — alle nachfolgenden Media-Playlist-Refreshs, Segment-GETs und VTT-Chunk-GETs unter dieser Session-URL erhalten **ebenfalls** `Alt-Svc`, auch wenn `?h3` in der jeweiligen Anfrage nicht vorhanden ist. Ohne Opt-in auf dem Master entsteht kein Sticky-Verhalten.

`Alt-Svc`-Gating:

1. Der QUIC-Listener ist global aktiviert (`http3-enable=true`); andernfalls wird die Ankündigung selbst bei gesetztem `?h3` unterdrückt.
2. Die Anfrage kam **nicht** über QUIC — bei Anfragen, die bereits über H3 laufen, ist `Alt-Svc` sinnlos und wird nicht ausgegeben.
3. Per-Session- oder Per-URL-`wantH3=true` (siehe Tabelle oben).
4. Der Admin- und der EPG-Server geben niemals `Alt-Svc` aus — sie verfügen über keinen QUIC-Listener.

Dieses Verhalten ist mit RFC 7838 §3 konform — der Server entscheidet selbst, bei welchen Antworten `Alt-Svc` ausgegeben wird.

## Szenario der QUIC-Umschaltung im Browser

Typischer Ablauf (Chrome / Firefox / Safari):

1. Der Player öffnet die Master-URL mit explizitem Opt-in:

   ```
   https://stream.example.com:41982/hls/test1/login/password/index.m3u8?h3=1
   ```
2. Die erste Anfrage erfolgt über HTTPS/TCP. Im Response gibt der Server `Alt-Svc: h3=":43984"; ma=86400` aus.
3. Der Browser merkt sich die Zuordnung `stream.example.com:41982 → h3=":43984"`. In Chrome lässt sie sich auf der Seite `chrome://net-internals/#alt-svc` einsehen; in Firefox — `about:networking#http3`.
4. Bei nachfolgenden Anfragen an denselben Origin (Playlist-Refresh, Segment-GETs, VTT) öffnet der Browser eine QUIC-Verbindung auf `udp/43984` und kommuniziert weiter über HTTP/3. In den DevTools → Network wird die Spalte **Protocol** für diese Anfragen `h3`.

Lässt sich die QUIC-Verbindung nicht aufbauen (UDP-Port am Firewall blockiert, Zertifikat im System nicht vertrauenswürdig), bleibt der Browser transparent auf HTTPS/TCP — der Stream läuft funktional ohne Unterbrechung weiter.

## Client-Accounting und Monitoring

Die reale IP-Adresse eines QUIC-Clients im Accounting aktiver Peers (`/data/http-clients`, Limits konkurrierender Verbindungen, IP-basierte ACLs) ist die **tatsächliche Peer-Adresse** der QUIC-Verbindung und nicht der Loopback der internen Backend-Brücke.

Das Attribut `ott-type` in `/data/http-clients` ist zusammengesetzt, im Format `<PROTO>/<scheme>`:

- `PROTO` — OTT-Protokoll: `HLS`, `DASH` oder `HTTP`.
- `scheme` — der tatsächliche Netzwerktransport: `http`, `https` oder `quic`.

Beispiele: `HLS/quic`, `DASH/https`, `HTTP/http`. Das Admin-UI zeigt sowohl das OTT-Protokoll als auch den Netzwerktransport jedes Clients in einer einzigen Spalte.

Das OTT-Sitzungs-Timeout beträgt **60 Sekunden**, unabhängig vom Transport. Wechselt ein Client zwischen Transporten, wird das Schema ausschließlich entlang der Prioritätskette `http` → `https` → `quic` aufgewertet. Ein paralleler Rückfall auf eine weniger gesicherte Verbindung überschreibt den aktuellen Typ nicht — im Accounting verbleibt der sicherste beobachtete Transport.

## Player-Kompatibilität

HTTP/3 für OTT unterstützen:

- **iOS AVPlayer / Safari** — nativ, über `Alt-Svc`; 0-RTT wird unterstützt.
- **Chrome, Firefox, Edge, Brave** — über `Alt-Svc`; HLS wird mit hls.js, DASH mit dash.js / Shaka wiedergegeben; der Player-Traffic erbt HTTP/3 vom Browser-fetch-API.
- **Android ExoPlayer** — über die Cronet-QUIC-Engine (nicht der Standardtransport; erfordert clientseitige Konfiguration).

**VLC** (libVLC) unterstützt HTTP/3 nicht — auf diesen Clients funktioniert der Stream weiter über HTTPS/TCP, ohne den QUIC-Vorteil.

Der praktische Vorteil von QUIC gegenüber HTTPS/TCP zeigt sich am deutlichsten in Mobilfunknetzen / Wi-Fi / verlustbehafteten Netzen:

- kein Head-of-Line-Blocking auf TCP-Ebene — ein Verlust in einem HTTP-Stream blockiert die übrigen nicht;
- 0-RTT-Handshake bei wiederaufgenommenen Verbindungen desselben Clients;
- stabilere ABR-Bitrate bei Paketverlusten von 1–5 %.

In verwalteten Netzen / Unternehmens-Wi-Fi fällt der Gewinn meist bescheiden aus — 5–10 % bei der Startup-Latenz und nahezu null im Steady-State. Die CPU-Last auf dem Server ist bei QUIC höher als bei Kernel-TCP — der Preis für TLS und Transport im User Space.

# Caching-Modell für OTT HLS und DASH

Der Server liefert Antworten in drei Kategorien, die sich in Inhaltslebensdauer und Cache-Eignung in Zwischenknoten (Reverse Proxy, CDN, Client-Cache) unterscheiden.

## 1. Caching-Modell

### 1.1. Ressourcen und HTTP-Header

| Ressource | URL | Content-Type | Cache-Control |
| --- | --- | --- | --- |
| TS-Segment (HLS) | `/h<sess>/<keyHex>.ts`, `/h<sess>/sub/<pid>/<keyHex>.vtt` | `video/mp2t` | `public, max-age=60, immutable` |
| fMP4-Segment (DASH / LL-HLS) | `/h<sess>/init.mp4`, `/h<sess>/<key\|N>.m4s` | `video/mp4` | `public, max-age=60, immutable` |
| DASH MPD | `/h<sess>/index.mpd` | `application/dash+xml; charset=utf-8` | `public, max-age=1` |
| HLS master | `/hls/<stream>/<login>/<pass>/index.m3u8` | `application/vnd.apple.mpegurl` | `public, max-age=1` |
| HLS media | `/h<sess>/index.m3u8`, `/h<sess>/sub/<pid>/index.m3u8` | `application/vnd.apple.mpegurl` | `public, max-age=1` |
| 302 Redirect | `/dash/<stream>/<login>/<pass>/index.mpd` | — | `no-cache, no-store` |
| Raw TS | `/http/<stream>/<login>/<pass>` | `video/mp2t` | nicht gesetzt; nicht gecacht |

### 1.2. Segmenteigenschaften

Der hexadezimale Segment-Identifier in der URL (`<keyHex>` in den Pfaden `/h<sess>/<keyHex>.ts`) wird als CRC64 über die Segment-Startzeit und die Stream-ID gebildet und ist global eindeutig. Die Segment-URL adressiert unveränderliche Inhalte — bei wiederholten Anfragen an dieselbe URL wird ein identischer Bytestrom zurückgegeben (solange das Segment innerhalb des Schiebefensters bleibt).

Die Direktive `immutable` unterdrückt die bedingte Revalidierung durch den Client (`If-None-Match`, `If-Modified-Since`). `max-age=60` ist mit dem typischen `timeShiftBufferDepth=40s` kompatibel.

CMAF-fMP4-Segmente (`.m4s`) und die gemeinsame `init.mp4` für **DASH** / **Low-Latency HLS** werden analog adressiert und nach demselben Modell zwischengespeichert (`immutable`, `max-age=60`). Partielle Segmente (*parts*) von LL-HLS sind Byte-Range-Anfragen in dieselbe `.m4s`, sodass sie keinen separaten Cache-Eintrag bilden.

### 1.3. Manifest-Eigenschaften

`max-age=1` begrenzt die obere Schranke der Inhalts-Veralterung im Cache auf eine Sekunde. Zusammen mit `proxy_cache_lock on` (nginx) werden Anfragenspitzen am Manifest zu einer einzigen Origin-Anfrage pro Sekunde zusammengefasst.

### 1.4. Inhaltsvariabilität

Bei `absPath=0` (Standard; ohne URL-Parameter `a`) enthalten HLS-media- und DASH-MPD-Manifeste keinen Sitzungs-Identifier im Body. Der Manifest-Inhalt ist zwischen Sitzungen identisch, die zur selben (stream, param)-Kombination gehören. Dadurch kann ein Reverse-Proxy-Cache bei normalisiertem Cache-Key einen einzigen Eintrag sitzungsübergreifend wiederverwenden.

Bei `absPath=1` (URL-Parameter `a=1`) enthält der Manifest-Body absolute URLs einschließlich Schema, Host und Sitzungs-Identifier. Der Inhalt wird sitzungsspezifisch; eine sitzungsübergreifende Cache-Wiederverwendung ist nicht möglich.

## 2. Client-Verhalten

| Klient | Manifest-Refresh-URL | Auswirkung auf die Sitzungszahl |
| --- | --- | --- |
| VLC 3.x HLS | `/h<sess>/index.m3u8` | Eine Sitzung pro Wiedergabe |
| VLC 3.x DASH | `/dash/<stream>/.../index.mpd` | Wird per Session-Reuse behandelt (siehe 3.3) |
| ffmpeg 5.x HLS | `/h<sess>/index.m3u8` | Eine Sitzung pro Wiedergabe |
| ffmpeg 5.x DASH | `/dash/<stream>/.../index.mpd` (Wiederholungsschleife) | Wird per Session-Reuse behandelt (siehe 3.3) |
| dash.js, hls.js | `/h<sess>/...` über `<Location>` / Session-URL | Eine Sitzung pro Wiedergabe |

## 3. Spezielle Mechanismen

### 3.1. HTTP 302 Redirect für DASH

Eine Anfrage der Form `/dash/<stream>/<login>/<pass>/index.mpd` liefert die Antwort `302 Found` mit dem Header `Location: /h<sess>/index.mpd`. Der Antwort-Body ist leer. Authentifizierung und Sitzungs-Allokation finden in der Phase der Redirect-Verarbeitung statt.

Clients, die Redirect-Caching unterstützen, greifen in nachfolgenden Anfragen direkt auf die Sitzungs-URL zu. Clients ohne Unterstützung wiederholen die Redirect-Anfrage. Die Kosten der Redirect-Wiederverarbeitung beschränken sich auf Authentifizierungsprüfung und Session-Reuse-Operationen.

### 3.2. Session-Reuse für DASH

Bei der Verarbeitung einer `/dash/.../index.mpd`-Anfrage desselben Logins an denselben Stream (mit demselben *adaptive*-Merkmal) findet der Server eine bereits bestehende DASH-Sitzung und gibt deren Kennung erneut zurück. Es wird keine neue Sitzung erstellt; ein Platz im Limit gleichzeitiger Verbindungen wird nicht verbraucht.

Gilt nur für DASH. Für HLS ist kein eigener Reuse-Mechanismus erforderlich: HLS-Clients aktualisieren die Media-Playlist über die Session-URL und erzeugen bei jedem Refresh keine neue Sitzung.

### 3.3. Wiederverwendung von Segmenten zwischen Sitzungen

Der Pfad `/h<sess>/<keyHex>.ts` ist unabhängig von `<sess>`, wenn `<keyHex>` auf Inhalt aufgelöst wird: `<keyHex>` identifiziert ein TS-Segment innerhalb eines Streams global eindeutig. Nginx mit einem normalisierten Cache-Key (Entfernen des Präfixes `/h<sess>/`) bedient jede Anfrage nach demselben `<keyHex>` aus einem einzigen Cache-Eintrag, unabhängig davon, welche Clients sie gestellt haben.

Dasselbe gilt für CMAF-fMP4-Segmente (`.m4s`) und `init.mp4`: Ihr Inhalt ist unveränderlich und wird innerhalb des Streams adressiert, sodass die Normalisierung des Cache-Keys dieselbe sitzungsübergreifende Deduplizierung im Cache ergibt.

## 4. Anfrageparameter

| Parameter | Standardwert | Auswirkung |
| --- | --- | --- |
| `a` | `0` | `1` — absolute URLs in den Manifesten; `0` — relative |
| `s` | `40` | `timeShiftBufferDepth` in Sekunden |
| `m` | `40` | Mindestfensterlänge für die Manifest-Ausgabe |
| `v` | `6` für *OTT/HLS* und *OTT/HLS/LL-HLS/LL-Dash*, `3` für *Peering/HLS* | `#EXT-X-VERSION` in HLS (von DASH ignoriert); ein expliziter Wert in der URL überschreibt den Default |
| `h3` | fehlt (off) | Opt-in für HTTP/3 (QUIC) — veranlasst den Server, `Alt-Svc` im Response auszugeben. Erkannte Werte: presence ⇒ on, `1`/`on`/`yes`/`true` ⇒ on, `0`/`off`/`no`/`false` ⇒ explicit off. Sticky auf der Session-URL `/h<sess>/...`. Siehe Abschnitt HTTP/3 (QUIC). |

Das Ändern eines Parameters per Query-String aktualisiert die in der Sitzung gespeicherten Werte beim nächsten erneuten Öffnen der Sitzung.

## 5. Lastcharakteristiken

Die Origin-Last skaliert mit der Anzahl gleichzeitig beobachteter unterschiedlicher Streams. Die Erhöhung der Anzahl gleichzeitig denselben Stream beobachtender Clients erhöht die Anzahl der Origin-Anfragen nicht, sofern ein Reverse-Proxy-Cache mit normalisiertem Cache-Key vorhanden ist.

| Szenario | Origin-Request-Rate (Ref.) |
| --- | --- |
| 1 Client pro Stream X | MPD: 0.4 req/s, segment: 0.2 req/s |
| N Clients auf einem Stream X (Cache aktiv) | MPD: 1 req/s, segment: 0.2 req/s |
| N ffmpeg-Clients im Replay-Modus auf einem Stream | MPD: 1 req/s (mit `proxy_cache_lock`) |
| N Clients auf N verschiedene Streams | MPD: 0.4·N req/s, segment: 0.2·N req/s |

## 6. Nginx als cachender Reverse-Proxy

### 6.1. Basiskonfiguration

```nginx
proxy_cache_path /var/cache/nginx/pss_segments
    levels=1:2 keys_zone=pss_segments:100m
    max_size=20g inactive=30m use_temp_path=off;

proxy_cache_path /var/cache/nginx/pss_manifests
    levels=1:2 keys_zone=pss_manifests:10m
    max_size=256m inactive=5m use_temp_path=off;

upstream pss_backend {
    server 127.0.0.1:41972;
    keepalive 64;
}

map $uri $pss_cache_key {
    ~^/h[0-9a-f]{16}(?<tail>/.+\.(ts|m3u8))$  "stream:$tail";
    default                                     $uri;
}

server {
    listen 80;
    server_name stream.example.com;

    location ~* "^/h[0-9a-f]{16}(/[0-9]+)?/([0-9a-f]+\.(ts|m4s)|init\.mp4)$" {
        proxy_cache               pss_segments;
        proxy_cache_key           $pss_cache_key;
        proxy_cache_valid         200 60s;
        proxy_cache_valid         404 403 0s;
        proxy_cache_lock          on;
        proxy_cache_use_stale     updating error timeout;
        proxy_cache_revalidate    on;
        add_header                X-Cache-Status $upstream_cache_status;

        proxy_pass                http://pss_backend;
        proxy_http_version        1.1;
        proxy_set_header          Connection "";
        proxy_buffering           on;
    }

    location ~* "(^/h[0-9a-f]{16}(/[0-9]+)?/index\.(m3u8|mpd)$|^/(hls|dash)/.*\.(m3u8|mpd)$)" {
        proxy_cache               pss_manifests;
        proxy_cache_key           $pss_cache_key;
        proxy_cache_valid         200 1s;
        proxy_cache_valid         404 403 0s;
        proxy_cache_lock          on;
        proxy_cache_lock_timeout  2s;
        proxy_cache_use_stale     updating;
        add_header                X-Cache-Status $upstream_cache_status;

        proxy_pass                http://pss_backend;
        proxy_http_version        1.1;
        proxy_set_header          Connection "";
    }

    location / {
        proxy_pass                http://pss_backend;
        proxy_http_version        1.1;
        proxy_set_header          Connection "";
        proxy_set_header          X-Forwarded-Proto $scheme;
        proxy_set_header          X-Forwarded-Host  $host;
        proxy_buffering           off;
        proxy_read_timeout        3600s;
    }
}
```

### 6.2. Zweck der Direktiven

| Direktive | Zweck |
| --- | --- |
| `proxy_cache_lock on` | Serialisiert Upstream-Anfragen bei parallelen Cache-Misses auf denselben Schlüssel |
| `proxy_cache_use_stale updating` | Liefert die veraltete Kopie an parallele Anfragen während der Cache-Aktualisierung |
| `proxy_cache_revalidate on` | Nutzt `If-Modified-Since` bei Cache Miss mit vorhandener Kopie |
| `proxy_cache_valid 404 403 0s` | Verbietet das Caching von Authorization-Fehlern und 404 |
| `keepalive 64` im Upstream | Verwaltet einen Pool persistenter Verbindungen zum Origin |
| `proxy_buffering on` | Für Segmente; aktiviert die Antwortpufferung in nginx |
| `proxy_buffering off` | Für den Bereich `/`; deaktiviert Buffering (Raw Streaming) |

### 6.3. Berechnung der `max_size` des Segmentcaches

Richtwert: `bitrate × timeShiftBufferDepth × distinct_streams × 2`

Beispiel: 10 Streams × 8 Mbps × 40 s × 2 ≈ 800 MB. Es wird empfohlen, einen 10-fachen Sicherheitsfaktor für Bitratenschwankungen einzuplanen.

### 6.4. TLS-Terminierung

Der Perfect-Streamer-Server akzeptiert Verbindungen auf HTTP- und HTTPS-Ports. Bei TLS-Terminierung am nginx verwendet das Upstream den HTTP-Port. Die Weiterleitung der Header `X-Forwarded-Proto` und `X-Forwarded-Host` ist erforderlich für die korrekte Bildung absoluter URLs bei `absPath=1`.

```nginx
server {
    listen 443 ssl http2;
    server_name stream.example.com;

    ssl_certificate           /etc/letsencrypt/live/stream.example.com/fullchain.pem;
    ssl_certificate_key       /etc/letsencrypt/live/stream.example.com/privkey.pem;
    ssl_protocols             TLSv1.2 TLSv1.3;
    ssl_session_cache         shared:SSL:10m;
    ssl_session_timeout       1d;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    location ... {
        proxy_pass                http://pss_backend;
        proxy_set_header          X-Forwarded-Proto https;
        proxy_set_header          X-Forwarded-Host  $host;
        proxy_set_header          Host              $host;
        # + caching directives from 6.1
    }
}

server {
    listen 80;
    server_name stream.example.com;
    return 301 https://$host$request_uri;
}
```

Bei HTTPS zwischen nginx und Origin gelten `proxy_ssl_verify` und `proxy_ssl_trusted_certificate`. Bei Loopback-Verbindungen ist Verschlüsselung überflüssig.

### 6.5. Multi-host

Wenn ein nginx-Prozess mehrere `server_name` bedient, wird `$host` zum Cache-Schlüssel hinzugefügt, um Inhalte zu isolieren:

```nginx
map $uri $pss_cache_key {
    ~^/h[0-9a-f]{16}(?<tail>/.+\.(ts|m3u8))$  "$host:stream:$tail";
    default                                     "$host:$uri";
}
```

Die `keys_zone`-Größe wird mit 8000 Keys/MB berechnet. Für Multi-Host-Installationen mit Tausenden von Streams werden `keys_zone=...:300m` oder mehr empfohlen.

## 7. Client-seitiges Caching

`Cache-Control: immutable` wird von den Browsern Chrome/Firefox/Safari berücksichtigt. Der Client-Cache liefert das Segment bei wiederholtem Zugriff ohne bedingte Anfrage zurück (auch bei Rückwärts-Seek innerhalb des Player-Buffers).

Service Workers können basierend auf dem Cache-Control-Inhalt eine `cache-first`-Strategie anwenden. DASH-Player (dash.js, Shaka) nutzen MSE über `SourceBuffer`; ein in den Buffer eingelegtes Segment bleibt ohne erneute HTTP-Anfrage verfügbar, bis es das Schiebe-Fenster verlässt.

Für Cross-Domain-Anfragen erlaubt der Header `Access-Control-Allow-Origin: *` Caching in shared caches ohne `Vary: Origin`. Beim Wechsel des ACAO-Werts auf einen konkreten Origin wird `Vary: Origin` erforderlich, was die Effizienz des shared cache reduziert.

## 8. Verteilung über CDN

Perfect Streamer ist mit Pull-from-Origin-CDNs kompatibel (Cloudflare, Akamai, Fastly, BunnyCDN, Amazon CloudFront).

**Origin shield.** Empfohlen werden ein oder mehrere Shield-Knoten zwischen CDN-Edge und Origin, um die Origin-Anfragerate bei global verteilten Clients zu senken.

**Purge.** Content-addressed Segmente erfordern keinen Purge. Bei Stream-Metadaten-Änderungen (Codec, Auflösung) aktualisieren sich Manifeste innerhalb von `max-age=1` ohne expliziten Purge.

**Cache Warming.** Bei erwartetem Lastanstieg auf einen Stream darf das CDN von mehreren Standorten aus vor Sendebeginn vorgeheizt werden.

**Geo-Verteilung.** Segmente (`max-age=60`) eignen sich gut für geografisch verteiltes Caching. Manifeste (`max-age=1`) tolerieren bis zu eine Sekunde Lieferverzögerung — akzeptabel für non-low-latency live.

## 9. Überwachung

### 9.1. `X-Cache-Status`

`add_header X-Cache-Status $upstream_cache_status;` in jeder gecachten Location ergänzen. Werte:

| Wert | Beschreibung |
| --- | --- |
| `HIT` | Antwort aus Cache |
| `MISS` | War nicht im Cache; vom Origin geholt und gespeichert |
| `EXPIRED` | Abgelaufen, erneuert |
| `UPDATING` | Stale-Kopie an parallele Anfrage während der Aktualisierung ausgeliefert |
| `STALE` | `use_stale` lieferte die abgelaufene Kopie (Origin nicht erreichbar) |
| `REVALIDATED` | Origin lieferte 304 Not Modified |
| `BYPASS` | `proxy_cache_bypass` wurde ausgelöst |

### 9.2. Access-Log-Format

```nginx
log_format pss_cache '$remote_addr $status $request_method "$request" '
                     '$body_bytes_sent rt=$request_time ut=$upstream_response_time '
                     'cache=$upstream_cache_status key=$pss_cache_key';

server {
    access_log /var/log/nginx/pss.log pss_cache;
}
```

### 9.3. Metriken

Das Modul `nginx-vts` exportiert Per-Zone-Metriken im Prometheus-Format:

```
GET /status/format/prometheus
```

Empfohlene Schwellwerte für Alerts:

| Metrik | Schwelle | Mögliche Ursache |
| --- | --- | --- |
| Segment HIT rate | < 90 % über 5 Minuten | Cache-Key-Normalisierung defekt; `max_size` zu klein |
| Manifest MISS rate | > 50 % über 1 Minute | `proxy_cache_lock` serialisiert die Anfragen nicht |
| Upstream response time p95 | > 500 ms über 1 Minute | Origin-Überlastung |
| Cache zone fill | > 90 % über 10 Minuten | Annäherung an `max_size`; LRU-Eviction wird geplant |

## 10. Diagnose

| Symptom | Wahrscheinliche Ursache | Lösung |
| --- | --- | --- |
| Niedrige Segment-HIT-Rate | `Vary: Origin` mit hoher Origin-Variabilität; defekte Normalisierung in `map` | Header und Regex in der `map`-Direktive prüfen |
| 404 bei Segmenten nach Verlassen des Fensters | Gecachter 404 bei Segment, das aus dem Sliding Window gefallen ist | `proxy_cache_valid 404 0s` in der Segments-Location ergänzen |
| Playback-Start-Verzögerung 2–5 s | `proxy_cache_lock_timeout` überschreitet die Ziel-Latenz | Auf 1–2 s senken; `proxy_cache_use_stale updating` aktivieren |
| Manifest aktualisiert nicht | `proxy_cache_valid` überschreibt `max-age` | `proxy_cache_valid 200 1s` explizit setzen |
| Wachsendes TIME_WAIT am Upstream | `keepalive` fehlt im Upstream-Block | `keepalive 64`, `proxy_http_version 1.1` und `proxy_set_header Connection ""` hinzufügen |
| 403 bei `/dash/.../<segment>.m4s` von ffmpeg | Der Client löst relative URLs gegen die Pre-Redirect-URL auf | Der Server gibt `<BaseURL>/h<sess>/</BaseURL>` aus (absolute Pfade); im aktuellen Build kompatibel |
| Lags, häufiges Rebuffering bei entfernten Clients | Niedriger effektiver TCP-Durchsatz aufgrund von Slow Start und Idle Restart bei großen RTTs (300 ms und mehr) | Tuning des Linux-Netzwerk-Stacks auf dem Origin: siehe 10.1 |

### 10.1. TCP-Tuning des Origin für High-RTT-Clients

Das Problem tritt bei Clients mit großem RTT zum Origin (z. B. 300 ms und mehr) auf, wenn die Stream-Bitrate nahe an der Kanalkapazität liegt. Symptome im Player (VLC, ffmpeg, dash.js) — häufiges Rebuffering, Warnungen wie `ES_OUT_SET_PCR called too late` (mit Anstieg von `pts_delay`), `buffer deadlock prevented`, Stream-Abbrüche. Auf dem Server wirkt der Client dabei normal, Fehler gibt es keine, und der Durchsatz auf `/data/stream/...` entspricht dem Eingangsstrom.

Ursache:

- **TCP slow start.** Jede neue TCP-Verbindung beginnt mit einem Congestion Window von etwa 14 KB und vergrößert es über mehrere RTTs. Bei einem RTT von 300 ms dauert das Erreichen des vollen Fensters 2-3 Sekunden. In dieser Zeit wird ein HLS/DASH-Segment von 5 s Dauer (4-6 MB) merklich langsamer als in Echtzeit heruntergeladen.
- **TCP idle restart.** Zwischen Segmentanfragen pausiert ein HLS-Pull-Modell-Client 4-5 s. Standardmäßig setzt der Linux-Kernel nach einer solchen Pause das Congestion Window der Verbindung auf das Initial cwnd zurück (Verhalten `net.ipv4.tcp_slow_start_after_idle=1`). Folglich beginnt die Keep-Alive-Verbindung beim nächsten GET die Übertragung erneut aus dem Slow Start — auch bei einer bereits aufgewärmten Sitzung.

Eine zusätzliche Verschärfung — das standardmäßige CUBIC-Congestion-Control kommt mit langen RTTs und Paketverlusten auf zwischengeschalteten Netzabschnitten schlecht zurecht.

Lösung — zwei sysctl-Parameter auf dem Origin:

```bash
# Keep congestion window across idle pauses inside keep-alive sessions.
sysctl -w net.ipv4.tcp_slow_start_after_idle=0

# Use BBR instead of CUBIC: better behaviour on long-RTT paths
# with mild packet loss; paces sending instead of bursting.
modprobe tcp_bbr
sysctl -w net.ipv4.tcp_congestion_control=bbr
```

Für eine dauerhafte Anwendung:

```bash
cat > /etc/sysctl.d/99-pss-net.conf <<EOF
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_congestion_control    = bbr
EOF
sysctl --system
```

Den Haupteffekt liefert der erste Parameter (`tcp_slow_start_after_idle=0`). Er beseitigt direkt den erneuten Slow Start zwischen Segment-Anfragen innerhalb einer Keep-Alive-Verbindung. Der zweite (BBR) bietet zusätzliche Robustheit und gilt für alle neuen Verbindungen.

Das Tuning erfordert keinen Neustart von Perfect Streamer und gilt unmittelbar nach `sysctl -w` für alle neuen TCP-Verbindungen. Bestehende Verbindungen behalten das Congestion Control, mit dem sie aufgebaut wurden.

## 11. Sicherheit

### 11.1. Session URL

Eine URL der Form `/h<sess>/...` erfüllt die Funktion eines Sitzungs-Tokens — eine erneute Authentifizierung ist nicht nötig. Die Lebensdauer ist durch das idle timeout begrenzt (Wert 30 s). Bei Inaktivität wird die Sitzung von der cleaner-Aufgabe entfernt.

Anforderungen:

- HTTPS für alle OTT-Pfade (`/hls/`, `/dash/`, `/h<sess>/`) in Produktion
- Die Session-ID im `Location`-Header der 302 wird nicht gecacht (`no-cache, no-store`)

### 11.2. Rate limiting

```nginx
limit_req_zone $binary_remote_addr zone=dash_top:10m  rate=5r/s;
limit_req_zone $binary_remote_addr zone=hls_top:10m   rate=5r/s;
limit_req_zone $binary_remote_addr zone=llhls_top:10m rate=5r/s;

server {
    location /dash/ {
        limit_req zone=dash_top burst=20 nodelay;
        proxy_pass http://pss_backend;
    }
    location /hls/ {
        limit_req zone=hls_top burst=20 nodelay;
        proxy_pass http://pss_backend;
    }
    location /llhls/ {
        limit_req zone=llhls_top burst=20 nodelay;
        proxy_pass http://pss_backend;
    }
}
```

Session-URLs (`/h<sess>/`) benötigen kein Rate Limiting — die Verarbeitung ist günstig, Antworten werden gecacht.

### 11.3. Caching von Fehlerantworten

```nginx
proxy_cache_valid 200 60s;
proxy_cache_valid 301 302 0s;
proxy_cache_valid 404 403 0s;
proxy_cache_valid any 1s;
```

Verbietet das Caching von Redirects (eindeutiges sess in Location) und von Antworten mit Auth- oder Not-Found-Fehlern.

### 11.4. Einschränkung des Netzwerkzugriffs auf den Origin

Port 41972 (41982 für HTTPS) muss für externen Verkehr geschlossen sein. Zulässige Konfigurationen:

1. Perfect Streamer an `127.0.0.1` binden (bei lokalem nginx)
2. Firewall-Regel:

```
iptables -A INPUT -p tcp --dport 41972 ! -s 10.0.0.0/8 -j DROP
```

## 12. Middleware-Integration

### 12.1. Prefix-Login-Modell

Perfect Streamer kann die Nutzeridentifikation über Prefix-Login an Middleware/Billing-Systeme delegieren. Ein externer Connector zum Billing-System ist im aktuellen Release nicht enthalten.

Konfiguration des Embedded-Benutzers:

```
{
  "id": 9,
  "login": "sub",
  "password": "xxx",
  "is-prefix": true,
  "max-conn-http-hls": 1,
  "accept-stream": [ ... ]
}
```

Mit `is-prefix: true` akzeptiert der Server URLs mit Logins der Form `<prefix><billing_user_id>`:

```
/dash/test1/sub42/xxx/index.mpd
/hls/test1/sub43/xxx/index.m3u8
```

### 12.2. Statistikformat

```
<clients>
  <client login-id="-1974387287" login="sub" match-login="sub42"
          sess-id="11331..." ott-type="dash" stream-id="10000" .../>
  <client login-id="-2147031294" login="sub" match-login="sub43"
          sess-id="11132..." ott-type="dash" stream-id="10000" .../>
</clients>
```

Das Feld `login-id` enthält den Hash des URL-Logins. `login` ist der konfigurierte Wert. `match-login` ist der vom Client genutzte URL-Login.

### 12.3. Einschränkungen des Prefix-Logins

- **Gemeinsames Passwort.** Alle Teilnehmer des Prefix-Pools nutzen einen einzigen Passwortwert. Eine Kompromittierung des Passworts gewährt Zugriff auf jedes `<prefix><string>`.
- **ACL-Granularität.** `accept-stream` gilt für den gesamten Prefix-Pool; eine subscriber-spezifische ACL gibt es ohne externes Billing nicht.
- **Passwort-Rotation.** Eine Passwortänderung trennt alle aktiven Teilnehmer. Für eine schrittweise Umstellung sind vorübergehend zwei Prefix-Logins erforderlich.

## 13. WebVTT-Untertitel

Die Untertitelquelle ist DVB Teletext / DVB Subtitling aus dem Eingangs-MPEG-TS. In den Abschnitten **Media Information** oder **Original Media Information** müssen Teletext-Untertitel-Spuren vorhanden sein. Im Abschnitt **Analyzer** kann zusätzlich überprüft werden, dass Pakete der entsprechenden PIDs aktiv sind.

Für OTT HLS/DASH muss der OTT-Modus aktiviert sein (im *Peering/HLS* sind WebVTT-Untertitel nicht verfügbar). Im Abschnitt **Output # OTT** muss der Chunk-Zähler **OTT WebVTT buffer chunk count** einen Wert ungleich null aufweisen.

Zur Diagnose der Untertitel **Analyze** und **Trace** am Stream aktivieren. Beim Stream-Start sollte im Stream-Log Folgendes erscheinen:

```
Start Teletext subtitle decoder
[ttxsubdec] ttx: pid=331 magazine=8 page=0x88 lang=***
```

Im Folgenden wird der dekodierte Untertiteltext in das Log geschrieben.

### 13.1. URLs der VTT-Segmente

| Schema | URL | Inhalt |
| --- | --- | --- |
| HLS master | `/hls/.../index.m3u8` | `#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",...,URI="/h<sess>/sub/<pid>/index.m3u8"` |
| HLS subtitle playlist | `/h<sess>/sub/<pid>/index.m3u8` | Liste `<keyHex>.vtt` mit `#EXTINF` |
| HLS-VTT-Segment | `/h<sess>/sub/<pid>/<keyHex>.vtt` | VTT mit HLS-spezifischer X-TIMESTAMP-MAP |
| DASH MPD AdaptationSet | in `index.mpd` | `contentType="text" mimeType="text/vtt"` + `<SegmentTemplate media="$Number$.vtt">` |
| DASH-VTT-Segment | `/h<sess>/sub/<pid>/<seq>.vtt` | VTT mit DASH-spezifischer X-TIMESTAMP-MAP |

`<keyHex>` ist ein 16-stelliger Hex-CRC64 aus Segment-Startzeit, Stream-ID und Untertitelspur-PID. `<seq>` ist die dezimale laufende Nummer eines Untertitel-Stream-Chunks (die Untertitel-Nummerierung ist von der TS-Chunk-Nummerierung unabhängig).
