MPEG-TS oder HLS: was ein Live-IPTV-Strom tatsächlich sendet und wie jedes von beiden scheitert

Eine Live-Adresse von einem Portal ist ein einziges HTTP-GET, das nie endet. Eine HLS-Adresse ist eine Textdatei, die die nächsten paar Sekunden auflistet. Fast alles andere folgt daraus.

var sourceKind = uri.Contains(".m3u8", StringComparison.OrdinalIgnoreCase) ? "hls" : "ts";

Eine Zeile, und das ist unsere gesamte Transporterkennung im Wiedergabepfad. Sie läuft bei jedem Live-Medienwechsel, an vier Aufrufstellen: Umschalten, Neuaufbau der Engine und zwei Übergabepfade beim Failover. Ein Teilstring-Test über die gesamte Adresse, bei dem alles, was nicht HLS ist, auf ts durchfällt. Lassen Sie ihn über die 2.203 Einträge der beiden Playlists laufen, die wir für die Parser-Arbeit aufbewahren, und er kennzeichnet 1.930 davon als hls und 273 als ts. Genau 7 dieser 2.203 Adressen enden auf .ts.

Das Etikett und die Wahrheit sind zweierlei, und die beiden Transporte, die es zu benennen versucht, sind es ebenso. Der eine ist ein einziges HTTP-GET, das nie fertig wird. Der andere ist eine Textdatei, die die nächsten paar Sekunden auflistet und erwartet, dass Sie für mehr zurückkommen.

Was der Teilstring falsch macht, ausgezählt

Diese beiden Playlists sind der Korpus hinter unserer Parser-Arbeit, kuratierte Verzeichnisdateien, und ihr überwältigender HLS-Anteil sagt nichts darüber aus, was ein Portal ausliefert. Der Portalpfad läuft andersherum, und das ist der Teil, den die meisten Darstellungen verkehrt herum haben: Eine Live-Adresse, die unser Client baut, fordert immer .ts an. Was zurückkommt, ist Sache des Portals, und wir prüfen es nie nach.

Wofür der Korpus taugt, ist zu zeigen, wie schlecht eine Adressendung einen Strom beschreibt. Schlecht ist die Antwort. Im gesamten Korpus enden 1.924 Pfade auf .m3u8 und 7 auf .ts. Unter den 273 Zeilen, die die Regel ts nennt, verteilen sich die Endungen so:

  • 147 ohne lesbare Endung, davon 16, weil eine IP und ein Port dort im Pfad stehen, wo ein Dateiname stünde
  • 75 mit der Endung .php
  • 17 mit der Endung .mpd, was ein DASH-Manifest ist und genau in der Weise adaptiv, die das Etikett ts bestreitet
  • 14 mit der Endung .htm
  • 7 mit der Endung .ts, 6 mit .m3u, 3 mit .2ts und je eines mit .smil, .dash, .mp4 und .wmv

Sechs Zeilen gehen den anderen Weg und werden als HLS klassifiziert, weil .m3u8 in der Abfragezeichenfolge steht statt am Ende des Pfades. Dass die Regel die Abfrage überhaupt liest, ist die einzige Stelle, an der sie einer schlichten Endungsprüfung widersprechen kann, denn keine Zeile im Korpus trägt das Token in der Pfadmitte. Diese Widersprüche und der zweite aus der Adresse abgeleitete Klassifikator im Dialog Stream-Informationen, der sie hervorbringt, sind in einem eigenen Artikel behandelt, zusammen mit der Endung der Playlist-Datei selbst, die eine andere Frage ist als die Endung irgendeiner Adresse in ihr.

Die rettende Gnade ist, dass das Etikett kaum etwas bewirkt. Es reitet in eine Debug-Zeile, wenn eine Sitzung scharfgeschaltet wird, und in das wd.fault-Serilog-Ereignis bei jedem Urteil, und kein Schwellenwert, kein Timeout und keine Verzweigung in der Wiederherstellungsmechanik liest es. Der typisierte Record, der es an ein Backend tragen sollte, ist deklariert und wird nie konstruiert. Der eigene Doc-Kommentar des Feldes sagt, wofür es da ist: Telemetrie plus Schwellenwerte je Art, die niemand geschrieben hat. Ein Klassifikator, der mindestens 17 von 2.203 Zeilen falsch etikettiert und von nichts konsultiert wird, ist ein merkwürdiges Ding zum Ausliefern, und erträglich ist er genau wegen der zweiten Hälfte.

Eine bessere Quelle gibt es auch nicht. Der Datensatz eines Live-Senders trägt eine Stream-ID, eine Portal-Basis, eine optionale direkte Adresse, Qualitätsfelder und ein Catch-up-Kennzeichen, und nichts, was einen Container, einen Transport oder einen MIME-Typ benennt. Der Transport ist in unserem Datenmodell keine Eigenschaft eines Senders, also bleibt nur die Adresse zum Ablesen.

