
Egor schloss den Deckel des Laptops und rieb sich vor Schlafmangel die roten Augen. "Die Kunden beschweren sich weiterhin über das Einfrieren des Streams. Das neue Fixpack hat überhaupt nicht geholfen. Was tun mit diesem (zensierten) HLS?" Er sagte ins Leere des Studiums.
Der Browser ist nicht nur Hypertext, sondern auch ein Streamer
Browser haben Spieler für eine lange Zeit erworben, aber mit einem Video-Encoder und Streaming ist die Geschichte anders. In nahezu jedem Browser der neuesten Version finden Sie jetzt Module zum Kodieren, Streamen, Dekodieren und Wiedergeben. Diese Funktionen sind über die JavaScript-API verfügbar, und die Implementierung wird als Web Real Time Communications oder WebRTC bezeichnet. Diese in Browser integrierte Bibliothek kann eine ganze Menge leisten: Videos von einer integrierten, virtuellen oder USB-Kamera aufnehmen, mit den Codecs H.264, VP8 und VP9 komprimieren und über das SRTP-Protokoll an das Netzwerk senden, d. H. fungiert als Software-Video-Streamer-Encoder. Als Ergebnis sehen wir einen Browser, der etwas Ähnliches wie ffmpeg oder gstreamer unter der Haube hat, der Video gut komprimiert, auf RTP streamt und Video-Streams abspielt.
Mit WebRTC können Sie eine Vielzahl von Streaming-Fällen in JavaScript implementieren:
- Streamen Sie den Stream vom Browser zum Server, um ihn aufzuzeichnen und anschließend zu verteilen
- Peer-to-Peer
- Spiele den Stream eines anderen Benutzers ab und sende deinen eigenen (Video-Chat)
- Konvertieren Sie andere Protokolle vom Server, z. B. RTMP, RTSP usw., und spielen Sie im Browser als WebRTC
Verbesserte Flusskontrollskripte könnten so aussehen:
HLS funktioniert dort, wo WebRTC nicht funktioniert
WebRTC funktioniert in den neuesten Browserversionen. Es gibt jedoch zwei der folgenden Faktoren: 1) Nicht alle Benutzer aktualisieren die Browser rechtzeitig und können möglicherweise drei Jahre lang auf einer Art Chrome sitzen. 2) Fast einmal pro Woche werden Updates veröffentlicht und neue Browser, WebView sowie andere Clients und Instant Messenger, die im Internet surfen können. Es ist unnötig zu erwähnen, dass nicht alle von ihnen WebRTC-Unterstützung haben, und wenn dies der Fall ist, kann dies ziemlich abgeschnitten sein. Sehen Sie, wie es jetzt ist:

