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 — Autorisierung per Login und Passwort
http://host:port/http/stream/login — Autorisierung per Login (Token)
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):
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.
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:
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:
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 anhttp3-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 |
|
|---|---|---|
Parameter fehlt |
off (default) |
nein |
|
on |
ja |
|
on |
ja |
|
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:
Der QUIC-Listener ist global aktiviert (
http3-enable=true); andernfalls wird die Ankündigung selbst bei gesetztem?h3unterdrückt.Die Anfrage kam nicht über QUIC — bei Anfragen, die bereits über H3 laufen, ist
Alt-Svcsinnlos und wird nicht ausgegeben.Per-Session- oder Per-URL-
wantH3=true(siehe Tabelle oben).Der Admin- und der EPG-Server geben niemals
Alt-Svcaus — 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):
Der Player öffnet die Master-URL mit explizitem Opt-in:
https://stream.example.com:41982/hls/test1/login/password/index.m3u8?h3=1
Die erste Anfrage erfolgt über HTTPS/TCP. Im Response gibt der Server
Alt-Svc: h3=":43984"; ma=86400aus.Der Browser merkt sich die Zuordnung
stream.example.com:41982 → h3=":43984". In Chrome lässt sie sich auf der Seitechrome://net-internals/#alt-svceinsehen; in Firefox —about:networking#http3.Bei nachfolgenden Anfragen an denselben Origin (Playlist-Refresh, Segment-GETs, VTT) öffnet der Browser eine QUIC-Verbindung auf
udp/43984und kommuniziert weiter über HTTP/3. In den DevTools → Network wird die Spalte Protocol für diese Anfragenh3.
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,DASHoderHTTP.scheme— der tatsächliche Netzwerktransport:http,httpsoderquic.
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) |
|
|
|
fMP4-Segment (DASH / LL-HLS) |
|
|
|
DASH MPD |
|
|
|
HLS master |
|
|
|
HLS media |
|
|
|
302 Redirect |
|
— |
|
Raw TS |
|
|
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 |
|
Eine Sitzung pro Wiedergabe |
VLC 3.x DASH |
|
Wird per Session-Reuse behandelt (siehe 3.3) |
ffmpeg 5.x HLS |
|
Eine Sitzung pro Wiedergabe |
ffmpeg 5.x DASH |
|
Wird per Session-Reuse behandelt (siehe 3.3) |
dash.js, hls.js |
|
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 |
|---|---|---|
|
|
|
|
|
|
|
|
Mindestfensterlänge für die Manifest-Ausgabe |
|
|
|
|
fehlt (off) |
Opt-in für HTTP/3 (QUIC) — veranlasst den Server, |
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 |
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¶
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 |
|---|---|
|
Serialisiert Upstream-Anfragen bei parallelen Cache-Misses auf denselben Schlüssel |
|
Liefert die veraltete Kopie an parallele Anfragen während der Cache-Aktualisierung |
|
Nutzt |
|
Verbietet das Caching von Authorization-Fehlern und 404 |
|
Verwaltet einen Pool persistenter Verbindungen zum Origin |
|
Für Segmente; aktiviert die Antwortpufferung in nginx |
|
Für den Bereich |
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.
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:
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 |
|---|---|
|
Antwort aus Cache |
|
War nicht im Cache; vom Origin geholt und gespeichert |
|
Abgelaufen, erneuert |
|
Stale-Kopie an parallele Anfrage während der Aktualisierung ausgeliefert |
|
|
|
Origin lieferte 304 Not Modified |
|
|
9.2. Access-Log-Format¶
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; |
Manifest MISS rate |
> 50 % über 1 Minute |
|
Upstream response time p95 |
> 500 ms über 1 Minute |
Origin-Überlastung |
Cache zone fill |
> 90 % über 10 Minuten |
Annäherung an |
10. Diagnose¶
Symptom |
Wahrscheinliche Ursache |
Lösung |
|---|---|---|
Niedrige Segment-HIT-Rate |
|
Header und Regex in der |
404 bei Segmenten nach Verlassen des Fensters |
Gecachter 404 bei Segment, das aus dem Sliding Window gefallen ist |
|
Playback-Start-Verzögerung 2–5 s |
|
Auf 1–2 s senken; |
Manifest aktualisiert nicht |
|
|
Wachsendes TIME_WAIT am Upstream |
|
|
403 bei |
Der Client löst relative URLs gegen die Pre-Redirect-URL auf |
Der Server gibt |
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:
# 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:
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 ProduktionDie Session-ID im
Location-Header der 302 wird nicht gecacht (no-cache, no-store)
11.2. Rate limiting¶
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¶
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:
Perfect Streamer an
127.0.0.1binden (bei lokalem nginx)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-streamgilt 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 subtitle playlist |
|
Liste |
HLS-VTT-Segment |
|
VTT mit HLS-spezifischer X-TIMESTAMP-MAP |
DASH MPD AdaptationSet |
in |
|
DASH-VTT-Segment |
|
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).