Sechs Adressen, und wie der Klassifikator jede einzelne nennt

Jeder Host unten ist eine reservierte Beispieldomäne und jeder Pfad erfunden, aber jede Zeile ist aus Formen zusammengesetzt, die der Korpus bezeugt.

1  https://example.com/live/user/pass/1234.ts
2  https://example.com/live/user/pass/1234.m3u8
3  https://example.net/hls/channel.mpd
4  https://example.org/live/9001/?file=chan.m3u8&output=playlist.m3u8
5  https://example.net/watch.htm?cont=1&output=7&forceUserAgent=1
6  https://example.net/play/9001

Zeile 1 ist das, was unser Portalbauer ausgibt, der eine Fall, in dem das Etikett stimmt und verdient ist. Zeile 2 ist derselbe Sender, als HLS angefordert, mit dem Teilstring dort, wo man ihn erwartet.

Zeile 3 ist ein DASH-Manifest. Sie enthält kein .m3u8, also wird sie als ts etikettiert, falsch in der interessantesten Richtung: Der Strom ist adaptiv, er hat Segmente, er hat ein Manifest, und alles, was das Etikett über ihn nahelegt, ist unwahr. Siebzehn Zeilen in der größeren Playlist enden so.

Zeile 4 ist der umgekehrte Fall. Der Pfad endet auf einem Schrägstrich und trägt überhaupt keine Endung, aber .m3u8 steht gleich zweimal in der Abfrage, einmal als Quellenhinweis und einmal als Wert eines Parameters namens output. Die Teilstring-Regel meldet HLS. Zwei echte Zeilen sind genau so geformt, und playlist.m3u8 ist ein Dateiname und kein Containername, also beantwortet selbst das Feld, das maßgeblich aussieht, die Frage nicht.

Zeile 5 ist die Form, die mich das Vertrauen in den output-Parameter verlieren ließ. Vierzehn Zeilen tragen output=7, und alle vierzehn sitzen auf einem Pfad mit der Endung .htm, neben Schlüsseln namens cont und forceUserAgent. Ein Feld namens output mit dem Wert 7 sagt einem Client nichts, und wir haben keine Möglichkeit zu erfahren, was die 7 bedeutet: Die mitauftretenden Schlüssel sind nicht die Xtream-Exportform, wir können also nicht einmal annehmen, dass sie die Bedeutung output=ts oder output=m3u8 trägt, die unser eigener Import-Parser dokumentiert. Die Endung, die der Dialog Stream-Informationen von diesem Pfad ablesen würde, lautet unterdessen HTM.

Zeile 6 hat überhaupt nichts Lesbares an sich, und sie ist die Mehrheit von allem, was die Regel ts nennt: 147 dieser 273 Zeilen. Sie bekommt ts, weil ts die Voreinstellung ist, nicht weil irgendetwas erkannt worden wäre, und genau das macht den ganzen Klassifikator zu einer Namenskonvention statt zu einer Messung.

Der Portalpfad fordert .ts an und sonst nie etwas anderes

Hier ist der gesamte Aufbau einer Live-Adresse für eine Portalquelle, ohne die Maskierung:

return string.Format(CultureInfo.InvariantCulture, "{0}/live/{1}/{2}/{3}.ts", baseText, user, pass, streamId);

Kein Parameter, keine Verzweigung, kein Optionsobjekt. Die einzige Logik in dieser Datei jenseits der Formatzeichenfolge ist das Maskieren von Benutzername und Passwort. Die einzige Gabelung im Auflösungspfad ist, ob die Zeile aus einer Playlist kam, die bereits eine vollständige Adresse enthielt, dann verwenden wir diese Adresse unangetastet, oder aus einem Portal, dann bauen wir die Zeile oben.

Catch-up wird von einer zweiten Funktion derselben Form gebaut, die eine Dauer in ganzen Minuten und einen Startstempel im Format yyyy-MM-dd:HH-mm einsetzt, und ihr Doc-Kommentar trägt die eine Warnung, die einer der beiden Bauer brauchte: Dieser Stempel ist die Ortszeit des Portalservers, dieselbe Uhr, nach der der Programmführer des Portals läuft, nicht die Uhr des Geräts. Auch sie endet auf .ts.