Separate Kopfschmerzen - die beliebtesten Apple-Geräte aller. Sie haben kürzlich Unterstützung für WebRTC erhalten und sind zeitweise in ihrem Verhalten im Vergleich zu orthodoxen Webkit-Browsern überraschend. Und wenn WebRTC nicht oder nicht sehr gut funktioniert, funktioniert HLS einwandfrei. In dieser Hinsicht ist Kompatibilität erforderlich und so etwas wie ein Konverter, der WebRTC in HLS konvertiert und auf fast jedem Gerät wiedergibt.
Ursprünglich war HLS nicht für Echtzeitströme konzipiert. In der Tat, was kann die Videozeit über HTTP sein? Die Aufgabe von HLS ist es, das Video in Stücke zu schneiden und es reibungslos und ohne Eile an den Player zu liefern, indem es nacheinander heruntergeladen wird. Der HLS-Player erwartet einen streng geformten und reibungslosen Videostream. Und hier entsteht ein Konflikt, da WebRTC es sich im Gegenteil erlauben kann, Pakete aufgrund von Echtzeitanforderungen und geringer Latenzzeit zu verlieren und eine schwebende FPS / GOP und eine variable Bitrate zu haben - genau das Gegenteil von HLS in Bezug auf Vorhersagbarkeit und Dimensionalität des Streams.
Ein naheliegender Ansatz: Die WebRTC-Depaketisierung (SRTP) und die anschließende Konvertierung in HLS funktionieren möglicherweise nicht im nativen Apple HLS-Player oder in einer Form, die für die Produktion mit Friesen ungeeignet ist. Ein nativer Player bedeutet hier einen Player, der in Apple iOS Safari, Mac OS Safari und Apple TV verwendet wird.
Wenn Sie den HLS-Frieze im nativen Player bemerken, ist dies möglicherweise der Fall, und die Quelle des Streams ist WebRTC oder ein anderer dynamischer Stream mit ungleichmäßigem Markup. Darüber hinaus gibt es bei der Implementierung von nativen Apple-Playern Verhaltensweisen, die nur empirisch verstanden werden können. Beispielsweise sollte der Server sofort mit dem Senden von HLS-Segmenten beginnen, unmittelbar nachdem die m3u8-Wiedergabeliste zurückgegeben wurde. Verzögerung pro Sekunde droht mit einem Einfrieren. Wenn sich die Bitstream-Konfiguration während des Vorgangs geändert hat (was beim WebRTC-Streaming ziemlich häufig vorkommt), kommt es auch zu einem Frieze.
Kämpfe gegen Friese bei einheimischen Spielern
Daher funktioniert die direkte und ehrliche WebRTC-Depaketierung und -Paketierung in HLS im Allgemeinen nicht. Beim Streaming-Videoserver Web Call Server (WCS) lösen wir das Problem auf zwei Arten und bieten die dritte als Alternative an:
1) Umcodierung.
Dies ist die zuverlässigste Methode, um den WebRTC-Stream an HLS-Anforderungen anzupassen, die gewünschte GOP, FPS usw. festzulegen. In einigen Fällen ist das Transcodieren jedoch keine gute Lösung. Beispielsweise ist das Transcodieren von 4k-Streams von VR-Videos eine so einfache Idee. Solche starken Streams sind in Bezug auf CPU-Zeit oder GPU-Ressourcen sehr teuer in der Transcodierung.

2) Anpassung und Ausrichtung des WebRTC-Flusses im laufenden Betrieb unter den Anforderungen von HLS.
Hierbei handelt es sich um spezielle Parser, die den H.264-Bitstream analysieren und ihn auf die Funktionen / Fehler nativer Apple HLS-Player korrigieren. Hier müssen wir zugeben, dass nicht-native Player wie video.js und hls.js toleranter gegenüber Streams mit dynamischer Bitrate und FPS sind, was WebRTC ist und nicht verlangsamt, wenn die Referenzimplementierung von Apple HLS im Wesentlichen in einem permanenten Einfrieren liegt.

3) Verwenden Sie RTMP als Stream-Quelle anstelle von WebRTC.
Obwohl das Flash nicht mehr unterstützt wird, wird das RTMP-Protokoll aktiv für das Streaming verwendet. Nehmen Sie dasselbe OBS Studio. Und ich muss zugeben, dass RTMP-Encoder im Allgemeinen gleichmäßigere Streams als WebRTC erzeugen und daher in HLS praktisch keine Fries erzeugen, d. H. Das Konvertieren von RTMP> HLS aus der Sicht von Friesen ist viel geeigneter, auch in nativen HLS-Playern. Wenn das Streaming vom Desktop und OBS ausgeführt wird, ist es daher besser, es für die Konvertierung in HLS zu verwenden. Wenn es sich bei der Quelle um einen Chrome-Browser handelt, kann RTMP nicht ohne die Installation von Plugins verwendet werden, und hier nur WebRTC.

Alle drei oben beschriebenen Methoden sind getestet und funktionieren, sodass die Möglichkeit besteht, basierend auf den Bedingungen der Aufgabe zu wählen.
WebRTC zu HLS auf CDN
In einem verteilten System können einige Probleme auftreten, wenn sich mehrere WebRTC-Stream-Delivery-Server zwischen der WebRTC-Stream-Quelle und dem HLS-Player befinden, in unserem Fall CDN , basierend auf dem WCS-Server. Es sieht so aus: Es gibt Origin - einen Server, der einen WebRTC-Stream empfängt, und es gibt Edge-Server, die diesen Stream einschließlich HLS verteilen. Es können viele Server vorhanden sein, was eine horizontale Skalierung des Systems ermöglicht. Beispielsweise können 1000 HLS-Server mit einem Origin-Server verbunden werden. In diesem Fall wird die Systemkapazität 1000-mal skaliert.