Zwei Dinge schränken das ein. Jede Xtream-Quelle trägt eine gespeicherte Einstellung Stream-Format mit den Optionen MPEG-TS und HLS (m3u8), und sie wird von nichts gelesen: Der Wert wandert durch die Einstellungen und wieder zurück, und das Gerät fordert weiterhin .ts an. Dieses tote Bedienelement, und der zweite Bauer auf der Katalogseite, der .m3u8 angehängt hätte, wenn irgendetwas ihn aufgerufen hätte, sind dort dokumentiert, wo sie hingehören. Die andere Einschränkung wiegt hier schwerer. All dies betrifft die Anfrage. Ein Portal darf eine .ts-Adresse woandershin umleiten oder HLS von ihr ausliefern, und wir schauen nie nach, also ist nichts in diesem Artikel ein Beleg dafür, was Portale tatsächlich senden.

Ein Transport Stream hat Takt; was ihm fehlt, ist eine Grenze, die der Player uns reicht

Die Rahmung im Titel ist ein Kategorienfehler. Lösen wir ihn zuerst auf. RFC 8216 Abschnitt 3.2 führt MPEG-2 Transport Streams unter den unterstützten Segmentformaten auf und verlangt, dass jedes solche Segment ein einziges Programm mit einer PAT und einer PMT enthält, ein HLS-Segment kann also aus denselben 188-Byte-Paketen bestehen, nur in eine Datei geschnitten. Wie oft das der Fall ist, haben wir nicht gemessen, und die Branche bewegt sich seit Jahren auf fMP4 zu. Was sich zuverlässig unterscheidet, ist die Auslieferung, und aus der Auslieferung stammt jeder Verhaltensunterschied weiter unten.

Ein Manifest gibt einem Client vier Dinge, die ein offener Socket nicht gibt:

  • Eine Anfrage, die scheitern kann. Jedes Segment ist eine eigene HTTP-Transaktion, ein 404, ein Timeout oder ein abgeschnittener Rumpf ist also ein Ereignis mit einem Zeitpunkt daran.
  • Einen Takt, den der Client durchsetzen kann. RFC 8216 verlangt von einem Live-Client, die Playlist neu zu laden, und setzt die Wartezeit aus der Zieldauer, Stille lässt sich also gegen etwas messen, das das Format selbst deklariert.
  • Eine angekündigte Diskontinuität, sodass ein Schnitt als Markierung ankommt statt als Uhrensprung, den man erschließen muss.
  • Eine Position. Eine Segmentliste und eine Zieldauer sagen zusammen, wie weit der Client vom Live-Rand entfernt ist.

Progressives MPEG-TS über HTTP gibt Ihnen ein GET, das nie endet, mit der gesamten Struktur in den Bytes: Pakete zu 188, eine Program Association Table, eine Program Map Table, Elementarströme auf eigenen PIDs, eine Program Clock Reference, die sie taktet, und Nullpakete auf PID 0x1FFF als Füllmaterial.

Der Satz, den ich hier zuerst geschrieben hatte, lautete, ein Bytestrom habe keine Grenze, an die man ein Timeout hängen könnte. Ich lag falsch, und ein Rundfunktechniker hätte mich sofort korrigiert: Auf Formatebene hat ein Transport Stream reichlich Takt. ISO/IEC 13818-1 begrenzt, wie weit Program Clock References auseinanderliegen dürfen, und der Überwachungsstandard von DVB, ETSI TR 101 290, baut seinen gesamten Priority-1-Satz aus genau diesen Grenzen: Sync-Verlust, eine PAT, die sich nicht innerhalb von 500 ms wiederholt, ein Kontinuitätszähler, der springt, eine PMT, die verschwindet. Schränke voller Messsonden lesen diese Grenzen den ganzen Tag. Unser eigenes Relay setzt sie voraus: Sein nulls-Fehler sendet weiterhin PAT und PMT, denn ein Strom ohne sie ist ein anderer Fehlerfall.

Was ein progressiver Strom nicht hat, ist eine Grenze, die der Player uns sichtbar macht. Was libvlc herüberreicht, ist eine Momentaufnahme kumulativer Zähler: am Zugriffslayer gelesene Bytes, vom Demuxer verbrauchte Bytes, dekodierte Bilder und angezeigte Bilder, und kein einziges Feld darin ist Tabellen-Timing. Das Timeout hat also keine prinzipielle Aufhängung, und ein Stillstand wird aus einer Differenz erschlossen, die auf null ging. Wie diese Differenzen gelesen werden und warum die Engine weiter gesunde Wiedergabe meldet, während das Bild eingefroren ist, ist ein eigener Artikel.

Unser Fehlerinjektions-Relay macht die Lücke greifbar. Es ist ein entwicklerlokales Gerüst, nie ausgerollt und nie Teil eines Dienstes, das auf dem Loopback einen synthetischen Single-Program-Transport-Stream mit rund 4.6 Mbit/s erzeugt und ihn auf Kommando zerbricht. Sein freeze-Modus stellt das Schreiben ein und lässt den Socket bestehen, und das gemessene Ergebnis ist die klarste Formulierung des Problems, die wir haben: Die Lesebyte-Differenz des Clients geht auf null, und es gibt, in den Worten des Relays selbst, "no event at all". Die Engine wirft keinen Fehler und meldet kein Ende des Stroms. Die Ursache ist, dass auf HTTP-Ebene nichts falsch ist, denn die Antwort ist weiterhin offen und wird weiterhin ausgeliefert. Der Preis ist, dass jede Stillstandserkennung, die wir für diesen Transport haben, auf einem Zähler und einem Fenster von vier Sekunden ruht, und wenn dieser Zähler je lügt, wird das Produkt mit ihm still.

Beim Bau des Relays musste als Erstes unser eigener Webserver überwunden werden. Kestrel erzwingt standardmäßig eine Mindestdatenrate der Antwort, 240 Byte pro Sekunde mit fünf Sekunden Karenz, und ein offen gehaltener, stiller Socket ist genau das, was er töten soll. Ein freeze-Fehler wäre beim Client als Socket-Schließen aufgetaucht: ein F1-Zugriffsstillstand-Test, der klammheimlich als F2-Ende-des-Stroms-Test lief, mit einer ungültigen Matrix und trotzdem lauter bestandenen Fällen. Drei Grenzwerte werden aufgehoben, bevor das Relay ein einziges Byte ausliefert.

Latenz ist auf dem einen Transport Ihr Puffer und auf dem anderen eine Untergrenze

RFC 8216 sagt, ein Client SOLLTE NICHT auf einem Segment starten, das weniger als drei Zieldauern vor dem Ende der Playlist liegt. Bei einer Zieldauer von sechs Sekunden, einer üblichen Wahl und keiner gemessenen, sind das achtzehn Sekunden hinter live, bevor der Client ein eigenes Bild gepuffert hat, und die Quelle hat diese Zahl gewählt, als sie den Strom segmentierte. Der Entwurf der zweiten Ausgabe behält drei Zieldauern als Standard bei und ergänzt einen eigenen Rückhalt für den Low-Latency-Modus, dessen Minimum das Doppelte der Part-Zieldauer ist, die Untergrenze bewegt sich also nur, wenn die Quelle den Strom in Parts schneidet. So oder so ist es die Entscheidung der Quelle, nicht die des Players.

Progressives MPEG-TS hat keine solche Untergrenze. Latenz ist, was der Client zu halten beschließt, und unsere aktuelle Abstimmung hält sehr wenig. Die Engine wird mit einem Netzwerk-Cache von 400 ms konstruiert, und der Live-Pfad wendet 1200 ms Netzwerk-Caching über 800 ms Live-Caching an. Multiview-Kacheln fallen stumm auf 350 und 200, mit Ton auf 500 und 350. Entfernte On-Demand-Wiedergabe bekommt 1500 ms, denn Scrubbing will einen tieferen Puffer als ein Live-Sender. Das sind Abstimmungswerte. Die nächste Person, die die Umschaltzeit misst, wird einige davon verschieben.

Kleine Puffer sind nicht umsonst. Das ist der Handel, den der Transport Ihnen aufdrängt, keine Vorliebe. Ein Bytestrom mit 1200 ms Polster sitzt nah an live und hat 1200 ms Toleranz für einen Aussetzer. Ein HLS-Client, der drei Segmente zurückliegt, hat sehr viel Toleranz und kann sie nicht ausgeben. Wenn unsere Rebuffer-Erkennung eine Schleife erklärt, hebt ihre Gegenmaßnahme beim nächsten Neustart die Cache-Untergrenze um 1000 ms an, gedeckelt bei 5000 ms, und das ist derselbe Handel, zur Laufzeit geschlossen statt in den Einstellungen.

Der Suchlauf kommt aus der Länge, nicht aus dem Transport

Keiner der beiden Transporte ist bei live in unserem Client suchlauffähig, und das Flag, das darüber entscheidet, konsultiert den Transport nie.

// A live stream with no known length is not seekable in any way the scrubber could honour,
// whatever the demuxer claims; both position and live edge stay unknown then.
var seekAvailable = isSeekable && durationMs > 0;

Zwei Bedingungen, beide vom Player abgelesen. Der Test, der das festnagelt, benennt den Transport in seinem Kommentar dort, wo der Code es nicht tut: "Typical live TS: demuxer may claim seekable but there is no length to scrub against." Er übergibt ein Seekable-Flag von true bei einer Länge von null und prüft, dass kein Suchlauf angeboten wird. Das ist die Codebasis, die in einem Test feststellt, dass ein progressiver Demuxer bereitwillig eine Fähigkeit behauptet, die er nicht einlösen kann, und dass die Länge das Feld ist, das die Wahrheit sagt.