Das Problem wurde bereits etwas höher identifiziert und tritt normalerweise bei nativen Playern auf: iOS Safari, Mac OS Safari, Apple TV. Mit native meinen wir einen Player, der mit einer direkten Anzeige der URL der Wiedergabeliste im Tag arbeitet, zum Beispiel <video src="https://host/test.m3u8"/>
. Sobald der Player eine Wiedergabeliste angefordert hat und diese Aktion tatsächlich der erste Schritt beim Abspielen des HLS-Streams ist, muss der Server unverzüglich beginnen, HLS-Videosegmente auszusenden. Wenn der Server nicht sofort beginnt, Segmente zu vergeben, entscheidet der Spieler, dass er getäuscht wurde, und hört auf zu spielen. Auch dieses Verhalten ist typisch für die nativen HLS-Player von Apple, aber wir können den Benutzern nicht sagen: "Bitte verwenden Sie nicht den iPhone Mac und Apple TV, um HLS-Streams abzuspielen", die Benutzer werden es nicht verstehen.
Wenn Sie versuchen, den HLS-Stream auf dem Edgeserver abzuspielen, sollte der Server sofort mit der Rückgabe von Segmenten beginnen. Wie wird dies jedoch durchgeführt, wenn kein Stream vorhanden ist? Tatsächlich fehlt beim Versuch, einen Stream auf diesem Server abzuspielen. Die CDN-Logik funktioniert nach dem Prinzip des verzögerten Ladens - wir leiten den Stream erst zum Server, wenn jemand diesen Stream auf diesem Server anfordert. Beim ersten Verbindungsaufbau ist ein Problem aufgetreten. Der erste, der den HLS-Stream vom Edge-Server angefordert hat und dies vom nativen Apple-Player aus rücksichtslos getan hat, erhält einen Fries, da es einige Zeit dauert, diesen Stream vom Origin-Server zu bestellen und abzurufen auf Edge und fahren Sie mit dem HLS-Slicing fort. Selbst wenn es drei Sekunden dauert, speichert der Player es nicht. Er wird in den Fries gehen.

Auch hier drohen zwei Entscheidungen: Eine ist normal, die andere nicht sehr. Man könnte den Lazy Loading-Ansatz im CDN aufgeben und Datenverkehr an alle Knoten senden, unabhängig davon, ob sich Zuschauer dort befinden oder nicht. Eine Lösung, die möglicherweise für diejenigen geeignet ist, die in Bezug auf Verkehr und Rechenressourcen keine Einschränkungen aufweisen. Origin überträgt den Datenverkehr auf alle Edgeserver. Dadurch werden alle Server und das Netzwerk zwischen ihnen ständig geladen. Vielleicht wäre dieses Schema nur für einige spezifische Lösungen mit einer kleinen Anzahl von eingehenden Flüssen geeignet. Beim Replizieren einer großen Anzahl von Threads ist ein solches Schema eindeutig ressourcenschwach. Und wenn Sie sich daran erinnern, dass wir nur das „Problem der ersten Verbindung über den nativen Browser“ lösen, ist es offensichtlich, dass es sich nicht lohnt.