Was libvlc für die Länge eines Live-HLS-Fensters meldet, haben wir nicht gemessen, und die Regel oben ist so geschrieben, dass es keine Rolle spielt. Wenn ein gleitendes Fenster je eine positive Länge lieferte, würde der Scrubber aufleuchten und die Transport-Überlagerung einen Suchlauf darüber anbieten. Ob das funktionieren würde, ist bei uns eine offene Frage und keine Behauptung.

Catch-up ist die ehrliche Fassung des Rückwärtssuchens auf einer Portalquelle, und es ist überhaupt kein Suchlauf: eine zweite Adresse von einem zweiten Bauer, die eine Dauer in Minuten und einen Startstempel auf der Uhr des Portals trägt und wie alles andere auf .ts endet. Die Aufnahme hat dieselbe Einschränkung aus derselben Ursache, denn der Aufzeichnungsfortschritt kann kein Prozentsatz einer Dauer sein, die die Eingabe nie deklariert.

Ein Schwellenwert in der Wiederherstellungsmechanik ist HLS-geformt, und es ist der einzige

Jedes Urteilsfenster ist transportunabhängig. Vier Sekunden ohne Bytes am Zugriffslayer, sechs Sekunden, in denen Bytes ankommen und der Demuxer nichts produziert, vier Sekunden stehendes Video bei laufendem Live-Ton, vier für beides zusammen stehend, fünfzehn auf einem Sender, der als bildratenschwach gemessen wurde. Keines davon hat einen zweiten Wert für HLS, und keines wird über die Quellenart ausgewählt.

Die Ausnahme ist die Rebuffer-Zählung, und die Optionsdatei nennt den Grund an Ort und Stelle: Episoden werden nur gezählt, wenn der Cache unter eine Untergrenze fällt, statt bei jeder Meldung unter 100, denn "live HLS cache wobbles across segment boundaries and raw sub-100 counting would flag healthy streams". Die Hysterese läuft von 62 Prozent zum Start einer Episode bis 88 zu ihrem Ende, wobei vier Episoden in rollenden 60 Sekunden eine Schleife erklären. Die Puffer-Abdeckung trägt für dasselbe Schwanken ihre eigene Hysterese, und ihr Kommentar beziffert den Effekt auf rund zwei Sekunden vor Keyframes. Beide gibt es, weil der Cache-Stand eines manifestgetriebenen Stroms von Natur aus schwingt und ein roher Schwellenwert dieses Schwingen als Krankheit liest.

Das Eingeständnis, das hierher gehört, ist größer als ein Schwellenwert. Das gesamte Zählermodell hinter der Fehlererkennung wurde auf rohem MPEG-TS kalibriert, wo der Zugriffslayer und der Demuxer in einem sauberen Verhältnis stromauf und stromab stehen und der Abstand zwischen ihnen etwas Bestimmtes bedeutet. Was ein adaptiver Demuxer mit diesem Verhältnis anstellt, wenn er eigene Abrufe absetzt, haben wir nicht gemessen, ich werde Ihnen also nicht sagen, dass die Aufteilung bei HLS falsch ist, sondern nur, dass sie nie geprüft wurde. Wir führen ein Etikett mit, das uns verzweigen ließe. Wir haben nie einen einzigen HLS-spezifischen Schwellenwert geschrieben, und ohne Flottentelemetrie können wir nicht sagen, was das kostet. Eine Asymmetrie behandeln wir, ohne es zu beabsichtigen: Die Neustart-Primitive verwirft das Medium und wendet die Adresse von Grund auf neu an, was laut Plan bei HLS-Sitzungen mit in der Adresse eingebetteten Tokens die Tokens neu erzeugt.

Die eine Fähigkeit, die ein Manifest uns im ausgelieferten Code wirklich einbringt, ist kleiner als all das. Obergrenzen für Renditions, nur auf Multiview-Kacheln angewandt, 640 mal 360 für eine stumme Kachel und 1280 mal 720 für die mit Ton, dazu die Anforderung der niedrigsten Rendition im stummen Profil. Auf progressivem MPEG-TS sind diese Optionen wirkungslos, denn es gibt keine Renditions zum Deckeln, und der Player nimmt sie stillschweigend an, statt sich zu beschweren. Deshalb hängen sie am Kachelprofil und nicht an der Quellenart: Eine Option, die nichts kostet, wenn sie nichts tut, ist billiger unbedingt anzuwenden als mit einem Klassifikator abzusichern, von dem wir bereits festgestellt haben, dass er mindestens 17 von 2.203 Zeilen falsch etikettiert. Live-Wiedergabe im Vollbild nutzt sie überhaupt nicht.

Die ehrliche Grenze: Die beiden hier vermessenen Playlists sind das gesamte Beweismaterial, und von Live-Adressen aus Portalen halten wir überhaupt keinen Korpus. Alles oben beschreibt die Anfrage, die unser Client stellt, und den Code, der auf das reagiert, was zurückkommt, nie das, was Portale senden. Die Adresse zu lesen, die Ihre eigene Quelle Ihnen reicht, bleibt der schnellste Weg herauszufinden, in welcher der beiden Formen Sie sich befinden. Auf den Windows- und Xbox-Apps bleibt das ein lokaler Vorgang: Sie öffnen die Adresse, auf die Sie sie zeigen, und werten sie auf dem Gerät aus, halten keine eigenen Sender und holen in Ihrem Namen nichts von irgendwoher. Der Dialog Stream-Informationen zeigt Ihnen die Behauptung, die die Adresse über sich selbst aufstellt, mit dem oben dargelegten Vorbehalt, was diese Zeile wirklich bedeutet, und ein kostenloses Konto genügt, um nachzusehen.

Was dieser Artikel gemessen hat35 Behauptungen, jeweils mit den Beweisen dahinter
AnspruchBeweiseGezählt
Der einzige Transport-Klassifikator im Wiedergabepfad ist ein Teilstring-Test auf ".m3u8" ohne Beachtung der Groß- und Kleinschreibung über die gesamte Adresse, ausgewertet bei jedem Live-Medienwechsel. Alles andere fällt auf "ts" zurück.n = 123.08.2026
Kein Schwellenwert, kein Timeout und keine Verzweigung im Watchdog liest die Quellenart. Jedes Vorkommen ist eine Deklaration, eine Zuweisung, eine Kopie oder ein Logfeld.n = 123.08.2026
Die Quellenart erreicht eine Debug-Zeile, wenn eine Sitzung scharfgeschaltet wird, und bei jedem Fehlerurteil ein wd.fault-Serilog-Ereignis auf Information-Ebene. Der typisierte Record, der sie an ein Backend tragen sollte, ist deklariert und wird nie konstruiert.n = 123.08.2026
Über die beiden Playlists laufen gelassen, die wir für die Parser-Arbeit aufbewahren, kennzeichnet der ausgelieferte Klassifikator 1.930 von 2.203 Zeilen als "hls" und 273 als "ts". Genau 7 der 2.203 Adressen enden auf ".ts".n = 220323.08.2026
Pfadendungen im gesamten Korpus: 1.924 .m3u8, 137 ohne Endung, 16 ohne Endung, weil eine ip:port-Angabe im Pfad steht, 75 .php, 17 .mpd, 14 .htm, 7 .ts, 6 .m3u, 3 .2ts sowie je einmal .smil, .dash, .mp4 und .wmv. Von den 273 Zeilen, die der Klassifikator "ts" nennt, haben 147 keine lesbare Endung.n = 220323.08.2026
Sechs Zeilen werden als HLS klassifiziert, weil ".m3u8" in der Abfragezeichenfolge auftaucht statt am Ende des Pfades. Jede dieser sechs hat einen Pfad ohne Endung. Keine Zeile im Korpus trägt das Token in der Pfadmitte, und keine Zeile trägt irgendwo einen Abfrageschlüssel "out".n = 220323.08.2026
Vierzehn Zeilen tragen einen output-Abfrageparameter mit dem Wert 7, und alle vierzehn sitzen auf Pfaden, die auf .htm enden, neben den Schlüsseln cont und forceUserAgent. Zwei Zeilen setzen output auf playlist.m3u8. Sechzig Zeilen haben get.php als letztes Pfadsegment, und keine einzige davon trägt überhaupt einen output-Parameter.n = 220323.08.2026
Die Endung einer Playlist-Datei sagt die Endungen der Adressen in ihrem Inneren nicht voraus. Die .m3u-Datei in unserem Korpus verweist auf 303 Adressen, die auf .m3u8 enden, und auf keine einzige, die auf .ts endet.n = 30823.08.2026
Die beiden hier vermessenen Playlists sind kuratierte Verzeichnisdateien, keine Portal-Exporte, und ihre HLS-Dominanz sagt nichts darüber aus, was ein Portal ausliefert.n = 223.08.2026
Der Xtream-Live-Adressbauer des Clients schreibt eine .ts-Endung fest, ohne Parameter und ohne Verzweigung, und der Catch-up-Bauer tut dasselbe. Das ist es, was wir anfordern; nichts hiervon beobachtet, was ein Portal zurückgibt.n = 123.08.2026
Das Bedienelement Stream-Format, das für Xtream-Quellen angeboten wird, normalisiert, speichert und lädt neu und wird von keinem Adressbauer und keinem Wiedergabecode gelesen. Worauf es auch gesetzt ist, der Desktop-Client fordert .ts an.n = 123.08.2026
Der Dialog Stream-Informationen leitet Protokoll aus dem Adressschema und Container aus der Dateiendung des Pfades ab und fällt auf "N/A" zurück, wenn der Pfad keine hat. Er ist ein zweiter aus der Adresse abgeleiteter Klassifikator, und er stimmt mit dem des Watchdogs nicht überein.n = 123.08.2026
Der Datensatz eines Live-Senders trägt kein Container-, Transport- oder MIME-Feld, also ist der Transport nie eine Sendereigenschaft und lässt sich nur an der Adresse ablesen.n = 123.08.2026
HLS liefert eine Media Playlist, die Media Segments unter einer deklarierten Zieldauer auflistet, und ein Client, der einer Live-Präsentation folgt, MUSS diese Playlist regelmäßig neu laden, um zu erfahren, welche Medien verfügbar sind.RFC 8216 section 4.3.3.1 (EXT-X-TARGETDURATION, REQUIRED) and section 6.3.4 (Reloading the Media Playlist File), verbatim: "The client MUST periodically reload a Media Playlist file to learn what media is currently available", and must wait at least the target duration between reloads that found a change.SpezifikationNicht zutreffend
RFC 8216 führt MPEG-2 Transport Streams unter den unterstützten Media-Segment-Formaten auf, ein HLS-Segment kann also aus denselben 188-Byte-Paketen bestehen, nur in eine Datei geschnitten. Wie oft das der Fall ist, haben wir nicht gemessen.RFC 8216 section 3.1 (Supported Media Segment Formats) and section 3.2 (MPEG-2 Transport Streams), which requires a single MPEG-2 Program per segment and a PAT plus PMT in each segment absent an EXT-X-MAP tag. Sections 3.3 through 3.5 cover fragmented MPEG-4, packed audio and WebVTT.SpezifikationNicht zutreffend
Ein Client, der eine Live-HLS-Präsentation abspielt, SOLLTE KEIN Startsegment wählen, das weniger als drei Zieldauern vor dem Ende der Playlist beginnt.RFC 8216 section 6.3.3 (Playing the Media Playlist File), verbatim: "If the EXT-X-ENDLIST tag is not present and the client intends to play the media normally, the client SHOULD NOT choose a segment that starts less than three target durations from the end of the Playlist file. Doing so can trigger playback stalls."SpezifikationNicht zutreffend
Der Entwurf der zweiten HLS-Ausgabe behält drei Zieldauern als Standardabstand zum Live-Rand bei und ergänzt PART-HOLD-BACK für den Low-Latency-Modus, dessen Minimum das Doppelte der Part Target Duration beträgt. Parts sind deutlich kürzer als Segmente, und genau so kommt Low-Latency-HLS bis auf ein Segment an den Rand heran.draft-pantos-hls-rfc8216bis section 4.4.3.8 (EXT-X-SERVER-CONTROL). HOLD-BACK: "Its value MUST be at least three times the Target Duration ... Its absence implies a value of three times the Target Duration." PART-HOLD-BACK: "Its value MUST be at least twice the Part Target Duration." The draft header reads "Obsoletes: 8216 (if approved)".SpezifikationNicht zutreffend
Ein Transport Stream ist zeitlich nicht strukturlos. ISO/IEC 13818-1 begrenzt, wie weit Program Clock References auseinanderliegen dürfen, und der Überwachungsstandard von DVB macht aus Tabellenwiederholung und Kontinuität Prüfungen mit Bestanden oder Durchgefallen.ISO/IEC 13818-1 (transport stream system layer, PCR interval constraint); ETSI TR 101 290 V1.4.1 (2020-06) Priority 1 measurements, which include TS_sync_loss, Sync_byte_error, PAT_error and PAT_error_2 on a 500 ms PAT repetition limit, Continuity_count_error, PMT_error and PMT_error_2, and PID_error.SpezifikationNicht zutreffend
Was der Player uns übergibt, ist eine Momentaufnahme kumulativer Pipeline-Zähler, und der Zustandsautomat arbeitet ausschließlich mit Differenzen zwischen aufeinanderfolgenden Messwerten. Kein Feld darin ist Tabellen-Timing.n = 123.08.2026
Ein MPEG-2 Transport Stream ist eine Folge von 188-Byte-Paketen, die eine Program Association Table, eine Program Map Table, Elementarströme auf eigenen PIDs, eine Program Clock Reference und Nullpakete auf PID 0x1FFF als Füllmaterial tragen.ISO/IEC 13818-1, transport stream packet syntax; mirrored in our own synthetic muxer at clients/windows/tools/FaultRelay/Media/TsMuxer.cs:15-20, which declares PacketSize 188, PatPid 0x0000, PmtPid 0x1000, VideoPid 0x0100, AudioPid 0x0101 and NullPid 0x1FFF.SpezifikationNicht zutreffend
Das Fehlerinjektions-Relay ist ein entwicklerlokales Testgerüst, das synthetisches Video auf dem Loopback erzeugt. Es wird nie ausgerollt, nie in ein Chart oder eine Compose-Datei aufgenommen und von keinem Backend-Dienst referenziert.n = 116.08.2026
Das Relay erzeugt in seinen Standardeinstellungen einen Single-Program-Transport-Stream mit rund 4.6 Mbit/s, mit PCR auf der Video-PID und Kontinuitätszählern pro PID.n = 116.08.2026
Ein Relay-Fehler, der das Schreiben einstellt und den Socket bestehen lässt, erzeugt beim Client eine Lesebyte-Differenz von null und überhaupt kein Engine-Ereignis.n = 116.08.2026
Ein Strom, der auf Programmtabellen plus Nullpakete reduziert ist, hält seine Byte-Rate, während der Demuxer verhungert. Diese Fehlerform gehört zum Container, nicht zur progressiven Auslieferung: Eine HLS-Präsentation mit Transport-Stream-Segmenten kann sie erzeugen, und eine mit fMP4-Segmenten hat kein entsprechendes Füllmaterial.n = 116.08.2026
Das Relay hebt drei Kestrel-Grenzwerte auf, bevor es ein einziges Byte ausliefert, denn die voreingestellte Mindestdatenrate der Antwort würde einen Byte-Freeze-Fehler abbrechen und jeden F1-Zugriffsstillstand-Test in einen F2-Socket-Schließen-Test verwandeln.n = 116.08.2026
Die voreingestellte Mindestdatenrate der Antwort von Kestrel beträgt 240 Byte pro Sekunde mit einer Karenzzeit von fünf Sekunden.Microsoft ASP.NET Core Kestrel options documentation, MinResponseDataRate default.SpezifikationNicht zutreffend
Das Live-Suchlauf-Flag ist die Konjunktion aus dem Seekable-Flag des Players und einer positiven Länge. Der Transport ist keine Eingabe, und Position wie Live-Rand bleiben null, wenn die Konjunktion scheitert.n = 123.08.2026
Der Aufnahmefortschritt kann bei einer Live-Aufzeichnung nicht als Prozentsatz gemeldet werden, weil die Dauer der Eingabe unbekannt ist.n = 123.08.2026
Die einzigen transportabhängigen Optionen, die wir ausliefern, sind Obergrenzen für Renditions, und sie gelten nur für Multiview-Kacheln: 640 mal 360 stumm, 1280 mal 720 mit Ton, dazu die Auswahl der niedrigsten Rendition im stummen Profil. Live im Vollbild bekommt keine davon.n = 123.08.2026
Aktuelle Abstimmung: Die Engine wird mit einem Netzwerk-Cache von 400 ms konstruiert, der Live-Pfad wendet 1200 ms Netzwerk- und 800 ms Live-Caching an, Multiview-Kacheln fallen auf 350/200 stumm und 500/350 mit Ton, und entferntes On-Demand nutzt 1500 ms.n = 123.08.2026
Jedes Urteilsfenster ist transportunabhängig: 4 s ohne Bytes, 6 s ausgehungerter Demuxer, 4 s stehendes Video, 4 s vollständiger Stillstand, 15 s auf einem Sender mit niedriger Bildrate.n = 523.08.2026
Der einzige von HLS geprägte Schwellenwert ist die Rebuffer-Zählung: Eine Episode wird nur unterhalb von 62 Prozent Cache gezählt und endet bei 88, vier Episoden in einem Fenster von 60 s erklären eine Schleife, und die Gegenmaßnahme hebt die Cache-Untergrenze je Urteil um 1000 ms bis zu einer Obergrenze von 5000 ms an.n = 123.08.2026
Die Puffer-Abdeckung trägt aus demselben Grund ihre eigene Hysterese, und der Codekommentar führt das Schwanken auf HLS-Segmentgrenzen rund zwei Sekunden vor Keyframes zurück.n = 123.08.2026
Das Zählermodell hinter der Fehlererkennung wurde gegen rohes MPEG-TS kalibriert, und kein von uns ausgelieferter Schwellenwert ist HLS-spezifisch.n = 123.08.2026
Die Neustart-Primitive verwirft das Medium und wendet die Adresse von Grund auf neu an, was laut Plan bei HLS-Sitzungen mit in der Adresse eingebetteten Tokens die Tokens neu erzeugt.n = 123.08.2026