Die zweite Option ist eleganter, aber auch eine Problemumgehung. Wir geben dem ersten verbundenen Benutzer ein Videobild, aber dies ist immer noch nicht der Stream, den er sehen möchte - dies ist ein Preloader. Da wir jetzt etwas geben müssen und es sofort tun müssen, aber nicht über den Quelldatenstrom verfügen (dieser ist noch bestellt und wird von Origin geliefert), bitten wir den Kunden, etwas zu warten und ihm ein Video des Preloaders mit bewegter Animation zu zeigen. Der Benutzer wartet einige Sekunden, der Preloader dreht sich und wenn der echte Stream eintrifft, zeigt er den echten Stream an. Infolgedessen sahen der erste Benutzer den Preloader und die nachfolgenden Benutzer, die sich zuletzt verbunden hatten, den normalen HLS-Stream vom CDN, der nach dem Prinzip des Lazy Loading arbeitete. Engineering Problem behoben.
Aber nicht bis zum Ende
Es scheint, dass alles gut funktioniert. CDN funktioniert, HLS-Streams werden von Edge-Edge-Servern abgerufen und das Problem der ersten Verbindung ist behoben. Und hier ist eine weitere Tücke: Wir geben den Preloader in einem festen Seitenverhältnis von 16: 9 an, und CDN kann Streams jedes Formats enthalten: 16: 9, 4: 3, 2: 1 (VR-Video). Und das ist ein Problem, denn wenn Sie dem Player einen Preloader im 16: 9-Format geben und der bestellte Stream im 4: 3-Format vorliegt, wartet der native Player erneut auf den Fries.
Daher entsteht eine neue Aufgabe - Sie müssen wissen, mit welchem Seitenverhältnis der Stream in das CDN eingeht, und dem Preloader das gleiche Verhältnis geben. Eine Funktion von WebRTC-Streams ist die Beibehaltung des Seitenverhältnisses beim Ändern der Auflösung und während des Transcodierens. Wenn der Browser die Auflösung verringert, verringert er sie im gleichen Verhältnis. Wenn der Server beschließt, den Stream zu transkodieren, behält er das Seitenverhältnis im gleichen Verhältnis bei. Daher ist es logisch, dass wenn wir den Preloader für HLS anzeigen möchten, wir ihn in demselben Seitenverhältnis anzeigen, in dem der Stream eingeht.

Das CDN funktioniert folgendermaßen: Wenn Datenverkehr auf den Origin-Server gelangt, werden die anderen Server im Netzwerk, einschließlich der Edgeserver, über den neuen Stream informiert. Das Problem ist, dass zu diesem Zeitpunkt die Auflösung des Quellstroms möglicherweise noch nicht bekannt ist. Die Auflösung wird von den H.264-Bitstream-Konfigurationen zusammen mit dem Schlüsselbild übernommen. Daher kann es vorkommen, dass der Edgeserver Informationen darüber erhält, dass ein Stream vorhanden ist, die Auflösung und das Seitenverhältnis jedoch nicht kennen, sodass der Preloader nicht ordnungsgemäß generiert werden kann. In diesem Zusammenhang ist es nur dann erforderlich, das Vorhandensein eines Streams im CDN zu signalisieren, wenn ein Schlüsselframe vorhanden ist. Dies gibt garantiert Auskunft über die Größe des Edge-Servers und ermöglicht die Generierung des richtigen Preloaders, um „das Problem des ersten verbundenen Viewers“ zu vermeiden.

Zusammenfassung
Das Konvertieren von WebRTC in HLS bietet im Allgemeinen Friese, wenn es in nativen Apple-Playern abgespielt wird. Das Problem wird gelöst, indem der H.264-Bitstream analysiert und an die HLS-Anforderungen von Apple angepasst wird, entweder durch Transcodierung oder durch Migration auf das RTMP-Protokoll und den Encoder als Stream-Quelle. In einem verteilten Netzwerk mit verzögertem Laden von Streams gibt es ein Problem mit dem ersten verbundenen Viewer, das mithilfe des Preloaders gelöst wird und die Auflösung auf der Origin-Serverseite bestimmt - dem Eintrittspunkt des Streams im CDN.
Referenzen
Webanrufserver - WebRTC-Server
WebRTC-Streaming- CDN mit geringer Latenz - WCS-basiertes CDN
Wiedergabe von WebRTC- und RTMP-Videostreams über HLS - Serverfunktionen zum Konvertieren von Streams aus verschiedenen Quellen in HLS